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