Blame view

fs/xattr.c 17.2 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
19
  #include <linux/syscalls.h>
  #include <linux/module.h>
0eeca2830   Robert Love   [PATCH] inotify
20
  #include <linux/fsnotify.h>
73241ccca   Amy Griffis   [PATCH] Collect m...
21
  #include <linux/audit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <asm/uaccess.h>
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
23

e0ad7b073   Andrew Morton   [PATCH] move xatt...
24
25
26
27
28
29
30
31
32
33
34
35
  /*
   * 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...
36
37
38
39
40
41
42
43
44
45
46
47
48
  		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 ...
49
  	 * The trusted.* namespace can only be accessed by privileged users.
e0ad7b073   Andrew Morton   [PATCH] move xatt...
50
  	 */
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
51
52
53
54
55
  	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...
56

55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
57
58
  	/*
  	 * In the user.* namespace, only regular files and directories can have
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
59
  	 * extended attributes. For sticky directories, only the owner and
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
60
  	 * privileged users can write attributes.
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
61
  	 */
e0ad7b073   Andrew Morton   [PATCH] move xatt...
62
  	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
63
  		if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
55b23bde1   Andreas Gruenbacher   xattr: Fix error ...
64
  			return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
65
  		if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
2e1496707   Serge E. Hallyn   userns: rename is...
66
  		    (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
e0ad7b073   Andrew Morton   [PATCH] move xatt...
67
68
  			return -EPERM;
  	}
f419a2e3b   Al Viro   [PATCH] kill name...
69
  	return inode_permission(inode, mask);
e0ad7b073   Andrew Morton   [PATCH] move xatt...
70
  }
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  /**
   *  __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_*...
89
90
  {
  	struct inode *inode = dentry->d_inode;
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
91
  	int error = -EOPNOTSUPP;
69b457329   Andi Kleen   Cache xattr secur...
92
93
  	int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
  				   XATTR_SECURITY_PREFIX_LEN);
e0ad7b073   Andrew Morton   [PATCH] move xatt...
94

69b457329   Andi Kleen   Cache xattr secur...
95
96
  	if (issec)
  		inode->i_flags &= ~S_NOSEC;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
97
98
99
100
101
102
103
  	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...
104
  	} else if (issec) {
e0ad7b073   Andrew Morton   [PATCH] move xatt...
105
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
106
107
108
109
110
  		error = security_inode_setsecurity(inode, suffix, value,
  						   size, flags);
  		if (!error)
  			fsnotify_xattr(dentry);
  	}
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  
  	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_*...
133
134
135
136
137
138
139
  out:
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_setxattr);
  
  ssize_t
424925940   David P. Quigley   VFS/Security: Rew...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  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...
165
166
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
  /*
   * 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...
222
  ssize_t
8f0cfa52a   David Howells   xattr: add missin...
223
  vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
224
225
226
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
227
228
229
  	error = xattr_permission(inode, name, MAY_READ);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
230
231
232
  	error = security_inode_getxattr(dentry, name);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
233
  	if (!strncmp(name, XATTR_SECURITY_PREFIX,
e0ad7b073   Andrew Morton   [PATCH] move xatt...
234
235
  				XATTR_SECURITY_PREFIX_LEN)) {
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
424925940   David P. Quigley   VFS/Security: Rew...
236
  		int ret = xattr_getsecurity(inode, suffix, value, size);
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
237
238
239
240
  		/*
  		 * Only overwrite the return value if a security module
  		 * is actually active.
  		 */
4bea58053   David P. Quigley   VFS: Reorder vfs_...
241
242
243
  		if (ret == -EOPNOTSUPP)
  			goto nolsm;
  		return ret;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
244
  	}
4bea58053   David P. Quigley   VFS: Reorder vfs_...
245
246
247
248
249
  nolsm:
  	if (inode->i_op->getxattr)
  		error = inode->i_op->getxattr(dentry, name, value, size);
  	else
  		error = -EOPNOTSUPP;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
250
251
252
253
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_getxattr);
659564c8a   Bill Nottingham   [PATCH] Introduce...
254
255
256
257
258
259
260
261
262
  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...
263
  	if (d->d_inode->i_op->listxattr) {
659564c8a   Bill Nottingham   [PATCH] Introduce...
264
265
266
267
268
269
270
271
272
  		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_*...
273
  int
8f0cfa52a   David Howells   xattr: add missin...
274
  vfs_removexattr(struct dentry *dentry, const char *name)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
275
276
277
278
279
280
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	if (!inode->i_op->removexattr)
  		return -EOPNOTSUPP;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
281
282
283
  	error = xattr_permission(inode, name, MAY_WRITE);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
284
285
286
287
288
289
290
  	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...
291
  	if (!error) {
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
292
  		fsnotify_xattr(dentry);
c7b87de23   Mimi Zohar   evm: evm_inode_po...
293
294
  		evm_inode_post_removexattr(dentry, name);
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
295
296
297
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_removexattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
  /*
   * Extended attribute SET operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
302
  setxattr(struct dentry *d, const char __user *name, const void __user *value,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  	 size_t size, int flags)
  {
  	int error;
  	void *kvalue = NULL;
  	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;
3939fcde2   Li Zefan   xattr: use memdup...
321
322
323
  		kvalue = memdup_user(value, size);
  		if (IS_ERR(kvalue))
  			return PTR_ERR(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
325
  	error = vfs_setxattr(d, kname, kvalue, size, flags);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
326
  	kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
329
330
331
  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
332
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
333
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
335
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
338
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
339
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
340
341
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
342
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
343
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
346
347
348
  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
349
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
350
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
352
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
355
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
356
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
357
358
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
359
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
360
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
363
364
  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
365
366
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
367
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
373
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
374
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
375
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
376
377
  	if (!error) {
  		error = setxattr(dentry, name, value, size, flags);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
378
  		mnt_drop_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
379
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute GET operations
   */
  static ssize_t
8f0cfa52a   David Howells   xattr: add missin...
388
389
  getxattr(struct dentry *d, const char __user *name, void __user *value,
  	 size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  {
  	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: ...
404
  		kvalue = kzalloc(size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
  		if (!kvalue)
  			return -ENOMEM;
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
408
  	error = vfs_getxattr(d, kname, kvalue, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
409
410
411
412
413
414
415
  	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
416
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
417
  	kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
420
421
  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
422
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
423
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
425
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
428
429
  	error = getxattr(path.dentry, name, value, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
432
433
  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
434
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
435
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
437
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
440
441
  	error = getxattr(path.dentry, name, value, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
444
445
  SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
  		void __user *, value, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
452
  {
  	struct file *f;
  	ssize_t error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
5a190ae69   Al Viro   [PATCH] pass dent...
453
  	audit_inode(NULL, f->f_path.dentry);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
454
  	error = getxattr(f->f_path.dentry, name, value, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	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;
  
  	if (size) {
  		if (size > XATTR_LIST_MAX)
  			size = XATTR_LIST_MAX;
  		klist = kmalloc(size, GFP_KERNEL);
  		if (!klist)
  			return -ENOMEM;
  	}
659564c8a   Bill Nottingham   [PATCH] Introduce...
475
  	error = vfs_listxattr(d, klist, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
476
477
478
479
480
481
482
  	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
483
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
484
  	kfree(klist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
487
488
  SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
490
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
492
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
495
496
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
499
500
  SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
502
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
504
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
507
508
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
511
  SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
516
517
518
  {
  	struct file *f;
  	ssize_t error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
5a190ae69   Al Viro   [PATCH] pass dent...
519
  	audit_inode(NULL, f->f_path.dentry);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
520
  	error = listxattr(f->f_path.dentry, list, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute REMOVE operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
529
  removexattr(struct dentry *d, const char __user *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
534
535
536
537
538
  {
  	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_*...
539
  	return vfs_removexattr(d, kname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
541
542
  SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
544
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
546
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
549
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
550
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
551
552
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
553
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
554
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
557
558
  SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
560
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
562
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
565
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
566
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
567
568
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
569
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
570
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
573
  SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
576
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
582
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
583
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
584
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
585
586
  	if (!error) {
  		error = removexattr(dentry, name);
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
587
  		mnt_drop_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
588
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  	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...
621
622
  static const struct xattr_handler *
  xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
624
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  
  	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...
645
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646

431547b3c   Christoph Hellwig   sanitize xattr ha...
647
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
650
  	return handler->get(dentry, name, buffer, size, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
658
659
  }
  
  /*
   * 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...
660
  	const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
  	unsigned int size = 0;
  
  	if (!buffer) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
664
665
666
667
  		for_each_xattr_handler(handlers, handler) {
  			size += handler->list(dentry, NULL, 0, NULL, 0,
  					      handler->flags);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
  	} else {
  		char *buf = buffer;
  
  		for_each_xattr_handler(handlers, handler) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
672
673
  			size = handler->list(dentry, buf, buffer_size,
  					     NULL, 0, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
  			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...
690
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
  
  	if (size == 0)
  		value = "";  /* empty EA, do not remove */
431547b3c   Christoph Hellwig   sanitize xattr ha...
694
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
  	if (!handler)
  		return -EOPNOTSUPP;
df7e13038   Jan Kara   vfs: Pass setxatt...
697
  	return handler->set(dentry, name, value, size, flags, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
  }
  
  /*
   * 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...
707
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708

431547b3c   Christoph Hellwig   sanitize xattr ha...
709
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
712
713
  	return handler->set(dentry, name, NULL, 0,
  			    XATTR_REPLACE, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
  }
  
  EXPORT_SYMBOL(generic_getxattr);
  EXPORT_SYMBOL(generic_listxattr);
  EXPORT_SYMBOL(generic_setxattr);
  EXPORT_SYMBOL(generic_removexattr);