Blame view

fs/open.c 26.3 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
  
  	error = locks_verify_truncate(inode, NULL, length);
be6d3e56a   Kentaro Takeda   introduce new LSM...
260
261
  	if (!error)
  		error = security_path_truncate(&path, length, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  	if (!error) {
  		DQUOT_INIT(inode);
2d8f30380   Al Viro   [PATCH] sanitize ...
264
  		error = do_truncate(path.dentry, length, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

9700382c3   david m. richter   VFS: fix a race i...
267
268
  put_write_and_out:
  	put_write_access(inode);
9ac9b8474   Dave Hansen   [PATCH] r/o bind ...
269
  mnt_drop_write_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
270
  	mnt_drop_write(path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  dput_and_out:
2d8f30380   Al Viro   [PATCH] sanitize ...
272
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
280
281
  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...
282
  static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  {
  	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...
300
  	dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  	inode = dentry->d_inode;
  	error = -EINVAL;
  	if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
  		goto out_putf;
  
  	error = -EINVAL;
  	/* Cannot ftruncate over 2^31 bytes without large file support */
  	if (small && length > MAX_NON_LFS)
  		goto out_putf;
  
  	error = -EPERM;
  	if (IS_APPEND(inode))
  		goto out_putf;
  
  	error = locks_verify_truncate(inode, file, length);
  	if (!error)
be6d3e56a   Kentaro Takeda   introduce new LSM...
317
318
319
  		error = security_path_truncate(&file->f_path, length,
  					       ATTR_MTIME|ATTR_CTIME);
  	if (!error)
6e656be89   Peter Staubach   [PATCH] ftruncate...
320
  		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
325
326
327
328
  out_putf:
  	fput(file);
  out:
  	return error;
  }
  
  asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
  {
0a489cb3b   Linus Torvalds   x86: don't allow ...
329
  	long ret = do_sys_ftruncate(fd, length, 1);
385910f2b   Linus Torvalds   x86: be careful a...
330
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
331
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
332
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
339
340
341
342
343
  }
  
  /* 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 ...
344
  	long ret = do_sys_ftruncate(fd, length, 0);
385910f2b   Linus Torvalds   x86: be careful a...
345
  	/* avoid REGPARM breakage on x86: */
54a015104   Roland McGrath   asmlinkage_protec...
346
  	asmlinkage_protect(2, ret, fd, length);
0a489cb3b   Linus Torvalds   x86: don't allow ...
347
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  }
  #endif
97ac73506   Amit Arora   sys_fallocate() i...
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
395
  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;
acfa4380e   Al Viro   inode->i_op is ne...
396
  	if (inode->i_op->fallocate)
97ac73506   Amit Arora   sys_fallocate() i...
397
398
  		ret = inode->i_op->fallocate(inode, mode, offset, len);
  	else
0d786d4a2   Ulrich Drepper   fallocate syscall...
399
  		ret = -EOPNOTSUPP;
97ac73506   Amit Arora   sys_fallocate() i...
400
401
402
403
404
405
  
  out_fput:
  	fput(file);
  out:
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
  /*
   * 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 ...
411
  asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  {
d84f4f992   David Howells   CRED: Inaugurate ...
413
414
  	const struct cred *old_cred;
  	struct cred *override_cred;
2d8f30380   Al Viro   [PATCH] sanitize ...
415
  	struct path path;
256984a83   Al Viro   [PATCH] preparati...
416
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
  	int res;
  
  	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
  		return -EINVAL;
d84f4f992   David Howells   CRED: Inaugurate ...
421
422
423
  	override_cred = prepare_creds();
  	if (!override_cred)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

d84f4f992   David Howells   CRED: Inaugurate ...
425
426
  	override_cred->fsuid = override_cred->uid;
  	override_cred->fsgid = override_cred->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427

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

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

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

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

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

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

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

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  #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_...
1015
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
  
  	if (!file_count(filp)) {
  		printk(KERN_ERR "VFS: Close: file count is 0
  ");
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1020
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  	}
45778ca81   Christoph Lameter   [PATCH] Remove f_...
1022
  	if (filp->f_op && filp->f_op->flush)
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
1023
  		retval = filp->f_op->flush(filp, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  
  	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...
1042
  	struct fdtable *fdt;
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1043
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
  
  	spin_lock(&files->file_lock);
badf16621   Dipankar Sarma   [PATCH] files: br...
1046
1047
  	fdt = files_fdtable(files);
  	if (fd >= fdt->max_fds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  		goto out_unlock;
badf16621   Dipankar Sarma   [PATCH] files: br...
1049
  	filp = fdt->fd[fd];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
  	if (!filp)
  		goto out_unlock;
ab2af1f50   Dipankar Sarma   [PATCH] files: fi...
1052
  	rcu_assign_pointer(fdt->fd[fd], NULL);
badf16621   Dipankar Sarma   [PATCH] files: br...
1053
  	FD_CLR(fd, fdt->close_on_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
  	__put_unused_fd(files, fd);
  	spin_unlock(&files->file_lock);
ee731f4f7   Ernie Petrides   [PATCH] fix wrong...
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  	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
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  
  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 ...
1081
  		tty_vhangup_self();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  		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...
1096
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  	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);