1 /*
2   File: fs/xattr.c
3 
4   Extended attribute handling.
5 
6   Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
7   Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
8  */
9 #include <linux/fs.h>
10 #include <linux/slab.h>
11 #include <linux/vmalloc.h>
12 #include <linux/smp_lock.h>
13 #include <linux/file.h>
14 #include <linux/xattr.h>
15 #include <asm/uaccess.h>
16 
17 /*
18  * Extended attribute memory allocation wrappers, originally
19  * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
20  * The vmalloc use here is very uncommon - extended attributes
21  * are supposed to be small chunks of metadata, and it is quite
22  * unusual to have very many extended attributes, so lists tend
23  * to be quite short as well.  The 64K upper limit is derived
24  * from the extended attribute size limit used by XFS.
25  * Intentionally allow zero @size for value/list size requests.
26  */
27 static void *
xattr_alloc(size_t size,size_t limit)28 xattr_alloc(size_t size, size_t limit)
29 {
30 	void *ptr;
31 
32 	if (size > limit)
33 		return ERR_PTR(-E2BIG);
34 
35 	if (!size)	/* size request, no buffer is needed */
36 		return NULL;
37 	else if (size <= PAGE_SIZE)
38 		ptr = kmalloc((unsigned long) size, GFP_KERNEL);
39 	else
40 		ptr = vmalloc((unsigned long) size);
41 	if (!ptr)
42 		return ERR_PTR(-ENOMEM);
43 	return ptr;
44 }
45 
46 static void
xattr_free(void * ptr,size_t size)47 xattr_free(void *ptr, size_t size)
48 {
49 	if (!size)	/* size request, no buffer was needed */
50 		return;
51 	else if (size <= PAGE_SIZE)
52 		kfree(ptr);
53 	else
54 		vfree(ptr);
55 }
56 
57 /*
58  * Extended attribute SET operations
59  */
60 static long
setxattr(struct dentry * d,char * name,void * value,size_t size,int flags)61 setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
62 {
63 	int error;
64 	void *kvalue;
65 	char kname[XATTR_NAME_MAX + 1];
66 
67 	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
68 		return -EINVAL;
69 
70 	error = strncpy_from_user(kname, name, sizeof(kname));
71 	if (error == 0 || error == sizeof(kname))
72 		error = -ERANGE;
73 	if (error < 0)
74 		return error;
75 
76 	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
77 	if (IS_ERR(kvalue))
78 		return PTR_ERR(kvalue);
79 
80 	if (size > 0 && copy_from_user(kvalue, value, size)) {
81 		xattr_free(kvalue, size);
82 		return -EFAULT;
83 	}
84 
85 	error = -EOPNOTSUPP;
86 	if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
87 		down(&d->d_inode->i_sem);
88 		lock_kernel();
89 		error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
90 		unlock_kernel();
91 		up(&d->d_inode->i_sem);
92 	}
93 
94 	xattr_free(kvalue, size);
95 	return error;
96 }
97 
98 asmlinkage long
sys_setxattr(char * path,char * name,void * value,size_t size,int flags)99 sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
100 {
101 	struct nameidata nd;
102 	int error;
103 
104 	error = user_path_walk(path, &nd);
105 	if (error)
106 		return error;
107 	error = setxattr(nd.dentry, name, value, size, flags);
108 	path_release(&nd);
109 	return error;
110 }
111 
112 asmlinkage long
sys_lsetxattr(char * path,char * name,void * value,size_t size,int flags)113 sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
114 {
115 	struct nameidata nd;
116 	int error;
117 
118 	error = user_path_walk_link(path, &nd);
119 	if (error)
120 		return error;
121 	error = setxattr(nd.dentry, name, value, size, flags);
122 	path_release(&nd);
123 	return error;
124 }
125 
126 asmlinkage long
sys_fsetxattr(int fd,char * name,void * value,size_t size,int flags)127 sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
128 {
129 	struct file *f;
130 	int error = -EBADF;
131 
132 	f = fget(fd);
133 	if (!f)
134 		return error;
135 	error = setxattr(f->f_dentry, name, value, size, flags);
136 	fput(f);
137 	return error;
138 }
139 
140 /*
141  * Extended attribute GET operations
142  */
143 static ssize_t
getxattr(struct dentry * d,char * name,void * value,size_t size)144 getxattr(struct dentry *d, char *name, void *value, size_t size)
145 {
146 	ssize_t error;
147 	void *kvalue;
148 	char kname[XATTR_NAME_MAX + 1];
149 
150 	error = strncpy_from_user(kname, name, sizeof(kname));
151 	if (error == 0 || error == sizeof(kname))
152 		error = -ERANGE;
153 	if (error < 0)
154 		return error;
155 
156 	kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
157 	if (IS_ERR(kvalue))
158 		return PTR_ERR(kvalue);
159 
160 	error = -EOPNOTSUPP;
161 	if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
162 		down(&d->d_inode->i_sem);
163 		lock_kernel();
164 		error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
165 		unlock_kernel();
166 		up(&d->d_inode->i_sem);
167 	}
168 
169 	if (kvalue && error > 0)
170 		if (copy_to_user(value, kvalue, error))
171 			error = -EFAULT;
172 	xattr_free(kvalue, size);
173 	return error;
174 }
175 
176 asmlinkage ssize_t
sys_getxattr(char * path,char * name,void * value,size_t size)177 sys_getxattr(char *path, char *name, void *value, size_t size)
178 {
179 	struct nameidata nd;
180 	ssize_t error;
181 
182 	error = user_path_walk(path, &nd);
183 	if (error)
184 		return error;
185 	error = getxattr(nd.dentry, name, value, size);
186 	path_release(&nd);
187 	return error;
188 }
189 
190 asmlinkage ssize_t
sys_lgetxattr(char * path,char * name,void * value,size_t size)191 sys_lgetxattr(char *path, char *name, void *value, size_t size)
192 {
193 	struct nameidata nd;
194 	ssize_t error;
195 
196 	error = user_path_walk_link(path, &nd);
197 	if (error)
198 		return error;
199 	error = getxattr(nd.dentry, name, value, size);
200 	path_release(&nd);
201 	return error;
202 }
203 
204 asmlinkage ssize_t
sys_fgetxattr(int fd,char * name,void * value,size_t size)205 sys_fgetxattr(int fd, char *name, void *value, size_t size)
206 {
207 	struct file *f;
208 	ssize_t error = -EBADF;
209 
210 	f = fget(fd);
211 	if (!f)
212 		return error;
213 	error = getxattr(f->f_dentry, name, value, size);
214 	fput(f);
215 	return error;
216 }
217 
218 /*
219  * Extended attribute LIST operations
220  */
221 static ssize_t
listxattr(struct dentry * d,char * list,size_t size)222 listxattr(struct dentry *d, char *list, size_t size)
223 {
224 	ssize_t error;
225 	char *klist;
226 
227 	klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
228 	if (IS_ERR(klist))
229 		return PTR_ERR(klist);
230 
231 	error = -EOPNOTSUPP;
232 	if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
233 		down(&d->d_inode->i_sem);
234 		lock_kernel();
235 		error = d->d_inode->i_op->listxattr(d, klist, size);
236 		unlock_kernel();
237 		up(&d->d_inode->i_sem);
238 	}
239 
240 	if (klist && error > 0)
241 		if (copy_to_user(list, klist, error))
242 			error = -EFAULT;
243 	xattr_free(klist, size);
244 	return error;
245 }
246 
247 asmlinkage ssize_t
sys_listxattr(char * path,char * list,size_t size)248 sys_listxattr(char *path, char *list, size_t size)
249 {
250 	struct nameidata nd;
251 	ssize_t error;
252 
253 	error = user_path_walk(path, &nd);
254 	if (error)
255 		return error;
256 	error = listxattr(nd.dentry, list, size);
257 	path_release(&nd);
258 	return error;
259 }
260 
261 asmlinkage ssize_t
sys_llistxattr(char * path,char * list,size_t size)262 sys_llistxattr(char *path, char *list, size_t size)
263 {
264 	struct nameidata nd;
265 	ssize_t error;
266 
267 	error = user_path_walk_link(path, &nd);
268 	if (error)
269 		return error;
270 	error = listxattr(nd.dentry, list, size);
271 	path_release(&nd);
272 	return error;
273 }
274 
275 asmlinkage ssize_t
sys_flistxattr(int fd,char * list,size_t size)276 sys_flistxattr(int fd, char *list, size_t size)
277 {
278 	struct file *f;
279 	ssize_t error = -EBADF;
280 
281 	f = fget(fd);
282 	if (!f)
283 		return error;
284 	error = listxattr(f->f_dentry, list, size);
285 	fput(f);
286 	return error;
287 }
288 
289 /*
290  * Extended attribute REMOVE operations
291  */
292 static long
removexattr(struct dentry * d,char * name)293 removexattr(struct dentry *d, char *name)
294 {
295 	int error;
296 	char kname[XATTR_NAME_MAX + 1];
297 
298 	error = strncpy_from_user(kname, name, sizeof(kname));
299 	if (error == 0 || error == sizeof(kname))
300 		error = -ERANGE;
301 	if (error < 0)
302 		return error;
303 
304 	error = -EOPNOTSUPP;
305 	if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
306 		down(&d->d_inode->i_sem);
307 		lock_kernel();
308 		error = d->d_inode->i_op->removexattr(d, kname);
309 		unlock_kernel();
310 		up(&d->d_inode->i_sem);
311 	}
312 	return error;
313 }
314 
315 asmlinkage long
sys_removexattr(char * path,char * name)316 sys_removexattr(char *path, char *name)
317 {
318 	struct nameidata nd;
319 	int error;
320 
321 	error = user_path_walk(path, &nd);
322 	if (error)
323 		return error;
324 	error = removexattr(nd.dentry, name);
325 	path_release(&nd);
326 	return error;
327 }
328 
329 asmlinkage long
sys_lremovexattr(char * path,char * name)330 sys_lremovexattr(char *path, char *name)
331 {
332 	struct nameidata nd;
333 	int error;
334 
335 	error = user_path_walk_link(path, &nd);
336 	if (error)
337 		return error;
338 	error = removexattr(nd.dentry, name);
339 	path_release(&nd);
340 	return error;
341 }
342 
343 asmlinkage long
sys_fremovexattr(int fd,char * name)344 sys_fremovexattr(int fd, char *name)
345 {
346 	struct file *f;
347 	int error = -EBADF;
348 
349 	f = fget(fd);
350 	if (!f)
351 		return error;
352 	error = removexattr(f->f_dentry, name);
353 	fput(f);
354 	return error;
355 }
356