diff options
-rw-r--r-- | drivers/gpu/drm/drm_lease.c | 16 | ||||
-rw-r--r-- | drivers/misc/cxl/api.c | 11 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/ocxl_hw.c | 8 | ||||
-rw-r--r-- | fs/aio.c | 8 | ||||
-rw-r--r-- | fs/anon_inodes.c | 3 | ||||
-rw-r--r-- | fs/binfmt_misc.c | 2 | ||||
-rw-r--r-- | fs/file_table.c | 46 | ||||
-rw-r--r-- | fs/hugetlbfs/inode.c | 3 | ||||
-rw-r--r-- | fs/internal.h | 6 | ||||
-rw-r--r-- | fs/namei.c | 45 | ||||
-rw-r--r-- | fs/open.c | 92 | ||||
-rw-r--r-- | fs/pipe.c | 15 | ||||
-rw-r--r-- | fs/proc/generic.c | 11 | ||||
-rw-r--r-- | include/linux/file.h | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 8 | ||||
-rw-r--r-- | include/linux/lsm_hooks.h | 2 | ||||
-rw-r--r-- | include/linux/security.h | 5 | ||||
-rw-r--r-- | ipc/shm.c | 8 | ||||
-rw-r--r-- | mm/memfd.c | 2 | ||||
-rw-r--r-- | mm/shmem.c | 3 | ||||
-rw-r--r-- | net/socket.c | 3 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 4 | ||||
-rw-r--r-- | security/security.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 4 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 6 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 2 |
26 files changed, 137 insertions, 183 deletions
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 50c73c0a20b9..b54fb78a283c 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -553,24 +553,13 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, /* Clone the lessor file to create a new file for us */ DRM_DEBUG_LEASE("Allocating lease file\n"); - path_get(&lessor_file->f_path); - lessee_file = alloc_file(&lessor_file->f_path, - lessor_file->f_mode, - fops_get(lessor_file->f_inode->i_fop)); - + lessee_file = file_clone_open(lessor_file); if (IS_ERR(lessee_file)) { ret = PTR_ERR(lessee_file); goto out_lessee; } - /* Initialize the new file for DRM */ - DRM_DEBUG_LEASE("Initializing the file with %p\n", lessee_file->f_op->open); - ret = lessee_file->f_op->open(lessee_file->f_inode, lessee_file); - if (ret) - goto out_lessee_file; - lessee_priv = lessee_file->private_data; - /* Change the file to a master one */ drm_master_put(&lessee_priv->master); lessee_priv->master = lessee; @@ -588,9 +577,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); return 0; -out_lessee_file: - fput(lessee_file); - out_lessee: drm_master_put(&lessee); diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 753b1a698fc4..0b5cb6cf91a0 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -102,16 +102,15 @@ static struct file *cxl_getfile(const char *name, path.mnt = mntget(cxl_vfs_mount); d_instantiate(path.dentry, inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); - if (IS_ERR(file)) - goto err_dput; - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); + if (IS_ERR(file)) { + path_put(&path); + goto err_fs; + } file->private_data = priv; return file; -err_dput: - path_put(&path); err_inode: iput(inode); err_fs: diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 0a95b5f25380..99bb393a8a34 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -129,20 +129,18 @@ static struct file *ocxlflash_getfile(struct device *dev, const char *name, path.mnt = mntget(ocxlflash_vfs_mount); d_instantiate(path.dentry, inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) { rc = PTR_ERR(file); dev_err(dev, "%s: alloc_file failed rc=%d\n", __func__, rc); - goto err5; + path_put(&path); + goto err3; } - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; out: return file; -err5: - path_put(&path); err4: iput(inode); err3: @@ -234,13 +234,9 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) path.mnt = mntget(aio_mnt); d_instantiate(path.dentry, inode); - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &aio_ring_fops); - if (IS_ERR(file)) { + file = alloc_file(&path, O_RDWR, &aio_ring_fops); + if (IS_ERR(file)) path_put(&path); - return file; - } - - file->f_flags = O_RDWR; return file; } diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 3168ee4e77f4..6b235ab1df6c 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -102,12 +102,11 @@ struct file *anon_inode_getfile(const char *name, d_instantiate(path.dentry, anon_inode_inode); - file = alloc_file(&path, OPEN_FMODE(flags), fops); + file = alloc_file(&path, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; return file; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 4b5fff31ef27..aa4a7a23ff99 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -205,7 +205,7 @@ static int load_misc_binary(struct linux_binprm *bprm) goto error; if (fmt->flags & MISC_FMT_OPEN_FILE) { - interp_file = filp_clone_open(fmt->interp_file); + interp_file = file_clone_open(fmt->interp_file); if (!IS_ERR(interp_file)) deny_write_access(interp_file); } else { diff --git a/fs/file_table.c b/fs/file_table.c index 7ec0b3e5f05d..9b70ed2bbc4e 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -51,6 +51,7 @@ static void file_free_rcu(struct rcu_head *head) static inline void file_free(struct file *f) { + security_file_free(f); percpu_counter_dec(&nr_files); call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); } @@ -100,9 +101,8 @@ int proc_nr_files(struct ctl_table *table, int write, * done, you will imbalance int the mount's writer count * and a warning at __fput() time. */ -struct file *get_empty_filp(void) +struct file *alloc_empty_file(int flags, const struct cred *cred) { - const struct cred *cred = current_cred(); static long old_max; struct file *f; int error; @@ -123,11 +123,10 @@ struct file *get_empty_filp(void) if (unlikely(!f)) return ERR_PTR(-ENOMEM); - percpu_counter_inc(&nr_files); f->f_cred = get_cred(cred); error = security_file_alloc(f); if (unlikely(error)) { - file_free(f); + file_free_rcu(&f->f_u.fu_rcuhead); return ERR_PTR(error); } @@ -136,7 +135,10 @@ struct file *get_empty_filp(void) spin_lock_init(&f->f_lock); mutex_init(&f->f_pos_lock); eventpoll_init_file(f); + f->f_flags = flags; + f->f_mode = OPEN_FMODE(flags); /* f->f_version: 0 */ + percpu_counter_inc(&nr_files); return f; over: @@ -152,15 +154,15 @@ over: * alloc_file - allocate and initialize a 'struct file' * * @path: the (dentry, vfsmount) pair for the new file - * @mode: the mode with which the new file will be opened + * @flags: O_... flags with which the new file will be opened * @fop: the 'struct file_operations' for the new file */ -struct file *alloc_file(const struct path *path, fmode_t mode, +struct file *alloc_file(const struct path *path, int flags, const struct file_operations *fop) { struct file *file; - file = get_empty_filp(); + file = alloc_empty_file(flags, current_cred()); if (IS_ERR(file)) return file; @@ -168,15 +170,15 @@ struct file *alloc_file(const struct path *path, fmode_t mode, file->f_inode = path->dentry->d_inode; file->f_mapping = path->dentry->d_inode->i_mapping; file->f_wb_err = filemap_sample_wb_err(file->f_mapping); - if ((mode & FMODE_READ) && + if ((file->f_mode & FMODE_READ) && likely(fop->read || fop->read_iter)) - mode |= FMODE_CAN_READ; - if ((mode & FMODE_WRITE) && + file->f_mode |= FMODE_CAN_READ; + if ((file->f_mode & FMODE_WRITE) && likely(fop->write || fop->write_iter)) - mode |= FMODE_CAN_WRITE; - file->f_mode = mode; + file->f_mode |= FMODE_CAN_WRITE; + file->f_mode |= FMODE_OPENED; file->f_op = fop; - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(path->dentry->d_inode); return file; } @@ -190,6 +192,9 @@ static void __fput(struct file *file) struct vfsmount *mnt = file->f_path.mnt; struct inode *inode = file->f_inode; + if (unlikely(!(file->f_mode & FMODE_OPENED))) + goto out; + might_sleep(); fsnotify_close(file); @@ -207,7 +212,6 @@ static void __fput(struct file *file) } if (file->f_op->release) file->f_op->release(inode, file); - security_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && !(file->f_mode & FMODE_PATH))) { cdev_put(inode->i_cdev); @@ -220,12 +224,10 @@ static void __fput(struct file *file) put_write_access(inode); __mnt_drop_write(mnt); } - file->f_path.dentry = NULL; - file->f_path.mnt = NULL; - file->f_inode = NULL; - file_free(file); dput(dentry); mntput(mnt); +out: + file_free(file); } static LLIST_HEAD(delayed_fput_list); @@ -300,14 +302,6 @@ void __fput_sync(struct file *file) EXPORT_SYMBOL(fput); -void put_filp(struct file *file) -{ - if (atomic_long_dec_and_test(&file->f_count)) { - security_file_free(file); - file_free(file); - } -} - void __init files_init(void) { filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index d508c7844681..71aed47422e2 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -1375,8 +1375,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, inode->i_size = size; clear_nlink(inode); - file = alloc_file(&path, FMODE_WRITE | FMODE_READ, - &hugetlbfs_file_operations); + file = alloc_file(&path, O_RDWR, &hugetlbfs_file_operations); if (IS_ERR(file)) goto out_dentry; /* inode is already attached */ diff --git a/fs/internal.h b/fs/internal.h index 980d005b21b4..52a346903748 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -93,7 +93,7 @@ extern void chroot_fs_refs(const struct path *, const struct path *); /* * file_table.c */ -extern struct file *get_empty_filp(void); +extern struct file *alloc_empty_file(int, const struct cred *); /* * super.c @@ -125,9 +125,7 @@ int do_fchmodat(int dfd, const char __user *filename, umode_t mode); int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, int flag); -extern int open_check_o_direct(struct file *f); -extern int vfs_open(const struct path *, struct file *, const struct cred *); -extern struct file *filp_clone_open(struct file *); +extern int vfs_open(const struct path *, struct file *); /* * inode.c diff --git a/fs/namei.c b/fs/namei.c index 734cef54fdf8..d152cc05fdc3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3396,19 +3396,15 @@ finish_open_created: if (error) goto out; BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ - error = vfs_open(&nd->path, file, current_cred()); + error = vfs_open(&nd->path, file); if (error) goto out; *opened |= FILE_OPENED; opened: - error = open_check_o_direct(file); - if (!error) - error = ima_file_check(file, op->acc_mode, *opened); + error = ima_file_check(file, op->acc_mode, *opened); if (!error && will_truncate) error = handle_truncate(file); out: - if (unlikely(error) && (*opened & FILE_OPENED)) - fput(file); if (unlikely(error > 0)) { WARN_ON(1); error = -EINVAL; @@ -3481,11 +3477,6 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags, goto out2; file->f_path.mnt = path.mnt; error = finish_open(file, child, NULL, opened); - if (error) - goto out2; - error = open_check_o_direct(file); - if (error) - fput(file); out2: mnt_drop_write(path.mnt); out: @@ -3499,7 +3490,7 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) int error = path_lookupat(nd, flags, &path); if (!error) { audit_inode(nd->name, path.dentry, 0); - error = vfs_open(&path, file, current_cred()); + error = vfs_open(&path, file); path_put(&path); } return error; @@ -3513,12 +3504,10 @@ static struct file *path_openat(struct nameidata *nd, int opened = 0; int error; - file = get_empty_filp(); + file = alloc_empty_file(op->open_flag, current_cred()); if (IS_ERR(file)) return file; - file->f_flags = op->open_flag; - if (unlikely(file->f_flags & __O_TMPFILE)) { error = do_tmpfile(nd, flags, op, file, &opened); goto out2; @@ -3533,7 +3522,7 @@ static struct file *path_openat(struct nameidata *nd, s = path_init(nd, flags); if (IS_ERR(s)) { - put_filp(file); + fput(file); return ERR_CAST(s); } while (!(error = link_path_walk(s, nd)) && @@ -3547,20 +3536,20 @@ static struct file *path_openat(struct nameidata *nd, } terminate_walk(nd); out2: - if (!(opened & FILE_OPENED)) { - BUG_ON(!error); - put_filp(file); + if (likely(!error)) { + if (likely(opened & FILE_OPENED)) + return file; + WARN_ON(1); + error = -EINVAL; } - if (unlikely(error)) { - if (error == -EOPENSTALE) { - if (flags & LOOKUP_RCU) - error = -ECHILD; - else - error = -ESTALE; - } - file = ERR_PTR(error); + fput(file); + if (error == -EOPENSTALE) { + if (flags & LOOKUP_RCU) + error = -ECHILD; + else + error = -ESTALE; } - return file; + return ERR_PTR(error); } struct file *do_filp_open(int dfd, struct filename *pathname, diff --git a/fs/open.c b/fs/open.c index d0e955b558ad..dd15711eb658 100644 --- a/fs/open.c +++ b/fs/open.c @@ -724,27 +724,13 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) return ksys_fchown(fd, user, group); } -int open_check_o_direct(struct file *f) -{ - /* NB: we're sure to have correct a_ops only after f_op->open */ - if (f->f_flags & O_DIRECT) { - if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) - return -EINVAL; - } - return 0; -} - static int do_dentry_open(struct file *f, struct inode *inode, - int (*open)(struct inode *, struct file *), - const struct cred *cred) + int (*open)(struct inode *, struct file *)) { static const struct file_operations empty_fops = {}; int error; - f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | - FMODE_PREAD | FMODE_PWRITE; - path_get(&f->f_path); f->f_inode = inode; f->f_mapping = inode->i_mapping; @@ -753,7 +739,7 @@ static int do_dentry_open(struct file *f, f->f_wb_err = filemap_sample_wb_err(f->f_mapping); if (unlikely(f->f_flags & O_PATH)) { - f->f_mode = FMODE_PATH; + f->f_mode = FMODE_PATH | FMODE_OPENED; f->f_op = &empty_fops; return 0; } @@ -780,7 +766,7 @@ static int do_dentry_open(struct file *f, goto cleanup_all; } - error = security_file_open(f, cred); + error = security_file_open(f); if (error) goto cleanup_all; @@ -788,6 +774,8 @@ static int do_dentry_open(struct file *f, if (error) goto cleanup_all; + /* normally all 3 are set; ->open() can clear them if needed */ + f->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (!open) open = f->f_op->open; if (open) { @@ -795,6 +783,7 @@ static int do_dentry_open(struct file *f, if (error) goto cleanup_all; } + f->f_mode |= FMODE_OPENED; if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); if ((f->f_mode & FMODE_READ) && @@ -809,9 +798,16 @@ static int do_dentry_open(struct file *f, 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) { + if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) + return -EINVAL; + } return 0; cleanup_all: + if (WARN_ON_ONCE(error > 0)) + error = -EINVAL; fops_put(f->f_op); if (f->f_mode & FMODE_WRITER) { put_write_access(inode); @@ -854,8 +850,7 @@ int finish_open(struct file *file, struct dentry *dentry, BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ file->f_path.dentry = dentry; - error = do_dentry_open(file, d_backing_inode(dentry), open, - current_cred()); + error = do_dentry_open(file, d_backing_inode(dentry), open); if (!error) *opened |= FILE_OPENED; @@ -896,8 +891,7 @@ EXPORT_SYMBOL(file_path); * @file: newly allocated file with f_flag initialized * @cred: credentials to use */ -int vfs_open(const struct path *path, struct file *file, - const struct cred *cred) +int vfs_open(const struct path *path, struct file *file) { struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0); @@ -905,7 +899,7 @@ int vfs_open(const struct path *path, struct file *file, return PTR_ERR(dentry); file->f_path = *path; - return do_dentry_open(file, d_backing_inode(dentry), NULL, cred); + return do_dentry_open(file, d_backing_inode(dentry), NULL); } struct file *dentry_open(const struct path *path, int flags, @@ -919,19 +913,11 @@ struct file *dentry_open(const struct path *path, int flags, /* We must always pass in a valid mount pointer. */ BUG_ON(!path->mnt); - f = get_empty_filp(); + f = alloc_empty_file(flags, cred); if (!IS_ERR(f)) { - f->f_flags = flags; - error = vfs_open(path, f, cred); - if (!error) { - /* from now on we need fput() to dispose of f */ - error = open_check_o_direct(f); - if (error) { - fput(f); - f = ERR_PTR(error); - } - } else { - put_filp(f); + error = vfs_open(path, f); + if (error) { + fput(f); f = ERR_PTR(error); } } @@ -939,6 +925,24 @@ struct file *dentry_open(const struct path *path, int flags, } EXPORT_SYMBOL(dentry_open); +struct file *open_with_fake_path(const struct path *path, int flags, + struct inode *inode, const struct cred *cred) +{ + struct file *f = alloc_empty_file(flags, cred); + if (!IS_ERR(f)) { + int error; + + f->f_path = *path; + error = do_dentry_open(f, inode, NULL); + if (error) { + fput(f); + f = ERR_PTR(error); + } + } + return f; +} +EXPORT_SYMBOL(open_with_fake_path); + static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; @@ -1063,26 +1067,6 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, } EXPORT_SYMBOL(file_open_root); -struct file *filp_clone_open(struct file *oldfile) -{ - struct file *file; - int retval; - - file = get_empty_filp(); - if (IS_ERR(file)) - return file; - - file->f_flags = oldfile->f_flags; - retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred); - if (retval) { - put_filp(file); - return ERR_PTR(retval); - } - - return file; -} -EXPORT_SYMBOL(filp_clone_open); - long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; diff --git a/fs/pipe.c b/fs/pipe.c index bb0840e234f3..1909422e5a78 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -760,29 +760,28 @@ int create_pipe_files(struct file **res, int flags) d_instantiate(path.dentry, inode); - f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops); + f = alloc_file(&path, O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)), + &pipefifo_fops); if (IS_ERR(f)) { err = PTR_ERR(f); goto err_dentry; } - f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)); f->private_data = inode->i_pipe; - res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops); + res[0] = alloc_file(&path, O_RDONLY | (flags & O_NONBLOCK), + &pipefifo_fops); if (IS_ERR(res[0])) { - err = PTR_ERR(res[0]); - goto err_file; + put_pipe_info(inode, inode->i_pipe); + fput(f); + return PTR_ERR(res[0]); } path_get(&path); res[0]->private_data = inode->i_pipe; - res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK); res[1] = f; return 0; -err_file: - put_filp(f); err_dentry: free_pipe_info(inode->i_pipe); path_put(&path); diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 6ac1c92997ea..bb1c1625b158 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -564,11 +564,20 @@ static int proc_seq_open(struct inode *inode, struct file *file) return seq_open(file, de->seq_ops); } +static int proc_seq_release(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *de = PDE(inode); + + if (de->state_size) + return seq_release_private(inode, file); + return seq_release(inode, file); +} + static const struct file_operations proc_seq_fops = { .open = proc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = proc_seq_release, }; struct proc_dir_entry *proc_create_seq_private(const char *name, umode_t mode, diff --git a/include/linux/file.h b/include/linux/file.h index 279720db984a..aed45d69811e 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -18,7 +18,7 @@ struct file_operations; struct vfsmount; struct dentry; struct path; -extern struct file *alloc_file(const struct path *, fmode_t mode, +extern struct file *alloc_file(const struct path *, int flags, const struct file_operations *fop); static inline void fput_light(struct file *file, int fput_needed) @@ -78,7 +78,6 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern void set_close_on_exec(unsigned int fd, int flag); extern bool get_close_on_exec(unsigned int fd); -extern void put_filp(struct file *); extern int get_unused_fd_flags(unsigned flags); extern void put_unused_fd(unsigned int fd); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5c91108846db..4ff7b7012186 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -148,6 +148,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* Has write method(s) */ #define FMODE_CAN_WRITE ((__force fmode_t)0x40000) +#define FMODE_OPENED ((__force fmode_t)0x80000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) @@ -2422,6 +2424,12 @@ extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int, umode_t); extern struct file * dentry_open(const struct path *, int, const struct cred *); +extern struct file * open_with_fake_path(const struct path *, int, + struct inode*, const struct cred *); +static inline struct file *file_clone_open(struct file *file) +{ + return dentry_open(&file->f_path, file->f_flags, file->f_cred); +} extern int filp_close(struct file *, fl_owner_t id); extern struct filename *getname_flags(const char __user *, int, int *); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 8f1131c8dd54..a8ee106b865d 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1569,7 +1569,7 @@ union security_list_options { int (*file_send_sigiotask)(struct task_struct *tsk, struct fown_struct *fown, int sig); int (*file_receive)(struct file *file); - int (*file_open)(struct file *file, const struct cred *cred); + int (*file_open)(struct file *file); int (*task_alloc)(struct task_struct *task, unsigned long clone_flags); void (*task_free)(struct task_struct *task); diff --git a/include/linux/security.h b/include/linux/security.h index 63030c85ee19..88d30fc975e7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -309,7 +309,7 @@ void security_file_set_fowner(struct file *file); int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig); int security_file_receive(struct file *file); -int security_file_open(struct file *file, const struct cred *cred); +int security_file_open(struct file *file); int security_task_alloc(struct task_struct *task, unsigned long clone_flags); void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); @@ -858,8 +858,7 @@ static inline int security_file_receive(struct file *file) return 0; } -static inline int security_file_open(struct file *file, - const struct cred *cred) +static inline int security_file_open(struct file *file) { return 0; } diff --git a/ipc/shm.c b/ipc/shm.c index 051a3e1fb8df..c702abd578a7 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1362,7 +1362,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, struct ipc_namespace *ns; struct shm_file_data *sfd; struct path path; - fmode_t f_mode; + int f_flags; unsigned long populate = 0; err = -EINVAL; @@ -1395,11 +1395,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, if (shmflg & SHM_RDONLY) { prot = PROT_READ; acc_mode = S_IRUGO; - f_mode = FMODE_READ; + f_flags = O_RDONLY; } else { prot = PROT_READ | PROT_WRITE; acc_mode = S_IRUGO | S_IWUGO; - f_mode = FMODE_READ | FMODE_WRITE; + f_flags = O_RDWR; } if (shmflg & SHM_EXEC) { prot |= PROT_EXEC; @@ -1449,7 +1449,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, goto out_nattch; } - file = alloc_file(&path, f_mode, + file = alloc_file(&path, f_flags, is_file_hugepages(shp->shm_file) ? &shm_file_operations_huge : &shm_file_operations); diff --git a/mm/memfd.c b/mm/memfd.c index 27069518e3c5..2bb5e257080e 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -326,7 +326,7 @@ SYSCALL_DEFINE2(memfd_create, goto err_fd; } file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; - file->f_flags |= O_RDWR | O_LARGEFILE; + file->f_flags |= O_LARGEFILE; if (flags & MFD_ALLOW_SEALING) { file_seals = memfd_file_seals_ptr(file); diff --git a/mm/shmem.c b/mm/shmem.c index 2cab84403055..84844e52bf24 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3942,8 +3942,7 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name, l if (IS_ERR(res)) goto put_path; - res = alloc_file(&path, FMODE_WRITE | FMODE_READ, - &shmem_file_operations); + res = alloc_file(&path, O_RDWR, &shmem_file_operations); if (IS_ERR(res)) goto put_path; diff --git a/net/socket.c b/net/socket.c index 8a109012608a..2cdbe8f71b7f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -411,7 +411,7 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) d_instantiate(path.dentry, SOCK_INODE(sock)); - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, + file = alloc_file(&path, O_RDWR | (flags & O_NONBLOCK), &socket_file_ops); if (IS_ERR(file)) { /* drop dentry, keep inode for a bit */ @@ -423,7 +423,6 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) } sock->file = file; - file->f_flags = O_RDWR | (flags & O_NONBLOCK); file->private_data = sock; return file; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 74f17376202b..8b8b70620bbe 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -395,7 +395,7 @@ static int apparmor_inode_getattr(const struct path *path) return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR); } -static int apparmor_file_open(struct file *file, const struct cred *cred) +static int apparmor_file_open(struct file *file) { struct aa_file_ctx *fctx = file_ctx(file); struct aa_label *label; @@ -414,7 +414,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) return 0; } - label = aa_get_newest_cred_label(cred); + label = aa_get_newest_cred_label(file->f_cred); if (!unconfined(label)) { struct inode *inode = file_inode(file); struct path_cond cond = { inode->i_uid, inode->i_mode }; diff --git a/security/security.c b/security/security.c index 68f46d849abe..5dce67070cdf 100644 --- a/security/security.c +++ b/security/security.c @@ -970,11 +970,11 @@ int security_file_receive(struct file *file) return call_int_hook(file_receive, 0, file); } -int security_file_open(struct file *file, const struct cred *cred) +int security_file_open(struct file *file) { int ret; - ret = call_int_hook(file_open, 0, file, cred); + ret = call_int_hook(file_open, 0, file); if (ret) return ret; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2b5ee5fbd652..18006be15713 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3862,7 +3862,7 @@ static int selinux_file_receive(struct file *file) return file_has_perm(cred, file, file_to_av(file)); } -static int selinux_file_open(struct file *file, const struct cred *cred) +static int selinux_file_open(struct file *file) { struct file_security_struct *fsec; struct inode_security_struct *isec; @@ -3886,7 +3886,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred) * new inode label or new policy. * This check is not redundant - do not remove. */ - return file_path_has_perm(cred, file, open_file_to_av(file)); + return file_path_has_perm(file->f_cred, file, open_file_to_av(file)); } /* task security operations */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7ad226018f51..e7b6c012431d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1927,9 +1927,9 @@ static int smack_file_receive(struct file *file) * * Returns 0 */ -static int smack_file_open(struct file *file, const struct cred *cred) +static int smack_file_open(struct file *file) { - struct task_smack *tsp = cred->security; + struct task_smack *tsp = file->f_cred->security; struct inode *inode = file_inode(file); struct smk_audit_info ad; int rc; @@ -1937,7 +1937,7 @@ static int smack_file_open(struct file *file, const struct cred *cred) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad); - rc = smk_bu_credfile(cred, file, MAY_READ, rc); + rc = smk_bu_credfile(file->f_cred, file, MAY_READ, rc); return rc; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 213b8c593668..9f932e2d6852 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -320,7 +320,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_file_open(struct file *f, const struct cred *cred) +static int tomoyo_file_open(struct file *f) { int flags = f->f_flags; /* Don't check read permission here if called from do_execve(). */ |