From 878e832ade6fc315e6ea59d95824bbb0430c6e8d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 6 Oct 2017 11:19:24 -0400 Subject: [PATCH 01/15] acct.h: get rid of detritus unused forward declarations of structs Signed-off-by: Al Viro --- include/linux/acct.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/acct.h b/include/linux/acct.h index dccc2d4fe7de..3912a45b8c89 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -19,9 +19,6 @@ #ifdef CONFIG_BSD_PROCESS_ACCT -struct vfsmount; -struct super_block; -struct pacct_struct; struct pid_namespace; extern int acct_parm[]; /* for sysctl */ extern void acct_collect(long exitcode, int group_dead); From 6aa211e8ce6916d8a0df88b4fbc790e9c78f5d9d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 25 Sep 2017 18:37:28 -0700 Subject: [PATCH 02/15] fix address space warnings in ipc/ Signed-off-by: Linus Torvalds Signed-off-by: Al Viro --- ipc/msg.c | 4 ++-- ipc/sem.c | 4 ++-- ipc/shm.c | 4 ++-- ipc/syscall.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ipc/msg.c b/ipc/msg.c index 06be5a9adfa4..ebb7ea24ee28 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -590,13 +590,13 @@ static int copy_compat_msqid_from_user(struct msqid64_ds *out, void __user *buf, { memset(out, 0, sizeof(*out)); if (version == IPC_64) { - struct compat_msqid64_ds *p = buf; + struct compat_msqid64_ds __user *p = buf; if (get_compat_ipc64_perm(&out->msg_perm, &p->msg_perm)) return -EFAULT; if (get_user(out->msg_qbytes, &p->msg_qbytes)) return -EFAULT; } else { - struct compat_msqid_ds *p = buf; + struct compat_msqid_ds __user *p = buf; if (get_compat_ipc_perm(&out->msg_perm, &p->msg_perm)) return -EFAULT; if (get_user(out->msg_qbytes, &p->msg_qbytes)) diff --git a/ipc/sem.c b/ipc/sem.c index f7385bce5fd3..6220e9616207 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1636,10 +1636,10 @@ static int copy_compat_semid_from_user(struct semid64_ds *out, void __user *buf, { memset(out, 0, sizeof(*out)); if (version == IPC_64) { - struct compat_semid64_ds *p = buf; + struct compat_semid64_ds __user *p = buf; return get_compat_ipc64_perm(&out->sem_perm, &p->sem_perm); } else { - struct compat_semid_ds *p = buf; + struct compat_semid_ds __user *p = buf; return get_compat_ipc_perm(&out->sem_perm, &p->sem_perm); } } diff --git a/ipc/shm.c b/ipc/shm.c index 1b3adfe3c60e..41706416a3c4 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1193,10 +1193,10 @@ static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf, { memset(out, 0, sizeof(*out)); if (version == IPC_64) { - struct compat_shmid64_ds *p = buf; + struct compat_shmid64_ds __user *p = buf; return get_compat_ipc64_perm(&out->shm_perm, &p->shm_perm); } else { - struct compat_shmid_ds *p = buf; + struct compat_shmid_ds __user *p = buf; return get_compat_ipc_perm(&out->shm_perm, &p->shm_perm); } } diff --git a/ipc/syscall.c b/ipc/syscall.c index 667022746ca5..977bffd5a7f8 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -171,7 +171,7 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, COMPAT_SHMLBA); if (err < 0) return err; - return put_user(raddr, (compat_ulong_t *)compat_ptr(third)); + return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third)); } case SHMDT: return sys_shmdt(compat_ptr(ptr)); From 0200894d11551a8abcff7872c2260d0801951f67 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2017 13:48:55 -0400 Subject: [PATCH 03/15] new helper: destroy_unused_super() Used for disposal of super_block instances that had never been reachable via any shared data structures. No need for RCU delay in there, everything can be called directly. Signed-off-by: Al Viro --- fs/super.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/fs/super.c b/fs/super.c index 166c4ee0d0ed..01b7e3fd09e8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -171,6 +171,21 @@ static void destroy_super(struct super_block *s) call_rcu(&s->rcu, destroy_super_rcu); } +/* Free a superblock that has never been seen by anyone */ +static void destroy_unused_super(struct super_block *s) +{ + if (!s) + return; + up_write(&s->s_umount); + list_lru_destroy(&s->s_dentry_lru); + list_lru_destroy(&s->s_inode_lru); + security_sb_free(s); + put_user_ns(s->s_user_ns); + kfree(s->s_subtype); + /* no delays needed */ + destroy_super_work(&s->destroy_work); +} + /** * alloc_super - create new superblock * @type: filesystem type superblock should belong to @@ -256,7 +271,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, return s; fail: - destroy_super(s); + destroy_unused_super(s); return NULL; } @@ -484,19 +499,12 @@ struct super_block *sget_userns(struct file_system_type *type, continue; if (user_ns != old->s_user_ns) { spin_unlock(&sb_lock); - if (s) { - up_write(&s->s_umount); - destroy_super(s); - } + destroy_unused_super(s); return ERR_PTR(-EBUSY); } if (!grab_super(old)) goto retry; - if (s) { - up_write(&s->s_umount); - destroy_super(s); - s = NULL; - } + destroy_unused_super(s); return old; } } @@ -511,8 +519,7 @@ struct super_block *sget_userns(struct file_system_type *type, err = set(s, data); if (err) { spin_unlock(&sb_lock); - up_write(&s->s_umount); - destroy_super(s); + destroy_unused_super(s); return ERR_PTR(err); } s->s_type = type; From c645b9309839be3f1543255db2abfe120f9d4f26 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 11 Oct 2017 13:48:55 -0400 Subject: [PATCH 04/15] fold destroy_super() into __put_super() There's only one caller of destroy_super() left now. Fold it there, and replace those list_lru_destroy() calls with checks that they had already been done (as they should have, when we were dropping the last active reference). Signed-off-by: Al Viro --- fs/super.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/fs/super.c b/fs/super.c index 01b7e3fd09e8..8ca15415351a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -154,23 +154,6 @@ static void destroy_super_rcu(struct rcu_head *head) schedule_work(&s->destroy_work); } -/** - * destroy_super - frees a superblock - * @s: superblock to free - * - * Frees a superblock. - */ -static void destroy_super(struct super_block *s) -{ - list_lru_destroy(&s->s_dentry_lru); - list_lru_destroy(&s->s_inode_lru); - security_sb_free(s); - WARN_ON(!list_empty(&s->s_mounts)); - put_user_ns(s->s_user_ns); - kfree(s->s_subtype); - call_rcu(&s->rcu, destroy_super_rcu); -} - /* Free a superblock that has never been seen by anyone */ static void destroy_unused_super(struct super_block *s) { @@ -280,11 +263,17 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, /* * Drop a superblock's refcount. The caller must hold sb_lock. */ -static void __put_super(struct super_block *sb) +static void __put_super(struct super_block *s) { - if (!--sb->s_count) { - list_del_init(&sb->s_list); - destroy_super(sb); + if (!--s->s_count) { + list_del_init(&s->s_list); + WARN_ON(s->s_dentry_lru.node); + WARN_ON(s->s_inode_lru.node); + WARN_ON(!list_empty(&s->s_mounts)); + security_sb_free(s); + put_user_ns(s->s_user_ns); + kfree(s->s_subtype); + call_rcu(&s->rcu, destroy_super_rcu); } } From 11e3e8d6d9274bf630859b4c47bc4e4d76f289db Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Oct 2017 17:31:46 +0200 Subject: [PATCH 05/15] elf_fdpic: fix unused variable warning The elf_fdpic code shows a harmless warning when built with MMU disabled, I ran into this now that fdpic is available on ARM randconfig builds since commit 50b2b2e691cd ("ARM: add ELF_FDPIC support"). fs/binfmt_elf_fdpic.c: In function 'elf_fdpic_dump_segments': fs/binfmt_elf_fdpic.c:1501:17: error: unused variable 'addr' [-Werror=unused-variable] This adds another #ifdef around the variable declaration to shut up the warning. Fixes: e6c1baa9b562 ("convert the rest of binfmt_elf_fdpic to dump_emit()") Acked-by: Nicolas Pitre Signed-off-by: Arnd Bergmann Signed-off-by: Al Viro --- fs/binfmt_elf_fdpic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index e70c039ac190..c4565061da84 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1489,7 +1489,9 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm) struct vm_area_struct *vma; for (vma = current->mm->mmap; vma; vma = vma->vm_next) { +#ifdef CONFIG_MMU unsigned long addr; +#endif if (!maydump(vma, cprm->mm_flags)) continue; From 73ecf5cf141a0c61775c10fdf3a6fc106f326f8c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2017 13:18:33 -0400 Subject: [PATCH 06/15] do_handle_open() should be static Signed-off-by: Al Viro --- fs/fhandle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/fhandle.c b/fs/fhandle.c index 58a61f55e0d0..75cef4deaa77 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -212,8 +212,8 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh, return retval; } -long do_handle_open(int mountdirfd, - struct file_handle __user *ufh, int open_flag) +static long do_handle_open(int mountdirfd, struct file_handle __user *ufh, + int open_flag) { long retval = 0; struct path path; From 53fd88ab61948f711147204c1c5017c7301979e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 14 Oct 2017 23:00:54 -0400 Subject: [PATCH 07/15] make vfs_ustat() static Signed-off-by: Al Viro --- fs/statfs.c | 2 +- include/linux/fs.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/statfs.c b/fs/statfs.c index fab9b6a3c116..6327edf79e0f 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -216,7 +216,7 @@ SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user return error; } -int vfs_ustat(dev_t dev, struct kstatfs *sbuf) +static int vfs_ustat(dev_t dev, struct kstatfs *sbuf) { struct super_block *s = user_get_super(dev); int err; diff --git a/include/linux/fs.h b/include/linux/fs.h index 339e73742e73..89323e03e648 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2169,7 +2169,6 @@ extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, extern int vfs_statfs(const struct path *, struct kstatfs *); extern int user_statfs(const char __user *, struct kstatfs *); extern int fd_statfs(int, struct kstatfs *); -extern int vfs_ustat(dev_t, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); extern bool our_mnt(struct vfsmount *mnt); From f175f307dd0bd1ca3825d244f9b870ff12981d3c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 15 Oct 2017 00:38:00 -0400 Subject: [PATCH 08/15] stubs for mount_bdev() and kill_block_super() in !CONFIG_BLOCK case Signed-off-by: Al Viro --- include/linux/fs.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/linux/fs.h b/include/linux/fs.h index 89323e03e648..31f8b2ea358c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2094,9 +2094,18 @@ struct file_system_type { extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, void *data, void *ns, struct user_namespace *user_ns, int (*fill_super)(struct super_block *, void *, int)); +#ifdef CONFIG_BLOCK extern struct dentry *mount_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int)); +#else +static inline struct dentry *mount_bdev(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int)) +{ + return ERR_PTR(-ENODEV); +} +#endif extern struct dentry *mount_single(struct file_system_type *fs_type, int flags, void *data, int (*fill_super)(struct super_block *, void *, int)); @@ -2105,7 +2114,14 @@ extern struct dentry *mount_nodev(struct file_system_type *fs_type, int (*fill_super)(struct super_block *, void *, int)); extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); void generic_shutdown_super(struct super_block *sb); +#ifdef CONFIG_BLOCK void kill_block_super(struct super_block *sb); +#else +static inline void kill_block_super(struct super_block *sb) +{ + BUG(); +} +#endif void kill_anon_super(struct super_block *sb); void kill_litter_super(struct super_block *sb); void deactivate_super(struct super_block *sb); From 684e73bee4b5ef626a017c101a20f91cf28a75e6 Mon Sep 17 00:00:00 2001 From: Hirofumi Nakagawa Date: Tue, 26 Sep 2017 03:21:26 +0900 Subject: [PATCH 09/15] vfs: remove unneeded unlikely() IS_ERR() macro it is already including unlikely(). Signed-off-by: Hirofumi Nakagawa Signed-off-by: Al Viro --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index c75ea03ca147..00384488fda1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3458,7 +3458,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags, goto out; child = vfs_tmpfile(path.dentry, op->mode, op->open_flag); error = PTR_ERR(child); - if (unlikely(IS_ERR(child))) + if (IS_ERR(child)) goto out2; dput(path.dentry); path.dentry = child; From dfd6fa39d96f5049edb7af26578873e65dbafc9a Mon Sep 17 00:00:00 2001 From: Hirofumi Nakagawa Date: Tue, 26 Sep 2017 03:21:27 +0900 Subject: [PATCH 10/15] pstore: remove unneeded unlikely() IS_ERR() macro it is already including unlikely(). Signed-off-by: Hirofumi Nakagawa Signed-off-by: Al Viro --- fs/pstore/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 2b21d180157c..7256149af306 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -654,7 +654,7 @@ static int pstore_write_user_compat(struct pstore_record *record, return -EINVAL; record->buf = memdup_user(buf, record->size); - if (unlikely(IS_ERR(record->buf))) { + if (IS_ERR(record->buf)) { ret = PTR_ERR(record->buf); goto out; } From d337b66a4c52c7b04eec661d86c2ef6e168965a2 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Wed, 27 Sep 2017 15:52:12 -0400 Subject: [PATCH 11/15] coda: fix 'kernel memory exposure attempt' in fsync When an application called fsync on a file in Coda a small request with just the file identifier was allocated, but the declared length was set to the size of union of all possible upcall requests. This bug has been around for a very long time and is now caught by the extra checking in usercopy that was introduced in Linux-4.8. The exposure happens when the Coda cache manager process reads the fsync upcall request at which point it is killed. As a result there is nobody servicing any further upcalls, trapping any processes that try to access the mounted Coda filesystem. Cc: stable@vger.kernel.org Signed-off-by: Jan Harkes Signed-off-by: Al Viro --- fs/coda/upcall.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index e82357c89979..8cf16d8c5261 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -446,8 +446,7 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid) UPARG(CODA_FSYNC); inp->coda_fsync.VFid = *fid; - error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs), - &outsize, inp); + error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error; From ceac204e1da942a634d3bb0db3e959edc78e47c7 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 29 Sep 2017 15:24:06 -0400 Subject: [PATCH 12/15] fs: make fiemap work from compat_ioctl We don't need to do anything special with fiemap to make it work with a 64bit kernel from 32bit userspace, so just go down to do_vfs_ioctl(). Without this patch we were incorrectly failing to do fiemap with a 32bit userspace on a 64bit kernel. Signed-off-by: Josef Bacik Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/compat_ioctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index d27b326d96f4..480f9366b4e3 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1579,6 +1579,7 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, case FICLONE: case FICLONERANGE: case FIDEDUPERANGE: + case FS_IOC_FIEMAP: goto do_ioctl; case FIBMAP: From 63dcb81e5b9e1faadf4b55450141bc4446e5a3d3 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 3 Oct 2017 08:53:07 +0300 Subject: [PATCH 13/15] include/linux/fs.h: fix comment about struct address_space Before commit 9c5d760b8d22 ("mm: split gfp_mask and mapping flags into separate fields") the private_* fields of struct adrress_space were grouped together and using "ditto" in comments describing the last fields was correct. With introduction of gpf_mask between private_lock and private_list "ditto" references the wrong description. Fix it by using the elaborate description. Signed-off-by: Mike Rapoport Signed-off-by: Al Viro --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 31f8b2ea358c..ccbac0ed672c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -403,7 +403,7 @@ struct address_space { unsigned long flags; /* error bits */ spinlock_t private_lock; /* for use by the address_space */ gfp_t gfp_mask; /* implicit gfp mask for allocations */ - struct list_head private_list; /* ditto */ + struct list_head private_list; /* for use by the address_space */ void *private_data; /* ditto */ errseq_t wb_err; } __attribute__((aligned(sizeof(long)))) __randomize_layout; From 5297908270549b734c7c2556745e2385b6d4941d Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Tue, 3 Oct 2017 12:58:14 +0200 Subject: [PATCH 14/15] vfs: stop clearing close on exec when closing a fd Codepaths allocating a fd always make sure the bit is set/unset depending on flags, thus clearing on close is redundant. Signed-off-by: Mateusz Guzik Signed-off-by: Al Viro --- fs/file.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index 1fc7fbbb4510..9d047bd046b0 100644 --- a/fs/file.c +++ b/fs/file.c @@ -631,7 +631,6 @@ int __close_fd(struct files_struct *files, unsigned fd) if (!file) goto out_unlock; rcu_assign_pointer(fdt->fd[fd], NULL); - __clear_close_on_exec(fd, fdt); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); return filp_close(file, files); From c02b1a9b41c2e728289f96850580a3651e0a8b5f Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Tue, 3 Oct 2017 12:58:15 +0200 Subject: [PATCH 15/15] vfs: grab the lock instead of blocking in __fd_install during resizing Explicit locking in the fallback case provides a safe state of the table. Getting rid of blocking semantics makes __fd_install usable again in non-sleepable contexts, which easies backporting efforts. There is a side effect of slightly nicer assembly for the common case as might_sleep can now be removed. Signed-off-by: Mateusz Guzik Signed-off-by: Al Viro --- Documentation/filesystems/porting | 4 ---- fs/file.c | 11 +++++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 93e0a2404532..17bb4dc28fae 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -501,10 +501,6 @@ in your dentry operations instead. is non-NULL. Note that link body isn't available anymore, so if you need it, store it as cookie. -- -[mandatory] - __fd_install() & fd_install() can now sleep. Callers should not - hold a spinlock or other resources that do not allow a schedule. --- [mandatory] any symlink that might use page_follow_link_light/page_put_link() must have inode_nohighmem(inode) called before anything might start playing with diff --git a/fs/file.c b/fs/file.c index 9d047bd046b0..4115503bb575 100644 --- a/fs/file.c +++ b/fs/file.c @@ -592,13 +592,16 @@ void __fd_install(struct files_struct *files, unsigned int fd, { struct fdtable *fdt; - might_sleep(); rcu_read_lock_sched(); - while (unlikely(files->resize_in_progress)) { + if (unlikely(files->resize_in_progress)) { rcu_read_unlock_sched(); - wait_event(files->resize_wait, !files->resize_in_progress); - rcu_read_lock_sched(); + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + BUG_ON(fdt->fd[fd] != NULL); + rcu_assign_pointer(fdt->fd[fd], file); + spin_unlock(&files->file_lock); + return; } /* coupled with smp_wmb() in expand_fdtable() */ smp_rmb();