1 /* 2 * (C) 2001 Clemson University and The University of Chicago 3 * 4 * See COPYING in top-level directory. 5 */ 6 7 /* 8 * Linux VFS extended attribute operations. 9 */ 10 11 #include "protocol.h" 12 #include "orangefs-kernel.h" 13 #include "orangefs-bufmap.h" 14 #include <linux/posix_acl_xattr.h> 15 #include <linux/xattr.h> 16 17 18 #define SYSTEM_ORANGEFS_KEY "system.pvfs2." 19 #define SYSTEM_ORANGEFS_KEY_LEN 13 20 21 /* 22 * this function returns 23 * 0 if the key corresponding to name is not meant to be printed as part 24 * of a listxattr. 25 * 1 if the key corresponding to name is meant to be returned as part of 26 * a listxattr. 27 * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing. 28 */ 29 static int is_reserved_key(const char *key, size_t size) 30 { 31 32 if (size < SYSTEM_ORANGEFS_KEY_LEN) 33 return 1; 34 35 return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ? 1 : 0; 36 } 37 38 static inline int convert_to_internal_xattr_flags(int setxattr_flags) 39 { 40 int internal_flag = 0; 41 42 if (setxattr_flags & XATTR_REPLACE) { 43 /* Attribute must exist! */ 44 internal_flag = ORANGEFS_XATTR_REPLACE; 45 } else if (setxattr_flags & XATTR_CREATE) { 46 /* Attribute must not exist */ 47 internal_flag = ORANGEFS_XATTR_CREATE; 48 } 49 return internal_flag; 50 } 51 52 53 /* 54 * Tries to get a specified key's attributes of a given 55 * file into a user-specified buffer. Note that the getxattr 56 * interface allows for the users to probe the size of an 57 * extended attribute by passing in a value of 0 to size. 58 * Thus our return value is always the size of the attribute 59 * unless the key does not exist for the file and/or if 60 * there were errors in fetching the attribute value. 61 */ 62 ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, 63 void *buffer, size_t size) 64 { 65 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 66 struct orangefs_kernel_op_s *new_op = NULL; 67 ssize_t ret = -ENOMEM; 68 ssize_t length = 0; 69 int fsuid; 70 int fsgid; 71 72 gossip_debug(GOSSIP_XATTR_DEBUG, 73 "%s: name %s, buffer_size %zd\n", 74 __func__, name, size); 75 76 if (S_ISLNK(inode->i_mode)) 77 return -EOPNOTSUPP; 78 79 if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) { 80 gossip_err("Invalid key length (%d)\n", 81 (int)strlen(name)); 82 return -EINVAL; 83 } 84 85 fsuid = from_kuid(&init_user_ns, current_fsuid()); 86 fsgid = from_kgid(&init_user_ns, current_fsgid()); 87 88 gossip_debug(GOSSIP_XATTR_DEBUG, 89 "getxattr on inode %pU, name %s " 90 "(uid %o, gid %o)\n", 91 get_khandle_from_ino(inode), 92 name, 93 fsuid, 94 fsgid); 95 96 down_read(&orangefs_inode->xattr_sem); 97 98 new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR); 99 if (!new_op) 100 goto out_unlock; 101 102 new_op->upcall.req.getxattr.refn = orangefs_inode->refn; 103 strcpy(new_op->upcall.req.getxattr.key, name); 104 105 /* 106 * NOTE: Although keys are meant to be NULL terminated textual 107 * strings, I am going to explicitly pass the length just in case 108 * we change this later on... 109 */ 110 new_op->upcall.req.getxattr.key_sz = strlen(name) + 1; 111 112 ret = service_operation(new_op, "orangefs_inode_getxattr", 113 get_interruptible_flag(inode)); 114 if (ret != 0) { 115 if (ret == -ENOENT) { 116 ret = -ENODATA; 117 gossip_debug(GOSSIP_XATTR_DEBUG, 118 "orangefs_inode_getxattr: inode %pU key %s" 119 " does not exist!\n", 120 get_khandle_from_ino(inode), 121 (char *)new_op->upcall.req.getxattr.key); 122 } 123 goto out_release_op; 124 } 125 126 /* 127 * Length returned includes null terminator. 128 */ 129 length = new_op->downcall.resp.getxattr.val_sz; 130 131 /* 132 * Just return the length of the queried attribute. 133 */ 134 if (size == 0) { 135 ret = length; 136 goto out_release_op; 137 } 138 139 /* 140 * Check to see if key length is > provided buffer size. 141 */ 142 if (length > size) { 143 ret = -ERANGE; 144 goto out_release_op; 145 } 146 147 memcpy(buffer, new_op->downcall.resp.getxattr.val, length); 148 memset(buffer + length, 0, size - length); 149 gossip_debug(GOSSIP_XATTR_DEBUG, 150 "orangefs_inode_getxattr: inode %pU " 151 "key %s key_sz %d, val_len %d\n", 152 get_khandle_from_ino(inode), 153 (char *)new_op-> 154 upcall.req.getxattr.key, 155 (int)new_op-> 156 upcall.req.getxattr.key_sz, 157 (int)ret); 158 159 ret = length; 160 161 out_release_op: 162 op_release(new_op); 163 out_unlock: 164 up_read(&orangefs_inode->xattr_sem); 165 return ret; 166 } 167 168 static int orangefs_inode_removexattr(struct inode *inode, const char *name, 169 int flags) 170 { 171 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 172 struct orangefs_kernel_op_s *new_op = NULL; 173 int ret = -ENOMEM; 174 175 down_write(&orangefs_inode->xattr_sem); 176 new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); 177 if (!new_op) 178 goto out_unlock; 179 180 new_op->upcall.req.removexattr.refn = orangefs_inode->refn; 181 /* 182 * NOTE: Although keys are meant to be NULL terminated 183 * textual strings, I am going to explicitly pass the 184 * length just in case we change this later on... 185 */ 186 strcpy(new_op->upcall.req.removexattr.key, name); 187 new_op->upcall.req.removexattr.key_sz = strlen(name) + 1; 188 189 gossip_debug(GOSSIP_XATTR_DEBUG, 190 "orangefs_inode_removexattr: key %s, key_sz %d\n", 191 (char *)new_op->upcall.req.removexattr.key, 192 (int)new_op->upcall.req.removexattr.key_sz); 193 194 ret = service_operation(new_op, 195 "orangefs_inode_removexattr", 196 get_interruptible_flag(inode)); 197 if (ret == -ENOENT) { 198 /* 199 * Request to replace a non-existent attribute is an error. 200 */ 201 if (flags & XATTR_REPLACE) 202 ret = -ENODATA; 203 else 204 ret = 0; 205 } 206 207 gossip_debug(GOSSIP_XATTR_DEBUG, 208 "orangefs_inode_removexattr: returning %d\n", ret); 209 210 op_release(new_op); 211 out_unlock: 212 up_write(&orangefs_inode->xattr_sem); 213 return ret; 214 } 215 216 /* 217 * Tries to set an attribute for a given key on a file. 218 * 219 * Returns a -ve number on error and 0 on success. Key is text, but value 220 * can be binary! 221 */ 222 int orangefs_inode_setxattr(struct inode *inode, const char *name, 223 const void *value, size_t size, int flags) 224 { 225 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 226 struct orangefs_kernel_op_s *new_op; 227 int internal_flag = 0; 228 int ret = -ENOMEM; 229 230 gossip_debug(GOSSIP_XATTR_DEBUG, 231 "%s: name %s, buffer_size %zd\n", 232 __func__, name, size); 233 234 if (size >= ORANGEFS_MAX_XATTR_VALUELEN || 235 flags < 0) { 236 gossip_err("orangefs_inode_setxattr: bogus values of size(%d), flags(%d)\n", 237 (int)size, 238 flags); 239 return -EINVAL; 240 } 241 242 internal_flag = convert_to_internal_xattr_flags(flags); 243 244 if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) { 245 gossip_err 246 ("orangefs_inode_setxattr: bogus key size (%d)\n", 247 (int)(strlen(name))); 248 return -EINVAL; 249 } 250 251 /* This is equivalent to a removexattr */ 252 if (size == 0 && value == NULL) { 253 gossip_debug(GOSSIP_XATTR_DEBUG, 254 "removing xattr (%s)\n", 255 name); 256 return orangefs_inode_removexattr(inode, name, flags); 257 } 258 259 gossip_debug(GOSSIP_XATTR_DEBUG, 260 "setxattr on inode %pU, name %s\n", 261 get_khandle_from_ino(inode), 262 name); 263 264 down_write(&orangefs_inode->xattr_sem); 265 new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); 266 if (!new_op) 267 goto out_unlock; 268 269 270 new_op->upcall.req.setxattr.refn = orangefs_inode->refn; 271 new_op->upcall.req.setxattr.flags = internal_flag; 272 /* 273 * NOTE: Although keys are meant to be NULL terminated textual 274 * strings, I am going to explicitly pass the length just in 275 * case we change this later on... 276 */ 277 strcpy(new_op->upcall.req.setxattr.keyval.key, name); 278 new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1; 279 memcpy(new_op->upcall.req.setxattr.keyval.val, value, size); 280 new_op->upcall.req.setxattr.keyval.val_sz = size; 281 282 gossip_debug(GOSSIP_XATTR_DEBUG, 283 "orangefs_inode_setxattr: key %s, key_sz %d " 284 " value size %zd\n", 285 (char *)new_op->upcall.req.setxattr.keyval.key, 286 (int)new_op->upcall.req.setxattr.keyval.key_sz, 287 size); 288 289 ret = service_operation(new_op, 290 "orangefs_inode_setxattr", 291 get_interruptible_flag(inode)); 292 293 gossip_debug(GOSSIP_XATTR_DEBUG, 294 "orangefs_inode_setxattr: returning %d\n", 295 ret); 296 297 /* when request is serviced properly, free req op struct */ 298 op_release(new_op); 299 out_unlock: 300 up_write(&orangefs_inode->xattr_sem); 301 return ret; 302 } 303 304 /* 305 * Tries to get a specified object's keys into a user-specified buffer of a 306 * given size. Note that like the previous instances of xattr routines, this 307 * also allows you to pass in a NULL pointer and 0 size to probe the size for 308 * subsequent memory allocations. Thus our return value is always the size of 309 * all the keys unless there were errors in fetching the keys! 310 */ 311 ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size) 312 { 313 struct inode *inode = dentry->d_inode; 314 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 315 struct orangefs_kernel_op_s *new_op; 316 __u64 token = ORANGEFS_ITERATE_START; 317 ssize_t ret = -ENOMEM; 318 ssize_t total = 0; 319 int count_keys = 0; 320 int key_size; 321 int i = 0; 322 int returned_count = 0; 323 324 if (size > 0 && buffer == NULL) { 325 gossip_err("%s: bogus NULL pointers\n", __func__); 326 return -EINVAL; 327 } 328 329 down_read(&orangefs_inode->xattr_sem); 330 new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR); 331 if (!new_op) 332 goto out_unlock; 333 334 if (buffer && size > 0) 335 memset(buffer, 0, size); 336 337 try_again: 338 key_size = 0; 339 new_op->upcall.req.listxattr.refn = orangefs_inode->refn; 340 new_op->upcall.req.listxattr.token = token; 341 new_op->upcall.req.listxattr.requested_count = 342 (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN; 343 ret = service_operation(new_op, __func__, 344 get_interruptible_flag(inode)); 345 if (ret != 0) 346 goto done; 347 348 if (size == 0) { 349 /* 350 * This is a bit of a big upper limit, but I did not want to 351 * spend too much time getting this correct, since users end 352 * up allocating memory rather than us... 353 */ 354 total = new_op->downcall.resp.listxattr.returned_count * 355 ORANGEFS_MAX_XATTR_NAMELEN; 356 goto done; 357 } 358 359 returned_count = new_op->downcall.resp.listxattr.returned_count; 360 if (returned_count < 0 || 361 returned_count >= ORANGEFS_MAX_XATTR_LISTLEN) { 362 gossip_err("%s: impossible value for returned_count:%d:\n", 363 __func__, 364 returned_count); 365 ret = -EIO; 366 goto done; 367 } 368 369 /* 370 * Check to see how much can be fit in the buffer. Fit only whole keys. 371 */ 372 for (i = 0; i < returned_count; i++) { 373 if (new_op->downcall.resp.listxattr.lengths[i] < 0 || 374 new_op->downcall.resp.listxattr.lengths[i] > 375 ORANGEFS_MAX_XATTR_NAMELEN) { 376 gossip_err("%s: impossible value for lengths[%d]\n", 377 __func__, 378 new_op->downcall.resp.listxattr.lengths[i]); 379 ret = -EIO; 380 goto done; 381 } 382 if (total + new_op->downcall.resp.listxattr.lengths[i] > size) 383 goto done; 384 385 /* 386 * Since many dumb programs try to setxattr() on our reserved 387 * xattrs this is a feeble attempt at defeating those by not 388 * listing them in the output of listxattr.. sigh 389 */ 390 if (is_reserved_key(new_op->downcall.resp.listxattr.key + 391 key_size, 392 new_op->downcall.resp. 393 listxattr.lengths[i])) { 394 gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n", 395 i, new_op->downcall.resp.listxattr.key + 396 key_size); 397 memcpy(buffer + total, 398 new_op->downcall.resp.listxattr.key + key_size, 399 new_op->downcall.resp.listxattr.lengths[i]); 400 total += new_op->downcall.resp.listxattr.lengths[i]; 401 count_keys++; 402 } else { 403 gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n", 404 i, new_op->downcall.resp.listxattr.key + 405 key_size); 406 } 407 key_size += new_op->downcall.resp.listxattr.lengths[i]; 408 } 409 410 /* 411 * Since the buffer was large enough, we might have to continue 412 * fetching more keys! 413 */ 414 token = new_op->downcall.resp.listxattr.token; 415 if (token != ORANGEFS_ITERATE_END) 416 goto try_again; 417 418 done: 419 gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" 420 " [size of buffer %ld] (filled in %d keys)\n", 421 __func__, 422 ret ? (int)ret : (int)total, 423 (long)size, 424 count_keys); 425 op_release(new_op); 426 if (ret == 0) 427 ret = total; 428 out_unlock: 429 up_read(&orangefs_inode->xattr_sem); 430 return ret; 431 } 432 433 static int orangefs_xattr_set_default(const struct xattr_handler *handler, 434 struct dentry *unused, 435 struct inode *inode, 436 const char *name, 437 const void *buffer, 438 size_t size, 439 int flags) 440 { 441 return orangefs_inode_setxattr(inode, name, buffer, size, flags); 442 } 443 444 static int orangefs_xattr_get_default(const struct xattr_handler *handler, 445 struct dentry *unused, 446 struct inode *inode, 447 const char *name, 448 void *buffer, 449 size_t size) 450 { 451 return orangefs_inode_getxattr(inode, name, buffer, size); 452 453 } 454 455 static struct xattr_handler orangefs_xattr_default_handler = { 456 .prefix = "", /* match any name => handlers called with full name */ 457 .get = orangefs_xattr_get_default, 458 .set = orangefs_xattr_set_default, 459 }; 460 461 const struct xattr_handler *orangefs_xattr_handlers[] = { 462 &posix_acl_access_xattr_handler, 463 &posix_acl_default_xattr_handler, 464 &orangefs_xattr_default_handler, 465 NULL 466 }; 467