Blame view

fs/open.c 23.6 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>
0eeca2830   Robert Love   [PATCH] inotify
11
  #include <linux/fsnotify.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
  #include <linux/tty.h>
  #include <linux/namei.h>
  #include <linux/backing-dev.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
16
  #include <linux/capability.h>
086f7316f   Andrew G. Morgan   security: filesys...
17
  #include <linux/securebits.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <linux/security.h>
  #include <linux/mount.h>
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
20
  #include <linux/fcntl.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include <asm/uaccess.h>
  #include <linux/fs.h>
ef3daeda7   Yoav Zach   [PATCH] Don't for...
24
  #include <linux/personality.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
  #include <linux/pagemap.h>
  #include <linux/syscalls.h>
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
27
  #include <linux/rcupdate.h>
73241ccca   Amy Griffis   [PATCH] Collect m...
28
  #include <linux/audit.h>
97ac73506   Amit Arora   sys_fallocate() i...
29
  #include <linux/falloc.h>
5ad4e53bd   Al Viro   Get rid of indire...
30
  #include <linux/fs_struct.h>
b65a9cfc2   Al Viro   Untangling ima me...
31
  #include <linux/ima.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

e81e3f4dc   Eric Paris   fs: move get_empt...
33
  #include "internal.h"
4a30131e7   NeilBrown   [PATCH] Fix some ...
34
35
  int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
  	struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  {
939a9421e   Amerigo Wang   vfs: allow file t...
37
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
  	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 ...
45
  	newattrs.ia_valid = ATTR_SIZE | time_attrs;
cc4e69dee   Miklos Szeredi   [PATCH] VFS: pass...
46
47
48
49
  	if (filp) {
  		newattrs.ia_file = filp;
  		newattrs.ia_valid |= ATTR_FILE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

7b82dc0e6   Linus Torvalds   Remove suid/sgid ...
51
  	/* Remove suid/sgid on truncate too */
939a9421e   Amerigo Wang   vfs: allow file t...
52
53
54
  	ret = should_remove_suid(dentry);
  	if (ret)
  		newattrs.ia_valid |= ret | ATTR_FORCE;
7b82dc0e6   Linus Torvalds   Remove suid/sgid ...
55

1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
56
  	mutex_lock(&dentry->d_inode->i_mutex);
939a9421e   Amerigo Wang   vfs: allow file t...
57
  	ret = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
58
  	mutex_unlock(&dentry->d_inode->i_mutex);
939a9421e   Amerigo Wang   vfs: allow file t...
59
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  }
2d8f30380   Al Viro   [PATCH] sanitize ...
61
  static long do_sys_truncate(const char __user *pathname, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
63
64
  	struct path path;
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
  	int error;
  
  	error = -EINVAL;
  	if (length < 0)	/* sorry, but loff_t says... */
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
70
  	error = user_path(pathname, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
73
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
81
82
  
  	/* 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 ...
83
  	error = mnt_want_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  	if (error)
  		goto dput_and_out;
256984a83   Al Viro   [PATCH] preparati...
86
  	error = inode_permission(inode, MAY_WRITE);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
87
88
  	if (error)
  		goto mnt_drop_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  
  	error = -EPERM;
c82e42da8   Miklos Szeredi   [patch 1/5] vfs: ...
91
  	if (IS_APPEND(inode))
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
92
  		goto mnt_drop_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93

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

9700382c3   david m. richter   VFS: fix a race i...
98
99
100
101
  	/*
  	 * Make sure that there are no leases.  get_write_access() protects
  	 * against the truncate racing with a lease-granting setlease().
  	 */
8737c9305   Al Viro   Switch may_open()...
102
  	error = break_lease(inode, O_WRONLY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  	if (error)
9700382c3   david m. richter   VFS: fix a race i...
104
  		goto put_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  
  	error = locks_verify_truncate(inode, NULL, length);
be6d3e56a   Kentaro Takeda   introduce new LSM...
107
108
  	if (!error)
  		error = security_path_truncate(&path, length, 0);
907f4554e   Christoph Hellwig   dquot: move dquot...
109
  	if (!error)
2d8f30380   Al Viro   [PATCH] sanitize ...
110
  		error = do_truncate(path.dentry, length, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111

9700382c3   david m. richter   VFS: fix a race i...
112
113
  put_write_and_out:
  	put_write_access(inode);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
114
  mnt_drop_write_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
115
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
117
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
  out:
  	return error;
  }
4fd8da8d6   Heiko Carstens   fs: change sys_tr...
121
  SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  {
4fd8da8d6   Heiko Carstens   fs: change sys_tr...
123
  	return do_sys_truncate(path, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  }
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
125
  static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  {
  	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...
143
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	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...
160
161
162
  		error = security_path_truncate(&file->f_path, length,
  					       ATTR_MTIME|ATTR_CTIME);
  	if (!error)
6e656be89   Peter Staubach   [PATCH] ftruncate...
163
  		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
  out_putf:
  	fput(file);
  out:
  	return error;
  }
bdc480e3b   Heiko Carstens   [CVE-2009-0029] S...
169
  SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
171
  	long ret = do_sys_ftruncate(fd, length, 1);
385910f2b   Linus Torvalds   x86: be careful a...
172
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
173
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
174
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
  }
  
  /* LFS versions of truncate are only needed on 32 bit machines */
  #if BITS_PER_LONG == 32
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
179
  SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  {
  	return do_sys_truncate(path, length);
  }
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
183
184
185
186
187
188
189
  #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
190

6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
191
  SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
193
  	long ret = do_sys_ftruncate(fd, length, 0);
385910f2b   Linus Torvalds   x86: be careful a...
194
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
195
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
196
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  }
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
198
199
200
201
202
203
  #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
204
  #endif
6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
205
  #endif /* BITS_PER_LONG == 32 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206

3e63cbb1e   Ankit Jain   fs: Add new pre-a...
207
208
  
  int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
97ac73506   Amit Arora   sys_fallocate() i...
209
  {
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
210
211
  	struct inode *inode = file->f_path.dentry->d_inode;
  	long ret;
97ac73506   Amit Arora   sys_fallocate() i...
212
213
  
  	if (offset < 0 || len <= 0)
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
214
  		return -EINVAL;
97ac73506   Amit Arora   sys_fallocate() i...
215
216
  
  	/* Return error if mode is not supported */
97ac73506   Amit Arora   sys_fallocate() i...
217
  	if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
218
  		return -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
219

97ac73506   Amit Arora   sys_fallocate() i...
220
  	if (!(file->f_mode & FMODE_WRITE))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
221
  		return -EBADF;
97ac73506   Amit Arora   sys_fallocate() i...
222
223
224
225
226
227
  	/*
  	 * Revalidate the write permissions, in case security policy has
  	 * changed since the files were opened.
  	 */
  	ret = security_file_permission(file, MAY_WRITE);
  	if (ret)
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
228
  		return ret;
97ac73506   Amit Arora   sys_fallocate() i...
229

97ac73506   Amit Arora   sys_fallocate() i...
230
  	if (S_ISFIFO(inode->i_mode))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
231
  		return -ESPIPE;
97ac73506   Amit Arora   sys_fallocate() i...
232

97ac73506   Amit Arora   sys_fallocate() i...
233
234
235
236
237
  	/*
  	 * Let individual file system decide if it supports preallocation
  	 * for directories or not.
  	 */
  	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
238
  		return -ENODEV;
97ac73506   Amit Arora   sys_fallocate() i...
239

97ac73506   Amit Arora   sys_fallocate() i...
240
241
  	/* Check for wrap through zero too */
  	if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
242
  		return -EFBIG;
97ac73506   Amit Arora   sys_fallocate() i...
243

3e63cbb1e   Ankit Jain   fs: Add new pre-a...
244
245
  	if (!inode->i_op->fallocate)
  		return -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
246

3e63cbb1e   Ankit Jain   fs: Add new pre-a...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  	return inode->i_op->fallocate(inode, mode, offset, len);
  }
  
  SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
  {
  	struct file *file;
  	int error = -EBADF;
  
  	file = fget(fd);
  	if (file) {
  		error = do_fallocate(file, mode, offset, len);
  		fput(file);
  	}
  
  	return error;
97ac73506   Amit Arora   sys_fallocate() i...
262
  }
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
263

6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
264
265
266
267
268
269
270
  #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...
271

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
  /*
   * 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...
277
  SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  {
d84f4f992   David Howells   CRED: Inaugurate ...
279
280
  	const struct cred *old_cred;
  	struct cred *override_cred;
2d8f30380   Al Viro   [PATCH] sanitize ...
281
  	struct path path;
256984a83   Al Viro   [PATCH] preparati...
282
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
  	int res;
  
  	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
287
288
289
  	override_cred = prepare_creds();
  	if (!override_cred)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290

d84f4f992   David Howells   CRED: Inaugurate ...
291
292
  	override_cred->fsuid = override_cred->uid;
  	override_cred->fsgid = override_cred->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293

086f7316f   Andrew G. Morgan   security: filesys...
294
  	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
1cdcbec1a   David Howells   CRED: Neuter sys_...
295
  		/* Clear the capabilities if we switch to a non-root user */
d84f4f992   David Howells   CRED: Inaugurate ...
296
297
  		if (override_cred->uid)
  			cap_clear(override_cred->cap_effective);
086f7316f   Andrew G. Morgan   security: filesys...
298
  		else
d84f4f992   David Howells   CRED: Inaugurate ...
299
300
  			override_cred->cap_effective =
  				override_cred->cap_permitted;
086f7316f   Andrew G. Morgan   security: filesys...
301
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302

d84f4f992   David Howells   CRED: Inaugurate ...
303
  	old_cred = override_creds(override_cred);
2d8f30380   Al Viro   [PATCH] sanitize ...
304
  	res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
305
306
  	if (res)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
307
  	inode = path.dentry->d_inode;
256984a83   Al Viro   [PATCH] preparati...
308
309
  
  	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
30524472c   Al Viro   [PATCH] take noex...
310
311
312
313
314
  		/*
  		 * MAY_EXEC on regular files is denied if the fs is mounted
  		 * with the "noexec" flag.
  		 */
  		res = -EACCES;
2d8f30380   Al Viro   [PATCH] sanitize ...
315
  		if (path.mnt->mnt_flags & MNT_NOEXEC)
30524472c   Al Viro   [PATCH] take noex...
316
317
  			goto out_path_release;
  	}
256984a83   Al Viro   [PATCH] preparati...
318
  	res = inode_permission(inode, mode | MAY_ACCESS);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
319
  	/* SuS v2 requires we report a read only fs too */
256984a83   Al Viro   [PATCH] preparati...
320
  	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
321
  		goto out_path_release;
2f676cbc0   Dave Hansen   [PATCH] r/o bind ...
322
323
324
325
326
327
328
329
330
331
  	/*
  	 * 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 ...
332
  	if (__mnt_is_readonly(path.mnt))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
333
  		res = -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334

6902d925d   Dave Hansen   [PATCH] r/o bind ...
335
  out_path_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
336
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
337
  out:
d84f4f992   David Howells   CRED: Inaugurate ...
338
339
  	revert_creds(old_cred);
  	put_cred(override_cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
  	return res;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
342
  SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
343
344
345
  {
  	return sys_faccessat(AT_FDCWD, filename, mode);
  }
3cdad4288   Heiko Carstens   [CVE-2009-0029] S...
346
  SYSCALL_DEFINE1(chdir, const char __user *, filename)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
348
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
350
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
353
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
  	if (error)
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
356
  	set_fs_pwd(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
359
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
  out:
  	return error;
  }
3cdad4288   Heiko Carstens   [CVE-2009-0029] S...
363
  SYSCALL_DEFINE1(fchdir, unsigned int, fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  {
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
  	int error;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
ac748a09f   Jan Blunck   Make set_fs_{root...
373
  	inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
  
  	error = -ENOTDIR;
  	if (!S_ISDIR(inode->i_mode))
  		goto out_putf;
256984a83   Al Viro   [PATCH] preparati...
378
  	error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  	if (!error)
ac748a09f   Jan Blunck   Make set_fs_{root...
380
  		set_fs_pwd(current->fs, &file->f_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
  out_putf:
  	fput(file);
  out:
  	return error;
  }
3480b2574   Heiko Carstens   [CVE-2009-0029] S...
386
  SYSCALL_DEFINE1(chroot, const char __user *, filename)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
388
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
390
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
393
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
  	if (error)
  		goto dput_and_out;
  
  	error = -EPERM;
  	if (!capable(CAP_SYS_CHROOT))
  		goto dput_and_out;
8b8efb440   Tetsuo Handa   LSM: Add security...
400
401
402
  	error = security_path_chroot(&path);
  	if (error)
  		goto dput_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403

2d8f30380   Al Viro   [PATCH] sanitize ...
404
  	set_fs_root(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  	error = 0;
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
407
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
  out:
  	return error;
  }
a26eab240   Heiko Carstens   [CVE-2009-0029] S...
411
  SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
417
418
419
420
421
  {
  	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...
422
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	inode = dentry->d_inode;
5a190ae69   Al Viro   [PATCH] pass dent...
424
  	audit_inode(NULL, dentry);
73241ccca   Amy Griffis   [PATCH] Collect m...
425

96029c4e0   npiggin@suse.de   fs: introduce mnt...
426
  	err = mnt_want_write_file(file);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
427
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  		goto out_putf;
fe542cf59   Tetsuo Handa   LSM: Move securit...
429
  	mutex_lock(&inode->i_mutex);
89eda0683   Tetsuo Handa   LSM: Add security...
430
431
  	err = security_path_chmod(dentry, file->f_vfsmnt, mode);
  	if (err)
fe542cf59   Tetsuo Handa   LSM: Move securit...
432
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
  	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);
fe542cf59   Tetsuo Handa   LSM: Move securit...
438
  out_unlock:
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
439
  	mutex_unlock(&inode->i_mutex);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
440
  	mnt_drop_write(file->f_path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
  out_putf:
  	fput(file);
  out:
  	return err;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
446
  SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
448
449
  	struct path path;
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
  	int error;
  	struct iattr newattrs;
2d8f30380   Al Viro   [PATCH] sanitize ...
452
  	error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
455
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456

2d8f30380   Al Viro   [PATCH] sanitize ...
457
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
458
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  		goto dput_and_out;
fe542cf59   Tetsuo Handa   LSM: Move securit...
460
  	mutex_lock(&inode->i_mutex);
89eda0683   Tetsuo Handa   LSM: Add security...
461
462
  	error = security_path_chmod(path.dentry, path.mnt, mode);
  	if (error)
fe542cf59   Tetsuo Handa   LSM: Move securit...
463
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
  	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 ...
468
  	error = notify_change(path.dentry, &newattrs);
fe542cf59   Tetsuo Handa   LSM: Move securit...
469
  out_unlock:
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
470
  	mutex_unlock(&inode->i_mutex);
2d8f30380   Al Viro   [PATCH] sanitize ...
471
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
473
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
  out:
  	return error;
  }
a26eab240   Heiko Carstens   [CVE-2009-0029] S...
477
  SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
478
479
480
  {
  	return sys_fchmodat(AT_FDCWD, filename, mode);
  }
fe542cf59   Tetsuo Handa   LSM: Move securit...
481
  static int chown_common(struct path *path, uid_t user, gid_t group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  {
fe542cf59   Tetsuo Handa   LSM: Move securit...
483
  	struct inode *inode = path->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
  	int error;
  	struct iattr newattrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
492
493
494
495
  	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...
496
497
  		newattrs.ia_valid |=
  			ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
498
  	mutex_lock(&inode->i_mutex);
fe542cf59   Tetsuo Handa   LSM: Move securit...
499
500
501
  	error = security_path_chown(path, user, group);
  	if (!error)
  		error = notify_change(path->dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
502
  	mutex_unlock(&inode->i_mutex);
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
503

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
506
  SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
508
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
510
  	error = user_path(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
511
512
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
513
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
514
515
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
516
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
517
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
518
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
519
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
520
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
  	return error;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
523
524
  SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
  		gid_t, group, int, flag)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
525
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
526
  	struct path path;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
527
528
529
530
531
532
533
  	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 ...
534
  	error = user_path_at(dfd, filename, follow, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
535
536
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
537
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
538
539
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
540
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
541
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
542
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
543
  	path_put(&path);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
544
545
546
  out:
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
547
  SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
549
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
551
  	error = user_lpath(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
552
553
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
554
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
555
556
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
557
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
558
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
559
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
560
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
561
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
564
  SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
  {
  	struct file * file;
  	int error = -EBADF;
6902d925d   Dave Hansen   [PATCH] r/o bind ...
568
  	struct dentry * dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
  
  	file = fget(fd);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
571
572
  	if (!file)
  		goto out;
96029c4e0   npiggin@suse.de   fs: introduce mnt...
573
  	error = mnt_want_write_file(file);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
574
575
  	if (error)
  		goto out_fput;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
576
  	dentry = file->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
577
  	audit_inode(NULL, dentry);
fe542cf59   Tetsuo Handa   LSM: Move securit...
578
  	error = chown_common(&file->f_path, user, group);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
579
580
  	mnt_drop_write(file->f_path.mnt);
  out_fput:
6902d925d   Dave Hansen   [PATCH] r/o bind ...
581
582
  	fput(file);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
  	return error;
  }
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  /*
   * 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...
613
  static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
482928d59   Al Viro   Fix f_flags/f_mod...
614
  					struct file *f,
745ca2475   David Howells   CRED: Pass creden...
615
616
  					int (*open)(struct inode *, struct file *),
  					const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  	struct inode *inode;
  	int error;
5300990c0   Al Viro   Sanitize f_flags ...
620
  	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
a1a5b3d93   Peter Staubach   [PATCH] open retu...
621
  				FMODE_PREAD | FMODE_PWRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
  	inode = dentry->d_inode;
  	if (f->f_mode & FMODE_WRITE) {
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
624
  		error = __get_file_write_access(inode, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
  		if (error)
  			goto cleanup_file;
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
627
628
  		if (!special_file(inode->i_mode))
  			file_take_write(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
  	}
  
  	f->f_mapping = inode->i_mapping;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
632
633
  	f->f_path.dentry = dentry;
  	f->f_path.mnt = mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
  	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...
637
  	error = security_dentry_open(f, cred);
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
638
639
  	if (error)
  		goto cleanup_all;
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
640
641
642
643
  	if (!open && f->f_op)
  		open = f->f_op->open;
  	if (open) {
  		error = open(inode, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
  		if (error)
  			goto cleanup_all;
  	}
b65a9cfc2   Al Viro   Untangling ima me...
647
  	ima_counts_get(f);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
648

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
  	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...
655
656
  		if (!f->f_mapping->a_ops ||
  		    ((!f->f_mapping->a_ops->direct_IO) &&
70688e4dd   Nick Piggin   xip: support non-...
657
  		    (!f->f_mapping->a_ops->get_xip_mem))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
661
662
663
664
665
666
  			fput(f);
  			f = ERR_PTR(-EINVAL);
  		}
  	}
  
  	return f;
  
  cleanup_all:
  	fops_put(f->f_op);
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
667
  	if (f->f_mode & FMODE_WRITE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  		put_write_access(inode);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
669
670
671
672
673
674
675
676
  		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 ...
677
  			mnt_drop_write(mnt);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
678
  		}
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
679
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  	file_kill(f);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
681
682
  	f->f_path.dentry = NULL;
  	f->f_path.mnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  cleanup_file:
  	put_filp(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
  	dput(dentry);
  	mntput(mnt);
  	return ERR_PTR(error);
  }
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
689
690
691
692
693
694
695
696
697
698
  /**
   * 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...
699
700
701
702
   * 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...
703
704
705
706
707
708
709
710
   * 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...
711
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
712
713
714
715
  	if (IS_ERR(nd->intent.open.file))
  		goto out;
  	if (IS_ERR(dentry))
  		goto out_err;
4ac913785   Jan Blunck   Embed a struct pa...
716
  	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
717
  					     nd->intent.open.file,
745ca2475   David Howells   CRED: Pass creden...
718
  					     open, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
  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
   */
482928d59   Al Viro   Fix f_flags/f_mod...
735
  struct file *nameidata_to_filp(struct nameidata *nd)
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
736
  {
745ca2475   David Howells   CRED: Pass creden...
737
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
738
739
740
741
742
  	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...
743
  	if (filp->f_path.dentry == NULL)
482928d59   Al Viro   Fix f_flags/f_mod...
744
  		filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,
745ca2475   David Howells   CRED: Pass creden...
745
  				     NULL, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
746
  	else
1d957f9bf   Jan Blunck   Introduce path_put()
747
  		path_put(&nd->path);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
748
749
  	return filp;
  }
6fdcc2162   Peter Staubach   [PATCH] memory le...
750
751
752
753
  /*
   * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
   * error.
   */
745ca2475   David Howells   CRED: Pass creden...
754
755
  struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
  			 const struct cred *cred)
a1a5b3d93   Peter Staubach   [PATCH] open retu...
756
757
758
  {
  	int error;
  	struct file *f;
e0e817392   David Howells   CRED: Add some co...
759
  	validate_creds(cred);
322ee5b36   Christoph Hellwig   [PATCH] check for...
760
761
762
763
764
765
766
767
768
769
770
771
  	/*
  	 * 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...
772
773
  	error = -ENFILE;
  	f = get_empty_filp();
6fdcc2162   Peter Staubach   [PATCH] memory le...
774
775
776
  	if (f == NULL) {
  		dput(dentry);
  		mntput(mnt);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
777
  		return ERR_PTR(error);
6fdcc2162   Peter Staubach   [PATCH] memory le...
778
  	}
a1a5b3d93   Peter Staubach   [PATCH] open retu...
779

482928d59   Al Viro   Fix f_flags/f_mod...
780
781
  	f->f_flags = flags;
  	return __dentry_open(dentry, mnt, f, NULL, cred);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
782
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  EXPORT_SYMBOL(dentry_open);
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
784
  static void __put_unused_fd(struct files_struct *files, unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
  {
badf16621   Dipankar Sarma   [PATCH] files: br...
786
787
  	struct fdtable *fdt = files_fdtable(files);
  	__FD_CLR(fd, fdt->open_fds);
0c9e63fd3   Eric Dumazet   [PATCH] Shrinks s...
788
789
  	if (fd < files->next_fd)
  		files->next_fd = fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  }
fc9b52cd8   Harvey Harrison   fs: remove fastca...
791
  void put_unused_fd(unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
798
799
800
801
  {
  	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 ...
802
   * Install a file pointer in the fd array.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
810
811
812
   *
   * 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...
813
  void fd_install(unsigned int fd, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  {
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
816
  	struct fdtable *fdt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
818
  	fdt = files_fdtable(files);
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
819
820
  	BUG_ON(fdt->fd[fd] != NULL);
  	rcu_assign_pointer(fdt->fd[fd], file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
  	spin_unlock(&files->file_lock);
  }
  
  EXPORT_SYMBOL(fd_install);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
825
  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  {
e922efc34   Miklos Szeredi   [PATCH] remove du...
827
828
  	char *tmp = getname(filename);
  	int fd = PTR_ERR(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  	if (!IS_ERR(tmp)) {
f23513e8d   Ulrich Drepper   Introduce O_CLOEXEC
831
  		fd = get_unused_fd_flags(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
  		if (fd >= 0) {
6e8341a11   Al Viro   Switch open_exec(...
833
  			struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
834
835
836
837
  			if (IS_ERR(f)) {
  				put_unused_fd(fd);
  				fd = PTR_ERR(f);
  			} else {
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
838
  				fsnotify_open(f->f_path.dentry);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
839
840
  				fd_install(fd, f);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
  		putname(tmp);
  	}
  	return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  }
e922efc34   Miklos Szeredi   [PATCH] remove du...
846

ca013e945   Heiko Carstens   [CVE-2009-0029] S...
847
  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
e922efc34   Miklos Szeredi   [PATCH] remove du...
848
  {
385910f2b   Linus Torvalds   x86: be careful a...
849
  	long ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
850
851
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
852
853
  	ret = do_sys_open(AT_FDCWD, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
854
  	asmlinkage_protect(3, ret, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
855
  	return ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
856
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857

6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
858
859
  SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
  		int, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
860
  {
385910f2b   Linus Torvalds   x86: be careful a...
861
  	long ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
862
863
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
864
865
  	ret = do_sys_open(dfd, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
866
  	asmlinkage_protect(4, ret, dfd, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
867
  	return ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
868
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
869

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
873
874
875
  #ifndef __alpha__
  
  /*
   * For backward compatibility?  Maybe this should be moved
   * into arch/i386 instead?
   */
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
876
  SYSCALL_DEFINE2(creat, const char __user *, pathname, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
881
882
883
884
885
886
887
888
  {
  	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_...
889
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
893
  
  	if (!file_count(filp)) {
  		printk(KERN_ERR "VFS: Close: file count is 0
  ");
45778ca81   Christoph Lameter   [PATCH] Remove f_...
894
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  	}
45778ca81   Christoph Lameter   [PATCH] Remove f_...
896
  	if (filp->f_op && filp->f_op->flush)
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
897
  		retval = filp->f_op->flush(filp, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
903
904
905
906
907
908
909
910
911
  
  	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...
912
  SYSCALL_DEFINE1(close, unsigned int, fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
915
  {
  	struct file * filp;
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
916
  	struct fdtable *fdt;
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
917
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
  
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
920
921
  	fdt = files_fdtable(files);
  	if (fd >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  		goto out_unlock;
badf16621   Dipankar Sarma   [PATCH] files: br...
923
  	filp = fdt->fd[fd];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
  	if (!filp)
  		goto out_unlock;
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
926
  	rcu_assign_pointer(fdt->fd[fd], NULL);
badf16621   Dipankar Sarma   [PATCH] files: br...
927
  	FD_CLR(fd, fdt->close_on_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
930
931
932
933
934
935
936
937
938
939
  	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
940
941
942
943
944
  
  out_unlock:
  	spin_unlock(&files->file_lock);
  	return -EBADF;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
950
  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...
951
  SYSCALL_DEFINE0(vhangup)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  {
  	if (capable(CAP_SYS_TTY_CONFIG)) {
2cb5998b5   Alan Cox   tty: the vhangup ...
954
  		tty_vhangup_self();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
958
959
960
961
962
963
964
965
966
967
968
  		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...
969
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  	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);