Blame view

fs/open.c 26.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   *  linux/fs/open.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  #include <linux/string.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/file.h>
9f3acc314   Al Viro   [PATCH] split lin...
10
  #include <linux/fdtable.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/quotaops.h>
0eeca2830   Robert Love   [PATCH] inotify
12
  #include <linux/fsnotify.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/tty.h>
  #include <linux/namei.h>
  #include <linux/backing-dev.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
18
  #include <linux/capability.h>
086f7316f   Andrew G. Morgan   security: filesys...
19
  #include <linux/securebits.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
  #include <linux/security.h>
  #include <linux/mount.h>
  #include <linux/vfs.h>
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
23
  #include <linux/fcntl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <asm/uaccess.h>
  #include <linux/fs.h>
ef3daeda7   Yoav Zach   [PATCH] Don't for...
26
  #include <linux/personality.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  #include <linux/pagemap.h>
  #include <linux/syscalls.h>
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
29
  #include <linux/rcupdate.h>
73241ccca   Amy Griffis   [PATCH] Collect m...
30
  #include <linux/audit.h>
97ac73506   Amit Arora   sys_fallocate() i...
31
  #include <linux/falloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

726c33422   David Howells   [PATCH] VFS: Perm...
33
  int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  {
  	int retval = -ENODEV;
726c33422   David Howells   [PATCH] VFS: Perm...
36
  	if (dentry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  		retval = -ENOSYS;
726c33422   David Howells   [PATCH] VFS: Perm...
38
  		if (dentry->d_sb->s_op->statfs) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  			memset(buf, 0, sizeof(*buf));
726c33422   David Howells   [PATCH] VFS: Perm...
40
  			retval = security_sb_statfs(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  			if (retval)
  				return retval;
726c33422   David Howells   [PATCH] VFS: Perm...
43
  			retval = dentry->d_sb->s_op->statfs(dentry, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
  			if (retval == 0 && buf->f_frsize == 0)
  				buf->f_frsize = buf->f_bsize;
  		}
  	}
  	return retval;
  }
  
  EXPORT_SYMBOL(vfs_statfs);
726c33422   David Howells   [PATCH] VFS: Perm...
52
  static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
  {
  	struct kstatfs st;
  	int retval;
726c33422   David Howells   [PATCH] VFS: Perm...
56
  	retval = vfs_statfs(dentry, &st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
  	if (retval)
  		return retval;
  
  	if (sizeof(*buf) == sizeof(st))
  		memcpy(buf, &st, sizeof(st));
  	else {
  		if (sizeof buf->f_blocks == 4) {
f4a67ccee   Jon Tollefson   fs: check for sta...
64
65
  			if ((st.f_blocks | st.f_bfree | st.f_bavail |
  			     st.f_bsize | st.f_frsize) &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  			    0xffffffff00000000ULL)
  				return -EOVERFLOW;
  			/*
  			 * f_files and f_ffree may be -1; it's okay to stuff
  			 * that into 32 bits
  			 */
  			if (st.f_files != -1 &&
  			    (st.f_files & 0xffffffff00000000ULL))
  				return -EOVERFLOW;
  			if (st.f_ffree != -1 &&
  			    (st.f_ffree & 0xffffffff00000000ULL))
  				return -EOVERFLOW;
  		}
  
  		buf->f_type = st.f_type;
  		buf->f_bsize = st.f_bsize;
  		buf->f_blocks = st.f_blocks;
  		buf->f_bfree = st.f_bfree;
  		buf->f_bavail = st.f_bavail;
  		buf->f_files = st.f_files;
  		buf->f_ffree = st.f_ffree;
  		buf->f_fsid = st.f_fsid;
  		buf->f_namelen = st.f_namelen;
  		buf->f_frsize = st.f_frsize;
  		memset(buf->f_spare, 0, sizeof(buf->f_spare));
  	}
  	return 0;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
94
  static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
  {
  	struct kstatfs st;
  	int retval;
726c33422   David Howells   [PATCH] VFS: Perm...
98
  	retval = vfs_statfs(dentry, &st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  	if (retval)
  		return retval;
  
  	if (sizeof(*buf) == sizeof(st))
  		memcpy(buf, &st, sizeof(st));
  	else {
  		buf->f_type = st.f_type;
  		buf->f_bsize = st.f_bsize;
  		buf->f_blocks = st.f_blocks;
  		buf->f_bfree = st.f_bfree;
  		buf->f_bavail = st.f_bavail;
  		buf->f_files = st.f_files;
  		buf->f_ffree = st.f_ffree;
  		buf->f_fsid = st.f_fsid;
  		buf->f_namelen = st.f_namelen;
  		buf->f_frsize = st.f_frsize;
  		memset(buf->f_spare, 0, sizeof(buf->f_spare));
  	}
  	return 0;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
119
  SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
121
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
123
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  	if (!error) {
  		struct statfs tmp;
2d8f30380   Al Viro   [PATCH] sanitize ...
126
  		error = vfs_statfs_native(path.dentry, &tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  			error = -EFAULT;
2d8f30380   Al Viro   [PATCH] sanitize ...
129
  		path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
  	}
  	return error;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
133
  SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
135
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
  	long error;
  
  	if (sz != sizeof(*buf))
  		return -EINVAL;
2d8f30380   Al Viro   [PATCH] sanitize ...
140
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  	if (!error) {
  		struct statfs64 tmp;
2d8f30380   Al Viro   [PATCH] sanitize ...
143
  		error = vfs_statfs64(path.dentry, &tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  			error = -EFAULT;
2d8f30380   Al Viro   [PATCH] sanitize ...
146
  		path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
  	}
  	return error;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
150
  SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
158
159
  {
  	struct file * file;
  	struct statfs tmp;
  	int error;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
160
  	error = vfs_statfs_native(file->f_path.dentry, &tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
  	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  		error = -EFAULT;
  	fput(file);
  out:
  	return error;
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
167
  SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
173
174
175
176
177
178
179
  {
  	struct file * file;
  	struct statfs64 tmp;
  	int error;
  
  	if (sz != sizeof(*buf))
  		return -EINVAL;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
180
  	error = vfs_statfs64(file->f_path.dentry, &tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
  	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
  		error = -EFAULT;
  	fput(file);
  out:
  	return error;
  }
4a30131e7   NeilBrown   [PATCH] Fix some ...
187
188
  int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
  	struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
  {
  	int err;
  	struct iattr newattrs;
  
  	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
  	if (length < 0)
  		return -EINVAL;
  
  	newattrs.ia_size = length;
4a30131e7   NeilBrown   [PATCH] Fix some ...
198
  	newattrs.ia_valid = ATTR_SIZE | time_attrs;
cc4e69dee   Miklos Szeredi   [PATCH] VFS: pass...
199
200
201
202
  	if (filp) {
  		newattrs.ia_file = filp;
  		newattrs.ia_valid |= ATTR_FILE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

7b82dc0e6   Linus Torvalds   Remove suid/sgid ...
204
205
  	/* Remove suid/sgid on truncate too */
  	newattrs.ia_valid |= should_remove_suid(dentry);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
206
  	mutex_lock(&dentry->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	err = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
208
  	mutex_unlock(&dentry->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  	return err;
  }
2d8f30380   Al Viro   [PATCH] sanitize ...
211
  static long do_sys_truncate(const char __user *pathname, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
213
214
  	struct path path;
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
  	int error;
  
  	error = -EINVAL;
  	if (length < 0)	/* sorry, but loff_t says... */
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
220
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
223
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
227
228
229
230
231
232
  
  	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
  	error = -EISDIR;
  	if (S_ISDIR(inode->i_mode))
  		goto dput_and_out;
  
  	error = -EINVAL;
  	if (!S_ISREG(inode->i_mode))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
233
  	error = mnt_want_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  	if (error)
  		goto dput_and_out;
256984a83   Al Viro   [PATCH] preparati...
236
  	error = inode_permission(inode, MAY_WRITE);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
237
238
  	if (error)
  		goto mnt_drop_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  
  	error = -EPERM;
c82e42da8   Miklos Szeredi   [patch 1/5] vfs: ...
241
  	if (IS_APPEND(inode))
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
242
  		goto mnt_drop_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243

9700382c3   david m. richter   VFS: fix a race i...
244
  	error = get_write_access(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	if (error)
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
246
  		goto mnt_drop_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

9700382c3   david m. richter   VFS: fix a race i...
248
249
250
251
252
  	/*
  	 * Make sure that there are no leases.  get_write_access() protects
  	 * against the truncate racing with a lease-granting setlease().
  	 */
  	error = break_lease(inode, FMODE_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  	if (error)
9700382c3   david m. richter   VFS: fix a race i...
254
  		goto put_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  
  	error = locks_verify_truncate(inode, NULL, length);
be6d3e56a   Kentaro Takeda   introduce new LSM...
257
258
  	if (!error)
  		error = security_path_truncate(&path, length, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	if (!error) {
9e3509e27   Jan Kara   vfs: Use lowercas...
260
  		vfs_dq_init(inode);
2d8f30380   Al Viro   [PATCH] sanitize ...
261
  		error = do_truncate(path.dentry, length, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263

9700382c3   david m. richter   VFS: fix a race i...
264
265
  put_write_and_out:
  	put_write_access(inode);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
266
  mnt_drop_write_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
267
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
269
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
  out:
  	return error;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
273
  SYSCALL_DEFINE2(truncate, const char __user *, path, unsigned long, length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
  {
  	/* on 32-bit boxen it will cut the range 2^31--2^32-1 off */
  	return do_sys_truncate(path, (long)length);
  }
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
278
  static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  {
  	struct inode * inode;
  	struct dentry *dentry;
  	struct file * file;
  	int error;
  
  	error = -EINVAL;
  	if (length < 0)
  		goto out;
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
  
  	/* explicitly opened as large or we are on 64-bit box */
  	if (file->f_flags & O_LARGEFILE)
  		small = 0;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
296
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  	inode = dentry->d_inode;
  	error = -EINVAL;
  	if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
  		goto out_putf;
  
  	error = -EINVAL;
  	/* Cannot ftruncate over 2^31 bytes without large file support */
  	if (small && length > MAX_NON_LFS)
  		goto out_putf;
  
  	error = -EPERM;
  	if (IS_APPEND(inode))
  		goto out_putf;
  
  	error = locks_verify_truncate(inode, file, length);
  	if (!error)
be6d3e56a   Kentaro Takeda   introduce new LSM...
313
314
315
  		error = security_path_truncate(&file->f_path, length,
  					       ATTR_MTIME|ATTR_CTIME);
  	if (!error)
6e656be89   Peter Staubach   [PATCH] ftruncate...
316
  		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
  out_putf:
  	fput(file);
  out:
  	return error;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
322
  SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
324
  	long ret = do_sys_ftruncate(fd, length, 1);
385910f2b   Linus Torvalds   x86: be careful a...
325
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
326
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
327
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
  }
  
  /* LFS versions of truncate are only needed on 32 bit machines */
  #if BITS_PER_LONG == 32
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
332
  SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
  {
  	return do_sys_truncate(path, length);
  }
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
336
337
338
339
340
341
342
  #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
  asmlinkage long SyS_truncate64(long path, loff_t length)
  {
  	return SYSC_truncate64((const char __user *) path, length);
  }
  SYSCALL_ALIAS(sys_truncate64, SyS_truncate64);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
344
  SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
346
  	long ret = do_sys_ftruncate(fd, length, 0);
385910f2b   Linus Torvalds   x86: be careful a...
347
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
348
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
349
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  }
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
351
352
353
354
355
356
  #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
  asmlinkage long SyS_ftruncate64(long fd, loff_t length)
  {
  	return SYSC_ftruncate64((unsigned int) fd, length);
  }
  SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  #endif
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
358
  #endif /* BITS_PER_LONG == 32 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
360
  SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
97ac73506   Amit Arora   sys_fallocate() i...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  {
  	struct file *file;
  	struct inode *inode;
  	long ret = -EINVAL;
  
  	if (offset < 0 || len <= 0)
  		goto out;
  
  	/* Return error if mode is not supported */
  	ret = -EOPNOTSUPP;
  	if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
  		goto out;
  
  	ret = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
  	if (!(file->f_mode & FMODE_WRITE))
  		goto out_fput;
  	/*
  	 * Revalidate the write permissions, in case security policy has
  	 * changed since the files were opened.
  	 */
  	ret = security_file_permission(file, MAY_WRITE);
  	if (ret)
  		goto out_fput;
  
  	inode = file->f_path.dentry->d_inode;
  
  	ret = -ESPIPE;
  	if (S_ISFIFO(inode->i_mode))
  		goto out_fput;
  
  	ret = -ENODEV;
  	/*
  	 * Let individual file system decide if it supports preallocation
  	 * for directories or not.
  	 */
  	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
  		goto out_fput;
  
  	ret = -EFBIG;
  	/* Check for wrap through zero too */
  	if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
  		goto out_fput;
acfa4380e   Al Viro   inode->i_op is ne...
406
  	if (inode->i_op->fallocate)
97ac73506   Amit Arora   sys_fallocate() i...
407
408
  		ret = inode->i_op->fallocate(inode, mode, offset, len);
  	else
0d786d4a2   Ulrich Drepper   fallocate syscall...
409
  		ret = -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
410
411
412
413
414
415
  
  out_fput:
  	fput(file);
  out:
  	return ret;
  }
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
416
417
418
419
420
421
422
  #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
  asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
  {
  	return SYSC_fallocate((int)fd, (int)mode, offset, len);
  }
  SYSCALL_ALIAS(sys_fallocate, SyS_fallocate);
  #endif
97ac73506   Amit Arora   sys_fallocate() i...
423

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
428
  /*
   * access() needs to use the real uid/gid, not the effective uid/gid.
   * We do this by temporarily clearing all FS-related capabilities and
   * switching the fsuid/fsgid around to the real ones.
   */
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
429
  SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  {
d84f4f992   David Howells   CRED: Inaugurate ...
431
432
  	const struct cred *old_cred;
  	struct cred *override_cred;
2d8f30380   Al Viro   [PATCH] sanitize ...
433
  	struct path path;
256984a83   Al Viro   [PATCH] preparati...
434
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
  	int res;
  
  	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
439
440
441
  	override_cred = prepare_creds();
  	if (!override_cred)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

d84f4f992   David Howells   CRED: Inaugurate ...
443
444
  	override_cred->fsuid = override_cred->uid;
  	override_cred->fsgid = override_cred->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445

086f7316f   Andrew G. Morgan   security: filesys...
446
  	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
1cdcbec1a   David Howells   CRED: Neuter sys_...
447
  		/* Clear the capabilities if we switch to a non-root user */
d84f4f992   David Howells   CRED: Inaugurate ...
448
449
  		if (override_cred->uid)
  			cap_clear(override_cred->cap_effective);
086f7316f   Andrew G. Morgan   security: filesys...
450
  		else
d84f4f992   David Howells   CRED: Inaugurate ...
451
452
  			override_cred->cap_effective =
  				override_cred->cap_permitted;
086f7316f   Andrew G. Morgan   security: filesys...
453
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

d84f4f992   David Howells   CRED: Inaugurate ...
455
  	old_cred = override_creds(override_cred);
2d8f30380   Al Viro   [PATCH] sanitize ...
456
  	res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
457
458
  	if (res)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
459
  	inode = path.dentry->d_inode;
256984a83   Al Viro   [PATCH] preparati...
460
461
  
  	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
30524472c   Al Viro   [PATCH] take noex...
462
463
464
465
466
  		/*
  		 * MAY_EXEC on regular files is denied if the fs is mounted
  		 * with the "noexec" flag.
  		 */
  		res = -EACCES;
2d8f30380   Al Viro   [PATCH] sanitize ...
467
  		if (path.mnt->mnt_flags & MNT_NOEXEC)
30524472c   Al Viro   [PATCH] take noex...
468
469
  			goto out_path_release;
  	}
256984a83   Al Viro   [PATCH] preparati...
470
  	res = inode_permission(inode, mode | MAY_ACCESS);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
471
  	/* SuS v2 requires we report a read only fs too */
256984a83   Al Viro   [PATCH] preparati...
472
  	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
473
  		goto out_path_release;
2f676cbc0   Dave Hansen   [PATCH] r/o bind ...
474
475
476
477
478
479
480
481
482
483
  	/*
  	 * This is a rare case where using __mnt_is_readonly()
  	 * is OK without a mnt_want/drop_write() pair.  Since
  	 * no actual write to the fs is performed here, we do
  	 * not need to telegraph to that to anyone.
  	 *
  	 * By doing this, we accept that this access is
  	 * inherently racy and know that the fs may change
  	 * state before we even see this result.
  	 */
2d8f30380   Al Viro   [PATCH] sanitize ...
484
  	if (__mnt_is_readonly(path.mnt))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
485
  		res = -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486

6902d925d   Dave Hansen   [PATCH] r/o bind ...
487
  out_path_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
488
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
489
  out:
d84f4f992   David Howells   CRED: Inaugurate ...
490
491
  	revert_creds(old_cred);
  	put_cred(override_cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
  	return res;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
494
  SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
495
496
497
  {
  	return sys_faccessat(AT_FDCWD, filename, mode);
  }
3cdad4288   Heiko Carstens   [CVE-2009-0029] S...
498
  SYSCALL_DEFINE1(chdir, const char __user *, filename)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
500
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
502
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
505
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
  	if (error)
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
508
  	set_fs_pwd(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
511
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
  out:
  	return error;
  }
3cdad4288   Heiko Carstens   [CVE-2009-0029] S...
515
  SYSCALL_DEFINE1(fchdir, unsigned int, fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  {
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
  	int error;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
ac748a09f   Jan Blunck   Make set_fs_{root...
525
  	inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
  
  	error = -ENOTDIR;
  	if (!S_ISDIR(inode->i_mode))
  		goto out_putf;
256984a83   Al Viro   [PATCH] preparati...
530
  	error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  	if (!error)
ac748a09f   Jan Blunck   Make set_fs_{root...
532
  		set_fs_pwd(current->fs, &file->f_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
  out_putf:
  	fput(file);
  out:
  	return error;
  }
3480b2574   Heiko Carstens   [CVE-2009-0029] S...
538
  SYSCALL_DEFINE1(chroot, const char __user *, filename)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
540
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
542
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
545
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
551
  	if (error)
  		goto dput_and_out;
  
  	error = -EPERM;
  	if (!capable(CAP_SYS_CHROOT))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
552
  	set_fs_root(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
  	error = 0;
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
555
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
  out:
  	return error;
  }
a26eab240   Heiko Carstens   [CVE-2009-0029] S...
559
  SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
565
566
567
568
569
  {
  	struct inode * inode;
  	struct dentry * dentry;
  	struct file * file;
  	int err = -EBADF;
  	struct iattr newattrs;
  
  	file = fget(fd);
  	if (!file)
  		goto out;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
570
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  	inode = dentry->d_inode;
5a190ae69   Al Viro   [PATCH] pass dent...
572
  	audit_inode(NULL, dentry);
73241ccca   Amy Griffis   [PATCH] Collect m...
573

2af482a7e   Dave Hansen   [PATCH] r/o bind ...
574
575
  	err = mnt_want_write(file->f_path.mnt);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  		goto out_putf;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
577
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
  	if (mode == (mode_t) -1)
  		mode = inode->i_mode;
  	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
  	err = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
583
  	mutex_unlock(&inode->i_mutex);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
584
  	mnt_drop_write(file->f_path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
  out_putf:
  	fput(file);
  out:
  	return err;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
590
  SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
592
593
  	struct path path;
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  	int error;
  	struct iattr newattrs;
2d8f30380   Al Viro   [PATCH] sanitize ...
596
  	error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
599
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600

2d8f30380   Al Viro   [PATCH] sanitize ...
601
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
602
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  		goto dput_and_out;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
604
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
  	if (mode == (mode_t) -1)
  		mode = inode->i_mode;
  	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
2d8f30380   Al Viro   [PATCH] sanitize ...
609
  	error = notify_change(path.dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
610
  	mutex_unlock(&inode->i_mutex);
2d8f30380   Al Viro   [PATCH] sanitize ...
611
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
613
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
  out:
  	return error;
  }
a26eab240   Heiko Carstens   [CVE-2009-0029] S...
617
  SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
618
619
620
  {
  	return sys_fchmodat(AT_FDCWD, filename, mode);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
  static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
  {
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
623
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
  	int error;
  	struct iattr newattrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
629
630
631
632
633
634
635
  	newattrs.ia_valid =  ATTR_CTIME;
  	if (user != (uid_t) -1) {
  		newattrs.ia_valid |= ATTR_UID;
  		newattrs.ia_uid = user;
  	}
  	if (group != (gid_t) -1) {
  		newattrs.ia_valid |= ATTR_GID;
  		newattrs.ia_gid = group;
  	}
  	if (!S_ISDIR(inode->i_mode))
b53767719   Serge E. Hallyn   Implement file po...
636
637
  		newattrs.ia_valid |=
  			ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
638
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  	error = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
640
  	mutex_unlock(&inode->i_mutex);
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
641

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
644
  SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
646
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
648
  	error = user_path(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
649
650
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
651
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
652
653
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
654
655
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
656
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
657
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
658
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
  	return error;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
661
662
  SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
  		gid_t, group, int, flag)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
663
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
664
  	struct path path;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
665
666
667
668
669
670
671
  	int error = -EINVAL;
  	int follow;
  
  	if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
  		goto out;
  
  	follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
2d8f30380   Al Viro   [PATCH] sanitize ...
672
  	error = user_path_at(dfd, filename, follow, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
673
674
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
675
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
676
677
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
678
679
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
680
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
681
  	path_put(&path);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
682
683
684
  out:
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
685
  SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
687
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
689
  	error = user_lpath(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
690
691
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
692
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
693
694
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
695
696
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
697
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
698
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
699
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
702
  SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
  {
  	struct file * file;
  	int error = -EBADF;
6902d925d   Dave Hansen   [PATCH] r/o bind ...
706
  	struct dentry * dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
  
  	file = fget(fd);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
709
710
  	if (!file)
  		goto out;
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
711
712
713
  	error = mnt_want_write(file->f_path.mnt);
  	if (error)
  		goto out_fput;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
714
  	dentry = file->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
715
  	audit_inode(NULL, dentry);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
716
  	error = chown_common(dentry, user, group);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
717
718
  	mnt_drop_write(file->f_path.mnt);
  out_fput:
6902d925d   Dave Hansen   [PATCH] r/o bind ...
719
720
  	fput(file);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
  	return error;
  }
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
  /*
   * You have to be very careful that these write
   * counts get cleaned up in error cases and
   * upon __fput().  This should probably never
   * be called outside of __dentry_open().
   */
  static inline int __get_file_write_access(struct inode *inode,
  					  struct vfsmount *mnt)
  {
  	int error;
  	error = get_write_access(inode);
  	if (error)
  		return error;
  	/*
  	 * Do not take mount writer counts on
  	 * special files since no writes to
  	 * the mount itself will occur.
  	 */
  	if (!special_file(inode->i_mode)) {
  		/*
  		 * Balanced in __fput()
  		 */
  		error = mnt_want_write(mnt);
  		if (error)
  			put_write_access(inode);
  	}
  	return error;
  }
a1a5b3d93   Peter Staubach   [PATCH] open retu...
751
  static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
752
  					int flags, struct file *f,
745ca2475   David Howells   CRED: Pass creden...
753
754
  					int (*open)(struct inode *, struct file *),
  					const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
  	struct inode *inode;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  	f->f_flags = flags;
aeb5d7270   Al Viro   [PATCH] introduce...
759
  	f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK |
a1a5b3d93   Peter Staubach   [PATCH] open retu...
760
  				FMODE_PREAD | FMODE_PWRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
  	inode = dentry->d_inode;
  	if (f->f_mode & FMODE_WRITE) {
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
763
  		error = __get_file_write_access(inode, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  		if (error)
  			goto cleanup_file;
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
766
767
  		if (!special_file(inode->i_mode))
  			file_take_write(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
  	}
  
  	f->f_mapping = inode->i_mapping;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
771
772
  	f->f_path.dentry = dentry;
  	f->f_path.mnt = mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
  	f->f_pos = 0;
  	f->f_op = fops_get(inode->i_fop);
  	file_move(f, &inode->i_sb->s_files);
745ca2475   David Howells   CRED: Pass creden...
776
  	error = security_dentry_open(f, cred);
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
777
778
  	if (error)
  		goto cleanup_all;
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
779
780
781
782
  	if (!open && f->f_op)
  		open = f->f_op->open;
  	if (open) {
  		error = open(inode, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
  		if (error)
  			goto cleanup_all;
  	}
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
786

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
  	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
  
  	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
  
  	/* NB: we're sure to have correct a_ops only after f_op->open */
  	if (f->f_flags & O_DIRECT) {
ceffc0785   Carsten Otte   [PATCH] xip: fs/m...
793
794
  		if (!f->f_mapping->a_ops ||
  		    ((!f->f_mapping->a_ops->direct_IO) &&
70688e4dd   Nick Piggin   xip: support non-...
795
  		    (!f->f_mapping->a_ops->get_xip_mem))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
802
803
804
  			fput(f);
  			f = ERR_PTR(-EINVAL);
  		}
  	}
  
  	return f;
  
  cleanup_all:
  	fops_put(f->f_op);
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
805
  	if (f->f_mode & FMODE_WRITE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
  		put_write_access(inode);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
807
808
809
810
811
812
813
814
  		if (!special_file(inode->i_mode)) {
  			/*
  			 * We don't consider this a real
  			 * mnt_want/drop_write() pair
  			 * because it all happenend right
  			 * here, so just reset the state.
  			 */
  			file_reset_write(f);
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
815
  			mnt_drop_write(mnt);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
816
  		}
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
817
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  	file_kill(f);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
819
820
  	f->f_path.dentry = NULL;
  	f->f_path.mnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  cleanup_file:
  	put_filp(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
  	dput(dentry);
  	mntput(mnt);
  	return ERR_PTR(error);
  }
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
827
828
829
830
831
832
833
834
835
836
  /**
   * lookup_instantiate_filp - instantiates the open intent filp
   * @nd: pointer to nameidata
   * @dentry: pointer to dentry
   * @open: open callback
   *
   * Helper for filesystems that want to use lookup open intents and pass back
   * a fully instantiated struct file to the caller.
   * This function is meant to be called from within a filesystem's
   * lookup method.
9a56c2139   Oleg Drokin   [PATCH] Add looku...
837
838
839
840
   * Beware of calling it for non-regular files! Those ->open methods might block
   * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
   * leading to a deadlock, as nobody can open that fifo anymore, because
   * another process to open fifo will block on locked parent when doing lookup).
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
841
842
843
844
845
846
847
848
   * Note that in case of error, nd->intent.open.file is destroyed, but the
   * path information remains valid.
   * If the open callback is set to NULL, then the standard f_op->open()
   * filesystem callback is substituted.
   */
  struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
  		int (*open)(struct inode *, struct file *))
  {
745ca2475   David Howells   CRED: Pass creden...
849
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
850
851
852
853
  	if (IS_ERR(nd->intent.open.file))
  		goto out;
  	if (IS_ERR(dentry))
  		goto out_err;
4ac913785   Jan Blunck   Embed a struct pa...
854
  	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
855
856
  					     nd->intent.open.flags - 1,
  					     nd->intent.open.file,
745ca2475   David Howells   CRED: Pass creden...
857
  					     open, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
  out:
  	return nd->intent.open.file;
  out_err:
  	release_open_intent(nd);
  	nd->intent.open.file = (struct file *)dentry;
  	goto out;
  }
  EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
  
  /**
   * nameidata_to_filp - convert a nameidata to an open filp.
   * @nd: pointer to nameidata
   * @flags: open flags
   *
   * Note that this function destroys the original nameidata
   */
  struct file *nameidata_to_filp(struct nameidata *nd, int flags)
  {
745ca2475   David Howells   CRED: Pass creden...
876
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
877
878
879
880
881
  	struct file *filp;
  
  	/* Pick up the filp from the open intent */
  	filp = nd->intent.open.file;
  	/* Has the filesystem initialised the file for us? */
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
882
  	if (filp->f_path.dentry == NULL)
4ac913785   Jan Blunck   Embed a struct pa...
883
  		filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
745ca2475   David Howells   CRED: Pass creden...
884
  				     NULL, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
885
  	else
1d957f9bf   Jan Blunck   Introduce path_put()
886
  		path_put(&nd->path);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
887
888
  	return filp;
  }
6fdcc2162   Peter Staubach   [PATCH] memory le...
889
890
891
892
  /*
   * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
   * error.
   */
745ca2475   David Howells   CRED: Pass creden...
893
894
  struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
  			 const struct cred *cred)
a1a5b3d93   Peter Staubach   [PATCH] open retu...
895
896
897
  {
  	int error;
  	struct file *f;
322ee5b36   Christoph Hellwig   [PATCH] check for...
898
899
900
901
902
903
904
905
906
907
908
909
  	/*
  	 * We must always pass in a valid mount pointer.   Historically
  	 * callers got away with not passing it, but we must enforce this at
  	 * the earliest possible point now to avoid strange problems deep in the
  	 * filesystem stack.
  	 */
  	if (!mnt) {
  		printk(KERN_WARNING "%s called with NULL vfsmount
  ", __func__);
  		dump_stack();
  		return ERR_PTR(-EINVAL);
  	}
a1a5b3d93   Peter Staubach   [PATCH] open retu...
910
911
  	error = -ENFILE;
  	f = get_empty_filp();
6fdcc2162   Peter Staubach   [PATCH] memory le...
912
913
914
  	if (f == NULL) {
  		dput(dentry);
  		mntput(mnt);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
915
  		return ERR_PTR(error);
6fdcc2162   Peter Staubach   [PATCH] memory le...
916
  	}
a1a5b3d93   Peter Staubach   [PATCH] open retu...
917

745ca2475   David Howells   CRED: Pass creden...
918
  	return __dentry_open(dentry, mnt, flags, f, NULL, cred);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
919
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  EXPORT_SYMBOL(dentry_open);
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
921
  static void __put_unused_fd(struct files_struct *files, unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  {
badf16621   Dipankar Sarma   [PATCH] files: br...
923
924
  	struct fdtable *fdt = files_fdtable(files);
  	__FD_CLR(fd, fdt->open_fds);
0c9e63fd3   Eric Dumazet   [PATCH] Shrinks s...
925
926
  	if (fd < files->next_fd)
  		files->next_fd = fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  }
fc9b52cd8   Harvey Harrison   fs: remove fastca...
928
  void put_unused_fd(unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
934
935
936
937
938
  {
  	struct files_struct *files = current->files;
  	spin_lock(&files->file_lock);
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
  }
  
  EXPORT_SYMBOL(put_unused_fd);
  
  /*
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
939
   * Install a file pointer in the fd array.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
946
947
948
949
   *
   * The VFS is full of places where we drop the files lock between
   * setting the open_fds bitmap and installing the file in the file
   * array.  At any such point, we are vulnerable to a dup2() race
   * installing a file in the array before us.  We need to detect this and
   * fput() the struct file we are about to overwrite in this case.
   *
   * It should never happen - if we allow dup2() do it, _really_ bad things
   * will follow.
   */
fc9b52cd8   Harvey Harrison   fs: remove fastca...
950
  void fd_install(unsigned int fd, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  {
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
953
  	struct fdtable *fdt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
955
  	fdt = files_fdtable(files);
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
956
957
  	BUG_ON(fdt->fd[fd] != NULL);
  	rcu_assign_pointer(fdt->fd[fd], file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
960
961
  	spin_unlock(&files->file_lock);
  }
  
  EXPORT_SYMBOL(fd_install);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
962
  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  {
e922efc34   Miklos Szeredi   [PATCH] remove du...
964
965
  	char *tmp = getname(filename);
  	int fd = PTR_ERR(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  	if (!IS_ERR(tmp)) {
f23513e8d   Ulrich Drepper   Introduce O_CLOEXEC
968
  		fd = get_unused_fd_flags(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  		if (fd >= 0) {
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
970
  			struct file *f = do_filp_open(dfd, tmp, flags, mode);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
971
972
973
974
  			if (IS_ERR(f)) {
  				put_unused_fd(fd);
  				fd = PTR_ERR(f);
  			} else {
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
975
  				fsnotify_open(f->f_path.dentry);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
976
977
  				fd_install(fd, f);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
  		putname(tmp);
  	}
  	return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
  }
e922efc34   Miklos Szeredi   [PATCH] remove du...
983

ca013e945   Heiko Carstens   [CVE-2009-0029] S...
984
  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
e922efc34   Miklos Szeredi   [PATCH] remove du...
985
  {
385910f2b   Linus Torvalds   x86: be careful a...
986
  	long ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
987
988
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
989
990
  	ret = do_sys_open(AT_FDCWD, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
991
  	asmlinkage_protect(3, ret, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
992
  	return ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
993
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994

6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
995
996
  SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
  		int, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
997
  {
385910f2b   Linus Torvalds   x86: be careful a...
998
  	long ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
999
1000
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
1001
1002
  	ret = do_sys_open(dfd, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
1003
  	asmlinkage_protect(4, ret, dfd, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
1004
  	return ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
1005
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
1006

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
1012
  #ifndef __alpha__
  
  /*
   * For backward compatibility?  Maybe this should be moved
   * into arch/i386 instead?
   */
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
1013
  SYSCALL_DEFINE2(creat, const char __user *, pathname, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  {
  	return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
  }
  
  #endif
  
  /*
   * "id" is the POSIX thread ID. We use the
   * files pointer for this..
   */
  int filp_close(struct file *filp, fl_owner_t id)
  {
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1026
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
  
  	if (!file_count(filp)) {
  		printk(KERN_ERR "VFS: Close: file count is 0
  ");
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1031
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
  	}
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1033
  	if (filp->f_op && filp->f_op->flush)
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
1034
  		retval = filp->f_op->flush(filp, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  
  	dnotify_flush(filp, id);
  	locks_remove_posix(filp, id);
  	fput(filp);
  	return retval;
  }
  
  EXPORT_SYMBOL(filp_close);
  
  /*
   * Careful here! We test whether the file pointer is NULL before
   * releasing the fd. This ensures that one clone task can't release
   * an fd while another clone is opening it.
   */
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
1049
  SYSCALL_DEFINE1(close, unsigned int, fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
1052
  {
  	struct file * filp;
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
1053
  	struct fdtable *fdt;
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1054
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
  
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
1057
1058
  	fdt = files_fdtable(files);
  	if (fd >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
  		goto out_unlock;
badf16621   Dipankar Sarma   [PATCH] files: br...
1060
  	filp = fdt->fd[fd];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
  	if (!filp)
  		goto out_unlock;
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
1063
  	rcu_assign_pointer(fdt->fd[fd], NULL);
badf16621   Dipankar Sarma   [PATCH] files: br...
1064
  	FD_CLR(fd, fdt->close_on_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  	retval = filp_close(filp, files);
  
  	/* can't restart close syscall because file table entry was cleared */
  	if (unlikely(retval == -ERESTARTSYS ||
  		     retval == -ERESTARTNOINTR ||
  		     retval == -ERESTARTNOHAND ||
  		     retval == -ERESTART_RESTARTBLOCK))
  		retval = -EINTR;
  
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
1081
  
  out_unlock:
  	spin_unlock(&files->file_lock);
  	return -EBADF;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
1084
1085
1086
1087
  EXPORT_SYMBOL(sys_close);
  
  /*
   * This routine simulates a hangup on the tty, to arrange that users
   * are given clean terminals at login time.
   */
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
1088
  SYSCALL_DEFINE0(vhangup)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
  {
  	if (capable(CAP_SYS_TTY_CONFIG)) {
2cb5998b5   Alan Cox   tty: the vhangup ...
1091
  		tty_vhangup_self();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  		return 0;
  	}
  	return -EPERM;
  }
  
  /*
   * Called when an inode is about to be open.
   * We use this to disallow opening large files on 32bit systems if
   * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
   * on this flag in sys_open.
   */
  int generic_file_open(struct inode * inode, struct file * filp)
  {
  	if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
a9c62a18a   Alan Cox   fs: correct SuS c...
1106
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  	return 0;
  }
  
  EXPORT_SYMBOL(generic_file_open);
  
  /*
   * This is used by subsystems that don't want seekable
   * file descriptors
   */
  int nonseekable_open(struct inode *inode, struct file *filp)
  {
  	filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
  	return 0;
  }
  
  EXPORT_SYMBOL(nonseekable_open);