Blame view
fs/open.c
26.3 KB
1da177e4c 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 Linux-2.6.12-rc2 |
9 |
#include <linux/file.h> |
9f3acc314 [PATCH] split lin... |
10 |
#include <linux/fdtable.h> |
0eeca2830 [PATCH] inotify |
11 |
#include <linux/fsnotify.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 |
#include <linux/tty.h> #include <linux/namei.h> #include <linux/backing-dev.h> |
16f7e0fe2 [PATCH] capable/c... |
16 |
#include <linux/capability.h> |
086f7316f security: filesys... |
17 |
#include <linux/securebits.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 |
#include <linux/security.h> #include <linux/mount.h> |
5590ff0d5 [PATCH] vfs: *at ... |
20 |
#include <linux/fcntl.h> |
5a0e3ad6a include cleanup: ... |
21 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 |
#include <asm/uaccess.h> #include <linux/fs.h> |
ef3daeda7 [PATCH] Don't for... |
24 |
#include <linux/personality.h> |
1da177e4c Linux-2.6.12-rc2 |
25 26 |
#include <linux/pagemap.h> #include <linux/syscalls.h> |
ab2af1f50 [PATCH] files: fi... |
27 |
#include <linux/rcupdate.h> |
73241ccca [PATCH] Collect m... |
28 |
#include <linux/audit.h> |
97ac73506 sys_fallocate() i... |
29 |
#include <linux/falloc.h> |
5ad4e53bd Get rid of indire... |
30 |
#include <linux/fs_struct.h> |
b65a9cfc2 Untangling ima me... |
31 |
#include <linux/ima.h> |
2dfc1cae4 inotify: remove i... |
32 |
#include <linux/dnotify.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
e81e3f4dc fs: move get_empt... |
34 |
#include "internal.h" |
4a30131e7 [PATCH] Fix some ... |
35 36 |
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) |
1da177e4c Linux-2.6.12-rc2 |
37 |
{ |
939a9421e vfs: allow file t... |
38 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 43 44 45 |
struct iattr newattrs; /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; newattrs.ia_size = length; |
4a30131e7 [PATCH] Fix some ... |
46 |
newattrs.ia_valid = ATTR_SIZE | time_attrs; |
cc4e69dee [PATCH] VFS: pass... |
47 48 49 50 |
if (filp) { newattrs.ia_file = filp; newattrs.ia_valid |= ATTR_FILE; } |
1da177e4c Linux-2.6.12-rc2 |
51 |
|
7b82dc0e6 Remove suid/sgid ... |
52 |
/* Remove suid/sgid on truncate too */ |
939a9421e vfs: allow file t... |
53 54 55 |
ret = should_remove_suid(dentry); if (ret) newattrs.ia_valid |= ret | ATTR_FORCE; |
7b82dc0e6 Remove suid/sgid ... |
56 |
|
1b1dcc1b5 [PATCH] mutex sub... |
57 |
mutex_lock(&dentry->d_inode->i_mutex); |
939a9421e vfs: allow file t... |
58 |
ret = notify_change(dentry, &newattrs); |
1b1dcc1b5 [PATCH] mutex sub... |
59 |
mutex_unlock(&dentry->d_inode->i_mutex); |
939a9421e vfs: allow file t... |
60 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
61 |
} |
2d8f30380 [PATCH] sanitize ... |
62 |
static long do_sys_truncate(const char __user *pathname, loff_t length) |
1da177e4c Linux-2.6.12-rc2 |
63 |
{ |
2d8f30380 [PATCH] sanitize ... |
64 65 |
struct path path; struct inode *inode; |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 70 |
int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; |
2d8f30380 [PATCH] sanitize ... |
71 |
error = user_path(pathname, &path); |
1da177e4c Linux-2.6.12-rc2 |
72 73 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
74 |
inode = path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
75 76 77 78 79 80 81 82 83 |
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; |
2d8f30380 [PATCH] sanitize ... |
84 |
error = mnt_want_write(path.mnt); |
1da177e4c Linux-2.6.12-rc2 |
85 86 |
if (error) goto dput_and_out; |
256984a83 [PATCH] preparati... |
87 |
error = inode_permission(inode, MAY_WRITE); |
9ac9b8474 [PATCH] r/o bind ... |
88 89 |
if (error) goto mnt_drop_write_and_out; |
1da177e4c Linux-2.6.12-rc2 |
90 91 |
error = -EPERM; |
c82e42da8 [patch 1/5] vfs: ... |
92 |
if (IS_APPEND(inode)) |
9ac9b8474 [PATCH] r/o bind ... |
93 |
goto mnt_drop_write_and_out; |
1da177e4c Linux-2.6.12-rc2 |
94 |
|
9700382c3 VFS: fix a race i... |
95 |
error = get_write_access(inode); |
1da177e4c Linux-2.6.12-rc2 |
96 |
if (error) |
9ac9b8474 [PATCH] r/o bind ... |
97 |
goto mnt_drop_write_and_out; |
1da177e4c Linux-2.6.12-rc2 |
98 |
|
9700382c3 VFS: fix a race i... |
99 100 101 102 |
/* * Make sure that there are no leases. get_write_access() protects * against the truncate racing with a lease-granting setlease(). */ |
8737c9305 Switch may_open()... |
103 |
error = break_lease(inode, O_WRONLY); |
1da177e4c Linux-2.6.12-rc2 |
104 |
if (error) |
9700382c3 VFS: fix a race i... |
105 |
goto put_write_and_out; |
1da177e4c Linux-2.6.12-rc2 |
106 107 |
error = locks_verify_truncate(inode, NULL, length); |
be6d3e56a introduce new LSM... |
108 |
if (!error) |
ea0d3ab23 LSM: Remove unuse... |
109 |
error = security_path_truncate(&path); |
907f4554e dquot: move dquot... |
110 |
if (!error) |
2d8f30380 [PATCH] sanitize ... |
111 |
error = do_truncate(path.dentry, length, 0, NULL); |
1da177e4c Linux-2.6.12-rc2 |
112 |
|
9700382c3 VFS: fix a race i... |
113 114 |
put_write_and_out: put_write_access(inode); |
9ac9b8474 [PATCH] r/o bind ... |
115 |
mnt_drop_write_and_out: |
2d8f30380 [PATCH] sanitize ... |
116 |
mnt_drop_write(path.mnt); |
1da177e4c Linux-2.6.12-rc2 |
117 |
dput_and_out: |
2d8f30380 [PATCH] sanitize ... |
118 |
path_put(&path); |
1da177e4c Linux-2.6.12-rc2 |
119 120 121 |
out: return error; } |
4fd8da8d6 fs: change sys_tr... |
122 |
SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) |
1da177e4c Linux-2.6.12-rc2 |
123 |
{ |
4fd8da8d6 fs: change sys_tr... |
124 |
return do_sys_truncate(path, length); |
1da177e4c Linux-2.6.12-rc2 |
125 |
} |
b01ec0ef6 [PATCH] tiny: Uni... |
126 |
static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
{ struct inode * inode; struct dentry *dentry; struct file * file; int error; error = -EINVAL; if (length < 0) goto out; error = -EBADF; file = fget(fd); if (!file) goto out; /* explicitly opened as large or we are on 64-bit box */ if (file->f_flags & O_LARGEFILE) small = 0; |
0f7fc9e4d [PATCH] VFS: chan... |
144 |
dentry = file->f_path.dentry; |
1da177e4c Linux-2.6.12-rc2 |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; error = -EINVAL; /* Cannot ftruncate over 2^31 bytes without large file support */ if (small && length > MAX_NON_LFS) goto out_putf; error = -EPERM; if (IS_APPEND(inode)) goto out_putf; error = locks_verify_truncate(inode, file, length); if (!error) |
ea0d3ab23 LSM: Remove unuse... |
161 |
error = security_path_truncate(&file->f_path); |
be6d3e56a introduce new LSM... |
162 |
if (!error) |
6e656be89 [PATCH] ftruncate... |
163 |
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); |
1da177e4c Linux-2.6.12-rc2 |
164 165 166 167 168 |
out_putf: fput(file); out: return error; } |
bdc480e3b [CVE-2009-0029] S... |
169 |
SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length) |
1da177e4c Linux-2.6.12-rc2 |
170 |
{ |
0a489cb3b x86: don't allow ... |
171 |
long ret = do_sys_ftruncate(fd, length, 1); |
385910f2b x86: be careful a... |
172 |
/* avoid REGPARM breakage on x86: */ |
54a015104 asmlinkage_protec... |
173 |
asmlinkage_protect(2, ret, fd, length); |
0a489cb3b x86: don't allow ... |
174 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
175 176 177 178 |
} /* LFS versions of truncate are only needed on 32 bit machines */ #if BITS_PER_LONG == 32 |
6673e0c3f [CVE-2009-0029] S... |
179 |
SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length) |
1da177e4c Linux-2.6.12-rc2 |
180 181 182 |
{ return do_sys_truncate(path, length); } |
6673e0c3f [CVE-2009-0029] S... |
183 184 185 186 187 188 189 |
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS asmlinkage long SyS_truncate64(long path, loff_t length) { return SYSC_truncate64((const char __user *) path, length); } SYSCALL_ALIAS(sys_truncate64, SyS_truncate64); #endif |
1da177e4c Linux-2.6.12-rc2 |
190 |
|
6673e0c3f [CVE-2009-0029] S... |
191 |
SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length) |
1da177e4c Linux-2.6.12-rc2 |
192 |
{ |
0a489cb3b x86: don't allow ... |
193 |
long ret = do_sys_ftruncate(fd, length, 0); |
385910f2b x86: be careful a... |
194 |
/* avoid REGPARM breakage on x86: */ |
54a015104 asmlinkage_protec... |
195 |
asmlinkage_protect(2, ret, fd, length); |
0a489cb3b x86: don't allow ... |
196 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
197 |
} |
6673e0c3f [CVE-2009-0029] S... |
198 199 200 201 202 203 |
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS asmlinkage long SyS_ftruncate64(long fd, loff_t length) { return SYSC_ftruncate64((unsigned int) fd, length); } SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64); |
1da177e4c Linux-2.6.12-rc2 |
204 |
#endif |
6673e0c3f [CVE-2009-0029] S... |
205 |
#endif /* BITS_PER_LONG == 32 */ |
1da177e4c Linux-2.6.12-rc2 |
206 |
|
3e63cbb1e fs: Add new pre-a... |
207 208 |
int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) |
97ac73506 sys_fallocate() i... |
209 |
{ |
3e63cbb1e fs: Add new pre-a... |
210 211 |
struct inode *inode = file->f_path.dentry->d_inode; long ret; |
97ac73506 sys_fallocate() i... |
212 213 |
if (offset < 0 || len <= 0) |
3e63cbb1e fs: Add new pre-a... |
214 |
return -EINVAL; |
97ac73506 sys_fallocate() i... |
215 216 |
/* Return error if mode is not supported */ |
79124f18b fs: add hole punc... |
217 218 219 220 221 222 |
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) return -EOPNOTSUPP; /* Punch hole must have keep size set */ if ((mode & FALLOC_FL_PUNCH_HOLE) && !(mode & FALLOC_FL_KEEP_SIZE)) |
3e63cbb1e fs: Add new pre-a... |
223 |
return -EOPNOTSUPP; |
97ac73506 sys_fallocate() i... |
224 |
|
97ac73506 sys_fallocate() i... |
225 |
if (!(file->f_mode & FMODE_WRITE)) |
3e63cbb1e fs: Add new pre-a... |
226 |
return -EBADF; |
1ca551c6c Check for immutab... |
227 228 229 230 231 232 233 |
/* It's not possible punch hole on append only file */ if (mode & FALLOC_FL_PUNCH_HOLE && IS_APPEND(inode)) return -EPERM; if (IS_IMMUTABLE(inode)) return -EPERM; |
97ac73506 sys_fallocate() i... |
234 235 236 237 238 239 |
/* * Revalidate the write permissions, in case security policy has * changed since the files were opened. */ ret = security_file_permission(file, MAY_WRITE); if (ret) |
3e63cbb1e fs: Add new pre-a... |
240 |
return ret; |
97ac73506 sys_fallocate() i... |
241 |
|
97ac73506 sys_fallocate() i... |
242 |
if (S_ISFIFO(inode->i_mode)) |
3e63cbb1e fs: Add new pre-a... |
243 |
return -ESPIPE; |
97ac73506 sys_fallocate() i... |
244 |
|
97ac73506 sys_fallocate() i... |
245 246 247 248 249 |
/* * Let individual file system decide if it supports preallocation * for directories or not. */ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
3e63cbb1e fs: Add new pre-a... |
250 |
return -ENODEV; |
97ac73506 sys_fallocate() i... |
251 |
|
97ac73506 sys_fallocate() i... |
252 253 |
/* Check for wrap through zero too */ if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) |
3e63cbb1e fs: Add new pre-a... |
254 |
return -EFBIG; |
97ac73506 sys_fallocate() i... |
255 |
|
2fe17c107 fallocate should ... |
256 |
if (!file->f_op->fallocate) |
3e63cbb1e fs: Add new pre-a... |
257 |
return -EOPNOTSUPP; |
97ac73506 sys_fallocate() i... |
258 |
|
2fe17c107 fallocate should ... |
259 |
return file->f_op->fallocate(file, mode, offset, len); |
3e63cbb1e fs: Add new pre-a... |
260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
} SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) { struct file *file; int error = -EBADF; file = fget(fd); if (file) { error = do_fallocate(file, mode, offset, len); fput(file); } return error; |
97ac73506 sys_fallocate() i... |
274 |
} |
3e63cbb1e fs: Add new pre-a... |
275 |
|
6673e0c3f [CVE-2009-0029] S... |
276 277 278 279 280 281 282 |
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) { return SYSC_fallocate((int)fd, (int)mode, offset, len); } SYSCALL_ALIAS(sys_fallocate, SyS_fallocate); #endif |
97ac73506 sys_fallocate() i... |
283 |
|
1da177e4c Linux-2.6.12-rc2 |
284 285 286 287 288 |
/* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ |
6559eed8c [CVE-2009-0029] S... |
289 |
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) |
1da177e4c Linux-2.6.12-rc2 |
290 |
{ |
d84f4f992 CRED: Inaugurate ... |
291 292 |
const struct cred *old_cred; struct cred *override_cred; |
2d8f30380 [PATCH] sanitize ... |
293 |
struct path path; |
256984a83 [PATCH] preparati... |
294 |
struct inode *inode; |
1da177e4c Linux-2.6.12-rc2 |
295 296 297 298 |
int res; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; |
d84f4f992 CRED: Inaugurate ... |
299 300 301 |
override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
302 |
|
d84f4f992 CRED: Inaugurate ... |
303 304 |
override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; |
1da177e4c Linux-2.6.12-rc2 |
305 |
|
086f7316f security: filesys... |
306 |
if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
1cdcbec1a CRED: Neuter sys_... |
307 |
/* Clear the capabilities if we switch to a non-root user */ |
d84f4f992 CRED: Inaugurate ... |
308 309 |
if (override_cred->uid) cap_clear(override_cred->cap_effective); |
086f7316f security: filesys... |
310 |
else |
d84f4f992 CRED: Inaugurate ... |
311 312 |
override_cred->cap_effective = override_cred->cap_permitted; |
086f7316f security: filesys... |
313 |
} |
1da177e4c Linux-2.6.12-rc2 |
314 |
|
d84f4f992 CRED: Inaugurate ... |
315 |
old_cred = override_creds(override_cred); |
2d8f30380 [PATCH] sanitize ... |
316 |
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
6902d925d [PATCH] r/o bind ... |
317 318 |
if (res) goto out; |
2d8f30380 [PATCH] sanitize ... |
319 |
inode = path.dentry->d_inode; |
256984a83 [PATCH] preparati... |
320 321 |
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { |
30524472c [PATCH] take noex... |
322 323 324 325 326 |
/* * MAY_EXEC on regular files is denied if the fs is mounted * with the "noexec" flag. */ res = -EACCES; |
2d8f30380 [PATCH] sanitize ... |
327 |
if (path.mnt->mnt_flags & MNT_NOEXEC) |
30524472c [PATCH] take noex... |
328 329 |
goto out_path_release; } |
256984a83 [PATCH] preparati... |
330 |
res = inode_permission(inode, mode | MAY_ACCESS); |
6902d925d [PATCH] r/o bind ... |
331 |
/* SuS v2 requires we report a read only fs too */ |
256984a83 [PATCH] preparati... |
332 |
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) |
6902d925d [PATCH] r/o bind ... |
333 |
goto out_path_release; |
2f676cbc0 [PATCH] r/o bind ... |
334 335 336 337 338 339 340 341 342 343 |
/* * This is a rare case where using __mnt_is_readonly() * is OK without a mnt_want/drop_write() pair. Since * no actual write to the fs is performed here, we do * not need to telegraph to that to anyone. * * By doing this, we accept that this access is * inherently racy and know that the fs may change * state before we even see this result. */ |
2d8f30380 [PATCH] sanitize ... |
344 |
if (__mnt_is_readonly(path.mnt)) |
6902d925d [PATCH] r/o bind ... |
345 |
res = -EROFS; |
1da177e4c Linux-2.6.12-rc2 |
346 |
|
6902d925d [PATCH] r/o bind ... |
347 |
out_path_release: |
2d8f30380 [PATCH] sanitize ... |
348 |
path_put(&path); |
6902d925d [PATCH] r/o bind ... |
349 |
out: |
d84f4f992 CRED: Inaugurate ... |
350 351 |
revert_creds(old_cred); put_cred(override_cred); |
1da177e4c Linux-2.6.12-rc2 |
352 353 |
return res; } |
ca013e945 [CVE-2009-0029] S... |
354 |
SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) |
5590ff0d5 [PATCH] vfs: *at ... |
355 356 357 |
{ return sys_faccessat(AT_FDCWD, filename, mode); } |
3cdad4288 [CVE-2009-0029] S... |
358 |
SYSCALL_DEFINE1(chdir, const char __user *, filename) |
1da177e4c Linux-2.6.12-rc2 |
359 |
{ |
2d8f30380 [PATCH] sanitize ... |
360 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
361 |
int error; |
2d8f30380 [PATCH] sanitize ... |
362 |
error = user_path_dir(filename, &path); |
1da177e4c Linux-2.6.12-rc2 |
363 364 |
if (error) goto out; |
9cfcac810 vfs: re-introduce... |
365 |
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); |
1da177e4c Linux-2.6.12-rc2 |
366 367 |
if (error) goto dput_and_out; |
2d8f30380 [PATCH] sanitize ... |
368 |
set_fs_pwd(current->fs, &path); |
1da177e4c Linux-2.6.12-rc2 |
369 370 |
dput_and_out: |
2d8f30380 [PATCH] sanitize ... |
371 |
path_put(&path); |
1da177e4c Linux-2.6.12-rc2 |
372 373 374 |
out: return error; } |
3cdad4288 [CVE-2009-0029] S... |
375 |
SYSCALL_DEFINE1(fchdir, unsigned int, fd) |
1da177e4c Linux-2.6.12-rc2 |
376 377 |
{ struct file *file; |
1da177e4c Linux-2.6.12-rc2 |
378 |
struct inode *inode; |
1da177e4c Linux-2.6.12-rc2 |
379 380 381 382 383 384 |
int error; error = -EBADF; file = fget(fd); if (!file) goto out; |
ac748a09f Make set_fs_{root... |
385 |
inode = file->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
386 387 388 389 |
error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) goto out_putf; |
9cfcac810 vfs: re-introduce... |
390 |
error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); |
1da177e4c Linux-2.6.12-rc2 |
391 |
if (!error) |
ac748a09f Make set_fs_{root... |
392 |
set_fs_pwd(current->fs, &file->f_path); |
1da177e4c Linux-2.6.12-rc2 |
393 394 395 396 397 |
out_putf: fput(file); out: return error; } |
3480b2574 [CVE-2009-0029] S... |
398 |
SYSCALL_DEFINE1(chroot, const char __user *, filename) |
1da177e4c Linux-2.6.12-rc2 |
399 |
{ |
2d8f30380 [PATCH] sanitize ... |
400 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
401 |
int error; |
2d8f30380 [PATCH] sanitize ... |
402 |
error = user_path_dir(filename, &path); |
1da177e4c Linux-2.6.12-rc2 |
403 404 |
if (error) goto out; |
9cfcac810 vfs: re-introduce... |
405 |
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); |
1da177e4c Linux-2.6.12-rc2 |
406 407 408 409 410 411 |
if (error) goto dput_and_out; error = -EPERM; if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; |
8b8efb440 LSM: Add security... |
412 413 414 |
error = security_path_chroot(&path); if (error) goto dput_and_out; |
1da177e4c Linux-2.6.12-rc2 |
415 |
|
2d8f30380 [PATCH] sanitize ... |
416 |
set_fs_root(current->fs, &path); |
1da177e4c Linux-2.6.12-rc2 |
417 418 |
error = 0; dput_and_out: |
2d8f30380 [PATCH] sanitize ... |
419 |
path_put(&path); |
1da177e4c Linux-2.6.12-rc2 |
420 421 422 |
out: return error; } |
e57712ebe merge fchmod() an... |
423 |
static int chmod_common(struct path *path, umode_t mode) |
1da177e4c Linux-2.6.12-rc2 |
424 |
{ |
e57712ebe merge fchmod() an... |
425 |
struct inode *inode = path->dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
426 |
struct iattr newattrs; |
e57712ebe merge fchmod() an... |
427 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
428 |
|
e57712ebe merge fchmod() an... |
429 430 431 |
error = mnt_want_write(path->mnt); if (error) return error; |
fe542cf59 LSM: Move securit... |
432 |
mutex_lock(&inode->i_mutex); |
cdcf116d4 switch security_p... |
433 |
error = security_path_chmod(path, mode); |
e57712ebe merge fchmod() an... |
434 |
if (error) |
fe542cf59 LSM: Move securit... |
435 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
436 437 |
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
e57712ebe merge fchmod() an... |
438 |
error = notify_change(path->dentry, &newattrs); |
fe542cf59 LSM: Move securit... |
439 |
out_unlock: |
1b1dcc1b5 [PATCH] mutex sub... |
440 |
mutex_unlock(&inode->i_mutex); |
e57712ebe merge fchmod() an... |
441 442 443 |
mnt_drop_write(path->mnt); return error; } |
49f0a0767 switch sys_chmod(... |
444 |
SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) |
e57712ebe merge fchmod() an... |
445 446 447 448 449 450 451 452 453 454 |
{ struct file * file; int err = -EBADF; file = fget(fd); if (file) { audit_inode(NULL, file->f_path.dentry); err = chmod_common(&file->f_path, mode); fput(file); } |
1da177e4c Linux-2.6.12-rc2 |
455 456 |
return err; } |
49f0a0767 switch sys_chmod(... |
457 |
SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode) |
1da177e4c Linux-2.6.12-rc2 |
458 |
{ |
2d8f30380 [PATCH] sanitize ... |
459 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
460 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
461 |
|
2d8f30380 [PATCH] sanitize ... |
462 |
error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
e57712ebe merge fchmod() an... |
463 464 465 466 |
if (!error) { error = chmod_common(&path, mode); path_put(&path); } |
1da177e4c Linux-2.6.12-rc2 |
467 468 |
return error; } |
49f0a0767 switch sys_chmod(... |
469 |
SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) |
5590ff0d5 [PATCH] vfs: *at ... |
470 471 472 |
{ return sys_fchmodat(AT_FDCWD, filename, mode); } |
fe542cf59 LSM: Move securit... |
473 |
static int chown_common(struct path *path, uid_t user, gid_t group) |
1da177e4c Linux-2.6.12-rc2 |
474 |
{ |
fe542cf59 LSM: Move securit... |
475 |
struct inode *inode = path->dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
476 477 |
int error; struct iattr newattrs; |
1da177e4c Linux-2.6.12-rc2 |
478 479 480 481 482 483 484 485 486 487 |
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 Implement file po... |
488 489 |
newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; |
1b1dcc1b5 [PATCH] mutex sub... |
490 |
mutex_lock(&inode->i_mutex); |
fe542cf59 LSM: Move securit... |
491 492 493 |
error = security_path_chown(path, user, group); if (!error) error = notify_change(path->dentry, &newattrs); |
1b1dcc1b5 [PATCH] mutex sub... |
494 |
mutex_unlock(&inode->i_mutex); |
beb29e058 [patch 4/4] vfs: ... |
495 |
|
1da177e4c Linux-2.6.12-rc2 |
496 497 |
return error; } |
ca013e945 [CVE-2009-0029] S... |
498 |
SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) |
1da177e4c Linux-2.6.12-rc2 |
499 |
{ |
2d8f30380 [PATCH] sanitize ... |
500 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
501 |
int error; |
2d8f30380 [PATCH] sanitize ... |
502 |
error = user_path(filename, &path); |
6902d925d [PATCH] r/o bind ... |
503 504 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
505 |
error = mnt_want_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
506 507 |
if (error) goto out_release; |
fe542cf59 LSM: Move securit... |
508 |
error = chown_common(&path, user, group); |
2d8f30380 [PATCH] sanitize ... |
509 |
mnt_drop_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
510 |
out_release: |
2d8f30380 [PATCH] sanitize ... |
511 |
path_put(&path); |
6902d925d [PATCH] r/o bind ... |
512 |
out: |
1da177e4c Linux-2.6.12-rc2 |
513 514 |
return error; } |
6559eed8c [CVE-2009-0029] S... |
515 516 |
SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, gid_t, group, int, flag) |
5590ff0d5 [PATCH] vfs: *at ... |
517 |
{ |
2d8f30380 [PATCH] sanitize ... |
518 |
struct path path; |
5590ff0d5 [PATCH] vfs: *at ... |
519 |
int error = -EINVAL; |
65cfc6722 readlinkat(), fch... |
520 |
int lookup_flags; |
5590ff0d5 [PATCH] vfs: *at ... |
521 |
|
65cfc6722 readlinkat(), fch... |
522 |
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) |
5590ff0d5 [PATCH] vfs: *at ... |
523 |
goto out; |
65cfc6722 readlinkat(), fch... |
524 525 526 527 |
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; if (flag & AT_EMPTY_PATH) lookup_flags |= LOOKUP_EMPTY; error = user_path_at(dfd, filename, lookup_flags, &path); |
6902d925d [PATCH] r/o bind ... |
528 529 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
530 |
error = mnt_want_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
531 532 |
if (error) goto out_release; |
fe542cf59 LSM: Move securit... |
533 |
error = chown_common(&path, user, group); |
2d8f30380 [PATCH] sanitize ... |
534 |
mnt_drop_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
535 |
out_release: |
2d8f30380 [PATCH] sanitize ... |
536 |
path_put(&path); |
5590ff0d5 [PATCH] vfs: *at ... |
537 538 539 |
out: return error; } |
ca013e945 [CVE-2009-0029] S... |
540 |
SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group) |
1da177e4c Linux-2.6.12-rc2 |
541 |
{ |
2d8f30380 [PATCH] sanitize ... |
542 |
struct path path; |
1da177e4c Linux-2.6.12-rc2 |
543 |
int error; |
2d8f30380 [PATCH] sanitize ... |
544 |
error = user_lpath(filename, &path); |
6902d925d [PATCH] r/o bind ... |
545 546 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
547 |
error = mnt_want_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
548 549 |
if (error) goto out_release; |
fe542cf59 LSM: Move securit... |
550 |
error = chown_common(&path, user, group); |
2d8f30380 [PATCH] sanitize ... |
551 |
mnt_drop_write(path.mnt); |
2af482a7e [PATCH] r/o bind ... |
552 |
out_release: |
2d8f30380 [PATCH] sanitize ... |
553 |
path_put(&path); |
6902d925d [PATCH] r/o bind ... |
554 |
out: |
1da177e4c Linux-2.6.12-rc2 |
555 556 |
return error; } |
ca013e945 [CVE-2009-0029] S... |
557 |
SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) |
1da177e4c Linux-2.6.12-rc2 |
558 559 560 |
{ struct file * file; int error = -EBADF; |
6902d925d [PATCH] r/o bind ... |
561 |
struct dentry * dentry; |
1da177e4c Linux-2.6.12-rc2 |
562 563 |
file = fget(fd); |
6902d925d [PATCH] r/o bind ... |
564 565 |
if (!file) goto out; |
96029c4e0 fs: introduce mnt... |
566 |
error = mnt_want_write_file(file); |
2af482a7e [PATCH] r/o bind ... |
567 568 |
if (error) goto out_fput; |
0f7fc9e4d [PATCH] VFS: chan... |
569 |
dentry = file->f_path.dentry; |
5a190ae69 [PATCH] pass dent... |
570 |
audit_inode(NULL, dentry); |
fe542cf59 LSM: Move securit... |
571 |
error = chown_common(&file->f_path, user, group); |
2a79f17e4 vfs: mnt_drop_wri... |
572 |
mnt_drop_write_file(file); |
2af482a7e [PATCH] r/o bind ... |
573 |
out_fput: |
6902d925d [PATCH] r/o bind ... |
574 575 |
fput(file); out: |
1da177e4c Linux-2.6.12-rc2 |
576 577 |
return error; } |
4a3fd211c [PATCH] r/o bind ... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
/* * 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 [PATCH] open retu... |
606 |
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
482928d59 Fix f_flags/f_mod... |
607 |
struct file *f, |
745ca2475 CRED: Pass creden... |
608 609 |
int (*open)(struct inode *, struct file *), const struct cred *cred) |
1da177e4c Linux-2.6.12-rc2 |
610 |
{ |
1abf0c718 New kind of open ... |
611 |
static const struct file_operations empty_fops = {}; |
1da177e4c Linux-2.6.12-rc2 |
612 613 |
struct inode *inode; int error; |
5300990c0 Sanitize f_flags ... |
614 |
f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | |
a1a5b3d93 [PATCH] open retu... |
615 |
FMODE_PREAD | FMODE_PWRITE; |
1abf0c718 New kind of open ... |
616 617 618 |
if (unlikely(f->f_flags & O_PATH)) f->f_mode = FMODE_PATH; |
1da177e4c Linux-2.6.12-rc2 |
619 620 |
inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { |
4a3fd211c [PATCH] r/o bind ... |
621 |
error = __get_file_write_access(inode, mnt); |
1da177e4c Linux-2.6.12-rc2 |
622 623 |
if (error) goto cleanup_file; |
ad775f5a8 [PATCH] r/o bind ... |
624 625 |
if (!special_file(inode->i_mode)) file_take_write(f); |
1da177e4c Linux-2.6.12-rc2 |
626 627 628 |
} f->f_mapping = inode->i_mapping; |
0f7fc9e4d [PATCH] VFS: chan... |
629 630 |
f->f_path.dentry = dentry; f->f_path.mnt = mnt; |
1da177e4c Linux-2.6.12-rc2 |
631 |
f->f_pos = 0; |
ee2ffa0df fs: cleanup files... |
632 |
file_sb_list_add(f, inode->i_sb); |
1da177e4c Linux-2.6.12-rc2 |
633 |
|
1abf0c718 New kind of open ... |
634 635 636 637 638 639 |
if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; return f; } f->f_op = fops_get(inode->i_fop); |
745ca2475 CRED: Pass creden... |
640 |
error = security_dentry_open(f, cred); |
788e7dd4c SELinux: Improve ... |
641 642 |
if (error) goto cleanup_all; |
f3c7691e8 leases: fix write... |
643 644 645 |
error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; |
834f2a4a1 VFS: Allow the fi... |
646 647 648 649 |
if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); |
1da177e4c Linux-2.6.12-rc2 |
650 651 652 |
if (error) goto cleanup_all; } |
890275b5e IMA: maintain i_r... |
653 654 |
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); |
834f2a4a1 VFS: Allow the fi... |
655 |
|
1da177e4c Linux-2.6.12-rc2 |
656 657 658 659 660 661 |
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 [PATCH] xip: fs/m... |
662 663 |
if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && |
70688e4dd xip: support non-... |
664 |
(!f->f_mapping->a_ops->get_xip_mem))) { |
1da177e4c Linux-2.6.12-rc2 |
665 666 667 668 669 670 671 672 673 |
fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); |
4a3fd211c [PATCH] r/o bind ... |
674 |
if (f->f_mode & FMODE_WRITE) { |
1da177e4c Linux-2.6.12-rc2 |
675 |
put_write_access(inode); |
ad775f5a8 [PATCH] r/o bind ... |
676 677 678 679 680 681 682 683 |
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 [PATCH] r/o bind ... |
684 |
mnt_drop_write(mnt); |
ad775f5a8 [PATCH] r/o bind ... |
685 |
} |
4a3fd211c [PATCH] r/o bind ... |
686 |
} |
ee2ffa0df fs: cleanup files... |
687 |
file_sb_list_del(f); |
0f7fc9e4d [PATCH] VFS: chan... |
688 689 |
f->f_path.dentry = NULL; f->f_path.mnt = NULL; |
1da177e4c Linux-2.6.12-rc2 |
690 691 |
cleanup_file: put_filp(f); |
1da177e4c Linux-2.6.12-rc2 |
692 693 694 695 |
dput(dentry); mntput(mnt); return ERR_PTR(error); } |
834f2a4a1 VFS: Allow the fi... |
696 697 698 699 700 701 702 703 704 705 |
/** * 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 [PATCH] Add looku... |
706 707 708 709 |
* 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 VFS: Allow the fi... |
710 711 712 713 714 715 716 717 |
* 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 CRED: Pass creden... |
718 |
const struct cred *cred = current_cred(); |
834f2a4a1 VFS: Allow the fi... |
719 720 721 722 |
if (IS_ERR(nd->intent.open.file)) goto out; if (IS_ERR(dentry)) goto out_err; |
4ac913785 Embed a struct pa... |
723 |
nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), |
834f2a4a1 VFS: Allow the fi... |
724 |
nd->intent.open.file, |
745ca2475 CRED: Pass creden... |
725 |
open, cred); |
834f2a4a1 VFS: Allow the fi... |
726 727 728 729 |
out: return nd->intent.open.file; out_err: release_open_intent(nd); |
5a9a43646 vfs: use ERR_CAST... |
730 |
nd->intent.open.file = ERR_CAST(dentry); |
834f2a4a1 VFS: Allow the fi... |
731 732 733 734 735 736 737 738 739 740 741 |
goto out; } EXPORT_SYMBOL_GPL(lookup_instantiate_filp); /** * nameidata_to_filp - convert a nameidata to an open filp. * @nd: pointer to nameidata * @flags: open flags * * Note that this function destroys the original nameidata */ |
482928d59 Fix f_flags/f_mod... |
742 |
struct file *nameidata_to_filp(struct nameidata *nd) |
834f2a4a1 VFS: Allow the fi... |
743 |
{ |
745ca2475 CRED: Pass creden... |
744 |
const struct cred *cred = current_cred(); |
834f2a4a1 VFS: Allow the fi... |
745 746 747 748 |
struct file *filp; /* Pick up the filp from the open intent */ filp = nd->intent.open.file; |
2dab59744 Fix possible filp... |
749 |
nd->intent.open.file = NULL; |
834f2a4a1 VFS: Allow the fi... |
750 |
/* Has the filesystem initialised the file for us? */ |
d893f1bc2 fix open/umount race |
751 752 |
if (filp->f_path.dentry == NULL) { path_get(&nd->path); |
482928d59 Fix f_flags/f_mod... |
753 |
filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, |
745ca2475 CRED: Pass creden... |
754 |
NULL, cred); |
d893f1bc2 fix open/umount race |
755 |
} |
834f2a4a1 VFS: Allow the fi... |
756 757 |
return filp; } |
6fdcc2162 [PATCH] memory le... |
758 759 760 761 |
/* * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an * error. */ |
745ca2475 CRED: Pass creden... |
762 763 |
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, const struct cred *cred) |
a1a5b3d93 [PATCH] open retu... |
764 765 766 |
{ int error; struct file *f; |
e0e817392 CRED: Add some co... |
767 |
validate_creds(cred); |
c212f9aaf fs: Use BUG_ON(!m... |
768 769 |
/* We must always pass in a valid mount pointer. */ BUG_ON(!mnt); |
322ee5b36 [PATCH] check for... |
770 |
|
a1a5b3d93 [PATCH] open retu... |
771 772 |
error = -ENFILE; f = get_empty_filp(); |
6fdcc2162 [PATCH] memory le... |
773 774 775 |
if (f == NULL) { dput(dentry); mntput(mnt); |
a1a5b3d93 [PATCH] open retu... |
776 |
return ERR_PTR(error); |
6fdcc2162 [PATCH] memory le... |
777 |
} |
a1a5b3d93 [PATCH] open retu... |
778 |
|
482928d59 Fix f_flags/f_mod... |
779 780 |
f->f_flags = flags; return __dentry_open(dentry, mnt, f, NULL, cred); |
a1a5b3d93 [PATCH] open retu... |
781 |
} |
1da177e4c Linux-2.6.12-rc2 |
782 |
EXPORT_SYMBOL(dentry_open); |
b01ec0ef6 [PATCH] tiny: Uni... |
783 |
static void __put_unused_fd(struct files_struct *files, unsigned int fd) |
1da177e4c Linux-2.6.12-rc2 |
784 |
{ |
badf16621 [PATCH] files: br... |
785 786 |
struct fdtable *fdt = files_fdtable(files); __FD_CLR(fd, fdt->open_fds); |
0c9e63fd3 [PATCH] Shrinks s... |
787 788 |
if (fd < files->next_fd) files->next_fd = fd; |
1da177e4c Linux-2.6.12-rc2 |
789 |
} |
fc9b52cd8 fs: remove fastca... |
790 |
void put_unused_fd(unsigned int fd) |
1da177e4c Linux-2.6.12-rc2 |
791 792 793 794 795 796 797 798 799 800 |
{ 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 [PATCH] vfs: *at ... |
801 |
* Install a file pointer in the fd array. |
1da177e4c Linux-2.6.12-rc2 |
802 803 804 805 806 807 808 809 810 811 |
* * 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 fs: remove fastca... |
812 |
void fd_install(unsigned int fd, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
813 814 |
{ struct files_struct *files = current->files; |
badf16621 [PATCH] files: br... |
815 |
struct fdtable *fdt; |
1da177e4c Linux-2.6.12-rc2 |
816 |
spin_lock(&files->file_lock); |
badf16621 [PATCH] files: br... |
817 |
fdt = files_fdtable(files); |
ab2af1f50 [PATCH] files: fi... |
818 819 |
BUG_ON(fdt->fd[fd] != NULL); rcu_assign_pointer(fdt->fd[fd], file); |
1da177e4c Linux-2.6.12-rc2 |
820 821 822 823 |
spin_unlock(&files->file_lock); } EXPORT_SYMBOL(fd_install); |
a218d0fdc switch open and m... |
824 |
static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) |
47c805dc2 switch do_filp_op... |
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 |
{ int lookup_flags = 0; int acc_mode; if (!(flags & O_CREAT)) mode = 0; op->mode = mode; /* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY; /* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only * check for O_DSYNC if the need any syncing at all we enforce it's * always set instead of having to deal with possibly weird behaviour * for malicious applications setting only __O_SYNC. */ if (flags & __O_SYNC) flags |= O_DSYNC; |
1abf0c718 New kind of open ... |
844 845 846 847 848 849 850 851 852 853 |
/* * If we have O_PATH in the open flag. Then we * cannot have anything other than the below set of flags */ if (flags & O_PATH) { flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; acc_mode = 0; } else { acc_mode = MAY_OPEN | ACC_MODE(flags); } |
47c805dc2 switch do_filp_op... |
854 |
|
1abf0c718 New kind of open ... |
855 |
op->open_flag = flags; |
47c805dc2 switch do_filp_op... |
856 857 858 859 860 861 862 863 864 865 866 |
/* O_TRUNC implies we need access checks for write permissions */ if (flags & O_TRUNC) acc_mode |= MAY_WRITE; /* Allow the LSM permission hook to distinguish append access from general write access. */ if (flags & O_APPEND) acc_mode |= MAY_APPEND; op->acc_mode = acc_mode; |
1abf0c718 New kind of open ... |
867 |
op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN; |
47c805dc2 switch do_filp_op... |
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
if (flags & O_CREAT) { op->intent |= LOOKUP_CREATE; if (flags & O_EXCL) op->intent |= LOOKUP_EXCL; } if (flags & O_DIRECTORY) lookup_flags |= LOOKUP_DIRECTORY; if (!(flags & O_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; return lookup_flags; } /** * filp_open - open file and return file pointer * * @filename: path to open * @flags: open flags as per the open(2) second argument * @mode: mode for the new file if O_CREAT is set, else ignored * * This is the helper to open a file from kernelspace if you really * have to. But in generally you should not do this, so please move * along, nothing to see here.. */ |
a218d0fdc switch open and m... |
892 |
struct file *filp_open(const char *filename, int flags, umode_t mode) |
47c805dc2 switch do_filp_op... |
893 894 895 896 897 898 |
{ struct open_flags op; int lookup = build_open_flags(flags, mode, &op); return do_filp_open(AT_FDCWD, filename, &op, lookup); } EXPORT_SYMBOL(filp_open); |
73d049a40 open-style analog... |
899 900 901 902 903 904 905 906 907 908 909 910 911 |
struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, const char *filename, int flags) { struct open_flags op; int lookup = build_open_flags(flags, 0, &op); if (flags & O_CREAT) return ERR_PTR(-EINVAL); if (!filename && (flags & O_DIRECTORY)) if (!dentry->d_inode->i_op->lookup) return ERR_PTR(-ENOTDIR); return do_file_open_root(dentry, mnt, filename, &op, lookup); } EXPORT_SYMBOL(file_open_root); |
a218d0fdc switch open and m... |
912 |
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) |
1da177e4c Linux-2.6.12-rc2 |
913 |
{ |
47c805dc2 switch do_filp_op... |
914 915 |
struct open_flags op; int lookup = build_open_flags(flags, mode, &op); |
e922efc34 [PATCH] remove du... |
916 917 |
char *tmp = getname(filename); int fd = PTR_ERR(tmp); |
1da177e4c Linux-2.6.12-rc2 |
918 |
|
1da177e4c Linux-2.6.12-rc2 |
919 |
if (!IS_ERR(tmp)) { |
f23513e8d Introduce O_CLOEXEC |
920 |
fd = get_unused_fd_flags(flags); |
1da177e4c Linux-2.6.12-rc2 |
921 |
if (fd >= 0) { |
47c805dc2 switch do_filp_op... |
922 |
struct file *f = do_filp_open(dfd, tmp, &op, lookup); |
fed2fc18a [PATCH] sys_open(... |
923 924 925 926 |
if (IS_ERR(f)) { put_unused_fd(fd); fd = PTR_ERR(f); } else { |
2a12a9d78 fsnotify: pass a ... |
927 |
fsnotify_open(f); |
fed2fc18a [PATCH] sys_open(... |
928 929 |
fd_install(fd, f); } |
1da177e4c Linux-2.6.12-rc2 |
930 |
} |
1da177e4c Linux-2.6.12-rc2 |
931 932 933 |
putname(tmp); } return fd; |
1da177e4c Linux-2.6.12-rc2 |
934 |
} |
e922efc34 [PATCH] remove du... |
935 |
|
a218d0fdc switch open and m... |
936 |
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) |
e922efc34 [PATCH] remove du... |
937 |
{ |
385910f2b x86: be careful a... |
938 |
long ret; |
e922efc34 [PATCH] remove du... |
939 940 |
if (force_o_largefile()) flags |= O_LARGEFILE; |
385910f2b x86: be careful a... |
941 942 |
ret = do_sys_open(AT_FDCWD, filename, flags, mode); /* avoid REGPARM breakage on x86: */ |
54a015104 asmlinkage_protec... |
943 |
asmlinkage_protect(3, ret, filename, flags, mode); |
385910f2b x86: be careful a... |
944 |
return ret; |
e922efc34 [PATCH] remove du... |
945 |
} |
1da177e4c Linux-2.6.12-rc2 |
946 |
|
6559eed8c [CVE-2009-0029] S... |
947 |
SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, |
a218d0fdc switch open and m... |
948 |
umode_t, mode) |
5590ff0d5 [PATCH] vfs: *at ... |
949 |
{ |
385910f2b x86: be careful a... |
950 |
long ret; |
5590ff0d5 [PATCH] vfs: *at ... |
951 952 |
if (force_o_largefile()) flags |= O_LARGEFILE; |
385910f2b x86: be careful a... |
953 954 |
ret = do_sys_open(dfd, filename, flags, mode); /* avoid REGPARM breakage on x86: */ |
54a015104 asmlinkage_protec... |
955 |
asmlinkage_protect(4, ret, dfd, filename, flags, mode); |
385910f2b x86: be careful a... |
956 |
return ret; |
5590ff0d5 [PATCH] vfs: *at ... |
957 |
} |
5590ff0d5 [PATCH] vfs: *at ... |
958 |
|
1da177e4c Linux-2.6.12-rc2 |
959 960 961 962 963 964 |
#ifndef __alpha__ /* * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ |
a218d0fdc switch open and m... |
965 |
SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode) |
1da177e4c Linux-2.6.12-rc2 |
966 967 968 969 970 971 972 973 974 975 976 977 |
{ 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 [PATCH] Remove f_... |
978 |
int retval = 0; |
1da177e4c Linux-2.6.12-rc2 |
979 980 981 982 |
if (!file_count(filp)) { printk(KERN_ERR "VFS: Close: file count is 0 "); |
45778ca81 [PATCH] Remove f_... |
983 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
984 |
} |
45778ca81 [PATCH] Remove f_... |
985 |
if (filp->f_op && filp->f_op->flush) |
75e1fcc0b [PATCH] vfs: add ... |
986 |
retval = filp->f_op->flush(filp, id); |
1da177e4c Linux-2.6.12-rc2 |
987 |
|
1abf0c718 New kind of open ... |
988 989 990 991 |
if (likely(!(filp->f_mode & FMODE_PATH))) { dnotify_flush(filp, id); locks_remove_posix(filp, id); } |
1da177e4c Linux-2.6.12-rc2 |
992 993 994 995 996 997 998 999 1000 1001 1002 |
fput(filp); return retval; } EXPORT_SYMBOL(filp_close); /* * Careful here! We test whether the file pointer is NULL before * releasing the fd. This ensures that one clone task can't release * an fd while another clone is opening it. */ |
ca013e945 [CVE-2009-0029] S... |
1003 |
SYSCALL_DEFINE1(close, unsigned int, fd) |
1da177e4c Linux-2.6.12-rc2 |
1004 1005 1006 |
{ struct file * filp; struct files_struct *files = current->files; |
badf16621 [PATCH] files: br... |
1007 |
struct fdtable *fdt; |
ee731f4f7 [PATCH] fix wrong... |
1008 |
int retval; |
1da177e4c Linux-2.6.12-rc2 |
1009 1010 |
spin_lock(&files->file_lock); |
badf16621 [PATCH] files: br... |
1011 1012 |
fdt = files_fdtable(files); if (fd >= fdt->max_fds) |
1da177e4c Linux-2.6.12-rc2 |
1013 |
goto out_unlock; |
badf16621 [PATCH] files: br... |
1014 |
filp = fdt->fd[fd]; |
1da177e4c Linux-2.6.12-rc2 |
1015 1016 |
if (!filp) goto out_unlock; |
ab2af1f50 [PATCH] files: fi... |
1017 |
rcu_assign_pointer(fdt->fd[fd], NULL); |
badf16621 [PATCH] files: br... |
1018 |
FD_CLR(fd, fdt->close_on_exec); |
1da177e4c Linux-2.6.12-rc2 |
1019 1020 |
__put_unused_fd(files, fd); spin_unlock(&files->file_lock); |
ee731f4f7 [PATCH] fix wrong... |
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
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 Linux-2.6.12-rc2 |
1031 1032 1033 1034 1035 |
out_unlock: spin_unlock(&files->file_lock); return -EBADF; } |
1da177e4c Linux-2.6.12-rc2 |
1036 1037 1038 1039 1040 1041 |
EXPORT_SYMBOL(sys_close); /* * This routine simulates a hangup on the tty, to arrange that users * are given clean terminals at login time. */ |
ca013e945 [CVE-2009-0029] S... |
1042 |
SYSCALL_DEFINE0(vhangup) |
1da177e4c Linux-2.6.12-rc2 |
1043 1044 |
{ if (capable(CAP_SYS_TTY_CONFIG)) { |
2cb5998b5 tty: the vhangup ... |
1045 |
tty_vhangup_self(); |
1da177e4c Linux-2.6.12-rc2 |
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 |
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 fs: correct SuS c... |
1060 |
return -EOVERFLOW; |
1da177e4c Linux-2.6.12-rc2 |
1061 1062 1063 1064 1065 1066 1067 |
return 0; } EXPORT_SYMBOL(generic_file_open); /* * This is used by subsystems that don't want seekable |
06b1e104b vfs: clarify that... |
1068 1069 1070 |
* file descriptors. The function is not supposed to ever fail, the only * reason it returns an 'int' and not 'void' is so that it can be plugged * directly into file_operations structure. |
1da177e4c Linux-2.6.12-rc2 |
1071 1072 1073 1074 1075 1076 1077 1078 |
*/ int nonseekable_open(struct inode *inode, struct file *filp) { filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); return 0; } EXPORT_SYMBOL(nonseekable_open); |