Blame view

fs/xattr.c 17.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
    File: fs/xattr.c
  
    Extended attribute handling.
  
    Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
    Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
    Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
   */
  #include <linux/fs.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include <linux/file.h>
  #include <linux/xattr.h>
18f335aff   Dave Hansen   [PATCH] r/o bind ...
14
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/namei.h>
  #include <linux/security.h>
c7b87de23   Mimi Zohar   evm: evm_inode_po...
17
  #include <linux/evm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/syscalls.h>
630d9c472   Paul Gortmaker   fs: reduce the us...
19
  #include <linux/export.h>
0eeca2830   Robert Love   [PATCH] inotify
20
  #include <linux/fsnotify.h>
73241ccca   Amy Griffis   [PATCH] Collect m...
21
  #include <linux/audit.h>
0d08d7b7e   Andrew Morton   fs/xattr.c:listxa...
22
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

0d08d7b7e   Andrew Morton   fs/xattr.c:listxa...
24
  #include <asm/uaccess.h>
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
25

e0ad7b073   Andrew Morton   [PATCH] move xatt...
26
27
28
29
30
31
32
33
34
35
36
37
  /*
   * Check permissions for extended attribute access.  This is a bit complicated
   * because different namespaces have very different rules.
   */
  static int
  xattr_permission(struct inode *inode, const char *name, int mask)
  {
  	/*
  	 * We can never set or remove an extended attribute on a read-only
  	 * filesystem  or on an immutable / append-only inode.
  	 */
  	if (mask & MAY_WRITE) {
e0ad7b073   Andrew Morton   [PATCH] move xatt...
38
39
40
41
42
43
44
45
46
47
48
49
50
  		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
  			return -EPERM;
  	}
  
  	/*
  	 * No restriction for security.* and system.* from the VFS.  Decision
  	 * on these is left to the underlying filesystem / security module.
  	 */
  	if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
  	    !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  		return 0;
  
  	/*
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
51
  	 * The trusted.* namespace can only be accessed by privileged users.
e0ad7b073   Andrew Morton   [PATCH] move xatt...
52
  	 */
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
53
54
55
56
57
  	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
  		if (!capable(CAP_SYS_ADMIN))
  			return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
  		return 0;
  	}
e0ad7b073   Andrew Morton   [PATCH] move xatt...
58

55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
59
60
  	/*
  	 * In the user.* namespace, only regular files and directories can have
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
61
  	 * extended attributes. For sticky directories, only the owner and
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
62
  	 * privileged users can write attributes.
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
63
  	 */
e0ad7b073   Andrew Morton   [PATCH] move xatt...
64
  	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
65
  		if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
66
  			return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
67
  		if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
2e1496707   Serge E. Hallyn   userns: rename is...
68
  		    (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
e0ad7b073   Andrew Morton   [PATCH] move xatt...
69
70
  			return -EPERM;
  	}
f419a2e3b   Al Viro   [PATCH] kill name...
71
  	return inode_permission(inode, mask);
e0ad7b073   Andrew Morton   [PATCH] move xatt...
72
  }
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  /**
   *  __vfs_setxattr_noperm - perform setxattr operation without performing
   *  permission checks.
   *
   *  @dentry - object to perform setxattr on
   *  @name - xattr name to set
   *  @value - value to set @name to
   *  @size - size of @value
   *  @flags - flags to pass into filesystem operations
   *
   *  returns the result of the internal setxattr or setsecurity operations.
   *
   *  This function requires the caller to lock the inode's i_mutex before it
   *  is executed. It also assumes that the caller will make the appropriate
   *  permission checks.
   */
  int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
  		const void *value, size_t size, int flags)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
91
92
  {
  	struct inode *inode = dentry->d_inode;
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
93
  	int error = -EOPNOTSUPP;
69b457329   Andi Kleen   Cache xattr secur...
94
95
  	int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
  				   XATTR_SECURITY_PREFIX_LEN);
e0ad7b073   Andrew Morton   [PATCH] move xatt...
96

69b457329   Andi Kleen   Cache xattr secur...
97
98
  	if (issec)
  		inode->i_flags &= ~S_NOSEC;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
99
100
101
102
103
104
105
  	if (inode->i_op->setxattr) {
  		error = inode->i_op->setxattr(dentry, name, value, size, flags);
  		if (!error) {
  			fsnotify_xattr(dentry);
  			security_inode_post_setxattr(dentry, name, value,
  						     size, flags);
  		}
69b457329   Andi Kleen   Cache xattr secur...
106
  	} else if (issec) {
e0ad7b073   Andrew Morton   [PATCH] move xatt...
107
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
108
109
110
111
112
  		error = security_inode_setsecurity(inode, suffix, value,
  						   size, flags);
  		if (!error)
  			fsnotify_xattr(dentry);
  	}
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  
  	return error;
  }
  
  
  int
  vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
  		size_t size, int flags)
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	error = xattr_permission(inode, name, MAY_WRITE);
  	if (error)
  		return error;
  
  	mutex_lock(&inode->i_mutex);
  	error = security_inode_setxattr(dentry, name, value, size, flags);
  	if (error)
  		goto out;
  
  	error = __vfs_setxattr_noperm(dentry, name, value, size, flags);
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
135
136
137
138
139
140
141
  out:
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_setxattr);
  
  ssize_t
424925940   David P. Quigley   VFS/Security: Rew...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  xattr_getsecurity(struct inode *inode, const char *name, void *value,
  			size_t size)
  {
  	void *buffer = NULL;
  	ssize_t len;
  
  	if (!value || !size) {
  		len = security_inode_getsecurity(inode, name, &buffer, false);
  		goto out_noalloc;
  	}
  
  	len = security_inode_getsecurity(inode, name, &buffer, true);
  	if (len < 0)
  		return len;
  	if (size < len) {
  		len = -ERANGE;
  		goto out;
  	}
  	memcpy(value, buffer, len);
  out:
  	security_release_secctx(buffer, len);
  out_noalloc:
  	return len;
  }
  EXPORT_SYMBOL_GPL(xattr_getsecurity);
1601fbad2   Mimi Zohar   xattr: define vfs...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  /*
   * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
   *
   * Allocate memory, if not already allocated, or re-allocate correct size,
   * before retrieving the extended attribute.
   *
   * Returns the result of alloc, if failed, or the getxattr operation.
   */
  ssize_t
  vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
  		   size_t xattr_size, gfp_t flags)
  {
  	struct inode *inode = dentry->d_inode;
  	char *value = *xattr_value;
  	int error;
  
  	error = xattr_permission(inode, name, MAY_READ);
  	if (error)
  		return error;
  
  	if (!inode->i_op->getxattr)
  		return -EOPNOTSUPP;
  
  	error = inode->i_op->getxattr(dentry, name, NULL, 0);
  	if (error < 0)
  		return error;
  
  	if (!value || (error > xattr_size)) {
  		value = krealloc(*xattr_value, error + 1, flags);
  		if (!value)
  			return -ENOMEM;
  		memset(value, 0, error + 1);
  	}
  
  	error = inode->i_op->getxattr(dentry, name, value, error);
  	*xattr_value = value;
  	return error;
  }
  
  /* Compare an extended attribute value with the given value */
  int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
  		  const char *value, size_t size, gfp_t flags)
  {
  	char *xattr_value = NULL;
  	int rc;
  
  	rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
  	if (rc < 0)
  		return rc;
  
  	if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
  		rc = -EINVAL;
  	else
  		rc = 0;
  	kfree(xattr_value);
  	return rc;
  }
424925940   David P. Quigley   VFS/Security: Rew...
224
  ssize_t
8f0cfa52a   David Howells   xattr: add missin...
225
  vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
226
227
228
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
229
230
231
  	error = xattr_permission(inode, name, MAY_READ);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
232
233
234
  	error = security_inode_getxattr(dentry, name);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
235
  	if (!strncmp(name, XATTR_SECURITY_PREFIX,
e0ad7b073   Andrew Morton   [PATCH] move xatt...
236
237
  				XATTR_SECURITY_PREFIX_LEN)) {
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
424925940   David P. Quigley   VFS/Security: Rew...
238
  		int ret = xattr_getsecurity(inode, suffix, value, size);
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
239
240
241
242
  		/*
  		 * Only overwrite the return value if a security module
  		 * is actually active.
  		 */
4bea58053   David P. Quigley   VFS: Reorder vfs_...
243
244
245
  		if (ret == -EOPNOTSUPP)
  			goto nolsm;
  		return ret;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
246
  	}
4bea58053   David P. Quigley   VFS: Reorder vfs_...
247
248
249
250
251
  nolsm:
  	if (inode->i_op->getxattr)
  		error = inode->i_op->getxattr(dentry, name, value, size);
  	else
  		error = -EOPNOTSUPP;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
252
253
254
255
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_getxattr);
659564c8a   Bill Nottingham   [PATCH] Introduce...
256
257
258
259
260
261
262
263
264
  ssize_t
  vfs_listxattr(struct dentry *d, char *list, size_t size)
  {
  	ssize_t error;
  
  	error = security_inode_listxattr(d);
  	if (error)
  		return error;
  	error = -EOPNOTSUPP;
acfa4380e   Al Viro   inode->i_op is ne...
265
  	if (d->d_inode->i_op->listxattr) {
659564c8a   Bill Nottingham   [PATCH] Introduce...
266
267
268
269
270
271
272
273
274
  		error = d->d_inode->i_op->listxattr(d, list, size);
  	} else {
  		error = security_inode_listsecurity(d->d_inode, list, size);
  		if (size && error > size)
  			error = -ERANGE;
  	}
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_listxattr);
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
275
  int
8f0cfa52a   David Howells   xattr: add missin...
276
  vfs_removexattr(struct dentry *dentry, const char *name)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
277
278
279
280
281
282
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	if (!inode->i_op->removexattr)
  		return -EOPNOTSUPP;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
283
284
285
  	error = xattr_permission(inode, name, MAY_WRITE);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
286
287
288
289
290
291
292
  	error = security_inode_removexattr(dentry, name);
  	if (error)
  		return error;
  
  	mutex_lock(&inode->i_mutex);
  	error = inode->i_op->removexattr(dentry, name);
  	mutex_unlock(&inode->i_mutex);
c7b87de23   Mimi Zohar   evm: evm_inode_po...
293
  	if (!error) {
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
294
  		fsnotify_xattr(dentry);
c7b87de23   Mimi Zohar   evm: evm_inode_po...
295
296
  		evm_inode_post_removexattr(dentry, name);
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
297
298
299
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_removexattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
  /*
   * Extended attribute SET operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
304
  setxattr(struct dentry *d, const char __user *name, const void __user *value,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
  	 size_t size, int flags)
  {
  	int error;
  	void *kvalue = NULL;
44c824982   Andrew Morton   fs/xattr.c:setxat...
309
  	void *vvalue = NULL;	/* If non-NULL, we used vmalloc() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  	char kname[XATTR_NAME_MAX + 1];
  
  	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
  		return -EINVAL;
  
  	error = strncpy_from_user(kname, name, sizeof(kname));
  	if (error == 0 || error == sizeof(kname))
  		error = -ERANGE;
  	if (error < 0)
  		return error;
  
  	if (size) {
  		if (size > XATTR_SIZE_MAX)
  			return -E2BIG;
44c824982   Andrew Morton   fs/xattr.c:setxat...
324
325
326
327
328
329
330
331
332
333
334
  		kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
  		if (!kvalue) {
  			vvalue = vmalloc(size);
  			if (!vvalue)
  				return -ENOMEM;
  			kvalue = vvalue;
  		}
  		if (copy_from_user(kvalue, value, size)) {
  			error = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
336
  	error = vfs_setxattr(d, kname, kvalue, size, flags);
44c824982   Andrew Morton   fs/xattr.c:setxat...
337
338
339
340
341
  out:
  	if (vvalue)
  		vfree(vvalue);
  	else
  		kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
344
345
346
  SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
  		const char __user *, name, const void __user *, value,
  		size_t, size, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
348
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
350
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
353
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
354
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
355
356
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
357
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
358
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
361
362
363
  SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
  		const char __user *, name, const void __user *, value,
  		size_t, size, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
365
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
367
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
370
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
371
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
372
373
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
374
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
375
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
378
379
  SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
  		const void __user *,value, size_t, size, int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
382
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
386
387
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
388
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
389
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
390
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
391
392
  	if (!error) {
  		error = setxattr(dentry, name, value, size, flags);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
393
  		mnt_drop_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
394
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute GET operations
   */
  static ssize_t
8f0cfa52a   David Howells   xattr: add missin...
403
404
  getxattr(struct dentry *d, const char __user *name, void __user *value,
  	 size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
411
412
413
414
415
416
417
418
  {
  	ssize_t error;
  	void *kvalue = NULL;
  	char kname[XATTR_NAME_MAX + 1];
  
  	error = strncpy_from_user(kname, name, sizeof(kname));
  	if (error == 0 || error == sizeof(kname))
  		error = -ERANGE;
  	if (error < 0)
  		return error;
  
  	if (size) {
  		if (size > XATTR_SIZE_MAX)
  			size = XATTR_SIZE_MAX;
d381d8a9a   James Morris   [PATCH] SELinux: ...
419
  		kvalue = kzalloc(size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
  		if (!kvalue)
  			return -ENOMEM;
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
423
  	error = vfs_getxattr(d, kname, kvalue, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
424
425
426
427
428
429
430
  	if (error > 0) {
  		if (size && copy_to_user(value, kvalue, error))
  			error = -EFAULT;
  	} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
  		/* The file system tried to returned a value bigger
  		   than XATTR_SIZE_MAX bytes. Not possible. */
  		error = -E2BIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
432
  	kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
435
436
  SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
  		const char __user *, name, void __user *, value, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
438
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
440
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
443
444
  	error = getxattr(path.dentry, name, value, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
447
448
  SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
  		const char __user *, name, void __user *, value, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
450
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
452
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
455
456
  	error = getxattr(path.dentry, name, value, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
459
460
  SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
  		void __user *, value, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
  {
  	struct file *f;
  	ssize_t error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
5a190ae69   Al Viro   [PATCH] pass dent...
468
  	audit_inode(NULL, f->f_path.dentry);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
469
  	error = getxattr(f->f_path.dentry, name, value, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
476
477
478
479
480
481
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute LIST operations
   */
  static ssize_t
  listxattr(struct dentry *d, char __user *list, size_t size)
  {
  	ssize_t error;
  	char *klist = NULL;
0d08d7b7e   Andrew Morton   fs/xattr.c:listxa...
482
  	char *vlist = NULL;	/* If non-NULL, we used vmalloc() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
  
  	if (size) {
  		if (size > XATTR_LIST_MAX)
  			size = XATTR_LIST_MAX;
703bf2d12   Dave Jones   fs/xattr.c: suppr...
487
  		klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL);
0d08d7b7e   Andrew Morton   fs/xattr.c:listxa...
488
489
490
491
492
493
  		if (!klist) {
  			vlist = vmalloc(size);
  			if (!vlist)
  				return -ENOMEM;
  			klist = vlist;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  	}
659564c8a   Bill Nottingham   [PATCH] Introduce...
495
  	error = vfs_listxattr(d, klist, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
496
497
498
499
500
501
502
  	if (error > 0) {
  		if (size && copy_to_user(list, klist, error))
  			error = -EFAULT;
  	} else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
  		/* The file system tried to returned a list bigger
  		   than XATTR_LIST_MAX bytes. Not possible. */
  		error = -E2BIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  	}
0d08d7b7e   Andrew Morton   fs/xattr.c:listxa...
504
505
506
507
  	if (vlist)
  		vfree(vlist);
  	else
  		kfree(klist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
510
511
  SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
513
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
515
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
518
519
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
522
523
  SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
525
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
527
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
530
531
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
534
  SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
541
  {
  	struct file *f;
  	ssize_t error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
5a190ae69   Al Viro   [PATCH] pass dent...
542
  	audit_inode(NULL, f->f_path.dentry);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
543
  	error = listxattr(f->f_path.dentry, list, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
550
551
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute REMOVE operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
552
  removexattr(struct dentry *d, const char __user *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
557
558
559
560
561
  {
  	int error;
  	char kname[XATTR_NAME_MAX + 1];
  
  	error = strncpy_from_user(kname, name, sizeof(kname));
  	if (error == 0 || error == sizeof(kname))
  		error = -ERANGE;
  	if (error < 0)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
562
  	return vfs_removexattr(d, kname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
564
565
  SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
567
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
569
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
572
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
573
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
574
575
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
576
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
577
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
580
581
  SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
583
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
585
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
588
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
589
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
590
591
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
592
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
593
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
596
  SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
599
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
605
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
606
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
607
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
608
609
  	if (!error) {
  		error = removexattr(dentry, name);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
610
  		mnt_drop_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
611
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  	fput(f);
  	return error;
  }
  
  
  static const char *
  strcmp_prefix(const char *a, const char *a_prefix)
  {
  	while (*a_prefix && *a == *a_prefix) {
  		a++;
  		a_prefix++;
  	}
  	return *a_prefix ? NULL : a;
  }
  
  /*
   * In order to implement different sets of xattr operations for each xattr
   * prefix with the generic xattr API, a filesystem should create a
   * null-terminated array of struct xattr_handler (one for each prefix) and
   * hang a pointer to it off of the s_xattr field of the superblock.
   *
   * The generic_fooxattr() functions will use this list to dispatch xattr
   * operations to the correct xattr_handler.
   */
  #define for_each_xattr_handler(handlers, handler)		\
  		for ((handler) = *(handlers)++;			\
  			(handler) != NULL;			\
  			(handler) = *(handlers)++)
  
  /*
   * Find the xattr_handler with the matching prefix.
   */
bb4354538   Stephen Hemminger   fs: xattr_handler...
644
645
  static const struct xattr_handler *
  xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
647
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  
  	if (!*name)
  		return NULL;
  
  	for_each_xattr_handler(handlers, handler) {
  		const char *n = strcmp_prefix(*name, handler->prefix);
  		if (n) {
  			*name = n;
  			break;
  		}
  	}
  	return handler;
  }
  
  /*
   * Find the handler for the prefix and dispatch its get() operation.
   */
  ssize_t
  generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
668
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669

431547b3c   Christoph Hellwig   sanitize xattr ha...
670
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
673
  	return handler->get(dentry, name, buffer, size, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
678
679
680
681
682
  }
  
  /*
   * Combine the results of the list() operation from every xattr_handler in the
   * list.
   */
  ssize_t
  generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
683
  	const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
  	unsigned int size = 0;
  
  	if (!buffer) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
687
688
689
690
  		for_each_xattr_handler(handlers, handler) {
  			size += handler->list(dentry, NULL, 0, NULL, 0,
  					      handler->flags);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
694
  	} else {
  		char *buf = buffer;
  
  		for_each_xattr_handler(handlers, handler) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
695
696
  			size = handler->list(dentry, buf, buffer_size,
  					     NULL, 0, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  			if (size > buffer_size)
  				return -ERANGE;
  			buf += size;
  			buffer_size -= size;
  		}
  		size = buf - buffer;
  	}
  	return size;
  }
  
  /*
   * Find the handler for the prefix and dispatch its set() operation.
   */
  int
  generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
713
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
  
  	if (size == 0)
  		value = "";  /* empty EA, do not remove */
431547b3c   Christoph Hellwig   sanitize xattr ha...
717
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
  	if (!handler)
  		return -EOPNOTSUPP;
df7e13038   Jan Kara   vfs: Pass setxatt...
720
  	return handler->set(dentry, name, value, size, flags, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
726
727
728
729
  }
  
  /*
   * Find the handler for the prefix and dispatch its set() operation to remove
   * any associated extended attribute.
   */
  int
  generic_removexattr(struct dentry *dentry, const char *name)
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
730
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731

431547b3c   Christoph Hellwig   sanitize xattr ha...
732
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
735
736
  	return handler->set(dentry, name, NULL, 0,
  			    XATTR_REPLACE, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
741
742
  }
  
  EXPORT_SYMBOL(generic_getxattr);
  EXPORT_SYMBOL(generic_listxattr);
  EXPORT_SYMBOL(generic_setxattr);
  EXPORT_SYMBOL(generic_removexattr);