From: Waiman Long <longman@redhat.com>
To: "Luis R. Rodriguez" <mcgrof@kernel.org>,
Kees Cook <keescook@chromium.org>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
Andrew Morton <akpm@linux-foundation.org>,
Al Viro <viro@zeniv.linux.org.uk>,
Matthew Wilcox <willy@infradead.org>,
Waiman Long <longman@redhat.com>
Subject: [PATCH 4/5] proc/sysctl: Handle CTL_FLAGS_SHOW_RANGE ctl_table flag
Date: Wed, 7 Mar 2018 15:34:28 -0500 [thread overview]
Message-ID: <1520454869-13871-5-git-send-email-longman@redhat.com> (raw)
In-Reply-To: <1520454869-13871-1-git-send-email-longman@redhat.com>
When registering ctl_table entries with CTL_FLAGS_SHOW_RANGE flag set,
it will populate the reserved range table entries with the proper
sysctl parameters to show the range the those ctl_table entries.
When unregistering the ctl_table, we also need to clear the reserved
range table entries to avoid referencing memory that will be freed.
Signed-off-by: Waiman Long <longman@redhat.com>
---
fs/proc/proc_sysctl.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++---
include/linux/sysctl.h | 1 +
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 493c975..5f8fde97 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -304,6 +304,16 @@ static void proc_sys_prune_dcache(struct ctl_table_header *head)
static void start_unregistering(struct ctl_table_header *p)
{
/*
+ * Clear reserved range table entries before freeing.
+ */
+ if (p->roffset) {
+ struct ctl_table *entry = p->ctl_table + p->roffset;
+
+ for (; entry->proc_handler == proc_show_minmax; entry++)
+ entry->procname = NULL;
+ }
+
+ /*
* if p->used is 0, nobody will ever touch that entry again;
* we'll eliminate all paths to it before dropping sysctl_lock
*/
@@ -1206,7 +1216,6 @@ static int insert_links(struct ctl_table_header *head)
if (head->set == root_set)
return 0;
-
core_parent = xlate_dir(root_set, head->parent);
if (IS_ERR(core_parent))
return 0;
@@ -1238,6 +1247,19 @@ static int insert_links(struct ctl_table_header *head)
return err;
}
+static bool sysctl_show_range(struct ctl_table *entry)
+{
+ if (!(entry->flags & CTL_FLAGS_SHOW_RANGE))
+ return false;
+
+ if ((entry->maxlen == sizeof(int)) || (entry->maxlen == sizeof(long)))
+ return true;
+
+ pr_warn("Warning: ctl_table entry \"%s\" doesn't support CTL_FLAGS_SHOW_RANGE\n",
+ entry->procname);
+ return false;
+}
+
/**
* __register_sysctl_table - register a leaf sysctl table
* @set: Sysctl tree to register on
@@ -1291,16 +1313,67 @@ struct ctl_table_header *__register_sysctl_table(
struct ctl_table *entry;
struct ctl_node *node;
int nr_entries = 0;
+ int nr_ranges = 0; /* # of entries with CTL_FLAGS_SHOW_RANGE */
+ int namelen = 0;
+ int i, j;
- for (entry = table; entry->procname; entry++)
+ for (entry = table; entry->procname; entry++) {
nr_entries++;
+ if (sysctl_show_range(entry)) {
+ nr_ranges++;
+ /* procname + "_range\0" suffix */
+ namelen += strlen(entry->procname) + 7;
+ }
+ }
+
+ if (nr_ranges) {
+ for (i = 0; entry->proc_handler == proc_show_minmax; entry++)
+ i++;
+
+ if (i < nr_ranges) {
+ pr_err("Error: Insufficient reserved ctl_table range entries (\"%s\")!\n",
+ table->procname);
+ return NULL;
+ } else if (i > nr_ranges) {
+ pr_warn("Warning: Too many reserved ctl_table range entries (\"%s\")!\n",
+ table->procname);
+ }
+ }
header = kzalloc(sizeof(struct ctl_table_header) +
- sizeof(struct ctl_node)*nr_entries, GFP_KERNEL);
+ sizeof(struct ctl_node)*(nr_entries + nr_ranges) +
+ namelen, GFP_KERNEL);
if (!header)
return NULL;
-
node = (struct ctl_node *)(header + 1);
+
+ /*
+ * Fill up reserved range entries for showing the ranges of those
+ * sysctl parameters that have the CTL_FLAGS_SHOW_RANGE flag set.
+ */
+ if (nr_ranges) {
+ int len;
+ char *namebuf = (char *)(node + nr_entries + nr_ranges);
+
+ header->roffset = nr_entries;
+ for (i = 0, j = nr_entries ; i < nr_entries; i++) {
+ if (!sysctl_show_range(&table[i]))
+ continue;
+
+ len = strlen(table[i].procname);
+ memcpy(namebuf, table[i].procname, len);
+ memcpy(namebuf + len, "_range\0", 7);
+ table[j].procname = namebuf;
+ table[j].data = (void *)&table[i];
+ table[j].mode = table[i].mode & 0444; /* Read only */
+
+ namebuf += len + 7;
+ namelen -= len + 7;
+ j++;
+ }
+ WARN_ON((j != nr_entries + nr_ranges) || namelen);
+ }
+
init_header(header, root, set, node, table);
if (sysctl_check_table(path, table))
goto fail;
@@ -1313,7 +1386,6 @@ struct ctl_table_header *__register_sysctl_table(
/* Find the directory for the ctl_table */
for (name = path; name; name = nextname) {
- int namelen;
nextname = strchr(name, '/');
if (nextname) {
namelen = nextname - name;
@@ -1342,6 +1414,13 @@ struct ctl_table_header *__register_sysctl_table(
drop_sysctl_table(&dir->header);
spin_unlock(&sysctl_lock);
fail:
+ if (nr_ranges) {
+ /*
+ * Clear procname of the reserved range table entries.
+ */
+ for (i = nr_entries; i < nr_entries + nr_ranges; i++)
+ table[i].procname = NULL;
+ }
kfree(header);
dump_stack();
return NULL;
@@ -1654,6 +1733,16 @@ void unregister_sysctl_table(struct ctl_table_header * header)
unregister_sysctl_table(subh);
kfree(table);
}
+ /*
+ * Clear reserved range table entries before freeing.
+ */
+ if (header->roffset) {
+ struct ctl_table *entry = header->ctl_table +
+ header->roffset;
+
+ for (; entry->proc_handler == proc_show_minmax; entry++)
+ entry->procname = NULL;
+ }
kfree(header);
return;
}
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index ca64d66..e922ee3 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -202,6 +202,7 @@ struct ctl_table_header
int used;
int count;
int nreg;
+ int roffset; /* Offset of reserved range entries */
};
struct rcu_head rcu;
};
--
1.8.3.1
next prev parent reply other threads:[~2018-03-07 20:35 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-07 20:34 [PATCH 0/5] sysctl: Enable easy addition of range showing sysctl parameters Waiman Long
2018-03-07 20:34 ` [PATCH 1/5] sysctl: Clarify how the ctl_table.flags should be set Waiman Long
2018-03-07 20:34 ` [PATCH 2/5] sysctl: Add a new handler proc_show_minmax() Waiman Long
2018-03-07 20:34 ` [PATCH 3/5] sysctl: Add a new ctl_table flag to show min/max range Waiman Long
2018-03-07 20:34 ` Waiman Long [this message]
2018-03-07 20:34 ` [PATCH 5/5] ipc: Show ranges of msgmni and shmmni with CTL_FLAGS_SHOW_RANGE Waiman Long
2018-03-07 22:48 ` [PATCH 0/5] sysctl: Enable easy addition of range showing sysctl parameters Andrew Morton
2018-03-08 19:21 ` Waiman Long
2018-03-08 18:34 ` Luis R. Rodriguez
2018-03-08 19:11 ` Waiman Long
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1520454869-13871-5-git-send-email-longman@redhat.com \
--to=longman@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=keescook@chromium.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox