mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
sysctl-6.6-rc1
Long ago we set out to remove the kitchen sink on kernel/sysctl.c arrays and placings sysctls to their own sybsystem or file to help avoid merge conflicts. Matthew Wilcox pointed out though that if we're going to do that we might as well also *save* space while at it and try to remove the extra last sysctl entry added at the end of each array, a sentintel, instead of bloating the kernel by adding a new sentinel with each array moved. Doing that was not so trivial, and has required slowing down the moves of kernel/sysctl.c arrays and measuring the impact on size by each new move. The complex part of the effort to help reduce the size of each sysctl is being done by the patient work of el señor Don Joel Granados. A lot of this is truly painful code refactoring and testing and then trying to measure the savings of each move and removing the sentinels. Although Joel already has code which does most of this work, experience with sysctl moves in the past shows is we need to be careful due to the slew of odd build failures that are possible due to the amount of random Kconfig options sysctls use. To that end Joel's work is split by first addressing the major housekeeping needed to remove the sentinels, which is part of this merge request. The rest of the work to actually remove the sentinels will be done later in future kernel releases. At first I was only going to send his first 7 patches of his patch series, posted 1 month ago, but in retrospect due to the testing the changes have received in linux-next and the minor changes they make this goes with the entire set of patches Joel had planned: just sysctl house keeping. There are networking changes but these are part of the house keeping too. The preliminary math is showing this will all help reduce the overall build time size of the kernel and run time memory consumed by the kernel by about ~64 bytes per array where we are able to remove each sentinel in the future. That also means there is no more bloating the kernel with the extra ~64 bytes per array moved as no new sentinels are created. Most of this has been in linux-next for about a month, the last 7 patches took a minor refresh 2 week ago based on feedback. -----BEGIN PGP SIGNATURE----- iQJGBAABCgAwFiEENnNq2KuOejlQLZofziMdCjCSiKcFAmTuVnMSHG1jZ3JvZkBr ZXJuZWwub3JnAAoJEM4jHQowkoinIckP/imvRlfkO6L0IP7MmJBRPtwY01rsTAKO Q14dZ//bG4DVQeGl1FdzrF6hhuLgekU0qW1YDFIWiCXO7CbaxaNBPSUkeW6ReVoC R/VHNUPxSR1PWQy1OTJV2t4XKri2sB7ijmUsfsATtISwhei9bggTHEysShtP4tv+ U87DzhoqMnbYIsfMo49KCqOa1Qm7TmjC1a7WAp6Fph3GJuXAzZR5pXpsd0NtOZ9x Ud5RT22icnQpMl7K+yPsqY6XcS5JkgBe/WbSzMAUkYZvBZFBq9t2D+OW5h9TZMhw piJWQ9X0Rm7qI2D15mJfXwaOhhyDhWci391hzdJmS6DI0prf6Ma2NFdAWOt/zomI uiRujS4bGeBUaK5F4TX2WQ1+jdMtAZ+0FncFnzt4U8q7dzUc91uVCm6iHW3gcfAb N7OEg2ZL0gkkgCZHqKxN8wpNQiC2KwnNk+HLAbnL2a/oJYfBtdopQmlxWfrN2hpF xxROiENqk483BRdMXDq6DR/gyDZmZWCobXIglSzlqCOjCOcLbDziIJ7pJk83ok09 h/QnXTYHf9protBq9OIQesgh2pwNzBBLifK84KZLKcb7IbdIKjpQrW5STp04oNGf wcGJzEz8tXUe0UKyMM47AcHQGzIy6cdXNLjyF8a+m7rnZzr1ndnMqZyRStZzuQin AUg2VWHKPmW9 =sq2p -----END PGP SIGNATURE----- Merge tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux Pull sysctl updates from Luis Chamberlain: "Long ago we set out to remove the kitchen sink on kernel/sysctl.c arrays and placings sysctls to their own sybsystem or file to help avoid merge conflicts. Matthew Wilcox pointed out though that if we're going to do that we might as well also *save* space while at it and try to remove the extra last sysctl entry added at the end of each array, a sentintel, instead of bloating the kernel by adding a new sentinel with each array moved. Doing that was not so trivial, and has required slowing down the moves of kernel/sysctl.c arrays and measuring the impact on size by each new move. The complex part of the effort to help reduce the size of each sysctl is being done by the patient work of el señor Don Joel Granados. A lot of this is truly painful code refactoring and testing and then trying to measure the savings of each move and removing the sentinels. Although Joel already has code which does most of this work, experience with sysctl moves in the past shows is we need to be careful due to the slew of odd build failures that are possible due to the amount of random Kconfig options sysctls use. To that end Joel's work is split by first addressing the major housekeeping needed to remove the sentinels, which is part of this merge request. The rest of the work to actually remove the sentinels will be done later in future kernel releases. The preliminary math is showing this will all help reduce the overall build time size of the kernel and run time memory consumed by the kernel by about ~64 bytes per array where we are able to remove each sentinel in the future. That also means there is no more bloating the kernel with the extra ~64 bytes per array moved as no new sentinels are created" * tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux: sysctl: Use ctl_table_size as stopping criteria for list macro sysctl: SIZE_MAX->ARRAY_SIZE in register_net_sysctl vrf: Update to register_net_sysctl_sz networking: Update to register_net_sysctl_sz netfilter: Update to register_net_sysctl_sz ax.25: Update to register_net_sysctl_sz sysctl: Add size to register_net_sysctl function sysctl: Add size arg to __register_sysctl_init sysctl: Add size to register_sysctl sysctl: Add a size arg to __register_sysctl_table sysctl: Add size argument to init_header sysctl: Add ctl_table_size to ctl_table_header sysctl: Use ctl_table_header in list_for_each_table_entry sysctl: Prefer ctl_table_header in proc_sysctl
This commit is contained in:
commit
adfd671676
@ -569,7 +569,7 @@ static void __init register_insn_emulation(struct insn_emulation *insn)
|
||||
sysctl->extra2 = &insn->max;
|
||||
sysctl->proc_handler = emulation_proc_handler;
|
||||
|
||||
register_sysctl("abi", sysctl);
|
||||
register_sysctl_sz("abi", sysctl, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,7 +365,7 @@ int appldata_register_ops(struct appldata_ops *ops)
|
||||
ops->ctl_table[0].proc_handler = appldata_generic_handler;
|
||||
ops->ctl_table[0].data = ops;
|
||||
|
||||
ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table);
|
||||
ops->sysctl_header = register_sysctl_sz(appldata_proc_name, ops->ctl_table, 1);
|
||||
if (!ops->sysctl_header)
|
||||
goto out;
|
||||
return 0;
|
||||
|
@ -1977,7 +1977,8 @@ static int vrf_netns_init_sysctl(struct net *net, struct netns_vrf *nn_vrf)
|
||||
/* init the extra1 parameter with the reference to current netns */
|
||||
table[0].extra1 = net;
|
||||
|
||||
nn_vrf->ctl_hdr = register_net_sysctl(net, "net/vrf", table);
|
||||
nn_vrf->ctl_hdr = register_net_sysctl_sz(net, "net/vrf", table,
|
||||
ARRAY_SIZE(vrf_table));
|
||||
if (!nn_vrf->ctl_hdr) {
|
||||
kfree(table);
|
||||
return -ENOMEM;
|
||||
|
@ -19,8 +19,9 @@
|
||||
#include <linux/kmemleak.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define list_for_each_table_entry(entry, table) \
|
||||
for ((entry) = (table); (entry)->procname; (entry)++)
|
||||
#define list_for_each_table_entry(entry, header) \
|
||||
entry = header->ctl_table; \
|
||||
for (size_t i = 0 ; i < header->ctl_table_size && entry->procname; ++i, entry++)
|
||||
|
||||
static const struct dentry_operations proc_sys_dentry_operations;
|
||||
static const struct file_operations proc_sys_file_operations;
|
||||
@ -43,7 +44,7 @@ static struct ctl_table sysctl_mount_point[] = {
|
||||
*/
|
||||
struct ctl_table_header *register_sysctl_mount_point(const char *path)
|
||||
{
|
||||
return register_sysctl(path, sysctl_mount_point);
|
||||
return register_sysctl_sz(path, sysctl_mount_point, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(register_sysctl_mount_point);
|
||||
|
||||
@ -188,9 +189,10 @@ static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)
|
||||
|
||||
static void init_header(struct ctl_table_header *head,
|
||||
struct ctl_table_root *root, struct ctl_table_set *set,
|
||||
struct ctl_node *node, struct ctl_table *table)
|
||||
struct ctl_node *node, struct ctl_table *table, size_t table_size)
|
||||
{
|
||||
head->ctl_table = table;
|
||||
head->ctl_table_size = table_size;
|
||||
head->ctl_table_arg = table;
|
||||
head->used = 0;
|
||||
head->count = 1;
|
||||
@ -204,7 +206,7 @@ static void init_header(struct ctl_table_header *head,
|
||||
if (node) {
|
||||
struct ctl_table *entry;
|
||||
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, head) {
|
||||
node->header = head;
|
||||
node++;
|
||||
}
|
||||
@ -215,7 +217,7 @@ static void erase_header(struct ctl_table_header *head)
|
||||
{
|
||||
struct ctl_table *entry;
|
||||
|
||||
list_for_each_table_entry(entry, head->ctl_table)
|
||||
list_for_each_table_entry(entry, head)
|
||||
erase_entry(head, entry);
|
||||
}
|
||||
|
||||
@ -242,7 +244,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
|
||||
err = insert_links(header);
|
||||
if (err)
|
||||
goto fail_links;
|
||||
list_for_each_table_entry(entry, header->ctl_table) {
|
||||
list_for_each_table_entry(entry, header) {
|
||||
err = insert_entry(header, entry);
|
||||
if (err)
|
||||
goto fail;
|
||||
@ -973,7 +975,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
|
||||
memcpy(new_name, name, namelen);
|
||||
table[0].procname = new_name;
|
||||
table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
|
||||
init_header(&new->header, set->dir.header.root, set, node, table);
|
||||
init_header(&new->header, set->dir.header.root, set, node, table, 1);
|
||||
|
||||
return new;
|
||||
}
|
||||
@ -1125,11 +1127,11 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sysctl_check_table(const char *path, struct ctl_table *table)
|
||||
static int sysctl_check_table(const char *path, struct ctl_table_header *header)
|
||||
{
|
||||
struct ctl_table *entry;
|
||||
int err = 0;
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, header) {
|
||||
if ((entry->proc_handler == proc_dostring) ||
|
||||
(entry->proc_handler == proc_dobool) ||
|
||||
(entry->proc_handler == proc_dointvec) ||
|
||||
@ -1159,8 +1161,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
|
||||
struct ctl_table_root *link_root)
|
||||
static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_header *head)
|
||||
{
|
||||
struct ctl_table *link_table, *entry, *link;
|
||||
struct ctl_table_header *links;
|
||||
@ -1170,7 +1171,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table
|
||||
|
||||
name_bytes = 0;
|
||||
nr_entries = 0;
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, head) {
|
||||
nr_entries++;
|
||||
name_bytes += strlen(entry->procname) + 1;
|
||||
}
|
||||
@ -1189,31 +1190,33 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table
|
||||
link_name = (char *)&link_table[nr_entries + 1];
|
||||
link = link_table;
|
||||
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, head) {
|
||||
int len = strlen(entry->procname) + 1;
|
||||
memcpy(link_name, entry->procname, len);
|
||||
link->procname = link_name;
|
||||
link->mode = S_IFLNK|S_IRWXUGO;
|
||||
link->data = link_root;
|
||||
link->data = head->root;
|
||||
link_name += len;
|
||||
link++;
|
||||
}
|
||||
init_header(links, dir->header.root, dir->header.set, node, link_table);
|
||||
init_header(links, dir->header.root, dir->header.set, node, link_table,
|
||||
head->ctl_table_size);
|
||||
links->nreg = nr_entries;
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
static bool get_links(struct ctl_dir *dir,
|
||||
struct ctl_table *table, struct ctl_table_root *link_root)
|
||||
struct ctl_table_header *header,
|
||||
struct ctl_table_root *link_root)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table_header *tmp_head;
|
||||
struct ctl_table *entry, *link;
|
||||
|
||||
/* Are there links available for every entry in table? */
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, header) {
|
||||
const char *procname = entry->procname;
|
||||
link = find_entry(&head, dir, procname, strlen(procname));
|
||||
link = find_entry(&tmp_head, dir, procname, strlen(procname));
|
||||
if (!link)
|
||||
return false;
|
||||
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
|
||||
@ -1224,10 +1227,10 @@ static bool get_links(struct ctl_dir *dir,
|
||||
}
|
||||
|
||||
/* The checks passed. Increase the registration count on the links */
|
||||
list_for_each_table_entry(entry, table) {
|
||||
list_for_each_table_entry(entry, header) {
|
||||
const char *procname = entry->procname;
|
||||
link = find_entry(&head, dir, procname, strlen(procname));
|
||||
head->nreg++;
|
||||
link = find_entry(&tmp_head, dir, procname, strlen(procname));
|
||||
tmp_head->nreg++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1246,13 +1249,13 @@ static int insert_links(struct ctl_table_header *head)
|
||||
if (IS_ERR(core_parent))
|
||||
return 0;
|
||||
|
||||
if (get_links(core_parent, head->ctl_table, head->root))
|
||||
if (get_links(core_parent, head, head->root))
|
||||
return 0;
|
||||
|
||||
core_parent->header.nreg++;
|
||||
spin_unlock(&sysctl_lock);
|
||||
|
||||
links = new_links(core_parent, head->ctl_table, head->root);
|
||||
links = new_links(core_parent, head);
|
||||
|
||||
spin_lock(&sysctl_lock);
|
||||
err = -ENOMEM;
|
||||
@ -1260,7 +1263,7 @@ static int insert_links(struct ctl_table_header *head)
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
if (get_links(core_parent, head->ctl_table, head->root)) {
|
||||
if (get_links(core_parent, head, head->root)) {
|
||||
kfree(links);
|
||||
goto out;
|
||||
}
|
||||
@ -1310,6 +1313,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.
|
||||
@ -1352,26 +1356,21 @@ 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_dir *dir;
|
||||
struct ctl_table *entry;
|
||||
struct ctl_node *node;
|
||||
int nr_entries = 0;
|
||||
|
||||
list_for_each_table_entry(entry, table)
|
||||
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);
|
||||
if (sysctl_check_table(path, table))
|
||||
init_header(header, root, set, node, table, table_size);
|
||||
if (sysctl_check_table(path, header))
|
||||
goto fail;
|
||||
|
||||
spin_lock(&sysctl_lock);
|
||||
@ -1401,7 +1400,7 @@ struct ctl_table_header *__register_sysctl_table(
|
||||
}
|
||||
|
||||
/**
|
||||
* register_sysctl - register a sysctl table
|
||||
* register_sysctl_sz - register a sysctl table
|
||||
* @path: The path to the directory the sysctl table is in. If the path
|
||||
* doesn't exist we will create it for you.
|
||||
* @table: the table structure. The calller must ensure the life of the @table
|
||||
@ -1411,18 +1410,20 @@ struct ctl_table_header *__register_sysctl_table(
|
||||
* to call unregister_sysctl_table() and can instead use something like
|
||||
* register_sysctl_init() which does not care for the result of the syctl
|
||||
* registration.
|
||||
* @table_size: The number of elements in table.
|
||||
*
|
||||
* Register a sysctl table. @table should be a filled in ctl_table
|
||||
* array. A completely 0 filled entry terminates the table.
|
||||
*
|
||||
* See __register_sysctl_table for more details.
|
||||
*/
|
||||
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
|
||||
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
|
||||
size_t table_size)
|
||||
{
|
||||
return __register_sysctl_table(&sysctl_table_root.default_set,
|
||||
path, table);
|
||||
path, table, table_size);
|
||||
}
|
||||
EXPORT_SYMBOL(register_sysctl);
|
||||
EXPORT_SYMBOL(register_sysctl_sz);
|
||||
|
||||
/**
|
||||
* __register_sysctl_init() - register sysctl table to path
|
||||
@ -1433,6 +1434,7 @@ EXPORT_SYMBOL(register_sysctl);
|
||||
* lifetime use of the sysctl.
|
||||
* @table_name: The name of sysctl table, only used for log printing when
|
||||
* registration fails
|
||||
* @table_size: The number of elements in table
|
||||
*
|
||||
* The sysctl interface is used by userspace to query or modify at runtime
|
||||
* a predefined value set on a variable. These variables however have default
|
||||
@ -1445,12 +1447,12 @@ EXPORT_SYMBOL(register_sysctl);
|
||||
* Context: if your base directory does not exist it will be created for you.
|
||||
*/
|
||||
void __init __register_sysctl_init(const char *path, struct ctl_table *table,
|
||||
const char *table_name)
|
||||
const char *table_name, size_t table_size)
|
||||
{
|
||||
struct ctl_table_header *hdr = register_sysctl(path, table);
|
||||
struct ctl_table_header *hdr = register_sysctl_sz(path, table, table_size);
|
||||
|
||||
if (unlikely(!hdr)) {
|
||||
pr_err("failed when register_sysctl %s to %s\n", table_name, path);
|
||||
pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path);
|
||||
return;
|
||||
}
|
||||
kmemleak_not_leak(hdr);
|
||||
@ -1471,7 +1473,7 @@ static void put_links(struct ctl_table_header *header)
|
||||
if (IS_ERR(core_parent))
|
||||
return;
|
||||
|
||||
list_for_each_table_entry(entry, header->ctl_table) {
|
||||
list_for_each_table_entry(entry, header) {
|
||||
struct ctl_table_header *link_head;
|
||||
struct ctl_table *link;
|
||||
const char *name = entry->procname;
|
||||
@ -1535,7 +1537,7 @@ void setup_sysctl_set(struct ctl_table_set *set,
|
||||
{
|
||||
memset(set, 0, sizeof(*set));
|
||||
set->is_seen = is_seen;
|
||||
init_header(&set->dir.header, root, set, NULL, root_table);
|
||||
init_header(&set->dir.header, root, set, NULL, root_table, 1);
|
||||
}
|
||||
|
||||
void retire_sysctl_set(struct ctl_table_set *set)
|
||||
|
@ -159,12 +159,22 @@ struct ctl_node {
|
||||
struct ctl_table_header *header;
|
||||
};
|
||||
|
||||
/* struct ctl_table_header is used to maintain dynamic lists of
|
||||
struct ctl_table trees. */
|
||||
/**
|
||||
* struct ctl_table_header - maintains dynamic lists of struct ctl_table trees
|
||||
* @ctl_table: pointer to the first element in ctl_table array
|
||||
* @ctl_table_size: number of elements pointed by @ctl_table
|
||||
* @used: The entry will never be touched when equal to 0.
|
||||
* @count: Upped every time something is added to @inodes and downed every time
|
||||
* something is removed from inodes
|
||||
* @nreg: When nreg drops to 0 the ctl_table_header will be unregistered.
|
||||
* @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()"
|
||||
*
|
||||
*/
|
||||
struct ctl_table_header {
|
||||
union {
|
||||
struct {
|
||||
struct ctl_table *ctl_table;
|
||||
int ctl_table_size;
|
||||
int used;
|
||||
int count;
|
||||
int nreg;
|
||||
@ -205,6 +215,9 @@ struct ctl_path {
|
||||
const char *procname;
|
||||
};
|
||||
|
||||
#define register_sysctl(path, table) \
|
||||
register_sysctl_sz(path, table, ARRAY_SIZE(table))
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
void proc_sys_poll_notify(struct ctl_table_poll *poll);
|
||||
@ -216,14 +229,16 @@ 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);
|
||||
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
|
||||
const char *path, struct ctl_table *table, size_t table_size);
|
||||
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
|
||||
size_t table_size);
|
||||
void unregister_sysctl_table(struct ctl_table_header * table);
|
||||
|
||||
extern int sysctl_init_bases(void);
|
||||
extern void __register_sysctl_init(const char *path, struct ctl_table *table,
|
||||
const char *table_name);
|
||||
#define register_sysctl_init(path, table) __register_sysctl_init(path, table, #table)
|
||||
const char *table_name, size_t table_size);
|
||||
#define register_sysctl_init(path, table) \
|
||||
__register_sysctl_init(path, table, #table, ARRAY_SIZE(table))
|
||||
extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
|
||||
|
||||
void do_sysctl_args(void);
|
||||
@ -252,7 +267,9 @@ static inline struct ctl_table_header *register_sysctl_mount_point(const char *p
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
|
||||
static inline struct ctl_table_header *register_sysctl_sz(const char *path,
|
||||
struct ctl_table *table,
|
||||
size_t table_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1272,7 +1272,9 @@ static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; }
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
|
||||
size_t ipv6_icmp_sysctl_table_size(void);
|
||||
struct ctl_table *ipv6_route_sysctl_init(struct net *net);
|
||||
size_t ipv6_route_sysctl_table_size(struct net *net);
|
||||
int ipv6_sysctl_register(void);
|
||||
void ipv6_sysctl_unregister(void);
|
||||
#endif
|
||||
|
@ -471,15 +471,17 @@ void unregister_pernet_device(struct pernet_operations *);
|
||||
|
||||
struct ctl_table;
|
||||
|
||||
#define register_net_sysctl(net, path, table) \
|
||||
register_net_sysctl_sz(net, path, table, ARRAY_SIZE(table))
|
||||
#ifdef CONFIG_SYSCTL
|
||||
int net_sysctl_init(void);
|
||||
struct ctl_table_header *register_net_sysctl(struct net *net, const char *path,
|
||||
struct ctl_table *table);
|
||||
struct ctl_table_header *register_net_sysctl_sz(struct net *net, const char *path,
|
||||
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(struct net *net,
|
||||
const char *path, struct ctl_table *table)
|
||||
static inline struct ctl_table_header *register_net_sysctl_sz(struct net *net,
|
||||
const char *path, struct ctl_table *table, size_t table_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
@ -364,7 +365,7 @@ static __init int user_namespace_sysctl_init(void)
|
||||
* default set so that registrations in the child sets work
|
||||
* properly.
|
||||
*/
|
||||
user_header = register_sysctl("user", empty);
|
||||
user_header = register_sysctl_sz("user", empty, 0);
|
||||
kmemleak_ignore(user_header);
|
||||
BUG_ON(!user_header);
|
||||
BUG_ON(!setup_userns_sysctls(&init_user_ns));
|
||||
|
@ -159,7 +159,8 @@ int ax25_register_dev_sysctl(ax25_dev *ax25_dev)
|
||||
table[k].data = &ax25_dev->values[k];
|
||||
|
||||
snprintf(path, sizeof(path), "net/ax25/%s", ax25_dev->dev->name);
|
||||
ax25_dev->sysheader = register_net_sysctl(&init_net, path, table);
|
||||
ax25_dev->sysheader = register_net_sysctl_sz(&init_net, path, table,
|
||||
ARRAY_SIZE(ax25_param_table));
|
||||
if (!ax25_dev->sysheader) {
|
||||
kfree(table);
|
||||
return -ENOMEM;
|
||||
|
@ -1135,7 +1135,8 @@ static int br_netfilter_sysctl_init_net(struct net *net)
|
||||
|
||||
br_netfilter_sysctl_default(brnet);
|
||||
|
||||
brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
|
||||
brnet->ctl_hdr = register_net_sysctl_sz(net, "net/bridge", table,
|
||||
ARRAY_SIZE(brnf_table));
|
||||
if (!brnet->ctl_hdr) {
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(table);
|
||||
|
@ -3779,6 +3779,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
|
||||
const char *dev_name_source;
|
||||
char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
|
||||
char *p_name;
|
||||
size_t neigh_vars_size;
|
||||
|
||||
t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL_ACCOUNT);
|
||||
if (!t)
|
||||
@ -3790,11 +3791,13 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
|
||||
t->neigh_vars[i].extra2 = p;
|
||||
}
|
||||
|
||||
neigh_vars_size = ARRAY_SIZE(t->neigh_vars);
|
||||
if (dev) {
|
||||
dev_name_source = dev->name;
|
||||
/* Terminate the table early */
|
||||
memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
|
||||
sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
|
||||
neigh_vars_size = NEIGH_VAR_BASE_REACHABLE_TIME_MS + 1;
|
||||
} else {
|
||||
struct neigh_table *tbl = p->tbl;
|
||||
dev_name_source = "default";
|
||||
@ -3841,8 +3844,9 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
|
||||
|
||||
snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
|
||||
p_name, dev_name_source);
|
||||
t->sysctl_header =
|
||||
register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
|
||||
t->sysctl_header = register_net_sysctl_sz(neigh_parms_net(p),
|
||||
neigh_path, t->neigh_vars,
|
||||
neigh_vars_size);
|
||||
if (!t->sysctl_header)
|
||||
goto free;
|
||||
|
||||
|
@ -712,7 +712,8 @@ static __net_init int sysctl_core_net_init(struct net *net)
|
||||
tmp->data += (char *)net - (char *)&init_net;
|
||||
}
|
||||
|
||||
net->core.sysctl_hdr = register_net_sysctl(net, "net/core", tbl);
|
||||
net->core.sysctl_hdr = register_net_sysctl_sz(net, "net/core", tbl,
|
||||
ARRAY_SIZE(netns_core_table));
|
||||
if (net->core.sysctl_hdr == NULL)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -360,6 +360,7 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
|
||||
struct ctl_table_header *hdr;
|
||||
struct netns_ieee802154_lowpan *ieee802154_lowpan =
|
||||
net_ieee802154_lowpan(net);
|
||||
size_t table_size = ARRAY_SIZE(lowpan_frags_ns_ctl_table);
|
||||
|
||||
table = lowpan_frags_ns_ctl_table;
|
||||
if (!net_eq(net, &init_net)) {
|
||||
@ -369,8 +370,10 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
|
||||
goto err_alloc;
|
||||
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
table[0].procname = NULL;
|
||||
table_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
table[0].data = &ieee802154_lowpan->fqdir->high_thresh;
|
||||
@ -379,7 +382,8 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
|
||||
table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh;
|
||||
table[2].data = &ieee802154_lowpan->fqdir->timeout;
|
||||
|
||||
hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/ieee802154/6lowpan", table,
|
||||
table_size);
|
||||
if (hdr == NULL)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -2737,7 +2737,8 @@ static __net_init int devinet_init_net(struct net *net)
|
||||
goto err_reg_dflt;
|
||||
|
||||
err = -ENOMEM;
|
||||
forw_hdr = register_net_sysctl(net, "net/ipv4", tbl);
|
||||
forw_hdr = register_net_sysctl_sz(net, "net/ipv4", tbl,
|
||||
ARRAY_SIZE(ctl_forward_entry));
|
||||
if (!forw_hdr)
|
||||
goto err_reg_ctl;
|
||||
net->ipv4.forw_hdr = forw_hdr;
|
||||
|
@ -615,7 +615,8 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net)
|
||||
table[2].data = &net->ipv4.fqdir->timeout;
|
||||
table[3].data = &net->ipv4.fqdir->max_dist;
|
||||
|
||||
hdr = register_net_sysctl(net, "net/ipv4", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/ipv4", table,
|
||||
ARRAY_SIZE(ip4_frags_ns_ctl_table));
|
||||
if (!hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -3592,6 +3592,7 @@ static struct ctl_table ipv4_route_netns_table[] = {
|
||||
static __net_init int sysctl_route_net_init(struct net *net)
|
||||
{
|
||||
struct ctl_table *tbl;
|
||||
size_t table_size = ARRAY_SIZE(ipv4_route_netns_table);
|
||||
|
||||
tbl = ipv4_route_netns_table;
|
||||
if (!net_eq(net, &init_net)) {
|
||||
@ -3603,8 +3604,10 @@ static __net_init int sysctl_route_net_init(struct net *net)
|
||||
|
||||
/* Don't export non-whitelisted sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
if (tbl[0].procname != ipv4_route_flush_procname)
|
||||
if (tbl[0].procname != ipv4_route_flush_procname) {
|
||||
tbl[0].procname = NULL;
|
||||
table_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the variables to point into the current struct net
|
||||
@ -3615,7 +3618,8 @@ static __net_init int sysctl_route_net_init(struct net *net)
|
||||
}
|
||||
tbl[0].extra1 = net;
|
||||
|
||||
net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl);
|
||||
net->ipv4.route_hdr = register_net_sysctl_sz(net, "net/ipv4/route",
|
||||
tbl, table_size);
|
||||
if (!net->ipv4.route_hdr)
|
||||
goto err_reg;
|
||||
return 0;
|
||||
|
@ -1519,7 +1519,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
|
||||
}
|
||||
}
|
||||
|
||||
net->ipv4.ipv4_hdr = register_net_sysctl(net, "net/ipv4", table);
|
||||
net->ipv4.ipv4_hdr = register_net_sysctl_sz(net, "net/ipv4", table,
|
||||
ARRAY_SIZE(ipv4_net_table));
|
||||
if (!net->ipv4.ipv4_hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -169,7 +169,8 @@ static __net_init int xfrm4_net_sysctl_init(struct net *net)
|
||||
table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
|
||||
}
|
||||
|
||||
hdr = register_net_sysctl(net, "net/ipv4", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/ipv4", table,
|
||||
ARRAY_SIZE(xfrm4_policy_table));
|
||||
if (!hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -7135,7 +7135,8 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
|
||||
|
||||
snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name);
|
||||
|
||||
p->sysctl_header = register_net_sysctl(net, path, table);
|
||||
p->sysctl_header = register_net_sysctl_sz(net, path, table,
|
||||
ARRAY_SIZE(addrconf_sysctl));
|
||||
if (!p->sysctl_header)
|
||||
goto free;
|
||||
|
||||
|
@ -1227,4 +1227,9 @@ struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
size_t ipv6_icmp_sysctl_table_size(void)
|
||||
{
|
||||
return ARRAY_SIZE(ipv6_icmp_table_template);
|
||||
}
|
||||
#endif
|
||||
|
@ -87,7 +87,8 @@ static int nf_ct_frag6_sysctl_register(struct net *net)
|
||||
table[2].data = &nf_frag->fqdir->high_thresh;
|
||||
table[2].extra1 = &nf_frag->fqdir->low_thresh;
|
||||
|
||||
hdr = register_net_sysctl(net, "net/netfilter", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/netfilter", table,
|
||||
ARRAY_SIZE(nf_ct_frag6_sysctl_table));
|
||||
if (hdr == NULL)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -470,7 +470,8 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
|
||||
table[1].extra2 = &net->ipv6.fqdir->high_thresh;
|
||||
table[2].data = &net->ipv6.fqdir->timeout;
|
||||
|
||||
hdr = register_net_sysctl(net, "net/ipv6", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/ipv6", table,
|
||||
ARRAY_SIZE(ip6_frags_ns_ctl_table));
|
||||
if (!hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -6453,6 +6453,15 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
size_t ipv6_route_sysctl_table_size(struct net *net)
|
||||
{
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
return 1;
|
||||
|
||||
return ARRAY_SIZE(ipv6_route_table_template);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __net_init ip6_route_net_init(struct net *net)
|
||||
|
@ -275,17 +275,23 @@ static int __net_init ipv6_sysctl_net_init(struct net *net)
|
||||
if (!ipv6_icmp_table)
|
||||
goto out_ipv6_route_table;
|
||||
|
||||
net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table);
|
||||
net->ipv6.sysctl.hdr = register_net_sysctl_sz(net, "net/ipv6",
|
||||
ipv6_table,
|
||||
ARRAY_SIZE(ipv6_table_template));
|
||||
if (!net->ipv6.sysctl.hdr)
|
||||
goto out_ipv6_icmp_table;
|
||||
|
||||
net->ipv6.sysctl.route_hdr =
|
||||
register_net_sysctl(net, "net/ipv6/route", ipv6_route_table);
|
||||
net->ipv6.sysctl.route_hdr = register_net_sysctl_sz(net,
|
||||
"net/ipv6/route",
|
||||
ipv6_route_table,
|
||||
ipv6_route_sysctl_table_size(net));
|
||||
if (!net->ipv6.sysctl.route_hdr)
|
||||
goto out_unregister_ipv6_table;
|
||||
|
||||
net->ipv6.sysctl.icmp_hdr =
|
||||
register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table);
|
||||
net->ipv6.sysctl.icmp_hdr = register_net_sysctl_sz(net,
|
||||
"net/ipv6/icmp",
|
||||
ipv6_icmp_table,
|
||||
ipv6_icmp_sysctl_table_size());
|
||||
if (!net->ipv6.sysctl.icmp_hdr)
|
||||
goto out_unregister_route_table;
|
||||
|
||||
|
@ -201,7 +201,8 @@ static int __net_init xfrm6_net_sysctl_init(struct net *net)
|
||||
table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
|
||||
}
|
||||
|
||||
hdr = register_net_sysctl(net, "net/ipv6", table);
|
||||
hdr = register_net_sysctl_sz(net, "net/ipv6", table,
|
||||
ARRAY_SIZE(xfrm6_policy_table));
|
||||
if (!hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -1419,7 +1419,8 @@ static int mpls_dev_sysctl_register(struct net_device *dev,
|
||||
|
||||
snprintf(path, sizeof(path), "net/mpls/conf/%s", dev->name);
|
||||
|
||||
mdev->sysctl = register_net_sysctl(net, path, table);
|
||||
mdev->sysctl = register_net_sysctl_sz(net, path, table,
|
||||
ARRAY_SIZE(mpls_dev_table));
|
||||
if (!mdev->sysctl)
|
||||
goto free;
|
||||
|
||||
@ -2689,7 +2690,8 @@ static int mpls_net_init(struct net *net)
|
||||
for (i = 0; i < ARRAY_SIZE(mpls_table) - 1; i++)
|
||||
table[i].data = (char *)net + (uintptr_t)table[i].data;
|
||||
|
||||
net->mpls.ctl = register_net_sysctl(net, "net/mpls", table);
|
||||
net->mpls.ctl = register_net_sysctl_sz(net, "net/mpls", table,
|
||||
ARRAY_SIZE(mpls_table));
|
||||
if (net->mpls.ctl == NULL) {
|
||||
kfree(table);
|
||||
return -ENOMEM;
|
||||
|
@ -164,7 +164,8 @@ static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
|
||||
table[5].data = &pernet->pm_type;
|
||||
table[6].data = &pernet->scheduler;
|
||||
|
||||
hdr = register_net_sysctl(net, MPTCP_SYSCTL_PATH, table);
|
||||
hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table,
|
||||
ARRAY_SIZE(mptcp_sysctl_table));
|
||||
if (!hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -4269,6 +4269,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
|
||||
struct net *net = ipvs->net;
|
||||
struct ctl_table *tbl;
|
||||
int idx, ret;
|
||||
size_t ctl_table_size = ARRAY_SIZE(vs_vars);
|
||||
|
||||
atomic_set(&ipvs->dropentry, 0);
|
||||
spin_lock_init(&ipvs->dropentry_lock);
|
||||
@ -4285,8 +4286,10 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
tbl[0].procname = NULL;
|
||||
ctl_table_size = 0;
|
||||
}
|
||||
} else
|
||||
tbl = vs_vars;
|
||||
/* Initialize sysctl defaults */
|
||||
@ -4357,7 +4360,8 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
|
||||
#endif
|
||||
|
||||
ret = -ENOMEM;
|
||||
ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl);
|
||||
ipvs->sysctl_hdr = register_net_sysctl_sz(net, "net/ipv4/vs", tbl,
|
||||
ctl_table_size);
|
||||
if (!ipvs->sysctl_hdr)
|
||||
goto err;
|
||||
ipvs->sysctl_tbl = tbl;
|
||||
|
@ -550,6 +550,7 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler = {
|
||||
static int __net_init __ip_vs_lblc_init(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
size_t vars_table_size = ARRAY_SIZE(vs_vars_table);
|
||||
|
||||
if (!ipvs)
|
||||
return -ENOENT;
|
||||
@ -562,16 +563,19 @@ static int __net_init __ip_vs_lblc_init(struct net *net)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
ipvs->lblc_ctl_table[0].procname = NULL;
|
||||
vars_table_size = 0;
|
||||
}
|
||||
|
||||
} else
|
||||
ipvs->lblc_ctl_table = vs_vars_table;
|
||||
ipvs->sysctl_lblc_expiration = DEFAULT_EXPIRATION;
|
||||
ipvs->lblc_ctl_table[0].data = &ipvs->sysctl_lblc_expiration;
|
||||
|
||||
ipvs->lblc_ctl_header =
|
||||
register_net_sysctl(net, "net/ipv4/vs", ipvs->lblc_ctl_table);
|
||||
ipvs->lblc_ctl_header = register_net_sysctl_sz(net, "net/ipv4/vs",
|
||||
ipvs->lblc_ctl_table,
|
||||
vars_table_size);
|
||||
if (!ipvs->lblc_ctl_header) {
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(ipvs->lblc_ctl_table);
|
||||
|
@ -736,6 +736,7 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
|
||||
static int __net_init __ip_vs_lblcr_init(struct net *net)
|
||||
{
|
||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||
size_t vars_table_size = ARRAY_SIZE(vs_vars_table);
|
||||
|
||||
if (!ipvs)
|
||||
return -ENOENT;
|
||||
@ -748,15 +749,18 @@ static int __net_init __ip_vs_lblcr_init(struct net *net)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
ipvs->lblcr_ctl_table[0].procname = NULL;
|
||||
vars_table_size = 0;
|
||||
}
|
||||
} else
|
||||
ipvs->lblcr_ctl_table = vs_vars_table;
|
||||
ipvs->sysctl_lblcr_expiration = DEFAULT_EXPIRATION;
|
||||
ipvs->lblcr_ctl_table[0].data = &ipvs->sysctl_lblcr_expiration;
|
||||
|
||||
ipvs->lblcr_ctl_header =
|
||||
register_net_sysctl(net, "net/ipv4/vs", ipvs->lblcr_ctl_table);
|
||||
ipvs->lblcr_ctl_header = register_net_sysctl_sz(net, "net/ipv4/vs",
|
||||
ipvs->lblcr_ctl_table,
|
||||
vars_table_size);
|
||||
if (!ipvs->lblcr_ctl_header) {
|
||||
if (!net_eq(net, &init_net))
|
||||
kfree(ipvs->lblcr_ctl_table);
|
||||
|
@ -1106,7 +1106,9 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
|
||||
table[NF_SYSCTL_CT_BUCKETS].mode = 0444;
|
||||
}
|
||||
|
||||
cnet->sysctl_header = register_net_sysctl(net, "net/netfilter", table);
|
||||
cnet->sysctl_header = register_net_sysctl_sz(net, "net/netfilter",
|
||||
table,
|
||||
ARRAY_SIZE(nf_ct_sysctl_table));
|
||||
if (!cnet->sysctl_header)
|
||||
goto out_unregister_netfilter;
|
||||
|
||||
|
@ -487,9 +487,10 @@ static int netfilter_log_sysctl_init(struct net *net)
|
||||
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
|
||||
table[i].extra2 = net;
|
||||
|
||||
net->nf.nf_log_dir_header = register_net_sysctl(net,
|
||||
"net/netfilter/nf_log",
|
||||
table);
|
||||
net->nf.nf_log_dir_header = register_net_sysctl_sz(net,
|
||||
"net/netfilter/nf_log",
|
||||
table,
|
||||
ARRAY_SIZE(nf_log_sysctl_table));
|
||||
if (!net->nf.nf_log_dir_header)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -565,7 +565,8 @@ static __net_init int rds_tcp_init_net(struct net *net)
|
||||
}
|
||||
tbl[RDS_TCP_SNDBUF].data = &rtn->sndbuf_size;
|
||||
tbl[RDS_TCP_RCVBUF].data = &rtn->rcvbuf_size;
|
||||
rtn->rds_tcp_sysctl = register_net_sysctl(net, "net/rds/tcp", tbl);
|
||||
rtn->rds_tcp_sysctl = register_net_sysctl_sz(net, "net/rds/tcp", tbl,
|
||||
ARRAY_SIZE(rds_tcp_sysctl_table));
|
||||
if (!rtn->rds_tcp_sysctl) {
|
||||
pr_warn("could not register sysctl\n");
|
||||
err = -ENOMEM;
|
||||
|
@ -612,7 +612,9 @@ int sctp_sysctl_net_register(struct net *net)
|
||||
table[SCTP_PF_RETRANS_IDX].extra2 = &net->sctp.ps_retrans;
|
||||
table[SCTP_PS_RETRANS_IDX].extra1 = &net->sctp.pf_retrans;
|
||||
|
||||
net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table);
|
||||
net->sctp.sysctl_header = register_net_sysctl_sz(net, "net/sctp",
|
||||
table,
|
||||
ARRAY_SIZE(sctp_net_table));
|
||||
if (net->sctp.sysctl_header == NULL) {
|
||||
kfree(table);
|
||||
return -ENOMEM;
|
||||
|
@ -87,7 +87,8 @@ int __net_init smc_sysctl_net_init(struct net *net)
|
||||
table[i].data += (void *)net - (void *)&init_net;
|
||||
}
|
||||
|
||||
net->smc.smc_hdr = register_net_sysctl(net, "net/smc", table);
|
||||
net->smc.smc_hdr = register_net_sysctl_sz(net, "net/smc", table,
|
||||
ARRAY_SIZE(smc_table));
|
||||
if (!net->smc.smc_hdr)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -101,7 +101,7 @@ __init int net_sysctl_init(void)
|
||||
* registering "/proc/sys/net" as an empty directory not in a
|
||||
* network namespace.
|
||||
*/
|
||||
net_header = register_sysctl("net", empty);
|
||||
net_header = register_sysctl_sz("net", empty, 0);
|
||||
if (!net_header)
|
||||
goto out;
|
||||
ret = register_pernet_subsys(&sysctl_pernet_ops);
|
||||
@ -122,12 +122,13 @@ __init int net_sysctl_init(void)
|
||||
* allocated.
|
||||
*/
|
||||
static void ensure_safe_net_sysctl(struct net *net, const char *path,
|
||||
struct ctl_table *table)
|
||||
struct ctl_table *table, size_t table_size)
|
||||
{
|
||||
struct ctl_table *ent;
|
||||
|
||||
pr_debug("Registering net sysctl (net %p): %s\n", net, path);
|
||||
for (ent = table; ent->procname; ent++) {
|
||||
ent = table;
|
||||
for (size_t i = 0; i < table_size && ent->procname; ent++, i++) {
|
||||
unsigned long addr;
|
||||
const char *where;
|
||||
|
||||
@ -160,15 +161,24 @@ 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)
|
||||
struct ctl_table_header *register_net_sysctl_sz(struct net *net,
|
||||
const char *path,
|
||||
struct ctl_table *table,
|
||||
size_t table_size)
|
||||
{
|
||||
if (!net_eq(net, &init_net))
|
||||
ensure_safe_net_sysctl(net, path, table);
|
||||
int count;
|
||||
struct ctl_table *entry;
|
||||
|
||||
return __register_sysctl_table(&net->sysctls, path, table);
|
||||
if (!net_eq(net, &init_net))
|
||||
ensure_safe_net_sysctl(net, path, table, table_size);
|
||||
|
||||
entry = table;
|
||||
for (count = 0 ; count < table_size && entry->procname; entry++, count++)
|
||||
;
|
||||
|
||||
return __register_sysctl_table(&net->sysctls, path, table, count);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_net_sysctl);
|
||||
EXPORT_SYMBOL_GPL(register_net_sysctl_sz);
|
||||
|
||||
void unregister_net_sysctl_table(struct ctl_table_header *header)
|
||||
{
|
||||
|
@ -36,7 +36,8 @@ int __net_init unix_sysctl_register(struct net *net)
|
||||
table[0].data = &net->unx.sysctl_max_dgram_qlen;
|
||||
}
|
||||
|
||||
net->unx.ctl = register_net_sysctl(net, "net/unix", table);
|
||||
net->unx.ctl = register_net_sysctl_sz(net, "net/unix", table,
|
||||
ARRAY_SIZE(unix_table));
|
||||
if (net->unx.ctl == NULL)
|
||||
goto err_reg;
|
||||
|
||||
|
@ -44,6 +44,7 @@ static struct ctl_table xfrm_table[] = {
|
||||
int __net_init xfrm_sysctl_init(struct net *net)
|
||||
{
|
||||
struct ctl_table *table;
|
||||
size_t table_size = ARRAY_SIZE(xfrm_table);
|
||||
|
||||
__xfrm_sysctl_init(net);
|
||||
|
||||
@ -56,10 +57,13 @@ int __net_init xfrm_sysctl_init(struct net *net)
|
||||
table[3].data = &net->xfrm.sysctl_acq_expires;
|
||||
|
||||
/* Don't export sysctls to unprivileged users */
|
||||
if (net->user_ns != &init_user_ns)
|
||||
if (net->user_ns != &init_user_ns) {
|
||||
table[0].procname = NULL;
|
||||
table_size = 0;
|
||||
}
|
||||
|
||||
net->xfrm.sysctl_hdr = register_net_sysctl(net, "net/core", table);
|
||||
net->xfrm.sysctl_hdr = register_net_sysctl_sz(net, "net/core", table,
|
||||
table_size);
|
||||
if (!net->xfrm.sysctl_hdr)
|
||||
goto out_register;
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user