Skip to content

Commit c6c75de

Browse files
Alexey Dobriyantorvalds
authored andcommitted
proc: fix lookup in /proc/net subdirectories after setns(2)
Commit 1fde6f2 ("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/[email protected] Fixes: 1da4d37 ("proc: revalidate misc dentries") Signed-off-by: Alexey Dobriyan <[email protected]> Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" <[email protected]> Cc: Al Viro <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fe71988 commit c6c75de

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

fs/proc/generic.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,16 @@ static const struct file_operations proc_dir_operations = {
349349
.iterate_shared = proc_readdir,
350350
};
351351

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+
352362
/*
353363
* proc directories can do almost nothing..
354364
*/
@@ -471,8 +481,8 @@ struct proc_dir_entry *proc_symlink(const char *name,
471481
}
472482
EXPORT_SYMBOL(proc_symlink);
473483

474-
struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
475-
struct proc_dir_entry *parent, void *data)
484+
struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
485+
struct proc_dir_entry *parent, void *data, bool force_lookup)
476486
{
477487
struct proc_dir_entry *ent;
478488

@@ -484,10 +494,20 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
484494
ent->data = data;
485495
ent->proc_dir_ops = &proc_dir_operations;
486496
ent->proc_iops = &proc_dir_inode_operations;
497+
if (force_lookup) {
498+
pde_force_lookup(ent);
499+
}
487500
ent = proc_register(parent, ent);
488501
}
489502
return ent;
490503
}
504+
EXPORT_SYMBOL_GPL(_proc_mkdir);
505+
506+
struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
507+
struct proc_dir_entry *parent, void *data)
508+
{
509+
return _proc_mkdir(name, mode, parent, data, false);
510+
}
491511
EXPORT_SYMBOL_GPL(proc_mkdir_data);
492512

493513
struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode,

fs/proc/internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,10 @@ extern unsigned long task_statm(struct mm_struct *,
310310
unsigned long *, unsigned long *,
311311
unsigned long *, unsigned long *);
312312
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+
}

fs/proc/proc_net.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,6 @@ static struct net *get_proc_net(const struct inode *inode)
3939
return maybe_get_net(PDE_NET(PDE(inode)));
4040
}
4141

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-
5842
static int seq_open_net(struct inode *inode, struct file *file)
5943
{
6044
unsigned int state_size = PDE(inode)->state_size;

include/linux/proc_fs.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ extern void proc_flush_pid(struct pid *);
8080

8181
extern struct proc_dir_entry *proc_symlink(const char *,
8282
struct proc_dir_entry *, const char *);
83+
struct proc_dir_entry *_proc_mkdir(const char *, umode_t, struct proc_dir_entry *, void *, bool);
8384
extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *);
8485
extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t,
8586
struct proc_dir_entry *, void *);
@@ -162,6 +163,11 @@ static inline struct proc_dir_entry *proc_symlink(const char *name,
162163
static inline struct proc_dir_entry *proc_mkdir(const char *name,
163164
struct proc_dir_entry *parent) {return NULL;}
164165
static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; }
166+
static inline struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
167+
struct proc_dir_entry *parent, void *data, bool force_lookup)
168+
{
169+
return NULL;
170+
}
165171
static inline struct proc_dir_entry *proc_mkdir_data(const char *name,
166172
umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; }
167173
static inline struct proc_dir_entry *proc_mkdir_mode(const char *name,
@@ -199,7 +205,7 @@ struct net;
199205
static inline struct proc_dir_entry *proc_net_mkdir(
200206
struct net *net, const char *name, struct proc_dir_entry *parent)
201207
{
202-
return proc_mkdir_data(name, 0, parent, net);
208+
return _proc_mkdir(name, 0, parent, net, true);
203209
}
204210

205211
struct ns_common;

0 commit comments

Comments
 (0)