Blame view

fs/open.c 26.2 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>
2dfc1cae4   Eric Paris   inotify: remove i...
32
  #include <linux/dnotify.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

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

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

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

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

9700382c3   david m. richter   VFS: fix a race i...
99
100
101
102
  	/*
  	 * 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()...
103
  	error = break_lease(inode, O_WRONLY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	if (error)
9700382c3   david m. richter   VFS: fix a race i...
105
  		goto put_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  
  	error = locks_verify_truncate(inode, NULL, length);
be6d3e56a   Kentaro Takeda   introduce new LSM...
108
  	if (!error)
ea0d3ab23   Tetsuo Handa   LSM: Remove unuse...
109
  		error = security_path_truncate(&path);
907f4554e   Christoph Hellwig   dquot: move dquot...
110
  	if (!error)
2d8f30380   Al Viro   [PATCH] sanitize ...
111
  		error = do_truncate(path.dentry, length, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112

9700382c3   david m. richter   VFS: fix a race i...
113
114
  put_write_and_out:
  	put_write_access(inode);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
115
  mnt_drop_write_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
116
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
118
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
  out:
  	return error;
  }
4fd8da8d6   Heiko Carstens   fs: change sys_tr...
122
  SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
4fd8da8d6   Heiko Carstens   fs: change sys_tr...
124
  	return do_sys_truncate(path, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  }
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
126
  static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  {
  	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...
144
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  	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)
ea0d3ab23   Tetsuo Handa   LSM: Remove unuse...
161
  		error = security_path_truncate(&file->f_path);
be6d3e56a   Kentaro Takeda   introduce new LSM...
162
  	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 */
79124f18b   Josef Bacik   fs: add hole punc...
217
218
219
220
221
222
  	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
  		return -EOPNOTSUPP;
  
  	/* Punch hole must have keep size set */
  	if ((mode & FALLOC_FL_PUNCH_HOLE) &&
  	    !(mode & FALLOC_FL_KEEP_SIZE))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
223
  		return -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
224

97ac73506   Amit Arora   sys_fallocate() i...
225
  	if (!(file->f_mode & FMODE_WRITE))
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
226
  		return -EBADF;
1ca551c6c   Marco Stornelli   Check for immutab...
227
228
229
230
231
232
233
  
  	/* It's not possible punch hole on append only file */
  	if (mode & FALLOC_FL_PUNCH_HOLE && IS_APPEND(inode))
  		return -EPERM;
  
  	if (IS_IMMUTABLE(inode))
  		return -EPERM;
97ac73506   Amit Arora   sys_fallocate() i...
234
235
236
237
238
239
  	/*
  	 * 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...
240
  		return ret;
97ac73506   Amit Arora   sys_fallocate() i...
241

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

97ac73506   Amit Arora   sys_fallocate() i...
245
246
247
248
249
  	/*
  	 * 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...
250
  		return -ENODEV;
97ac73506   Amit Arora   sys_fallocate() i...
251

97ac73506   Amit Arora   sys_fallocate() i...
252
253
  	/* 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...
254
  		return -EFBIG;
97ac73506   Amit Arora   sys_fallocate() i...
255

2fe17c107   Christoph Hellwig   fallocate should ...
256
  	if (!file->f_op->fallocate)
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
257
  		return -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
258

2fe17c107   Christoph Hellwig   fallocate should ...
259
  	return file->f_op->fallocate(file, mode, offset, len);
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  }
  
  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...
274
  }
3e63cbb1e   Ankit Jain   fs: Add new pre-a...
275

6673e0c3f   Heiko Carstens   [CVE-2009-0029] S...
276
277
278
279
280
281
282
  #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...
283

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
  /*
   * 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...
289
  SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  {
d84f4f992   David Howells   CRED: Inaugurate ...
291
292
  	const struct cred *old_cred;
  	struct cred *override_cred;
2d8f30380   Al Viro   [PATCH] sanitize ...
293
  	struct path path;
256984a83   Al Viro   [PATCH] preparati...
294
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
  	int res;
  
  	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
299
300
301
  	override_cred = prepare_creds();
  	if (!override_cred)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302

d84f4f992   David Howells   CRED: Inaugurate ...
303
304
  	override_cred->fsuid = override_cred->uid;
  	override_cred->fsgid = override_cred->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

086f7316f   Andrew G. Morgan   security: filesys...
306
  	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
1cdcbec1a   David Howells   CRED: Neuter sys_...
307
  		/* Clear the capabilities if we switch to a non-root user */
d84f4f992   David Howells   CRED: Inaugurate ...
308
309
  		if (override_cred->uid)
  			cap_clear(override_cred->cap_effective);
086f7316f   Andrew G. Morgan   security: filesys...
310
  		else
d84f4f992   David Howells   CRED: Inaugurate ...
311
312
  			override_cred->cap_effective =
  				override_cred->cap_permitted;
086f7316f   Andrew G. Morgan   security: filesys...
313
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314

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

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

2d8f30380   Al Viro   [PATCH] sanitize ...
416
  	set_fs_root(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  	error = 0;
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
419
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
  out:
  	return error;
  }
e57712ebe   Al Viro   merge fchmod() an...
423
  static int chmod_common(struct path *path, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  {
e57712ebe   Al Viro   merge fchmod() an...
425
  	struct inode *inode = path->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  	struct iattr newattrs;
e57712ebe   Al Viro   merge fchmod() an...
427
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428

e57712ebe   Al Viro   merge fchmod() an...
429
430
431
  	error = mnt_want_write(path->mnt);
  	if (error)
  		return error;
fe542cf59   Tetsuo Handa   LSM: Move securit...
432
  	mutex_lock(&inode->i_mutex);
e57712ebe   Al Viro   merge fchmod() an...
433
434
  	error = security_path_chmod(path->dentry, path->mnt, mode);
  	if (error)
fe542cf59   Tetsuo Handa   LSM: Move securit...
435
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
  	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
e57712ebe   Al Viro   merge fchmod() an...
438
  	error = notify_change(path->dentry, &newattrs);
fe542cf59   Tetsuo Handa   LSM: Move securit...
439
  out_unlock:
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
440
  	mutex_unlock(&inode->i_mutex);
e57712ebe   Al Viro   merge fchmod() an...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  	mnt_drop_write(path->mnt);
  	return error;
  }
  
  SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
  {
  	struct file * file;
  	int err = -EBADF;
  
  	file = fget(fd);
  	if (file) {
  		audit_inode(NULL, file->f_path.dentry);
  		err = chmod_common(&file->f_path, mode);
  		fput(file);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  	return err;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
458
  SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
460
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

2d8f30380   Al Viro   [PATCH] sanitize ...
463
  	error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
e57712ebe   Al Viro   merge fchmod() an...
464
465
466
467
  	if (!error) {
  		error = chmod_common(&path, mode);
  		path_put(&path);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  	return error;
  }
a26eab240   Heiko Carstens   [CVE-2009-0029] S...
470
  SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
471
472
473
  {
  	return sys_fchmodat(AT_FDCWD, filename, mode);
  }
fe542cf59   Tetsuo Handa   LSM: Move securit...
474
  static int chown_common(struct path *path, uid_t user, gid_t group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  {
fe542cf59   Tetsuo Handa   LSM: Move securit...
476
  	struct inode *inode = path->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  	int error;
  	struct iattr newattrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
487
488
  	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...
489
490
  		newattrs.ia_valid |=
  			ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
491
  	mutex_lock(&inode->i_mutex);
fe542cf59   Tetsuo Handa   LSM: Move securit...
492
493
494
  	error = security_path_chown(path, user, group);
  	if (!error)
  		error = notify_change(path->dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
495
  	mutex_unlock(&inode->i_mutex);
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
496

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
499
  SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
501
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
503
  	error = user_path(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
504
505
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
506
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
507
508
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
509
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
510
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
511
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
512
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
513
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
  	return error;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
516
517
  SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
  		gid_t, group, int, flag)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
518
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
519
  	struct path path;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
520
  	int error = -EINVAL;
65cfc6722   Al Viro   readlinkat(), fch...
521
  	int lookup_flags;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
522

65cfc6722   Al Viro   readlinkat(), fch...
523
  	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
524
  		goto out;
65cfc6722   Al Viro   readlinkat(), fch...
525
526
527
528
  	lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
  	if (flag & AT_EMPTY_PATH)
  		lookup_flags |= LOOKUP_EMPTY;
  	error = user_path_at(dfd, filename, lookup_flags, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
529
530
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
531
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
532
533
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
534
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
535
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
536
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
537
  	path_put(&path);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
538
539
540
  out:
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
541
  SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
543
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
545
  	error = user_lpath(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
546
547
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
548
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
549
550
  	if (error)
  		goto out_release;
fe542cf59   Tetsuo Handa   LSM: Move securit...
551
  	error = chown_common(&path, user, group);
2d8f30380   Al Viro   [PATCH] sanitize ...
552
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
553
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
554
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
555
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  	return error;
  }
ca013e945   Heiko Carstens   [CVE-2009-0029] S...
558
  SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
  {
  	struct file * file;
  	int error = -EBADF;
6902d925d   Dave Hansen   [PATCH] r/o bind ...
562
  	struct dentry * dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
  
  	file = fget(fd);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
565
566
  	if (!file)
  		goto out;
96029c4e0   npiggin@suse.de   fs: introduce mnt...
567
  	error = mnt_want_write_file(file);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
568
569
  	if (error)
  		goto out_fput;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
570
  	dentry = file->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
571
  	audit_inode(NULL, dentry);
fe542cf59   Tetsuo Handa   LSM: Move securit...
572
  	error = chown_common(&file->f_path, user, group);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
573
574
  	mnt_drop_write(file->f_path.mnt);
  out_fput:
6902d925d   Dave Hansen   [PATCH] r/o bind ...
575
576
  	fput(file);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  	return error;
  }
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  /*
   * 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...
607
  static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
482928d59   Al Viro   Fix f_flags/f_mod...
608
  					struct file *f,
745ca2475   David Howells   CRED: Pass creden...
609
610
  					int (*open)(struct inode *, struct file *),
  					const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  {
1abf0c718   Al Viro   New kind of open ...
612
  	static const struct file_operations empty_fops = {};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
  	struct inode *inode;
  	int error;
5300990c0   Al Viro   Sanitize f_flags ...
615
  	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
a1a5b3d93   Peter Staubach   [PATCH] open retu...
616
  				FMODE_PREAD | FMODE_PWRITE;
1abf0c718   Al Viro   New kind of open ...
617
618
619
  
  	if (unlikely(f->f_flags & O_PATH))
  		f->f_mode = FMODE_PATH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
  	inode = dentry->d_inode;
  	if (f->f_mode & FMODE_WRITE) {
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
622
  		error = __get_file_write_access(inode, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
  		if (error)
  			goto cleanup_file;
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
625
626
  		if (!special_file(inode->i_mode))
  			file_take_write(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  	}
  
  	f->f_mapping = inode->i_mapping;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
630
631
  	f->f_path.dentry = dentry;
  	f->f_path.mnt = mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  	f->f_pos = 0;
ee2ffa0df   Nick Piggin   fs: cleanup files...
633
  	file_sb_list_add(f, inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

1abf0c718   Al Viro   New kind of open ...
635
636
637
638
639
640
  	if (unlikely(f->f_mode & FMODE_PATH)) {
  		f->f_op = &empty_fops;
  		return f;
  	}
  
  	f->f_op = fops_get(inode->i_fop);
745ca2475   David Howells   CRED: Pass creden...
641
  	error = security_dentry_open(f, cred);
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
642
643
  	if (error)
  		goto cleanup_all;
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
644
645
646
647
  	if (!open && f->f_op)
  		open = f->f_op->open;
  	if (open) {
  		error = open(inode, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
  		if (error)
  			goto cleanup_all;
  	}
890275b5e   Mimi Zohar   IMA: maintain i_r...
651
652
  	if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
  		i_readcount_inc(inode);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
653

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

a1a5b3d93   Peter Staubach   [PATCH] open retu...
769
770
  	error = -ENFILE;
  	f = get_empty_filp();
6fdcc2162   Peter Staubach   [PATCH] memory le...
771
772
773
  	if (f == NULL) {
  		dput(dentry);
  		mntput(mnt);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
774
  		return ERR_PTR(error);
6fdcc2162   Peter Staubach   [PATCH] memory le...
775
  	}
a1a5b3d93   Peter Staubach   [PATCH] open retu...
776

482928d59   Al Viro   Fix f_flags/f_mod...
777
778
  	f->f_flags = flags;
  	return __dentry_open(dentry, mnt, f, NULL, cred);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
779
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  EXPORT_SYMBOL(dentry_open);
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
781
  static void __put_unused_fd(struct files_struct *files, unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
  {
badf16621   Dipankar Sarma   [PATCH] files: br...
783
784
  	struct fdtable *fdt = files_fdtable(files);
  	__FD_CLR(fd, fdt->open_fds);
0c9e63fd3   Eric Dumazet   [PATCH] Shrinks s...
785
786
  	if (fd < files->next_fd)
  		files->next_fd = fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  }
fc9b52cd8   Harvey Harrison   fs: remove fastca...
788
  void put_unused_fd(unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
793
794
795
796
797
798
  {
  	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 ...
799
   * Install a file pointer in the fd array.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
804
805
806
807
808
809
   *
   * 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...
810
  void fd_install(unsigned int fd, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
  {
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
813
  	struct fdtable *fdt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
815
  	fdt = files_fdtable(files);
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
816
817
  	BUG_ON(fdt->fd[fd] != NULL);
  	rcu_assign_pointer(fdt->fd[fd], file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
  	spin_unlock(&files->file_lock);
  }
  
  EXPORT_SYMBOL(fd_install);
47c805dc2   Al Viro   switch do_filp_op...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  static inline int build_open_flags(int flags, int mode, struct open_flags *op)
  {
  	int lookup_flags = 0;
  	int acc_mode;
  
  	if (!(flags & O_CREAT))
  		mode = 0;
  	op->mode = mode;
  
  	/* Must never be set by userspace */
  	flags &= ~FMODE_NONOTIFY;
  
  	/*
  	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
  	 * check for O_DSYNC if the need any syncing at all we enforce it's
  	 * always set instead of having to deal with possibly weird behaviour
  	 * for malicious applications setting only __O_SYNC.
  	 */
  	if (flags & __O_SYNC)
  		flags |= O_DSYNC;
1abf0c718   Al Viro   New kind of open ...
842
843
844
845
846
847
848
849
850
851
  	/*
  	 * If we have O_PATH in the open flag. Then we
  	 * cannot have anything other than the below set of flags
  	 */
  	if (flags & O_PATH) {
  		flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
  		acc_mode = 0;
  	} else {
  		acc_mode = MAY_OPEN | ACC_MODE(flags);
  	}
47c805dc2   Al Viro   switch do_filp_op...
852

1abf0c718   Al Viro   New kind of open ...
853
  	op->open_flag = flags;
47c805dc2   Al Viro   switch do_filp_op...
854
855
856
857
858
859
860
861
862
863
864
  
  	/* O_TRUNC implies we need access checks for write permissions */
  	if (flags & O_TRUNC)
  		acc_mode |= MAY_WRITE;
  
  	/* Allow the LSM permission hook to distinguish append
  	   access from general write access. */
  	if (flags & O_APPEND)
  		acc_mode |= MAY_APPEND;
  
  	op->acc_mode = acc_mode;
1abf0c718   Al Viro   New kind of open ...
865
  	op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
47c805dc2   Al Viro   switch do_filp_op...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  	if (flags & O_CREAT) {
  		op->intent |= LOOKUP_CREATE;
  		if (flags & O_EXCL)
  			op->intent |= LOOKUP_EXCL;
  	}
  
  	if (flags & O_DIRECTORY)
  		lookup_flags |= LOOKUP_DIRECTORY;
  	if (!(flags & O_NOFOLLOW))
  		lookup_flags |= LOOKUP_FOLLOW;
  	return lookup_flags;
  }
  
  /**
   * filp_open - open file and return file pointer
   *
   * @filename:	path to open
   * @flags:	open flags as per the open(2) second argument
   * @mode:	mode for the new file if O_CREAT is set, else ignored
   *
   * This is the helper to open a file from kernelspace if you really
   * have to.  But in generally you should not do this, so please move
   * along, nothing to see here..
   */
  struct file *filp_open(const char *filename, int flags, int mode)
  {
  	struct open_flags op;
  	int lookup = build_open_flags(flags, mode, &op);
  	return do_filp_open(AT_FDCWD, filename, &op, lookup);
  }
  EXPORT_SYMBOL(filp_open);
73d049a40   Al Viro   open-style analog...
897
898
899
900
901
902
903
904
905
906
907
908
909
  struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
  			    const char *filename, int flags)
  {
  	struct open_flags op;
  	int lookup = build_open_flags(flags, 0, &op);
  	if (flags & O_CREAT)
  		return ERR_PTR(-EINVAL);
  	if (!filename && (flags & O_DIRECTORY))
  		if (!dentry->d_inode->i_op->lookup)
  			return ERR_PTR(-ENOTDIR);
  	return do_file_open_root(dentry, mnt, filename, &op, lookup);
  }
  EXPORT_SYMBOL(file_open_root);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
910
  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  {
47c805dc2   Al Viro   switch do_filp_op...
912
913
  	struct open_flags op;
  	int lookup = build_open_flags(flags, mode, &op);
e922efc34   Miklos Szeredi   [PATCH] remove du...
914
915
  	char *tmp = getname(filename);
  	int fd = PTR_ERR(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  	if (!IS_ERR(tmp)) {
f23513e8d   Ulrich Drepper   Introduce O_CLOEXEC
918
  		fd = get_unused_fd_flags(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  		if (fd >= 0) {
47c805dc2   Al Viro   switch do_filp_op...
920
  			struct file *f = do_filp_open(dfd, tmp, &op, lookup);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
921
922
923
924
  			if (IS_ERR(f)) {
  				put_unused_fd(fd);
  				fd = PTR_ERR(f);
  			} else {
2a12a9d78   Eric Paris   fsnotify: pass a ...
925
  				fsnotify_open(f);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
926
927
  				fd_install(fd, f);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
  		putname(tmp);
  	}
  	return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  }
e922efc34   Miklos Szeredi   [PATCH] remove du...
933

ca013e945   Heiko Carstens   [CVE-2009-0029] S...
934
  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
e922efc34   Miklos Szeredi   [PATCH] remove du...
935
  {
385910f2b   Linus Torvalds   x86: be careful a...
936
  	long ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
937
938
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
939
940
  	ret = do_sys_open(AT_FDCWD, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
941
  	asmlinkage_protect(3, ret, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
942
  	return ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
943
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944

6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
945
946
  SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
  		int, mode)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
947
  {
385910f2b   Linus Torvalds   x86: be careful a...
948
  	long ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
949
950
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
951
952
  	ret = do_sys_open(dfd, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
953
  	asmlinkage_protect(4, ret, dfd, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
954
  	return ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
955
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
956

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
962
  #ifndef __alpha__
  
  /*
   * For backward compatibility?  Maybe this should be moved
   * into arch/i386 instead?
   */
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
963
  SYSCALL_DEFINE2(creat, const char __user *, pathname, int, mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
967
968
969
970
971
972
973
974
975
  {
  	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_...
976
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
  
  	if (!file_count(filp)) {
  		printk(KERN_ERR "VFS: Close: file count is 0
  ");
45778ca81   Christoph Lameter   [PATCH] Remove f_...
981
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
  	}
45778ca81   Christoph Lameter   [PATCH] Remove f_...
983
  	if (filp->f_op && filp->f_op->flush)
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
984
  		retval = filp->f_op->flush(filp, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985

1abf0c718   Al Viro   New kind of open ...
986
987
988
989
  	if (likely(!(filp->f_mode & FMODE_PATH))) {
  		dnotify_flush(filp, id);
  		locks_remove_posix(filp, id);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
992
993
994
995
996
997
998
999
1000
  	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...
1001
  SYSCALL_DEFINE1(close, unsigned int, fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
  {
  	struct file * filp;
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
1005
  	struct fdtable *fdt;
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1006
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
  
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
1009
1010
  	fdt = files_fdtable(files);
  	if (fd >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
  		goto out_unlock;
badf16621   Dipankar Sarma   [PATCH] files: br...
1012
  	filp = fdt->fd[fd];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
  	if (!filp)
  		goto out_unlock;
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
1015
  	rcu_assign_pointer(fdt->fd[fd], NULL);
badf16621   Dipankar Sarma   [PATCH] files: br...
1016
  	FD_CLR(fd, fdt->close_on_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  	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
1029
1030
1031
1032
1033
  
  out_unlock:
  	spin_unlock(&files->file_lock);
  	return -EBADF;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
  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...
1040
  SYSCALL_DEFINE0(vhangup)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
  {
  	if (capable(CAP_SYS_TTY_CONFIG)) {
2cb5998b5   Alan Cox   tty: the vhangup ...
1043
  		tty_vhangup_self();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
  		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...
1058
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
1060
1061
1062
1063
1064
1065
  	return 0;
  }
  
  EXPORT_SYMBOL(generic_file_open);
  
  /*
   * This is used by subsystems that don't want seekable
06b1e104b   Dmitry Torokhov   vfs: clarify that...
1066
1067
1068
   * file descriptors. The function is not supposed to ever fail, the only
   * reason it returns an 'int' and not 'void' is so that it can be plugged
   * directly into file_operations structure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
1073
1074
1075
1076
   */
  int nonseekable_open(struct inode *inode, struct file *filp)
  {
  	filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
  	return 0;
  }
  
  EXPORT_SYMBOL(nonseekable_open);