diff options
Diffstat (limited to 'net/sysctl_net.c')
| -rw-r--r-- | net/sysctl_net.c | 75 | 
1 files changed, 30 insertions, 45 deletions
diff --git a/net/sysctl_net.c b/net/sysctl_net.c index ca84212cfbf..e7000be321b 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -12,6 +12,7 @@   */  #include <linux/mm.h> +#include <linux/export.h>  #include <linux/sysctl.h>  #include <linux/nsproxy.h> @@ -25,10 +26,6 @@  #include <linux/if_ether.h>  #endif -#ifdef CONFIG_TR -#include <linux/if_tr.h> -#endif -  static struct ctl_table_set *  net_ctl_header_lookup(struct ctl_table_root *root, struct nsproxy *namespaces)  { @@ -41,15 +38,24 @@ static int is_seen(struct ctl_table_set *set)  }  /* Return standard mode bits for table entry. */ -static int net_ctl_permissions(struct ctl_table_root *root, -			       struct nsproxy *nsproxy, +static int net_ctl_permissions(struct ctl_table_header *head,  			       struct ctl_table *table)  { +	struct net *net = container_of(head->set, struct net, sysctls); +	kuid_t root_uid = make_kuid(net->user_ns, 0); +	kgid_t root_gid = make_kgid(net->user_ns, 0); +  	/* Allow network administrator to have same access as root. */ -	if (capable(CAP_NET_ADMIN)) { +	if (ns_capable(net->user_ns, CAP_NET_ADMIN) || +	    uid_eq(root_uid, current_euid())) {  		int mode = (table->mode >> 6) & 7;  		return (mode << 6) | (mode << 3) | mode;  	} +	/* Allow netns root group to have the same access as the root group */ +	if (in_egroup_p(root_gid)) { +		int mode = (table->mode >> 3) & 7; +		return (mode << 3) | mode; +	}  	return table->mode;  } @@ -58,30 +64,15 @@ static struct ctl_table_root net_sysctl_root = {  	.permissions = net_ctl_permissions,  }; -static int net_ctl_ro_header_perms(struct ctl_table_root *root, -		struct nsproxy *namespaces, struct ctl_table *table) -{ -	if (net_eq(namespaces->net_ns, &init_net)) -		return table->mode; -	else -		return table->mode & ~0222; -} - -static struct ctl_table_root net_sysctl_ro_root = { -	.permissions = net_ctl_ro_header_perms, -}; -  static int __net_init sysctl_net_init(struct net *net)  { -	setup_sysctl_set(&net->sysctls, -			 &net_sysctl_ro_root.default_set, -			 is_seen); +	setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);  	return 0;  }  static void __net_exit sysctl_net_exit(struct net *net)  { -	WARN_ON(!list_empty(&net->sysctls.list)); +	retire_sysctl_set(&net->sysctls);  }  static struct pernet_operations sysctl_pernet_ops = { @@ -89,38 +80,32 @@ static struct pernet_operations sysctl_pernet_ops = {  	.exit = sysctl_net_exit,  }; -static __init int sysctl_init(void) +static struct ctl_table_header *net_header; +__init int net_sysctl_init(void)  { -	int ret; +	static struct ctl_table empty[1]; +	int ret = -ENOMEM; +	/* Avoid limitations in the sysctl implementation by +	 * registering "/proc/sys/net" as an empty directory not in a +	 * network namespace. +	 */ +	net_header = register_sysctl("net", empty); +	if (!net_header) +		goto out;  	ret = register_pernet_subsys(&sysctl_pernet_ops);  	if (ret)  		goto out;  	register_sysctl_root(&net_sysctl_root); -	setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL, NULL); -	register_sysctl_root(&net_sysctl_ro_root);  out:  	return ret;  } -subsys_initcall(sysctl_init); - -struct ctl_table_header *register_net_sysctl_table(struct net *net, -	const struct ctl_path *path, struct ctl_table *table) -{ -	struct nsproxy namespaces; -	namespaces = *current->nsproxy; -	namespaces.net_ns = net; -	return __register_sysctl_paths(&net_sysctl_root, -					&namespaces, path, table); -} -EXPORT_SYMBOL_GPL(register_net_sysctl_table); -struct ctl_table_header *register_net_sysctl_rotable(const -		struct ctl_path *path, struct ctl_table *table) +struct ctl_table_header *register_net_sysctl(struct net *net, +	const char *path, struct ctl_table *table)  { -	return __register_sysctl_paths(&net_sysctl_ro_root, -			&init_nsproxy, path, table); +	return __register_sysctl_table(&net->sysctls, path, table);  } -EXPORT_SYMBOL_GPL(register_net_sysctl_rotable); +EXPORT_SYMBOL_GPL(register_net_sysctl);  void unregister_net_sysctl_table(struct ctl_table_header *header)  {  | 
