LVS
lvs-devel
Google
 
Web LinuxVirtualServer.org

[PATCH v3 05/14] sysctl: Add a size arg to __register_sysctl_table

To: mcgrof@xxxxxxxxxx
Subject: [PATCH v3 05/14] sysctl: Add a size arg to __register_sysctl_table
Cc: rds-devel@xxxxxxxxxxxxxx, "David S. Miller" <davem@xxxxxxxxxxxxx>, Florian Westphal <fw@xxxxxxxxx>, willy@xxxxxxxxxxxxx, Jan Karcher <jaka@xxxxxxxxxxxxx>, Wen Gu <guwen@xxxxxxxxxxxxxxxxx>, Simon Horman <horms@xxxxxxxxxxxx>, Tony Lu <tonylu@xxxxxxxxxxxxxxxxx>, linux-wpan@xxxxxxxxxxxxxxx, Matthieu Baerts <matthieu.baerts@xxxxxxxxxxxx>, Christian Borntraeger <borntraeger@xxxxxxxxxxxxx>, mptcp@xxxxxxxxxxxxxxx, Heiko Carstens <hca@xxxxxxxxxxxxx>, Stefan Schmidt <stefan@xxxxxxxxxxxxxxxxxx>, Will Deacon <will@xxxxxxxxxx>, Julian Anastasov <ja@xxxxxx>, netfilter-devel@xxxxxxxxxxxxxxx, Joerg Reuter <jreuter@xxxxxxxx>, linux-kernel@xxxxxxxxxxxxxxx, Alexander Gordeev <agordeev@xxxxxxxxxxxxx>, linux-sctp@xxxxxxxxxxxxxxx, Xin Long <lucien.xin@xxxxxxxxx>, Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>, linux-hams@xxxxxxxxxxxxxxx, Vasily Gorbik <gor@xxxxxxxxxxxxx>, coreteam@xxxxxxxxxxxxx, Ralf Baechle <ralf@xxxxxxxxxxxxxx>, Steffen Klassert <steffen.klassert@xxxxxxxxxxx>, Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>, keescook@xxxxxxxxxxxx, Roopa Prabhu <roopa@xxxxxxxxxx>, David Ahern <dsahern@xxxxxxxxxx>, linux-arm-kernel@xxxxxxxxxxxxxxxxxxx, Catalin Marinas <catalin.marinas@xxxxxxx>, Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx>, Wenjia Zhang <wenjia@xxxxxxxxxxxxx>, josh@xxxxxxxxxxxxxxxx, linux-fsdevel@xxxxxxxxxxxxxxx, Alexander Aring <alex.aring@xxxxxxxxx>, Nikolay Aleksandrov <razor@xxxxxxxxxxxxx>, netdev@xxxxxxxxxxxxxxx, Santosh Shilimkar <santosh.shilimkar@xxxxxxxxxx>, linux-s390@xxxxxxxxxxxxxxx, Sven Schnelle <svens@xxxxxxxxxxxxx>, "D. Wythe" <alibuda@xxxxxxxxxxxxxxxxx>, Eric Dumazet <edumazet@xxxxxxxxxx>, lvs-devel@xxxxxxxxxxxxxxx, linux-rdma@xxxxxxxxxxxxxxx, Paolo Abeni <pabeni@xxxxxxxxxx>, Iurii Zaikin <yzaikin@xxxxxxxxxx>, Marcelo Ricardo Leitner <marcelo.leitner@xxxxxxxxx>, bridge@xxxxxxxxxxxxxxxxxxxxxxxxxx, Karsten Graul <kgraul@xxxxxxxxxxxxx>, Mat Martineau <martineau@xxxxxxxxxx>, Miquel Raynal <miquel.raynal@xxxxxxxxxxx>, Jakub Kicinski <kuba@xxxxxxxxxx>, Joel Granados <j.granados@xxxxxxxxxxx>
From: Joel Granados <joel.granados@xxxxxxxxx>
Date: Wed, 9 Aug 2023 12:49:57 +0200
We make these changes in order to prepare __register_sysctl_table and
its callers for when we remove the sentinel element (empty element at
the end of ctl_table arrays). We don't actually remove any sentinels in
this commit, but we *do* make sure to use ARRAY_SIZE so the table_size
is available when the removal occurs.

We add a table_size argument to __register_sysctl_table and adjust
callers, all of which pass ctl_table pointers and need an explicit call
to ARRAY_SIZE. We implement a size calculation in register_net_sysctl in
order to forward the size of the array pointer received from the network
register calls.

The new table_size argument does not yet have any effect in the
init_header call which is still dependent on the sentinel's presence.
table_size *does* however drive the `kzalloc` allocation in
__register_sysctl_table with no adverse effects as the allocated memory
is either one element greater than the calculated ctl_table array (for
the calls in ipc_sysctl.c, mq_sysctl.c and ucount.c) or the exact size
of the calculated ctl_table array (for the call from sysctl_net.c and
register_sysctl). This approach will allows us to "just" remove the
sentinel without further changes to __register_sysctl_table as
table_size will represent the exact size for all the callers at that
point.

Signed-off-by: Joel Granados <j.granados@xxxxxxxxxxx>
---
 fs/proc/proc_sysctl.c  | 23 ++++++++++++-----------
 include/linux/sysctl.h |  2 +-
 ipc/ipc_sysctl.c       |  4 +++-
 ipc/mq_sysctl.c        |  4 +++-
 kernel/ucount.c        |  3 ++-
 net/sysctl_net.c       |  8 +++++++-
 6 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index fa1438f1a355..b8dd78e344ff 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -1312,6 +1312,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir 
*dir, const char *path)
  *      should not be free'd after registration. So it should not be
  *      used on stack. It can either be a global or dynamically allocated
  *      by the caller and free'd later after sysctl unregistration.
+ * @table_size : The number of elements in table
  *
  * Register a sysctl table hierarchy. @table should be a filled in ctl_table
  * array. A completely 0 filled entry terminates the table.
@@ -1354,27 +1355,20 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir 
*dir, const char *path)
  */
 struct ctl_table_header *__register_sysctl_table(
        struct ctl_table_set *set,
-       const char *path, struct ctl_table *table)
+       const char *path, struct ctl_table *table, size_t table_size)
 {
        struct ctl_table_root *root = set->dir.header.root;
        struct ctl_table_header *header;
-       struct ctl_table_header h_tmp;
        struct ctl_dir *dir;
-       struct ctl_table *entry;
        struct ctl_node *node;
-       int nr_entries = 0;
-
-       h_tmp.ctl_table = table;
-       list_for_each_table_entry(entry, (&h_tmp))
-               nr_entries++;
 
        header = kzalloc(sizeof(struct ctl_table_header) +
-                        sizeof(struct ctl_node)*nr_entries, 
GFP_KERNEL_ACCOUNT);
+                        sizeof(struct ctl_node)*table_size, 
GFP_KERNEL_ACCOUNT);
        if (!header)
                return NULL;
 
        node = (struct ctl_node *)(header + 1);
-       init_header(header, root, set, node, table, nr_entries);
+       init_header(header, root, set, node, table, table_size);
        if (sysctl_check_table(path, header))
                goto fail;
 
@@ -1423,8 +1417,15 @@ struct ctl_table_header *__register_sysctl_table(
  */
 struct ctl_table_header *register_sysctl(const char *path, struct ctl_table 
*table)
 {
+       int count = 0;
+       struct ctl_table *entry;
+       struct ctl_table_header t_hdr;
+
+       t_hdr.ctl_table = table;
+       list_for_each_table_entry(entry, (&t_hdr))
+               count++;
        return __register_sysctl_table(&sysctl_table_root.default_set,
-                                       path, table);
+                                       path, table, count);
 }
 EXPORT_SYMBOL(register_sysctl);
 
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 33252ad58ebe..0495c858989f 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -226,7 +226,7 @@ extern void retire_sysctl_set(struct ctl_table_set *set);
 
 struct ctl_table_header *__register_sysctl_table(
        struct ctl_table_set *set,
-       const char *path, struct ctl_table *table);
+       const char *path, struct ctl_table *table, size_t table_size);
 struct ctl_table_header *register_sysctl(const char *path, struct ctl_table 
*table);
 void unregister_sysctl_table(struct ctl_table_header * table);
 
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index ef313ecfb53a..8c62e443f78b 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -259,7 +259,9 @@ bool setup_ipc_sysctls(struct ipc_namespace *ns)
                                tbl[i].data = NULL;
                }
 
-               ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, 
"kernel", tbl);
+               ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set,
+                                                         "kernel", tbl,
+                                                         
ARRAY_SIZE(ipc_sysctls));
        }
        if (!ns->ipc_sysctls) {
                kfree(tbl);
diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c
index fbf6a8b93a26..ebb5ed81c151 100644
--- a/ipc/mq_sysctl.c
+++ b/ipc/mq_sysctl.c
@@ -109,7 +109,9 @@ bool setup_mq_sysctls(struct ipc_namespace *ns)
                                tbl[i].data = NULL;
                }
 
-               ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, 
"fs/mqueue", tbl);
+               ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
+                                                        "fs/mqueue", tbl,
+                                                        
ARRAY_SIZE(mq_sysctls));
        }
        if (!ns->mq_sysctls) {
                kfree(tbl);
diff --git a/kernel/ucount.c b/kernel/ucount.c
index ee8e57fd6f90..2b80264bb79f 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -104,7 +104,8 @@ bool setup_userns_sysctls(struct user_namespace *ns)
                for (i = 0; i < UCOUNT_COUNTS; i++) {
                        tbl[i].data = &ns->ucount_max[i];
                }
-               ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
+               ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl,
+                                                     ARRAY_SIZE(user_table));
        }
        if (!ns->sysctls) {
                kfree(tbl);
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 4b45ed631eb8..8ee4b74bc009 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -163,10 +163,16 @@ static void ensure_safe_net_sysctl(struct net *net, const 
char *path,
 struct ctl_table_header *register_net_sysctl(struct net *net,
        const char *path, struct ctl_table *table)
 {
+       int count = 0;
+       struct ctl_table *entry;
+
        if (!net_eq(net, &init_net))
                ensure_safe_net_sysctl(net, path, table);
 
-       return __register_sysctl_table(&net->sysctls, path, table);
+       for (entry = table; entry->procname; entry++)
+               count++;
+
+       return __register_sysctl_table(&net->sysctls, path, table, count);
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl);
 
-- 
2.30.2


<Prev in Thread] Current Thread [Next in Thread>