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

Merge branch 'proc-per-ns'

Dmitry Torokhov says:

====================
Make /proc per net namespace objects belong to container

Currently [almost] all /proc objects belong to the global root, even if
data belongs to a given namespace within a container and (at least for
sysctls) we work around permssions checks to allow container's root to
access the data.

This series changes ownership of net namespace /proc objects
(/proc/net/self/* and /proc/sys/net/*) to be container's root and not
global root when there exists mapping for container's root in user
namespace.

This helps when running Android CTS in a container, but I think it makes
sense regardless.

Changes from V1:

- added fix for crash when !CONFIG_NET_NS (new patch #1)
- addressed Eric'c comments for error handling style in patch #3 and
added his Ack
- adjusted patch #2 to use the same style of erro handling
- sent out as series instead of separate patches
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+61 -13
+2
fs/proc/generic.c
··· 390 390 atomic_set(&ent->count, 1); 391 391 spin_lock_init(&ent->pde_unload_lock); 392 392 INIT_LIST_HEAD(&ent->pde_openers); 393 + proc_set_user(ent, (*parent)->uid, (*parent)->gid); 394 + 393 395 out: 394 396 return ent; 395 397 }
+13
fs/proc/proc_net.c
··· 21 21 #include <linux/bitops.h> 22 22 #include <linux/mount.h> 23 23 #include <linux/nsproxy.h> 24 + #include <linux/uidgid.h> 24 25 #include <net/net_namespace.h> 25 26 #include <linux/seq_file.h> 26 27 ··· 186 185 static __net_init int proc_net_ns_init(struct net *net) 187 186 { 188 187 struct proc_dir_entry *netd, *net_statd; 188 + kuid_t uid; 189 + kgid_t gid; 189 190 int err; 190 191 191 192 err = -ENOMEM; ··· 201 198 netd->namelen = 3; 202 199 netd->parent = &proc_root; 203 200 memcpy(netd->name, "net", 4); 201 + 202 + uid = make_kuid(net->user_ns, 0); 203 + if (!uid_valid(uid)) 204 + uid = netd->uid; 205 + 206 + gid = make_kgid(net->user_ns, 0); 207 + if (!gid_valid(gid)) 208 + gid = netd->gid; 209 + 210 + proc_set_user(netd, uid, gid); 204 211 205 212 err = -EEXIST; 206 213 net_statd = proc_net_mkdir(net, "stat", netd);
+5
fs/proc/proc_sysctl.c
··· 430 430 static struct inode *proc_sys_make_inode(struct super_block *sb, 431 431 struct ctl_table_header *head, struct ctl_table *table) 432 432 { 433 + struct ctl_table_root *root = head->root; 433 434 struct inode *inode; 434 435 struct proc_inode *ei; 435 436 ··· 458 457 if (is_empty_dir(head)) 459 458 make_empty_dir_inode(inode); 460 459 } 460 + 461 + if (root->set_ownership) 462 + root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); 463 + 461 464 out: 462 465 return inode; 463 466 }
+4
include/linux/sysctl.h
··· 25 25 #include <linux/rcupdate.h> 26 26 #include <linux/wait.h> 27 27 #include <linux/rbtree.h> 28 + #include <linux/uidgid.h> 28 29 #include <uapi/linux/sysctl.h> 29 30 30 31 /* For the /proc/sys support */ ··· 158 157 struct ctl_table_set default_set; 159 158 struct ctl_table_set *(*lookup)(struct ctl_table_root *root, 160 159 struct nsproxy *namespaces); 160 + void (*set_ownership)(struct ctl_table_header *head, 161 + struct ctl_table *table, 162 + kuid_t *uid, kgid_t *gid); 161 163 int (*permissions)(struct ctl_table_header *head, struct ctl_table *table); 162 164 }; 163 165
+17 -4
net/core/net_namespace.c
··· 37 37 }; 38 38 EXPORT_SYMBOL(init_net); 39 39 40 + static bool init_net_initialized; 41 + 40 42 #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 41 43 42 44 static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; ··· 752 750 if (setup_net(&init_net, &init_user_ns)) 753 751 panic("Could not setup the initial network namespace"); 754 752 753 + init_net_initialized = true; 754 + 755 755 rtnl_lock(); 756 756 list_add_tail_rcu(&init_net.list, &net_namespace_list); 757 757 rtnl_unlock(); ··· 815 811 static int __register_pernet_operations(struct list_head *list, 816 812 struct pernet_operations *ops) 817 813 { 814 + if (!init_net_initialized) { 815 + list_add_tail(&ops->list, list); 816 + return 0; 817 + } 818 + 818 819 return ops_init(ops, &init_net); 819 820 } 820 821 821 822 static void __unregister_pernet_operations(struct pernet_operations *ops) 822 823 { 823 - LIST_HEAD(net_exit_list); 824 - list_add(&init_net.exit_list, &net_exit_list); 825 - ops_exit_list(ops, &net_exit_list); 826 - ops_free_list(ops, &net_exit_list); 824 + if (!init_net_initialized) { 825 + list_del(&ops->list); 826 + } else { 827 + LIST_HEAD(net_exit_list); 828 + list_add(&init_net.exit_list, &net_exit_list); 829 + ops_exit_list(ops, &net_exit_list); 830 + ops_free_list(ops, &net_exit_list); 831 + } 827 832 } 828 833 829 834 #endif /* CONFIG_NET_NS */
+20 -9
net/sysctl_net.c
··· 42 42 struct ctl_table *table) 43 43 { 44 44 struct net *net = container_of(head->set, struct net, sysctls); 45 - kuid_t root_uid = make_kuid(net->user_ns, 0); 46 - kgid_t root_gid = make_kgid(net->user_ns, 0); 47 45 48 46 /* Allow network administrator to have same access as root. */ 49 - if (ns_capable_noaudit(net->user_ns, CAP_NET_ADMIN) || 50 - uid_eq(root_uid, current_euid())) { 47 + if (ns_capable(net->user_ns, CAP_NET_ADMIN)) { 51 48 int mode = (table->mode >> 6) & 7; 52 49 return (mode << 6) | (mode << 3) | mode; 53 50 } 54 - /* Allow netns root group to have the same access as the root group */ 55 - if (in_egroup_p(root_gid)) { 56 - int mode = (table->mode >> 3) & 7; 57 - return (mode << 3) | mode; 58 - } 51 + 59 52 return table->mode; 53 + } 54 + 55 + static void net_ctl_set_ownership(struct ctl_table_header *head, 56 + struct ctl_table *table, 57 + kuid_t *uid, kgid_t *gid) 58 + { 59 + struct net *net = container_of(head->set, struct net, sysctls); 60 + kuid_t ns_root_uid; 61 + kgid_t ns_root_gid; 62 + 63 + ns_root_uid = make_kuid(net->user_ns, 0); 64 + if (uid_valid(ns_root_uid)) 65 + *uid = ns_root_uid; 66 + 67 + ns_root_gid = make_kgid(net->user_ns, 0); 68 + if (gid_valid(ns_root_gid)) 69 + *gid = ns_root_gid; 60 70 } 61 71 62 72 static struct ctl_table_root net_sysctl_root = { 63 73 .lookup = net_ctl_header_lookup, 64 74 .permissions = net_ctl_permissions, 75 + .set_ownership = net_ctl_set_ownership, 65 76 }; 66 77 67 78 static int __net_init sysctl_net_init(struct net *net)