1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Extended attribute handling for AFS. We use xattrs to get and set metadata 3 * instead of providing pioctl(). 4 * 5 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 6 * Written by David Howells (dhowells@redhat.com) 7 */ 8 9 #include <linux/slab.h> 10 #include <linux/fs.h> 11 #include <linux/xattr.h> 12 #include "internal.h" 13 14 static const char afs_xattr_list[] = 15 "afs.acl\0" 16 "afs.cell\0" 17 "afs.fid\0" 18 "afs.volume\0" 19 "afs.yfs.acl\0" 20 "afs.yfs.acl_inherited\0" 21 "afs.yfs.acl_num_cleaned\0" 22 "afs.yfs.vol_acl"; 23 24 /* 25 * Retrieve a list of the supported xattrs. 26 */ 27 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) 28 { 29 if (size == 0) 30 return sizeof(afs_xattr_list); 31 if (size < sizeof(afs_xattr_list)) 32 return -ERANGE; 33 memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list)); 34 return sizeof(afs_xattr_list); 35 } 36 37 /* 38 * Deal with the result of a successful fetch ACL operation. 39 */ 40 static void afs_acl_success(struct afs_operation *op) 41 { 42 afs_vnode_commit_status(op, &op->file[0]); 43 } 44 45 static void afs_acl_put(struct afs_operation *op) 46 { 47 kfree(op->acl); 48 } 49 50 static const struct afs_operation_ops afs_fetch_acl_operation = { 51 .issue_afs_rpc = afs_fs_fetch_acl, 52 .success = afs_acl_success, 53 .put = afs_acl_put, 54 }; 55 56 /* 57 * Get a file's ACL. 58 */ 59 static int afs_xattr_get_acl(const struct xattr_handler *handler, 60 struct dentry *dentry, 61 struct inode *inode, const char *name, 62 void *buffer, size_t size) 63 { 64 struct afs_operation *op; 65 struct afs_vnode *vnode = AFS_FS_I(inode); 66 struct afs_acl *acl = NULL; 67 int ret; 68 69 op = afs_alloc_operation(NULL, vnode->volume); 70 if (IS_ERR(op)) 71 return -ENOMEM; 72 73 afs_op_set_vnode(op, 0, vnode); 74 op->ops = &afs_fetch_acl_operation; 75 76 afs_begin_vnode_operation(op); 77 afs_wait_for_operation(op); 78 acl = op->acl; 79 op->acl = NULL; 80 ret = afs_put_operation(op); 81 82 if (ret == 0) { 83 ret = acl->size; 84 if (size > 0) { 85 if (acl->size <= size) 86 memcpy(buffer, acl->data, acl->size); 87 else 88 ret = -ERANGE; 89 } 90 } 91 92 kfree(acl); 93 return ret; 94 } 95 96 static bool afs_make_acl(struct afs_operation *op, 97 const void *buffer, size_t size) 98 { 99 struct afs_acl *acl; 100 101 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 102 if (!acl) { 103 afs_op_nomem(op); 104 return false; 105 } 106 107 acl->size = size; 108 memcpy(acl->data, buffer, size); 109 op->acl = acl; 110 return true; 111 } 112 113 static const struct afs_operation_ops afs_store_acl_operation = { 114 .issue_afs_rpc = afs_fs_store_acl, 115 .success = afs_acl_success, 116 .put = afs_acl_put, 117 }; 118 119 /* 120 * Set a file's AFS3 ACL. 121 */ 122 static int afs_xattr_set_acl(const struct xattr_handler *handler, 123 struct user_namespace *mnt_userns, 124 struct dentry *dentry, 125 struct inode *inode, const char *name, 126 const void *buffer, size_t size, int flags) 127 { 128 struct afs_operation *op; 129 struct afs_vnode *vnode = AFS_FS_I(inode); 130 131 if (flags == XATTR_CREATE) 132 return -EINVAL; 133 134 op = afs_alloc_operation(NULL, vnode->volume); 135 if (IS_ERR(op)) 136 return -ENOMEM; 137 138 afs_op_set_vnode(op, 0, vnode); 139 if (!afs_make_acl(op, buffer, size)) 140 return afs_put_operation(op); 141 142 op->ops = &afs_store_acl_operation; 143 return afs_do_sync_operation(op); 144 } 145 146 static const struct xattr_handler afs_xattr_afs_acl_handler = { 147 .name = "afs.acl", 148 .get = afs_xattr_get_acl, 149 .set = afs_xattr_set_acl, 150 }; 151 152 static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = { 153 .issue_yfs_rpc = yfs_fs_fetch_opaque_acl, 154 .success = afs_acl_success, 155 /* Don't free op->yacl in .put here */ 156 }; 157 158 /* 159 * Get a file's YFS ACL. 160 */ 161 static int afs_xattr_get_yfs(const struct xattr_handler *handler, 162 struct dentry *dentry, 163 struct inode *inode, const char *name, 164 void *buffer, size_t size) 165 { 166 struct afs_operation *op; 167 struct afs_vnode *vnode = AFS_FS_I(inode); 168 struct yfs_acl *yacl = NULL; 169 char buf[16], *data; 170 int which = 0, dsize, ret = -ENOMEM; 171 172 if (strcmp(name, "acl") == 0) 173 which = 0; 174 else if (strcmp(name, "acl_inherited") == 0) 175 which = 1; 176 else if (strcmp(name, "acl_num_cleaned") == 0) 177 which = 2; 178 else if (strcmp(name, "vol_acl") == 0) 179 which = 3; 180 else 181 return -EOPNOTSUPP; 182 183 yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL); 184 if (!yacl) 185 goto error; 186 187 if (which == 0) 188 yacl->flags |= YFS_ACL_WANT_ACL; 189 else if (which == 3) 190 yacl->flags |= YFS_ACL_WANT_VOL_ACL; 191 192 op = afs_alloc_operation(NULL, vnode->volume); 193 if (IS_ERR(op)) 194 goto error_yacl; 195 196 afs_op_set_vnode(op, 0, vnode); 197 op->yacl = yacl; 198 op->ops = &yfs_fetch_opaque_acl_operation; 199 200 afs_begin_vnode_operation(op); 201 afs_wait_for_operation(op); 202 ret = afs_put_operation(op); 203 204 if (ret == 0) { 205 switch (which) { 206 case 0: 207 data = yacl->acl->data; 208 dsize = yacl->acl->size; 209 break; 210 case 1: 211 data = buf; 212 dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag); 213 break; 214 case 2: 215 data = buf; 216 dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned); 217 break; 218 case 3: 219 data = yacl->vol_acl->data; 220 dsize = yacl->vol_acl->size; 221 break; 222 default: 223 ret = -EOPNOTSUPP; 224 goto error_yacl; 225 } 226 227 ret = dsize; 228 if (size > 0) { 229 if (dsize <= size) 230 memcpy(buffer, data, dsize); 231 else 232 ret = -ERANGE; 233 } 234 } 235 236 error_yacl: 237 yfs_free_opaque_acl(yacl); 238 error: 239 return ret; 240 } 241 242 static const struct afs_operation_ops yfs_store_opaque_acl2_operation = { 243 .issue_yfs_rpc = yfs_fs_store_opaque_acl2, 244 .success = afs_acl_success, 245 .put = afs_acl_put, 246 }; 247 248 /* 249 * Set a file's YFS ACL. 250 */ 251 static int afs_xattr_set_yfs(const struct xattr_handler *handler, 252 struct user_namespace *mnt_userns, 253 struct dentry *dentry, 254 struct inode *inode, const char *name, 255 const void *buffer, size_t size, int flags) 256 { 257 struct afs_operation *op; 258 struct afs_vnode *vnode = AFS_FS_I(inode); 259 260 if (flags == XATTR_CREATE || 261 strcmp(name, "acl") != 0) 262 return -EINVAL; 263 264 op = afs_alloc_operation(NULL, vnode->volume); 265 if (IS_ERR(op)) 266 return -ENOMEM; 267 268 afs_op_set_vnode(op, 0, vnode); 269 if (!afs_make_acl(op, buffer, size)) 270 return afs_put_operation(op); 271 272 op->ops = &yfs_store_opaque_acl2_operation; 273 return afs_do_sync_operation(op); 274 } 275 276 static const struct xattr_handler afs_xattr_yfs_handler = { 277 .prefix = "afs.yfs.", 278 .get = afs_xattr_get_yfs, 279 .set = afs_xattr_set_yfs, 280 }; 281 282 /* 283 * Get the name of the cell on which a file resides. 284 */ 285 static int afs_xattr_get_cell(const struct xattr_handler *handler, 286 struct dentry *dentry, 287 struct inode *inode, const char *name, 288 void *buffer, size_t size) 289 { 290 struct afs_vnode *vnode = AFS_FS_I(inode); 291 struct afs_cell *cell = vnode->volume->cell; 292 size_t namelen; 293 294 namelen = cell->name_len; 295 if (size == 0) 296 return namelen; 297 if (namelen > size) 298 return -ERANGE; 299 memcpy(buffer, cell->name, namelen); 300 return namelen; 301 } 302 303 static const struct xattr_handler afs_xattr_afs_cell_handler = { 304 .name = "afs.cell", 305 .get = afs_xattr_get_cell, 306 }; 307 308 /* 309 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of 310 * hex numbers separated by colons. 311 */ 312 static int afs_xattr_get_fid(const struct xattr_handler *handler, 313 struct dentry *dentry, 314 struct inode *inode, const char *name, 315 void *buffer, size_t size) 316 { 317 struct afs_vnode *vnode = AFS_FS_I(inode); 318 char text[16 + 1 + 24 + 1 + 8 + 1]; 319 size_t len; 320 321 /* The volume ID is 64-bit, the vnode ID is 96-bit and the 322 * uniquifier is 32-bit. 323 */ 324 len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid); 325 if (vnode->fid.vnode_hi) 326 len += scnprintf(text + len, sizeof(text) - len, "%x%016llx", 327 vnode->fid.vnode_hi, vnode->fid.vnode); 328 else 329 len += scnprintf(text + len, sizeof(text) - len, "%llx", 330 vnode->fid.vnode); 331 len += scnprintf(text + len, sizeof(text) - len, ":%x", 332 vnode->fid.unique); 333 334 if (size == 0) 335 return len; 336 if (len > size) 337 return -ERANGE; 338 memcpy(buffer, text, len); 339 return len; 340 } 341 342 static const struct xattr_handler afs_xattr_afs_fid_handler = { 343 .name = "afs.fid", 344 .get = afs_xattr_get_fid, 345 }; 346 347 /* 348 * Get the name of the volume on which a file resides. 349 */ 350 static int afs_xattr_get_volume(const struct xattr_handler *handler, 351 struct dentry *dentry, 352 struct inode *inode, const char *name, 353 void *buffer, size_t size) 354 { 355 struct afs_vnode *vnode = AFS_FS_I(inode); 356 const char *volname = vnode->volume->name; 357 size_t namelen; 358 359 namelen = strlen(volname); 360 if (size == 0) 361 return namelen; 362 if (namelen > size) 363 return -ERANGE; 364 memcpy(buffer, volname, namelen); 365 return namelen; 366 } 367 368 static const struct xattr_handler afs_xattr_afs_volume_handler = { 369 .name = "afs.volume", 370 .get = afs_xattr_get_volume, 371 }; 372 373 const struct xattr_handler *afs_xattr_handlers[] = { 374 &afs_xattr_afs_acl_handler, 375 &afs_xattr_afs_cell_handler, 376 &afs_xattr_afs_fid_handler, 377 &afs_xattr_afs_volume_handler, 378 &afs_xattr_yfs_handler, /* afs.yfs. prefix */ 379 NULL 380 }; 381