Replace the warning and file permission change with an error when an "unsafe" net sysctl registration is detected.
One of the barriers preventing the const qualification of the ctl_tables in the net directory is the permission (->mode) change in ensure_safe_net_sysctl. This prep commit removes that barrier and ensures that the received ctl_table pointer to the net ctl_table register function is const. Signed-off-by: Joel Granados <[email protected]> --- include/net/net_namespace.h | 5 +++-- net/sysctl_net.c | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 501af1999fe8393d7c282a87645d1c4ceabadddc..e5ee673b9fcf846aefcc309d4cca1a8fc870aae2 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -525,12 +525,13 @@ struct ctl_table; #ifdef CONFIG_SYSCTL int net_sysctl_init(void); struct ctl_table_header *register_net_sysctl_sz(struct net *net, const char *path, - struct ctl_table *table, size_t table_size); + const struct ctl_table *table, + size_t table_size); void unregister_net_sysctl_table(struct ctl_table_header *header); #else static inline int net_sysctl_init(void) { return 0; } static inline struct ctl_table_header *register_net_sysctl_sz(struct net *net, - const char *path, struct ctl_table *table, size_t table_size) + const char *path, const struct ctl_table *table, size_t table_size) { return NULL; } diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 19e8048241bacb18de853d3b904d0f97fd2fe78a..07f8434d4258c615c231ca7e29274de44b012665 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -114,16 +114,17 @@ __init int net_sysctl_init(void) goto out; } -/* Verify that sysctls for non-init netns are safe by either: +/* Return error when sysctls for non-init netns are unsafe by verifying: * 1) being read-only, or * 2) having a data pointer which points outside of the global kernel/module * data segment, and rather into the heap where a per-net object was * allocated. */ -static void ensure_safe_net_sysctl(struct net *net, const char *path, - struct ctl_table *table, size_t table_size) +static int ensure_safe_net_sysctl(struct net *net, const char *path, + const struct ctl_table *table, + size_t table_size) { - struct ctl_table *ent; + const struct ctl_table *ent; pr_debug("Registering net sysctl (net %p): %s\n", net, path); ent = table; @@ -149,24 +150,24 @@ static void ensure_safe_net_sysctl(struct net *net, const char *path, else continue; - /* If it is writable and points to kernel/module global - * data, then it's probably a netns leak. - */ + /* Warn on netns leak. */ WARN(1, "sysctl %s/%s: data points to %s global data: %ps\n", - path, ent->procname, where, ent->data); + path, ent->procname, where, ent->data); - /* Make it "safe" by dropping writable perms */ - ent->mode &= ~0222; + return -EACCES; } + + return 0; } struct ctl_table_header *register_net_sysctl_sz(struct net *net, const char *path, - struct ctl_table *table, + const struct ctl_table *table, size_t table_size) { if (!net_eq(net, &init_net)) - ensure_safe_net_sysctl(net, path, table, table_size); + if (ensure_safe_net_sysctl(net, path, table, table_size)) + return NULL; return __register_sysctl_table(&net->sysctls, path, table, table_size); } -- 2.50.1

