From: Sasha Levin Date: Sat, 9 Jan 2021 16:03:23 +0000 (-0500) Subject: Fixes for 5.4 X-Git-Tag: v4.4.251~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=774b458def0bffa69859b7a8e37d52879f502ced;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.4 Signed-off-by: Sasha Levin --- diff --git a/queue-5.4/proc-change-nlink-under-proc_subdir_lock.patch b/queue-5.4/proc-change-nlink-under-proc_subdir_lock.patch new file mode 100644 index 00000000000..f260b8b706b --- /dev/null +++ b/queue-5.4/proc-change-nlink-under-proc_subdir_lock.patch @@ -0,0 +1,116 @@ +From 9957078a9f6ed9bfe32ee6330522f0d5b44c7022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Dec 2019 16:49:59 -0800 +Subject: proc: change ->nlink under proc_subdir_lock + +From: Alexey Dobriyan + +[ Upstream commit e06689bf57017ac022ccf0f2a5071f760821ce0f ] + +Currently gluing PDE into global /proc tree is done under lock, but +changing ->nlink is not. Additionally struct proc_dir_entry::nlink is +not atomic so updates can be lost. + +Link: http://lkml.kernel.org/r/20190925202436.GA17388@avx2 +Signed-off-by: Alexey Dobriyan +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + fs/proc/generic.c | 31 +++++++++++++++---------------- + 1 file changed, 15 insertions(+), 16 deletions(-) + +diff --git a/fs/proc/generic.c b/fs/proc/generic.c +index 64e9ee1b129e2..d4f353187d67c 100644 +--- a/fs/proc/generic.c ++++ b/fs/proc/generic.c +@@ -138,8 +138,12 @@ static int proc_getattr(const struct path *path, struct kstat *stat, + { + struct inode *inode = d_inode(path->dentry); + struct proc_dir_entry *de = PDE(inode); +- if (de && de->nlink) +- set_nlink(inode, de->nlink); ++ if (de) { ++ nlink_t nlink = READ_ONCE(de->nlink); ++ if (nlink > 0) { ++ set_nlink(inode, nlink); ++ } ++ } + + generic_fillattr(inode, stat); + return 0; +@@ -362,6 +366,7 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, + write_unlock(&proc_subdir_lock); + goto out_free_inum; + } ++ dir->nlink++; + write_unlock(&proc_subdir_lock); + + return dp; +@@ -472,10 +477,7 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, + ent->data = data; + ent->proc_fops = &proc_dir_operations; + ent->proc_iops = &proc_dir_inode_operations; +- parent->nlink++; + ent = proc_register(parent, ent); +- if (!ent) +- parent->nlink--; + } + return ent; + } +@@ -505,10 +507,7 @@ struct proc_dir_entry *proc_create_mount_point(const char *name) + ent->data = NULL; + ent->proc_fops = NULL; + ent->proc_iops = NULL; +- parent->nlink++; + ent = proc_register(parent, ent); +- if (!ent) +- parent->nlink--; + } + return ent; + } +@@ -666,8 +665,12 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) + len = strlen(fn); + + de = pde_subdir_find(parent, fn, len); +- if (de) ++ if (de) { + rb_erase(&de->subdir_node, &parent->subdir); ++ if (S_ISDIR(de->mode)) { ++ parent->nlink--; ++ } ++ } + write_unlock(&proc_subdir_lock); + if (!de) { + WARN(1, "name '%s'\n", name); +@@ -676,9 +679,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) + + proc_entry_rundown(de); + +- if (S_ISDIR(de->mode)) +- parent->nlink--; +- de->nlink = 0; + WARN(pde_subdir_first(de), + "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n", + __func__, de->parent->name, de->name, pde_subdir_first(de)->name); +@@ -714,13 +714,12 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) + de = next; + continue; + } +- write_unlock(&proc_subdir_lock); +- +- proc_entry_rundown(de); + next = de->parent; + if (S_ISDIR(de->mode)) + next->nlink--; +- de->nlink = 0; ++ write_unlock(&proc_subdir_lock); ++ ++ proc_entry_rundown(de); + if (de == root) + break; + pde_put(de); +-- +2.27.0 + diff --git a/queue-5.4/proc-fix-lookup-in-proc-net-subdirectories-after-set.patch b/queue-5.4/proc-fix-lookup-in-proc-net-subdirectories-after-set.patch new file mode 100644 index 00000000000..c741d12db3a --- /dev/null +++ b/queue-5.4/proc-fix-lookup-in-proc-net-subdirectories-after-set.patch @@ -0,0 +1,173 @@ +From 1718d51d68e7eb566ffc1d972a22b68266f992bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Dec 2020 20:42:39 -0800 +Subject: proc: fix lookup in /proc/net subdirectories after setns(2) + +From: Alexey Dobriyan + +[ Upstream commit c6c75deda81344c3a95d1d1f606d5cee109e5d54 ] + +Commit 1fde6f21d90f ("proc: fix /proc/net/* after setns(2)") only forced +revalidation of regular files under /proc/net/ + +However, /proc/net/ is unusual in the sense of /proc/net/foo handlers +take netns pointer from parent directory which is old netns. + +Steps to reproduce: + + (void)open("/proc/net/sctp/snmp", O_RDONLY); + unshare(CLONE_NEWNET); + + int fd = open("/proc/net/sctp/snmp", O_RDONLY); + read(fd, &c, 1); + +Read will read wrong data from original netns. + +Patch forces lookup on every directory under /proc/net . + +Link: https://lkml.kernel.org/r/20201205160916.GA109739@localhost.localdomain +Fixes: 1da4d377f943 ("proc: revalidate misc dentries") +Signed-off-by: Alexey Dobriyan +Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + fs/proc/generic.c | 24 ++++++++++++++++++++++-- + fs/proc/internal.h | 7 +++++++ + fs/proc/proc_net.c | 16 ---------------- + include/linux/proc_fs.h | 8 +++++++- + 4 files changed, 36 insertions(+), 19 deletions(-) + +diff --git a/fs/proc/generic.c b/fs/proc/generic.c +index d4f353187d67c..8c3dbe13e647c 100644 +--- a/fs/proc/generic.c ++++ b/fs/proc/generic.c +@@ -342,6 +342,16 @@ static const struct file_operations proc_dir_operations = { + .iterate_shared = proc_readdir, + }; + ++static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ return 0; ++} ++ ++const struct dentry_operations proc_net_dentry_ops = { ++ .d_revalidate = proc_net_d_revalidate, ++ .d_delete = always_delete_dentry, ++}; ++ + /* + * proc directories can do almost nothing.. + */ +@@ -464,8 +474,8 @@ struct proc_dir_entry *proc_symlink(const char *name, + } + EXPORT_SYMBOL(proc_symlink); + +-struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, +- struct proc_dir_entry *parent, void *data) ++struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, void *data, bool force_lookup) + { + struct proc_dir_entry *ent; + +@@ -477,10 +487,20 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, + ent->data = data; + ent->proc_fops = &proc_dir_operations; + ent->proc_iops = &proc_dir_inode_operations; ++ if (force_lookup) { ++ pde_force_lookup(ent); ++ } + ent = proc_register(parent, ent); + } + return ent; + } ++EXPORT_SYMBOL_GPL(_proc_mkdir); ++ ++struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, void *data) ++{ ++ return _proc_mkdir(name, mode, parent, data, false); ++} + EXPORT_SYMBOL_GPL(proc_mkdir_data); + + struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, +diff --git a/fs/proc/internal.h b/fs/proc/internal.h +index cd0c8d5ce9a13..269acc165055d 100644 +--- a/fs/proc/internal.h ++++ b/fs/proc/internal.h +@@ -299,3 +299,10 @@ extern unsigned long task_statm(struct mm_struct *, + unsigned long *, unsigned long *, + unsigned long *, unsigned long *); + extern void task_mem(struct seq_file *, struct mm_struct *); ++ ++extern const struct dentry_operations proc_net_dentry_ops; ++static inline void pde_force_lookup(struct proc_dir_entry *pde) ++{ ++ /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ ++ pde->proc_dops = &proc_net_dentry_ops; ++} +diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c +index 76ae278df1c47..313b7c751867f 100644 +--- a/fs/proc/proc_net.c ++++ b/fs/proc/proc_net.c +@@ -39,22 +39,6 @@ static struct net *get_proc_net(const struct inode *inode) + return maybe_get_net(PDE_NET(PDE(inode))); + } + +-static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) +-{ +- return 0; +-} +- +-static const struct dentry_operations proc_net_dentry_ops = { +- .d_revalidate = proc_net_d_revalidate, +- .d_delete = always_delete_dentry, +-}; +- +-static void pde_force_lookup(struct proc_dir_entry *pde) +-{ +- /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ +- pde->proc_dops = &proc_net_dentry_ops; +-} +- + static int seq_open_net(struct inode *inode, struct file *file) + { + unsigned int state_size = PDE(inode)->state_size; +diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h +index a705aa2d03f91..865d02c224ada 100644 +--- a/include/linux/proc_fs.h ++++ b/include/linux/proc_fs.h +@@ -21,6 +21,7 @@ extern void proc_flush_task(struct task_struct *); + + extern struct proc_dir_entry *proc_symlink(const char *, + struct proc_dir_entry *, const char *); ++struct proc_dir_entry *_proc_mkdir(const char *, umode_t, struct proc_dir_entry *, void *, bool); + extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *); + extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t, + struct proc_dir_entry *, void *); +@@ -99,6 +100,11 @@ static inline struct proc_dir_entry *proc_symlink(const char *name, + static inline struct proc_dir_entry *proc_mkdir(const char *name, + struct proc_dir_entry *parent) {return NULL;} + static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; } ++static inline struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, void *data, bool force_lookup) ++{ ++ return NULL; ++} + static inline struct proc_dir_entry *proc_mkdir_data(const char *name, + umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; } + static inline struct proc_dir_entry *proc_mkdir_mode(const char *name, +@@ -136,7 +142,7 @@ struct net; + static inline struct proc_dir_entry *proc_net_mkdir( + struct net *net, const char *name, struct proc_dir_entry *parent) + { +- return proc_mkdir_data(name, 0, parent, net); ++ return _proc_mkdir(name, 0, parent, net, true); + } + + struct ns_common; +-- +2.27.0 + diff --git a/queue-5.4/series b/queue-5.4/series index a91ef68f5c4..106cf91ae53 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -5,3 +5,5 @@ scsi-ide-do-not-set-the-rqf_preempt-flag-for-sense-r.patch scsi-scsi_transport_spi-set-rqf_pm-for-domain-valida.patch lib-genalloc-fix-the-overflow-when-size-is-too-big.patch depmod-handle-the-case-of-sbin-depmod-without-sbin-i.patch +proc-change-nlink-under-proc_subdir_lock.patch +proc-fix-lookup-in-proc-net-subdirectories-after-set.patch