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 op->error = -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 dentry *dentry, 124 struct inode *inode, const char *name, 125 const void *buffer, size_t size, int flags) 126 { 127 struct afs_operation *op; 128 struct afs_vnode *vnode = AFS_FS_I(inode); 129 130 if (flags == XATTR_CREATE) 131 return -EINVAL; 132 133 op = afs_alloc_operation(NULL, vnode->volume); 134 if (IS_ERR(op)) 135 return -ENOMEM; 136 137 afs_op_set_vnode(op, 0, vnode); 138 if (!afs_make_acl(op, buffer, size)) 139 return afs_put_operation(op); 140 141 op->ops = &afs_store_acl_operation; 142 return afs_do_sync_operation(op); 143 } 144 145 static const struct xattr_handler afs_xattr_afs_acl_handler = { 146 .name = "afs.acl", 147 .get = afs_xattr_get_acl, 148 .set = afs_xattr_set_acl, 149 }; 150 151 static void yfs_acl_put(struct afs_operation *op) 152 { 153 yfs_free_opaque_acl(op->yacl); 154 } 155 156 static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = { 157 .issue_yfs_rpc = yfs_fs_fetch_opaque_acl, 158 .success = afs_acl_success, 159 /* Don't free op->yacl in .put here */ 160 }; 161 162 /* 163 * Get a file's YFS ACL. 164 */ 165 static int afs_xattr_get_yfs(const struct xattr_handler *handler, 166 struct dentry *dentry, 167 struct inode *inode, const char *name, 168 void *buffer, size_t size) 169 { 170 struct afs_operation *op; 171 struct afs_vnode *vnode = AFS_FS_I(inode); 172 struct yfs_acl *yacl = NULL; 173 char buf[16], *data; 174 int which = 0, dsize, ret = -ENOMEM; 175 176 if (strcmp(name, "acl") == 0) 177 which = 0; 178 else if (strcmp(name, "acl_inherited") == 0) 179 which = 1; 180 else if (strcmp(name, "acl_num_cleaned") == 0) 181 which = 2; 182 else if (strcmp(name, "vol_acl") == 0) 183 which = 3; 184 else 185 return -EOPNOTSUPP; 186 187 yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL); 188 if (!yacl) 189 goto error; 190 191 if (which == 0) 192 yacl->flags |= YFS_ACL_WANT_ACL; 193 else if (which == 3) 194 yacl->flags |= YFS_ACL_WANT_VOL_ACL; 195 196 op = afs_alloc_operation(NULL, vnode->volume); 197 if (IS_ERR(op)) 198 goto error_yacl; 199 200 afs_op_set_vnode(op, 0, vnode); 201 op->yacl = yacl; 202 op->ops = &yfs_fetch_opaque_acl_operation; 203 204 afs_begin_vnode_operation(op); 205 afs_wait_for_operation(op); 206 ret = afs_put_operation(op); 207 208 if (ret == 0) { 209 switch (which) { 210 case 0: 211 data = yacl->acl->data; 212 dsize = yacl->acl->size; 213 break; 214 case 1: 215 data = buf; 216 dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag); 217 break; 218 case 2: 219 data = buf; 220 dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned); 221 break; 222 case 3: 223 data = yacl->vol_acl->data; 224 dsize = yacl->vol_acl->size; 225 break; 226 default: 227 ret = -EOPNOTSUPP; 228 goto error_yacl; 229 } 230 231 ret = dsize; 232 if (size > 0) { 233 if (dsize <= size) 234 memcpy(buffer, data, dsize); 235 else 236 ret = -ERANGE; 237 } 238 } 239 240 error_yacl: 241 yfs_free_opaque_acl(yacl); 242 error: 243 return ret; 244 } 245 246 static const struct afs_operation_ops yfs_store_opaque_acl2_operation = { 247 .issue_yfs_rpc = yfs_fs_store_opaque_acl2, 248 .success = afs_acl_success, 249 .put = yfs_acl_put, 250 }; 251 252 /* 253 * Set a file's YFS ACL. 254 */ 255 static int afs_xattr_set_yfs(const struct xattr_handler *handler, 256 struct dentry *dentry, 257 struct inode *inode, const char *name, 258 const void *buffer, size_t size, int flags) 259 { 260 struct afs_operation *op; 261 struct afs_vnode *vnode = AFS_FS_I(inode); 262 263 if (flags == XATTR_CREATE || 264 strcmp(name, "acl") != 0) 265 return -EINVAL; 266 267 op = afs_alloc_operation(NULL, vnode->volume); 268 if (IS_ERR(op)) 269 return -ENOMEM; 270 271 afs_op_set_vnode(op, 0, vnode); 272 if (!afs_make_acl(op, buffer, size)) 273 return afs_put_operation(op); 274 275 op->ops = &yfs_store_opaque_acl2_operation; 276 return afs_do_sync_operation(op); 277 } 278 279 static const struct xattr_handler afs_xattr_yfs_handler = { 280 .prefix = "afs.yfs.", 281 .get = afs_xattr_get_yfs, 282 .set = afs_xattr_set_yfs, 283 }; 284 285 /* 286 * Get the name of the cell on which a file resides. 287 */ 288 static int afs_xattr_get_cell(const struct xattr_handler *handler, 289 struct dentry *dentry, 290 struct inode *inode, const char *name, 291 void *buffer, size_t size) 292 { 293 struct afs_vnode *vnode = AFS_FS_I(inode); 294 struct afs_cell *cell = vnode->volume->cell; 295 size_t namelen; 296 297 namelen = cell->name_len; 298 if (size == 0) 299 return namelen; 300 if (namelen > size) 301 return -ERANGE; 302 memcpy(buffer, cell->name, namelen); 303 return namelen; 304 } 305 306 static const struct xattr_handler afs_xattr_afs_cell_handler = { 307 .name = "afs.cell", 308 .get = afs_xattr_get_cell, 309 }; 310 311 /* 312 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of 313 * hex numbers separated by colons. 314 */ 315 static int afs_xattr_get_fid(const struct xattr_handler *handler, 316 struct dentry *dentry, 317 struct inode *inode, const char *name, 318 void *buffer, size_t size) 319 { 320 struct afs_vnode *vnode = AFS_FS_I(inode); 321 char text[16 + 1 + 24 + 1 + 8 + 1]; 322 size_t len; 323 324 /* The volume ID is 64-bit, the vnode ID is 96-bit and the 325 * uniquifier is 32-bit. 326 */ 327 len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid); 328 if (vnode->fid.vnode_hi) 329 len += scnprintf(text + len, sizeof(text) - len, "%x%016llx", 330 vnode->fid.vnode_hi, vnode->fid.vnode); 331 else 332 len += scnprintf(text + len, sizeof(text) - len, "%llx", 333 vnode->fid.vnode); 334 len += scnprintf(text + len, sizeof(text) - len, ":%x", 335 vnode->fid.unique); 336 337 if (size == 0) 338 return len; 339 if (len > size) 340 return -ERANGE; 341 memcpy(buffer, text, len); 342 return len; 343 } 344 345 static const struct xattr_handler afs_xattr_afs_fid_handler = { 346 .name = "afs.fid", 347 .get = afs_xattr_get_fid, 348 }; 349 350 /* 351 * Get the name of the volume on which a file resides. 352 */ 353 static int afs_xattr_get_volume(const struct xattr_handler *handler, 354 struct dentry *dentry, 355 struct inode *inode, const char *name, 356 void *buffer, size_t size) 357 { 358 struct afs_vnode *vnode = AFS_FS_I(inode); 359 const char *volname = vnode->volume->name; 360 size_t namelen; 361 362 namelen = strlen(volname); 363 if (size == 0) 364 return namelen; 365 if (namelen > size) 366 return -ERANGE; 367 memcpy(buffer, volname, namelen); 368 return namelen; 369 } 370 371 static const struct xattr_handler afs_xattr_afs_volume_handler = { 372 .name = "afs.volume", 373 .get = afs_xattr_get_volume, 374 }; 375 376 const struct xattr_handler *afs_xattr_handlers[] = { 377 &afs_xattr_afs_acl_handler, 378 &afs_xattr_afs_cell_handler, 379 &afs_xattr_afs_fid_handler, 380 &afs_xattr_afs_volume_handler, 381 &afs_xattr_yfs_handler, /* afs.yfs. prefix */ 382 NULL 383 }; 384