mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
![Al Viro](/assets/img/avatar_default.png)
Piss-poor sysctl registration API strikes again, film at 11... What we really need is _pathname_ required to be present in already registered table, so that kernel could warn about bad order. That's the next target for sysctl stuff (and generally saner and more explicit order of initialization of ipv[46] internals wouldn't hurt either). For the time being, here are full fixups required by ..._rotable() stuff; we make per-net sysctl sets descendents of "ro" one and make sure that sufficient skeleton is there before we start registering per-net sysctls. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
130 lines
3 KiB
C
130 lines
3 KiB
C
/* -*- linux-c -*-
|
|
* sysctl_net.c: sysctl interface to net subsystem.
|
|
*
|
|
* Begun April 1, 1996, Mike Shaver.
|
|
* Added /proc/sys/net directories for each protocol family. [MS]
|
|
*
|
|
* Revision 1.2 1996/05/08 20:24:40 shaver
|
|
* Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and
|
|
* NET_IPV4_IP_FORWARD.
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/sysctl.h>
|
|
#include <linux/nsproxy.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#ifdef CONFIG_INET
|
|
#include <net/ip.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_NET
|
|
#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)
|
|
{
|
|
return &namespaces->net_ns->sysctls;
|
|
}
|
|
|
|
static int is_seen(struct ctl_table_set *set)
|
|
{
|
|
return ¤t->nsproxy->net_ns->sysctls == set;
|
|
}
|
|
|
|
/* Return standard mode bits for table entry. */
|
|
static int net_ctl_permissions(struct ctl_table_root *root,
|
|
struct nsproxy *nsproxy,
|
|
struct ctl_table *table)
|
|
{
|
|
/* Allow network administrator to have same access as root. */
|
|
if (capable(CAP_NET_ADMIN)) {
|
|
int mode = (table->mode >> 6) & 7;
|
|
return (mode << 6) | (mode << 3) | mode;
|
|
}
|
|
return table->mode;
|
|
}
|
|
|
|
static struct ctl_table_root net_sysctl_root = {
|
|
.lookup = net_ctl_header_lookup,
|
|
.permissions = net_ctl_permissions,
|
|
};
|
|
|
|
static int net_ctl_ro_header_perms(struct ctl_table_root *root,
|
|
struct nsproxy *namespaces, struct ctl_table *table)
|
|
{
|
|
if (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 sysctl_net_init(struct net *net)
|
|
{
|
|
setup_sysctl_set(&net->sysctls,
|
|
&net_sysctl_ro_root.default_set,
|
|
is_seen);
|
|
return 0;
|
|
}
|
|
|
|
static void sysctl_net_exit(struct net *net)
|
|
{
|
|
WARN_ON(!list_empty(&net->sysctls.list));
|
|
return;
|
|
}
|
|
|
|
static struct pernet_operations sysctl_pernet_ops = {
|
|
.init = sysctl_net_init,
|
|
.exit = sysctl_net_exit,
|
|
};
|
|
|
|
static __init int sysctl_init(void)
|
|
{
|
|
int ret;
|
|
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)
|
|
{
|
|
return __register_sysctl_paths(&net_sysctl_ro_root,
|
|
&init_nsproxy, path, table);
|
|
}
|
|
EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
|
|
|
|
void unregister_net_sysctl_table(struct ctl_table_header *header)
|
|
{
|
|
unregister_sysctl_table(header);
|
|
}
|
|
EXPORT_SYMBOL_GPL(unregister_net_sysctl_table);
|