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 |  4 ++--
 net/sysctl_net.c            | 24 ++++++++++++------------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 
80de5e98a66d6c9273aa7c5b9d489b22cef8559a..dca0ec809483bec604f4ca3d99dfea32834af8fa
 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -522,12 +522,12 @@ 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..4714887113d90a191c300c9c49a6317d5609efeb
 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -114,16 +114,16 @@ __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 +149,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



Reply via email to