Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

proc: fix lookup in /proc/net subdirectories after setns(2)

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 <adobriyan@gmail.com>
Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" <tommi.t.rantala@nokia.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alexey Dobriyan and committed by
Linus Torvalds
c6c75ded fe719888

+36 -19
+22 -2
fs/proc/generic.c
··· 349 349 .iterate_shared = proc_readdir, 350 350 }; 351 351 352 + static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) 353 + { 354 + return 0; 355 + } 356 + 357 + const struct dentry_operations proc_net_dentry_ops = { 358 + .d_revalidate = proc_net_d_revalidate, 359 + .d_delete = always_delete_dentry, 360 + }; 361 + 352 362 /* 353 363 * proc directories can do almost nothing.. 354 364 */ ··· 481 471 } 482 472 EXPORT_SYMBOL(proc_symlink); 483 473 484 - struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, 485 - struct proc_dir_entry *parent, void *data) 474 + struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, 475 + struct proc_dir_entry *parent, void *data, bool force_lookup) 486 476 { 487 477 struct proc_dir_entry *ent; 488 478 ··· 494 484 ent->data = data; 495 485 ent->proc_dir_ops = &proc_dir_operations; 496 486 ent->proc_iops = &proc_dir_inode_operations; 487 + if (force_lookup) { 488 + pde_force_lookup(ent); 489 + } 497 490 ent = proc_register(parent, ent); 498 491 } 499 492 return ent; 493 + } 494 + EXPORT_SYMBOL_GPL(_proc_mkdir); 495 + 496 + struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, 497 + struct proc_dir_entry *parent, void *data) 498 + { 499 + return _proc_mkdir(name, mode, parent, data, false); 500 500 } 501 501 EXPORT_SYMBOL_GPL(proc_mkdir_data); 502 502
+7
fs/proc/internal.h
··· 310 310 unsigned long *, unsigned long *, 311 311 unsigned long *, unsigned long *); 312 312 extern void task_mem(struct seq_file *, struct mm_struct *); 313 + 314 + extern const struct dentry_operations proc_net_dentry_ops; 315 + static inline void pde_force_lookup(struct proc_dir_entry *pde) 316 + { 317 + /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ 318 + pde->proc_dops = &proc_net_dentry_ops; 319 + }
-16
fs/proc/proc_net.c
··· 39 39 return maybe_get_net(PDE_NET(PDE(inode))); 40 40 } 41 41 42 - static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) 43 - { 44 - return 0; 45 - } 46 - 47 - static const struct dentry_operations proc_net_dentry_ops = { 48 - .d_revalidate = proc_net_d_revalidate, 49 - .d_delete = always_delete_dentry, 50 - }; 51 - 52 - static void pde_force_lookup(struct proc_dir_entry *pde) 53 - { 54 - /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ 55 - pde->proc_dops = &proc_net_dentry_ops; 56 - } 57 - 58 42 static int seq_open_net(struct inode *inode, struct file *file) 59 43 { 60 44 unsigned int state_size = PDE(inode)->state_size;
+7 -1
include/linux/proc_fs.h
··· 80 80 81 81 extern struct proc_dir_entry *proc_symlink(const char *, 82 82 struct proc_dir_entry *, const char *); 83 + struct proc_dir_entry *_proc_mkdir(const char *, umode_t, struct proc_dir_entry *, void *, bool); 83 84 extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *); 84 85 extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t, 85 86 struct proc_dir_entry *, void *); ··· 163 162 static inline struct proc_dir_entry *proc_mkdir(const char *name, 164 163 struct proc_dir_entry *parent) {return NULL;} 165 164 static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; } 165 + static inline struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, 166 + struct proc_dir_entry *parent, void *data, bool force_lookup) 167 + { 168 + return NULL; 169 + } 166 170 static inline struct proc_dir_entry *proc_mkdir_data(const char *name, 167 171 umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; } 168 172 static inline struct proc_dir_entry *proc_mkdir_mode(const char *name, ··· 205 199 static inline struct proc_dir_entry *proc_net_mkdir( 206 200 struct net *net, const char *name, struct proc_dir_entry *parent) 207 201 { 208 - return proc_mkdir_data(name, 0, parent, net); 202 + return _proc_mkdir(name, 0, parent, net, true); 209 203 } 210 204 211 205 struct ns_common;