Blame view

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

e0ad7b073   Andrew Morton   [PATCH] move xatt...
23
24
25
26
27
28
29
30
31
32
33
34
  /*
   * 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...
35
36
37
38
39
40
41
42
43
44
45
46
47
  		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;
  
  	/*
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
48
  	 * The trusted.* namespace can only be accessed by a privileged user.
e0ad7b073   Andrew Morton   [PATCH] move xatt...
49
50
51
  	 */
  	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
  		return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
52
53
54
55
  	/* In user.* namespace, only regular files and directories can have
  	 * extended attributes. For sticky directories, only the owner and
  	 * privileged user can write attributes.
  	 */
e0ad7b073   Andrew Morton   [PATCH] move xatt...
56
  	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
f1f2d8713   Andreas Gruenbacher   [PATCH] Fix user....
57
58
59
  		if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
  			return -EPERM;
  		if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
3bd858ab1   Satyam Sharma   Introduce is_owne...
60
  		    (mask & MAY_WRITE) && !is_owner_or_cap(inode))
e0ad7b073   Andrew Morton   [PATCH] move xatt...
61
62
  			return -EPERM;
  	}
f419a2e3b   Al Viro   [PATCH] kill name...
63
  	return inode_permission(inode, mask);
e0ad7b073   Andrew Morton   [PATCH] move xatt...
64
  }
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  /**
   *  __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_*...
83
84
  {
  	struct inode *inode = dentry->d_inode;
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
85
  	int error = -EOPNOTSUPP;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
86

5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
87
88
89
90
91
92
93
94
  	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);
  		}
  	} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
e0ad7b073   Andrew Morton   [PATCH] move xatt...
95
96
  				XATTR_SECURITY_PREFIX_LEN)) {
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
97
98
99
100
101
  		error = security_inode_setsecurity(inode, suffix, value,
  						   size, flags);
  		if (!error)
  			fsnotify_xattr(dentry);
  	}
b1ab7e4b2   David P. Quigley   VFS: Factor out p...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  
  	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_*...
124
125
126
127
128
129
130
  out:
  	mutex_unlock(&inode->i_mutex);
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_setxattr);
  
  ssize_t
424925940   David P. Quigley   VFS/Security: Rew...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  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);
  
  ssize_t
8f0cfa52a   David Howells   xattr: add missin...
158
  vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
159
160
161
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
162
163
164
  	error = xattr_permission(inode, name, MAY_READ);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
165
166
167
  	error = security_inode_getxattr(dentry, name);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
168
  	if (!strncmp(name, XATTR_SECURITY_PREFIX,
e0ad7b073   Andrew Morton   [PATCH] move xatt...
169
170
  				XATTR_SECURITY_PREFIX_LEN)) {
  		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
424925940   David P. Quigley   VFS/Security: Rew...
171
  		int ret = xattr_getsecurity(inode, suffix, value, size);
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
172
173
174
175
  		/*
  		 * Only overwrite the return value if a security module
  		 * is actually active.
  		 */
4bea58053   David P. Quigley   VFS: Reorder vfs_...
176
177
178
  		if (ret == -EOPNOTSUPP)
  			goto nolsm;
  		return ret;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
179
  	}
4bea58053   David P. Quigley   VFS: Reorder vfs_...
180
181
182
183
184
  nolsm:
  	if (inode->i_op->getxattr)
  		error = inode->i_op->getxattr(dentry, name, value, size);
  	else
  		error = -EOPNOTSUPP;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
185
186
187
188
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_getxattr);
659564c8a   Bill Nottingham   [PATCH] Introduce...
189
190
191
192
193
194
195
196
197
  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...
198
  	if (d->d_inode->i_op->listxattr) {
659564c8a   Bill Nottingham   [PATCH] Introduce...
199
200
201
202
203
204
205
206
207
  		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_*...
208
  int
8f0cfa52a   David Howells   xattr: add missin...
209
  vfs_removexattr(struct dentry *dentry, const char *name)
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
210
211
212
213
214
215
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	if (!inode->i_op->removexattr)
  		return -EOPNOTSUPP;
e0ad7b073   Andrew Morton   [PATCH] move xatt...
216
217
218
  	error = xattr_permission(inode, name, MAY_WRITE);
  	if (error)
  		return error;
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
219
220
221
222
223
224
225
226
227
228
229
230
231
  	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);
  
  	if (!error)
  		fsnotify_xattr(dentry);
  	return error;
  }
  EXPORT_SYMBOL_GPL(vfs_removexattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
  /*
   * Extended attribute SET operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
236
  setxattr(struct dentry *d, const char __user *name, const void __user *value,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  	 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...
255
256
257
  		kvalue = memdup_user(value, size);
  		if (IS_ERR(kvalue))
  			return PTR_ERR(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
259
  	error = vfs_setxattr(d, kname, kvalue, size, flags);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
260
  	kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
263
264
265
  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
266
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
267
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
269
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
272
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
273
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
274
275
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
276
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
277
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
280
281
282
  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
283
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
284
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
286
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
289
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
290
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
291
292
  		error = setxattr(path.dentry, name, value, size, flags);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
293
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
294
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
297
298
  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
299
300
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
301
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
307
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
308
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
309
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
310
311
312
313
  	if (!error) {
  		error = setxattr(dentry, name, value, size, flags);
  		mnt_drop_write(f->f_path.mnt);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
320
321
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute GET operations
   */
  static ssize_t
8f0cfa52a   David Howells   xattr: add missin...
322
323
  getxattr(struct dentry *d, const char __user *name, void __user *value,
  	 size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  {
  	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: ...
338
  		kvalue = kzalloc(size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  		if (!kvalue)
  			return -ENOMEM;
  	}
5be196e5f   Christoph Hellwig   [PATCH] add vfs_*...
342
  	error = vfs_getxattr(d, kname, kvalue, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
343
344
345
346
347
348
349
  	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
350
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
351
  	kfree(kvalue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
354
355
  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
356
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
357
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
359
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
362
363
  	error = getxattr(path.dentry, name, value, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
366
367
  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
368
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
369
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
371
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
374
375
  	error = getxattr(path.dentry, name, value, size);
  	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_DEFINE4(fgetxattr, int, fd, const char __user *, name,
  		void __user *, value, size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
  {
  	struct file *f;
  	ssize_t error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
5a190ae69   Al Viro   [PATCH] pass dent...
387
  	audit_inode(NULL, f->f_path.dentry);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
388
  	error = getxattr(f->f_path.dentry, name, value, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  	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...
409
  	error = vfs_listxattr(d, klist, size);
f549d6c18   Stephen Smalley   [PATCH] Generic V...
410
411
412
413
414
415
416
  	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
417
  	}
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
418
  	kfree(klist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
421
422
  SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
424
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
426
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
429
430
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
433
434
  SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
  		size_t, size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
436
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  	ssize_t error;
2d8f30380   Al Viro   [PATCH] sanitize ...
438
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
441
442
  	error = listxattr(path.dentry, list, size);
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  	return error;
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
445
  SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, 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 = listxattr(f->f_path.dentry, list, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
  	fput(f);
  	return error;
  }
  
  /*
   * Extended attribute REMOVE operations
   */
  static long
8f0cfa52a   David Howells   xattr: add missin...
463
  removexattr(struct dentry *d, const char __user *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
468
469
470
471
472
  {
  	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_*...
473
  	return vfs_removexattr(d, kname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  }
64fd1de3d   Heiko Carstens   [CVE-2009-0029] S...
475
476
  SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
478
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
480
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
483
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
484
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
485
486
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
487
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
488
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
491
492
  SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
  		const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
494
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
496
  	error = user_lpath(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  	if (error)
  		return error;
2d8f30380   Al Viro   [PATCH] sanitize ...
499
  	error = mnt_want_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
500
  	if (!error) {
2d8f30380   Al Viro   [PATCH] sanitize ...
501
502
  		error = removexattr(path.dentry, name);
  		mnt_drop_write(path.mnt);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
503
  	}
2d8f30380   Al Viro   [PATCH] sanitize ...
504
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
  	return error;
  }
6a6160a7b   Heiko Carstens   [CVE-2009-0029] S...
507
  SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  {
  	struct file *f;
73241ccca   Amy Griffis   [PATCH] Collect m...
510
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
  	int error = -EBADF;
  
  	f = fget(fd);
  	if (!f)
  		return error;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
516
  	dentry = f->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
517
  	audit_inode(NULL, dentry);
96029c4e0   npiggin@suse.de   fs: introduce mnt...
518
  	error = mnt_want_write_file(f);
18f335aff   Dave Hansen   [PATCH] r/o bind ...
519
520
521
522
  	if (!error) {
  		error = removexattr(dentry, name);
  		mnt_drop_write(f->f_path.mnt);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
  	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...
555
556
  static const struct xattr_handler *
  xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  {
bb4354538   Stephen Hemminger   fs: xattr_handler...
558
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  
  	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...
579
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

431547b3c   Christoph Hellwig   sanitize xattr ha...
581
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
584
  	return handler->get(dentry, name, buffer, size, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
  }
  
  /*
   * 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...
594
  	const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
  	unsigned int size = 0;
  
  	if (!buffer) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
598
599
600
601
  		for_each_xattr_handler(handlers, handler) {
  			size += handler->list(dentry, NULL, 0, NULL, 0,
  					      handler->flags);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
  	} else {
  		char *buf = buffer;
  
  		for_each_xattr_handler(handlers, handler) {
431547b3c   Christoph Hellwig   sanitize xattr ha...
606
607
  			size = handler->list(dentry, buf, buffer_size,
  					     NULL, 0, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  			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...
624
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  
  	if (size == 0)
  		value = "";  /* empty EA, do not remove */
431547b3c   Christoph Hellwig   sanitize xattr ha...
628
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
631
  	return handler->set(dentry, name, value, size, 0, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
637
638
639
640
  }
  
  /*
   * 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...
641
  	const struct xattr_handler *handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642

431547b3c   Christoph Hellwig   sanitize xattr ha...
643
  	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  	if (!handler)
  		return -EOPNOTSUPP;
431547b3c   Christoph Hellwig   sanitize xattr ha...
646
647
  	return handler->set(dentry, name, NULL, 0,
  			    XATTR_REPLACE, handler->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
  }
  
  EXPORT_SYMBOL(generic_getxattr);
  EXPORT_SYMBOL(generic_listxattr);
  EXPORT_SYMBOL(generic_setxattr);
  EXPORT_SYMBOL(generic_removexattr);