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

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

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

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

9700382c3   david m. richter   VFS: fix a race i...
251
252
253
254
255
  	/*
  	 * Make sure that there are no leases.  get_write_access() protects
  	 * against the truncate racing with a lease-granting setlease().
  	 */
  	error = break_lease(inode, FMODE_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	if (error)
9700382c3   david m. richter   VFS: fix a race i...
257
  		goto put_write_and_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
  
  	error = locks_verify_truncate(inode, NULL, length);
  	if (!error) {
  		DQUOT_INIT(inode);
2d8f30380   Al Viro   [PATCH] sanitize ...
262
  		error = do_truncate(path.dentry, length, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

9700382c3   david m. richter   VFS: fix a race i...
265
266
  put_write_and_out:
  	put_write_access(inode);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
267
  mnt_drop_write_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
268
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
270
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
278
279
  out:
  	return error;
  }
  
  asmlinkage long sys_truncate(const char __user * path, unsigned long length)
  {
  	/* on 32-bit boxen it will cut the range 2^31--2^32-1 off */
  	return do_sys_truncate(path, (long)length);
  }
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
280
  static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  {
  	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...
298
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  	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)
6e656be89   Peter Staubach   [PATCH] ftruncate...
315
  		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
  out_putf:
  	fput(file);
  out:
  	return error;
  }
  
  asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
324
  	long ret = do_sys_ftruncate(fd, length, 1);
385910f2b   Linus Torvalds   x86: be careful a...
325
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
326
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
327
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
  }
  
  /* LFS versions of truncate are only needed on 32 bit machines */
  #if BITS_PER_LONG == 32
  asmlinkage long sys_truncate64(const char __user * path, loff_t length)
  {
  	return do_sys_truncate(path, length);
  }
  
  asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
339
  	long ret = do_sys_ftruncate(fd, length, 0);
385910f2b   Linus Torvalds   x86: be careful a...
340
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
341
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
342
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
  }
  #endif
97ac73506   Amit Arora   sys_fallocate() i...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
  {
  	struct file *file;
  	struct inode *inode;
  	long ret = -EINVAL;
  
  	if (offset < 0 || len <= 0)
  		goto out;
  
  	/* Return error if mode is not supported */
  	ret = -EOPNOTSUPP;
  	if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
  		goto out;
  
  	ret = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
  	if (!(file->f_mode & FMODE_WRITE))
  		goto out_fput;
  	/*
  	 * Revalidate the write permissions, in case security policy has
  	 * changed since the files were opened.
  	 */
  	ret = security_file_permission(file, MAY_WRITE);
  	if (ret)
  		goto out_fput;
  
  	inode = file->f_path.dentry->d_inode;
  
  	ret = -ESPIPE;
  	if (S_ISFIFO(inode->i_mode))
  		goto out_fput;
  
  	ret = -ENODEV;
  	/*
  	 * Let individual file system decide if it supports preallocation
  	 * for directories or not.
  	 */
  	if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
  		goto out_fput;
  
  	ret = -EFBIG;
  	/* Check for wrap through zero too */
  	if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
  		goto out_fput;
  
  	if (inode->i_op && inode->i_op->fallocate)
  		ret = inode->i_op->fallocate(inode, mode, offset, len);
  	else
0d786d4a2   Ulrich Drepper   fallocate syscall...
395
  		ret = -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
396
397
398
399
400
401
  
  out_fput:
  	fput(file);
  out:
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
404
405
406
  /*
   * 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.
   */
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
407
  asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  {
d84f4f992   David Howells   CRED: Inaugurate ...
409
410
  	const struct cred *old_cred;
  	struct cred *override_cred;
2d8f30380   Al Viro   [PATCH] sanitize ...
411
  	struct path path;
256984a83   Al Viro   [PATCH] preparati...
412
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
  	int res;
  
  	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
417
418
419
  	override_cred = prepare_creds();
  	if (!override_cred)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420

d84f4f992   David Howells   CRED: Inaugurate ...
421
422
  	override_cred->fsuid = override_cred->uid;
  	override_cred->fsgid = override_cred->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423

086f7316f   Andrew G. Morgan   security: filesys...
424
  	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
1cdcbec1a   David Howells   CRED: Neuter sys_...
425
  		/* Clear the capabilities if we switch to a non-root user */
d84f4f992   David Howells   CRED: Inaugurate ...
426
427
  		if (override_cred->uid)
  			cap_clear(override_cred->cap_effective);
086f7316f   Andrew G. Morgan   security: filesys...
428
  		else
d84f4f992   David Howells   CRED: Inaugurate ...
429
430
  			override_cred->cap_effective =
  				override_cred->cap_permitted;
086f7316f   Andrew G. Morgan   security: filesys...
431
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432

d84f4f992   David Howells   CRED: Inaugurate ...
433
  	old_cred = override_creds(override_cred);
2d8f30380   Al Viro   [PATCH] sanitize ...
434
  	res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
435
436
  	if (res)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
437
  	inode = path.dentry->d_inode;
256984a83   Al Viro   [PATCH] preparati...
438
439
  
  	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
30524472c   Al Viro   [PATCH] take noex...
440
441
442
443
444
  		/*
  		 * MAY_EXEC on regular files is denied if the fs is mounted
  		 * with the "noexec" flag.
  		 */
  		res = -EACCES;
2d8f30380   Al Viro   [PATCH] sanitize ...
445
  		if (path.mnt->mnt_flags & MNT_NOEXEC)
30524472c   Al Viro   [PATCH] take noex...
446
447
  			goto out_path_release;
  	}
256984a83   Al Viro   [PATCH] preparati...
448
  	res = inode_permission(inode, mode | MAY_ACCESS);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
449
  	/* SuS v2 requires we report a read only fs too */
256984a83   Al Viro   [PATCH] preparati...
450
  	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
451
  		goto out_path_release;
2f676cbc0   Dave Hansen   [PATCH] r/o bind ...
452
453
454
455
456
457
458
459
460
461
  	/*
  	 * 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 ...
462
  	if (__mnt_is_readonly(path.mnt))
6902d925d   Dave Hansen   [PATCH] r/o bind ...
463
  		res = -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

6902d925d   Dave Hansen   [PATCH] r/o bind ...
465
  out_path_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
466
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
467
  out:
d84f4f992   David Howells   CRED: Inaugurate ...
468
469
  	revert_creds(old_cred);
  	put_cred(override_cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
  	return res;
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
472
473
474
475
  asmlinkage long sys_access(const char __user *filename, int mode)
  {
  	return sys_faccessat(AT_FDCWD, filename, mode);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  asmlinkage long sys_chdir(const char __user * filename)
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
478
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
480
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
483
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
  	if (error)
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
486
  	set_fs_pwd(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
489
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
  out:
  	return error;
  }
  
  asmlinkage long sys_fchdir(unsigned int fd)
  {
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
  	int error;
  
  	error = -EBADF;
  	file = fget(fd);
  	if (!file)
  		goto out;
ac748a09f   Jan Blunck   Make set_fs_{root...
504
  	inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
  
  	error = -ENOTDIR;
  	if (!S_ISDIR(inode->i_mode))
  		goto out_putf;
256984a83   Al Viro   [PATCH] preparati...
509
  	error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  	if (!error)
ac748a09f   Jan Blunck   Make set_fs_{root...
511
  		set_fs_pwd(current->fs, &file->f_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
516
517
518
519
  out_putf:
  	fput(file);
  out:
  	return error;
  }
  
  asmlinkage long sys_chroot(const char __user * filename)
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
520
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
522
  	error = user_path_dir(filename, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
525
  	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
  	if (error)
  		goto dput_and_out;
  
  	error = -EPERM;
  	if (!capable(CAP_SYS_CHROOT))
  		goto dput_and_out;
2d8f30380   Al Viro   [PATCH] sanitize ...
532
  	set_fs_root(current->fs, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  	error = 0;
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
535
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  out:
  	return error;
  }
  
  asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
  {
  	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...
551
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  	inode = dentry->d_inode;
5a190ae69   Al Viro   [PATCH] pass dent...
553
  	audit_inode(NULL, dentry);
73241ccca   Amy Griffis   [PATCH] Collect m...
554

2af482a7e   Dave Hansen   [PATCH] r/o bind ...
555
556
  	err = mnt_want_write(file->f_path.mnt);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  		goto out_putf;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
558
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
  	if (mode == (mode_t) -1)
  		mode = inode->i_mode;
  	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
  	err = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
564
  	mutex_unlock(&inode->i_mutex);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
565
  	mnt_drop_write(file->f_path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
  out_putf:
  	fput(file);
  out:
  	return err;
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
571
572
  asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
  			     mode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
574
575
  	struct path path;
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  	int error;
  	struct iattr newattrs;
2d8f30380   Al Viro   [PATCH] sanitize ...
578
  	error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
581
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

2d8f30380   Al Viro   [PATCH] sanitize ...
583
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
584
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  		goto dput_and_out;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
586
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
  	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 ...
591
  	error = notify_change(path.dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
592
  	mutex_unlock(&inode->i_mutex);
2d8f30380   Al Viro   [PATCH] sanitize ...
593
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
595
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
  out:
  	return error;
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
599
600
601
602
  asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
  {
  	return sys_fchmodat(AT_FDCWD, filename, mode);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
  {
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
605
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  	int error;
  	struct iattr newattrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
  	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...
618
619
  		newattrs.ia_valid |=
  			ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
620
  	mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	error = notify_change(dentry, &newattrs);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
622
  	mutex_unlock(&inode->i_mutex);
beb29e058   Miklos Szeredi   [patch 4/4] vfs: ...
623

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
  	return error;
  }
  
  asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
629
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
631
  	error = user_path(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
632
633
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
634
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
635
636
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
637
638
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
639
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
640
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
641
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
  	return error;
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
644
645
646
  asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
  			     gid_t group, int flag)
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
647
  	struct path path;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
648
649
650
651
652
653
654
  	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 ...
655
  	error = user_path_at(dfd, filename, follow, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
656
657
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
658
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
659
660
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
661
662
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
663
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
664
  	path_put(&path);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
665
666
667
  out:
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
670
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	int error;
2d8f30380   Al Viro   [PATCH] sanitize ...
672
  	error = user_lpath(filename, &path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
673
674
  	if (error)
  		goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
675
  	error = mnt_want_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
676
677
  	if (error)
  		goto out_release;
2d8f30380   Al Viro   [PATCH] sanitize ...
678
679
  	error = chown_common(path.dentry, user, group);
  	mnt_drop_write(path.mnt);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
680
  out_release:
2d8f30380   Al Viro   [PATCH] sanitize ...
681
  	path_put(&path);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
682
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
690
  	return error;
  }
  
  
  asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
  {
  	struct file * file;
  	int error = -EBADF;
6902d925d   Dave Hansen   [PATCH] r/o bind ...
691
  	struct dentry * dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  
  	file = fget(fd);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
694
695
  	if (!file)
  		goto out;
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
696
697
698
  	error = mnt_want_write(file->f_path.mnt);
  	if (error)
  		goto out_fput;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
699
  	dentry = file->f_path.dentry;
5a190ae69   Al Viro   [PATCH] pass dent...
700
  	audit_inode(NULL, dentry);
6902d925d   Dave Hansen   [PATCH] r/o bind ...
701
  	error = chown_common(dentry, user, group);
2af482a7e   Dave Hansen   [PATCH] r/o bind ...
702
703
  	mnt_drop_write(file->f_path.mnt);
  out_fput:
6902d925d   Dave Hansen   [PATCH] r/o bind ...
704
705
  	fput(file);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  	return error;
  }
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  /*
   * 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...
736
  static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
737
  					int flags, struct file *f,
745ca2475   David Howells   CRED: Pass creden...
738
739
  					int (*open)(struct inode *, struct file *),
  					const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
  	struct inode *inode;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  	f->f_flags = flags;
aeb5d7270   Al Viro   [PATCH] introduce...
744
  	f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK |
a1a5b3d93   Peter Staubach   [PATCH] open retu...
745
  				FMODE_PREAD | FMODE_PWRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
  	inode = dentry->d_inode;
  	if (f->f_mode & FMODE_WRITE) {
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
748
  		error = __get_file_write_access(inode, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
  		if (error)
  			goto cleanup_file;
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
751
752
  		if (!special_file(inode->i_mode))
  			file_take_write(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
  	}
  
  	f->f_mapping = inode->i_mapping;
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
756
757
  	f->f_path.dentry = dentry;
  	f->f_path.mnt = mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
  	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...
761
  	error = security_dentry_open(f, cred);
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
762
763
  	if (error)
  		goto cleanup_all;
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
764
765
766
767
  	if (!open && f->f_op)
  		open = f->f_op->open;
  	if (open) {
  		error = open(inode, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
  		if (error)
  			goto cleanup_all;
  	}
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
771

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
776
777
  	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...
778
779
  		if (!f->f_mapping->a_ops ||
  		    ((!f->f_mapping->a_ops->direct_IO) &&
70688e4dd   Nick Piggin   xip: support non-...
780
  		    (!f->f_mapping->a_ops->get_xip_mem))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
786
787
788
789
  			fput(f);
  			f = ERR_PTR(-EINVAL);
  		}
  	}
  
  	return f;
  
  cleanup_all:
  	fops_put(f->f_op);
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
790
  	if (f->f_mode & FMODE_WRITE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  		put_write_access(inode);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
792
793
794
795
796
797
798
799
  		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 ...
800
  			mnt_drop_write(mnt);
ad775f5a8   Dave Hansen   [PATCH] r/o bind ...
801
  		}
4a3fd211c   Dave Hansen   [PATCH] r/o bind ...
802
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  	file_kill(f);
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
804
805
  	f->f_path.dentry = NULL;
  	f->f_path.mnt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
  cleanup_file:
  	put_filp(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
  	dput(dentry);
  	mntput(mnt);
  	return ERR_PTR(error);
  }
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
812
813
814
815
816
817
818
819
820
821
  /**
   * 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...
822
823
824
825
   * 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...
826
827
828
829
830
831
832
833
   * 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...
834
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
835
836
837
838
  	if (IS_ERR(nd->intent.open.file))
  		goto out;
  	if (IS_ERR(dentry))
  		goto out_err;
4ac913785   Jan Blunck   Embed a struct pa...
839
  	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
840
841
  					     nd->intent.open.flags - 1,
  					     nd->intent.open.file,
745ca2475   David Howells   CRED: Pass creden...
842
  					     open, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
  out:
  	return nd->intent.open.file;
  out_err:
  	release_open_intent(nd);
  	nd->intent.open.file = (struct file *)dentry;
  	goto out;
  }
  EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
  
  /**
   * nameidata_to_filp - convert a nameidata to an open filp.
   * @nd: pointer to nameidata
   * @flags: open flags
   *
   * Note that this function destroys the original nameidata
   */
  struct file *nameidata_to_filp(struct nameidata *nd, int flags)
  {
745ca2475   David Howells   CRED: Pass creden...
861
  	const struct cred *cred = current_cred();
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
862
863
864
865
866
  	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...
867
  	if (filp->f_path.dentry == NULL)
4ac913785   Jan Blunck   Embed a struct pa...
868
  		filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
745ca2475   David Howells   CRED: Pass creden...
869
  				     NULL, cred);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
870
  	else
1d957f9bf   Jan Blunck   Introduce path_put()
871
  		path_put(&nd->path);
834f2a4a1   Trond Myklebust   VFS: Allow the fi...
872
873
  	return filp;
  }
6fdcc2162   Peter Staubach   [PATCH] memory le...
874
875
876
877
  /*
   * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
   * error.
   */
745ca2475   David Howells   CRED: Pass creden...
878
879
  struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
  			 const struct cred *cred)
a1a5b3d93   Peter Staubach   [PATCH] open retu...
880
881
882
  {
  	int error;
  	struct file *f;
322ee5b36   Christoph Hellwig   [PATCH] check for...
883
884
885
886
887
888
889
890
891
892
893
894
  	/*
  	 * 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...
895
896
  	error = -ENFILE;
  	f = get_empty_filp();
6fdcc2162   Peter Staubach   [PATCH] memory le...
897
898
899
  	if (f == NULL) {
  		dput(dentry);
  		mntput(mnt);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
900
  		return ERR_PTR(error);
6fdcc2162   Peter Staubach   [PATCH] memory le...
901
  	}
a1a5b3d93   Peter Staubach   [PATCH] open retu...
902

745ca2475   David Howells   CRED: Pass creden...
903
  	return __dentry_open(dentry, mnt, flags, f, NULL, cred);
a1a5b3d93   Peter Staubach   [PATCH] open retu...
904
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  EXPORT_SYMBOL(dentry_open);
b01ec0ef6   Matt Mackall   [PATCH] tiny: Uni...
906
  static void __put_unused_fd(struct files_struct *files, unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  {
badf16621   Dipankar Sarma   [PATCH] files: br...
908
909
  	struct fdtable *fdt = files_fdtable(files);
  	__FD_CLR(fd, fdt->open_fds);
0c9e63fd3   Eric Dumazet   [PATCH] Shrinks s...
910
911
  	if (fd < files->next_fd)
  		files->next_fd = fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  }
fc9b52cd8   Harvey Harrison   fs: remove fastca...
913
  void put_unused_fd(unsigned int fd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
919
920
921
922
923
  {
  	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 ...
924
   * Install a file pointer in the fd array.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
931
932
933
934
   *
   * 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...
935
  void fd_install(unsigned int fd, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  {
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
938
  	struct fdtable *fdt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
940
  	fdt = files_fdtable(files);
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
941
942
  	BUG_ON(fdt->fd[fd] != NULL);
  	rcu_assign_pointer(fdt->fd[fd], file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
  	spin_unlock(&files->file_lock);
  }
  
  EXPORT_SYMBOL(fd_install);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
947
  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
  {
e922efc34   Miklos Szeredi   [PATCH] remove du...
949
950
  	char *tmp = getname(filename);
  	int fd = PTR_ERR(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  	if (!IS_ERR(tmp)) {
f23513e8d   Ulrich Drepper   Introduce O_CLOEXEC
953
  		fd = get_unused_fd_flags(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
  		if (fd >= 0) {
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
955
  			struct file *f = do_filp_open(dfd, tmp, flags, mode);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
956
957
958
959
  			if (IS_ERR(f)) {
  				put_unused_fd(fd);
  				fd = PTR_ERR(f);
  			} else {
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
960
  				fsnotify_open(f->f_path.dentry);
fed2fc18a   Telemaque Ndizihiwe   [PATCH] sys_open(...
961
962
  				fd_install(fd, f);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
  		putname(tmp);
  	}
  	return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  }
e922efc34   Miklos Szeredi   [PATCH] remove du...
968
969
970
  
  asmlinkage long sys_open(const char __user *filename, int flags, int mode)
  {
385910f2b   Linus Torvalds   x86: be careful a...
971
  	long ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
972
973
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
974
975
  	ret = do_sys_open(AT_FDCWD, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
976
  	asmlinkage_protect(3, ret, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
977
  	return ret;
e922efc34   Miklos Szeredi   [PATCH] remove du...
978
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979

5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
980
981
982
  asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
  			   int mode)
  {
385910f2b   Linus Torvalds   x86: be careful a...
983
  	long ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
984
985
  	if (force_o_largefile())
  		flags |= O_LARGEFILE;
385910f2b   Linus Torvalds   x86: be careful a...
986
987
  	ret = do_sys_open(dfd, filename, flags, mode);
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
988
  	asmlinkage_protect(4, ret, dfd, filename, flags, mode);
385910f2b   Linus Torvalds   x86: be careful a...
989
  	return ret;
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
990
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
991

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  #ifndef __alpha__
  
  /*
   * For backward compatibility?  Maybe this should be moved
   * into arch/i386 instead?
   */
  asmlinkage long sys_creat(const char __user * pathname, int mode)
  {
  	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_...
1011
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
  
  	if (!file_count(filp)) {
  		printk(KERN_ERR "VFS: Close: file count is 0
  ");
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1016
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  	}
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1018
  	if (filp->f_op && filp->f_op->flush)
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
1019
  		retval = filp->f_op->flush(filp, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  
  	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.
   */
  asmlinkage long sys_close(unsigned int fd)
  {
  	struct file * filp;
  	struct files_struct *files = current->files;
badf16621   Dipankar Sarma   [PATCH] files: br...
1038
  	struct fdtable *fdt;
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1039
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
  
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
1042
1043
  	fdt = files_fdtable(files);
  	if (fd >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  		goto out_unlock;
badf16621   Dipankar Sarma   [PATCH] files: br...
1045
  	filp = fdt->fd[fd];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
  	if (!filp)
  		goto out_unlock;
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
1048
  	rcu_assign_pointer(fdt->fd[fd], NULL);
badf16621   Dipankar Sarma   [PATCH] files: br...
1049
  	FD_CLR(fd, fdt->close_on_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  	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
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  
  out_unlock:
  	spin_unlock(&files->file_lock);
  	return -EBADF;
  }
  
  EXPORT_SYMBOL(sys_close);
  
  /*
   * This routine simulates a hangup on the tty, to arrange that users
   * are given clean terminals at login time.
   */
  asmlinkage long sys_vhangup(void)
  {
  	if (capable(CAP_SYS_TTY_CONFIG)) {
2cb5998b5   Alan Cox   tty: the vhangup ...
1077
  		tty_vhangup_self();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
  		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...
1092
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  	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);