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