1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * acl.c 4 * 5 * Copyright (C) 2004, 2008 Oracle. All rights reserved. 6 * 7 * CREDITS: 8 * Lots of code in this file is copy from linux/fs/ext3/acl.c. 9 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 10 */ 11 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 #include <linux/string.h> 16 #include <linux/fs_struct.h> 17 18 #include <cluster/masklog.h> 19 20 #include "ocfs2.h" 21 #include "alloc.h" 22 #include "dlmglue.h" 23 #include "file.h" 24 #include "inode.h" 25 #include "journal.h" 26 #include "ocfs2_fs.h" 27 28 #include "xattr.h" 29 #include "acl.h" 30 31 /* 32 * Convert from xattr value to acl struct. 33 */ 34 static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size) 35 { 36 int n, count; 37 struct posix_acl *acl; 38 39 if (!value) 40 return NULL; 41 if (size < sizeof(struct posix_acl_entry)) 42 return ERR_PTR(-EINVAL); 43 44 count = size / sizeof(struct posix_acl_entry); 45 46 acl = posix_acl_alloc(count, GFP_NOFS); 47 if (!acl) 48 return ERR_PTR(-ENOMEM); 49 for (n = 0; n < count; n++) { 50 struct ocfs2_acl_entry *entry = 51 (struct ocfs2_acl_entry *)value; 52 53 acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); 54 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); 55 switch(acl->a_entries[n].e_tag) { 56 case ACL_USER: 57 acl->a_entries[n].e_uid = 58 make_kuid(&init_user_ns, 59 le32_to_cpu(entry->e_id)); 60 break; 61 case ACL_GROUP: 62 acl->a_entries[n].e_gid = 63 make_kgid(&init_user_ns, 64 le32_to_cpu(entry->e_id)); 65 break; 66 default: 67 break; 68 } 69 value += sizeof(struct posix_acl_entry); 70 71 } 72 return acl; 73 } 74 75 /* 76 * Convert acl struct to xattr value. 77 */ 78 static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size) 79 { 80 struct ocfs2_acl_entry *entry = NULL; 81 char *ocfs2_acl; 82 size_t n; 83 84 *size = acl->a_count * sizeof(struct posix_acl_entry); 85 86 ocfs2_acl = kmalloc(*size, GFP_NOFS); 87 if (!ocfs2_acl) 88 return ERR_PTR(-ENOMEM); 89 90 entry = (struct ocfs2_acl_entry *)ocfs2_acl; 91 for (n = 0; n < acl->a_count; n++, entry++) { 92 entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); 93 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); 94 switch(acl->a_entries[n].e_tag) { 95 case ACL_USER: 96 entry->e_id = cpu_to_le32( 97 from_kuid(&init_user_ns, 98 acl->a_entries[n].e_uid)); 99 break; 100 case ACL_GROUP: 101 entry->e_id = cpu_to_le32( 102 from_kgid(&init_user_ns, 103 acl->a_entries[n].e_gid)); 104 break; 105 default: 106 entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); 107 break; 108 } 109 } 110 return ocfs2_acl; 111 } 112 113 static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, 114 int type, 115 struct buffer_head *di_bh) 116 { 117 int name_index; 118 char *value = NULL; 119 struct posix_acl *acl; 120 int retval; 121 122 switch (type) { 123 case ACL_TYPE_ACCESS: 124 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 125 break; 126 case ACL_TYPE_DEFAULT: 127 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 128 break; 129 default: 130 return ERR_PTR(-EINVAL); 131 } 132 133 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0); 134 if (retval > 0) { 135 value = kmalloc(retval, GFP_NOFS); 136 if (!value) 137 return ERR_PTR(-ENOMEM); 138 retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, 139 "", value, retval); 140 } 141 142 if (retval > 0) 143 acl = ocfs2_acl_from_xattr(value, retval); 144 else if (retval == -ENODATA || retval == 0) 145 acl = NULL; 146 else 147 acl = ERR_PTR(retval); 148 149 kfree(value); 150 151 return acl; 152 } 153 154 /* 155 * Helper function to set i_mode in memory and disk. Some call paths 156 * will not have di_bh or a journal handle to pass, in which case it 157 * will create it's own. 158 */ 159 static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, 160 handle_t *handle, umode_t new_mode) 161 { 162 int ret, commit_handle = 0; 163 struct ocfs2_dinode *di; 164 165 if (di_bh == NULL) { 166 ret = ocfs2_read_inode_block(inode, &di_bh); 167 if (ret) { 168 mlog_errno(ret); 169 goto out; 170 } 171 } else 172 get_bh(di_bh); 173 174 if (handle == NULL) { 175 handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), 176 OCFS2_INODE_UPDATE_CREDITS); 177 if (IS_ERR(handle)) { 178 ret = PTR_ERR(handle); 179 mlog_errno(ret); 180 goto out_brelse; 181 } 182 183 commit_handle = 1; 184 } 185 186 di = (struct ocfs2_dinode *)di_bh->b_data; 187 ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, 188 OCFS2_JOURNAL_ACCESS_WRITE); 189 if (ret) { 190 mlog_errno(ret); 191 goto out_commit; 192 } 193 194 inode->i_mode = new_mode; 195 inode_set_ctime_current(inode); 196 di->i_mode = cpu_to_le16(inode->i_mode); 197 di->i_ctime = cpu_to_le64(inode_get_ctime_sec(inode)); 198 di->i_ctime_nsec = cpu_to_le32(inode_get_ctime_nsec(inode)); 199 ocfs2_update_inode_fsync_trans(handle, inode, 0); 200 201 ocfs2_journal_dirty(handle, di_bh); 202 203 out_commit: 204 if (commit_handle) 205 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); 206 out_brelse: 207 brelse(di_bh); 208 out: 209 return ret; 210 } 211 212 /* 213 * Set the access or default ACL of an inode. 214 */ 215 static int ocfs2_set_acl(handle_t *handle, 216 struct inode *inode, 217 struct buffer_head *di_bh, 218 int type, 219 struct posix_acl *acl, 220 struct ocfs2_alloc_context *meta_ac, 221 struct ocfs2_alloc_context *data_ac) 222 { 223 int name_index; 224 void *value = NULL; 225 size_t size = 0; 226 int ret; 227 228 if (S_ISLNK(inode->i_mode)) 229 return -EOPNOTSUPP; 230 231 switch (type) { 232 case ACL_TYPE_ACCESS: 233 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; 234 break; 235 case ACL_TYPE_DEFAULT: 236 name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; 237 if (!S_ISDIR(inode->i_mode)) 238 return acl ? -EACCES : 0; 239 break; 240 default: 241 return -EINVAL; 242 } 243 244 if (acl) { 245 value = ocfs2_acl_to_xattr(acl, &size); 246 if (IS_ERR(value)) 247 return (int)PTR_ERR(value); 248 } 249 250 if (handle) 251 ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, 252 "", value, size, 0, 253 meta_ac, data_ac); 254 else 255 ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); 256 257 kfree(value); 258 if (!ret) 259 set_cached_acl(inode, type, acl); 260 261 return ret; 262 } 263 264 int ocfs2_iop_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 265 struct posix_acl *acl, int type) 266 { 267 struct buffer_head *bh = NULL; 268 int status, had_lock; 269 struct ocfs2_lock_holder oh; 270 struct inode *inode = d_inode(dentry); 271 272 had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh); 273 if (had_lock < 0) 274 return had_lock; 275 if (type == ACL_TYPE_ACCESS && acl) { 276 umode_t mode; 277 278 status = posix_acl_update_mode(&nop_mnt_idmap, inode, &mode, 279 &acl); 280 if (status) 281 goto unlock; 282 283 status = ocfs2_acl_set_mode(inode, bh, NULL, mode); 284 if (status) 285 goto unlock; 286 } 287 status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL); 288 unlock: 289 ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock); 290 brelse(bh); 291 return status; 292 } 293 294 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu) 295 { 296 struct ocfs2_super *osb; 297 struct buffer_head *di_bh = NULL; 298 struct posix_acl *acl; 299 int had_lock; 300 struct ocfs2_lock_holder oh; 301 302 if (rcu) 303 return ERR_PTR(-ECHILD); 304 305 osb = OCFS2_SB(inode->i_sb); 306 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 307 return NULL; 308 309 had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh); 310 if (had_lock < 0) 311 return ERR_PTR(had_lock); 312 313 down_read(&OCFS2_I(inode)->ip_xattr_sem); 314 acl = ocfs2_get_acl_nolock(inode, type, di_bh); 315 up_read(&OCFS2_I(inode)->ip_xattr_sem); 316 317 ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock); 318 brelse(di_bh); 319 return acl; 320 } 321 322 int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh) 323 { 324 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 325 struct posix_acl *acl; 326 int ret; 327 328 if (S_ISLNK(inode->i_mode)) 329 return -EOPNOTSUPP; 330 331 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 332 return 0; 333 334 down_read(&OCFS2_I(inode)->ip_xattr_sem); 335 acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh); 336 up_read(&OCFS2_I(inode)->ip_xattr_sem); 337 if (IS_ERR_OR_NULL(acl)) 338 return PTR_ERR_OR_ZERO(acl); 339 ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 340 if (ret) 341 return ret; 342 ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, 343 acl, NULL, NULL); 344 posix_acl_release(acl); 345 return ret; 346 } 347 348 /* 349 * Initialize the ACLs of a new inode. If parent directory has default ACL, 350 * then clone to new inode. Called from ocfs2_mknod. 351 */ 352 int ocfs2_init_acl(handle_t *handle, 353 struct inode *inode, 354 struct inode *dir, 355 struct buffer_head *di_bh, 356 struct buffer_head *dir_bh, 357 struct ocfs2_alloc_context *meta_ac, 358 struct ocfs2_alloc_context *data_ac) 359 { 360 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 361 struct posix_acl *acl = NULL; 362 int ret = 0, ret2; 363 umode_t mode; 364 365 if (!S_ISLNK(inode->i_mode)) { 366 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { 367 down_read(&OCFS2_I(dir)->ip_xattr_sem); 368 acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, 369 dir_bh); 370 up_read(&OCFS2_I(dir)->ip_xattr_sem); 371 if (IS_ERR(acl)) 372 return PTR_ERR(acl); 373 } 374 if (!acl) { 375 mode = inode->i_mode & ~current_umask(); 376 ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 377 if (ret) { 378 mlog_errno(ret); 379 goto cleanup; 380 } 381 } 382 } 383 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 384 if (S_ISDIR(inode->i_mode)) { 385 ret = ocfs2_set_acl(handle, inode, di_bh, 386 ACL_TYPE_DEFAULT, acl, 387 meta_ac, data_ac); 388 if (ret) 389 goto cleanup; 390 } 391 mode = inode->i_mode; 392 ret = __posix_acl_create(&acl, GFP_NOFS, &mode); 393 if (ret < 0) 394 return ret; 395 396 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 397 if (ret2) { 398 mlog_errno(ret2); 399 ret = ret2; 400 goto cleanup; 401 } 402 if (ret > 0) { 403 ret = ocfs2_set_acl(handle, inode, 404 di_bh, ACL_TYPE_ACCESS, 405 acl, meta_ac, data_ac); 406 } 407 } 408 cleanup: 409 posix_acl_release(acl); 410 return ret; 411 } 412