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