diff -bur linux-3.2.9-vs2.3.2.7/fs/proc/generic.c linux-3.2.9-vs2.3.2.7-melbar/fs/proc/generic.c --- linux-3.2.9-vs2.3.2.7/fs/proc/generic.c 2012-03-10 10:34:52.000000000 -0300 +++ linux-3.2.9-vs2.3.2.7-melbar/fs/proc/generic.c 2013-05-01 20:29:03.834308882 -0300 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "internal.h" @@ -606,7 +607,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, const char *name, mode_t mode, - nlink_t nlink) + nlink_t nlink, + int vx_flags) { struct proc_dir_entry *ent = NULL; const char *fn = name; @@ -634,7 +636,7 @@ ent->nlink = nlink; atomic_set(&ent->count, 1); ent->pde_users = 0; - ent->vx_flags = IATTR_PROC_DEFAULT; + ent->vx_flags = vx_flags; spin_lock_init(&ent->pde_unload_lock); ent->pde_unload_completion = NULL; INIT_LIST_HEAD(&ent->pde_openers); @@ -648,7 +650,7 @@ struct proc_dir_entry *ent; ent = __proc_create(&parent, name, - (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1); + (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1,IATTR_PROC_DEFAULT); if (ent) { ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); @@ -674,7 +676,7 @@ { struct proc_dir_entry *ent; - ent = __proc_create(&parent, name, S_IFDIR | mode, 2); + ent = __proc_create(&parent, name, S_IFDIR | mode, 2, IATTR_PROC_DEFAULT); if (ent) { if (proc_register(parent, ent) < 0) { kfree(ent); @@ -690,7 +692,7 @@ { struct proc_dir_entry *ent; - ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2); + ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2, IATTR_ADMIN); if (ent) { ent->data = net; if (proc_register(parent, ent) < 0) { @@ -727,7 +729,7 @@ nlink = 1; } - ent = __proc_create(&parent, name, mode, nlink); + ent = __proc_create(&parent, name, mode, nlink, IATTR_PROC_DEFAULT); if (ent) { if (proc_register(parent, ent) < 0) { kfree(ent); @@ -745,6 +747,8 @@ { struct proc_dir_entry *pde; nlink_t nlink; + int do_check_netns = 0; + int vx_flags = IATTR_PROC_DEFAULT; if (S_ISDIR(mode)) { if ((mode & S_IALLUGO) == 0) @@ -758,7 +762,33 @@ nlink = 1; } - pde = __proc_create(&parent, name, mode, nlink); + // If we're creating an entry below /proc/.../net and we're not the + // initial network namespace, use IATTR_ADMIN instead of IATTR_PROC_DEFAULT + // (that includes IATTR_HIDE, which causes the whole problem of /proc/net + // not being shown on vservers with network namespaces). + // This is most certainly a big fat ugly kludge... perhaps we should make + // vx_check know about net namespaces or change the pernet_operations + // know about vservers (this would require chances in a lot of places, + // I guess). This is a quick fix I came up with without delving too deep + // or risk changing too many things. Anyway, as far as I can see, it solves + // the problem without creating creating any new security holes. + + if (parent && parent->namelen == 3) { + if (!memcmp(parent->name,"net",3) && parent->parent) { + if ( parent->parent->namelen == 2 ) { + if (memcmp(parent->parent->name,"ns",2)) { + do_check_netns = 1; + } + } else { + do_check_netns = 1; + } + } + if (do_check_netns) { + if (parent->data != (void *)&init_net) vx_flags = IATTR_ADMIN; + } + } + + pde = __proc_create(&parent, name, mode, nlink, vx_flags); if (!pde) goto out; pde->proc_fops = proc_fops;