linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Waiman Long <longman@redhat.com>
To: "Luis R. Rodriguez" <mcgrof@kernel.org>,
	Kees Cook <keescook@chromium.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Jonathan Corbet <corbet@lwn.net>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-doc@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>,
	Matthew Wilcox <willy@infradead.org>,
	"Eric W. Biederman" <ebiederm@xmission.com>,
	Waiman Long <longman@redhat.com>
Subject: [PATCH v6 3/8] sysctl: Warn when a clamped sysctl parameter is set out of range
Date: Fri, 27 Apr 2018 17:00:33 -0400	[thread overview]
Message-ID: <1524862838-8247-4-git-send-email-longman@redhat.com> (raw)
In-Reply-To: <1524862838-8247-1-git-send-email-longman@redhat.com>

Even with clamped sysctl parameters, it is still not that straight
forward to figure out the exact range of those parameters. One may
try to write extreme parameter values to see if they get clamped.
To make it easier, a warning with the expected range will now be
printed into the kernel ring buffer when a clamped sysctl parameter
receives an out of range value.

The pr_warn_ratelimited() macro is used to limit the number of warning
messages that can be printed within a given period of time.

Signed-off-by: Waiman Long <longman@redhat.com>
---
 kernel/sysctl.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 5b84c1d..76b2f1b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -17,6 +17,7 @@
  * The list_for_each() macro wasn't appropriate for the sysctl loop.
  *  Removed it and replaced it with older style, 03/23/00, Bill Wendling
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
 #include <linux/aio.h>
@@ -2516,6 +2517,7 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
  * @min: pointer to minimum allowable value
  * @max: pointer to maximum allowable value
  * @flags: pointer to flags
+ * @name: sysctl parameter name
  *
  * The do_proc_dointvec_minmax_conv_param structure provides the
  * minimum and maximum values for doing range checking for those sysctl
@@ -2525,6 +2527,7 @@ struct do_proc_dointvec_minmax_conv_param {
 	int *min;
 	int *max;
 	uint16_t *flags;
+	const char *name;
 };
 
 static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
@@ -2534,12 +2537,14 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
 	struct do_proc_dointvec_minmax_conv_param *param = data;
 	if (write) {
 		int val = *negp ? -*lvalp : *lvalp;
+		bool clamped = false;
 		bool clamp = param->flags &&
 			   (*param->flags & CTL_FLAGS_CLAMP_SIGNED_RANGE);
 
 		if (param->min && *param->min > val) {
 			if (clamp) {
 				val = *param->min;
+				clamped = true;
 			} else {
 				return -EINVAL;
 			}
@@ -2547,11 +2552,17 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
 		if (param->max && *param->max < val) {
 			if (clamp) {
 				val = *param->max;
+				clamped = true;
 			} else {
 				return -EINVAL;
 			}
 		}
 		*valp = val;
+		if (clamped && param->name)
+			pr_warn_ratelimited("\"%s\" was set out of range [%d, %d], clamped to %d.\n",
+				param->name,
+				param->min ? *param->min : -INT_MAX,
+				param->max ? *param->max :  INT_MAX, val);
 	} else {
 		int val = *valp;
 		if (val < 0) {
@@ -2589,6 +2600,7 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
 		.min = (int *) table->extra1,
 		.max = (int *) table->extra2,
 		.flags = &table->flags,
+		.name  = table->procname,
 	};
 	return do_proc_dointvec(table, write, buffer, lenp, ppos,
 				do_proc_dointvec_minmax_conv, &param);
@@ -2599,6 +2611,7 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
  * @min: pointer to minimum allowable value
  * @max: pointer to maximum allowable value
  * @flags: pointer to flags
+ * @name: sysctl parameter name
  *
  * The do_proc_douintvec_minmax_conv_param structure provides the
  * minimum and maximum values for doing range checking for those sysctl
@@ -2608,6 +2621,7 @@ struct do_proc_douintvec_minmax_conv_param {
 	unsigned int *min;
 	unsigned int *max;
 	uint16_t *flags;
+	const char *name;
 };
 
 static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
@@ -2618,6 +2632,7 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
 
 	if (write) {
 		unsigned int val = *lvalp;
+		bool clamped = false;
 		bool clamp = param->flags &&
 			   (*param->flags & CTL_FLAGS_CLAMP_UNSIGNED_RANGE);
 
@@ -2627,6 +2642,7 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
 		if (param->min && *param->min > val) {
 			if (clamp) {
 				val = *param->min;
+				clamped = true;
 			} else {
 				return -ERANGE;
 			}
@@ -2634,11 +2650,17 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
 		if (param->max && *param->max < val) {
 			if (clamp) {
 				val = *param->max;
+				clamped = true;
 			} else {
 				return -ERANGE;
 			}
 		}
 		*valp = val;
+		if (clamped && param->name)
+			pr_warn_ratelimited("\"%s\" was set out of range [%u, %u], clamped to %u.\n",
+				param->name,
+				param->min ? *param->min : 0,
+				param->max ? *param->max : UINT_MAX, val);
 	} else {
 		unsigned int val = *valp;
 		*lvalp = (unsigned long) val;
@@ -2674,6 +2696,7 @@ int proc_douintvec_minmax(struct ctl_table *table, int write,
 		.min = (unsigned int *) table->extra1,
 		.max = (unsigned int *) table->extra2,
 		.flags = &table->flags,
+		.name  = table->procname,
 	};
 	return do_proc_douintvec(table, write, buffer, lenp, ppos,
 				 do_proc_douintvec_minmax_conv, &param);
@@ -2780,6 +2803,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 
 		if (write) {
 			bool neg;
+			bool clamped = false;
 
 			left -= proc_skip_spaces(&p);
 
@@ -2794,6 +2818,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 			if (min && val < *min) {
 				if (flags & CTL_FLAGS_CLAMP_UNSIGNED_RANGE) {
 					val = *min;
+					clamped = true;
 				} else {
 					continue;
 				}
@@ -2801,11 +2826,16 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 			if (max && val > *max) {
 				if (flags & CTL_FLAGS_CLAMP_UNSIGNED_RANGE) {
 					val = *max;
+					clamped = true;
 				} else {
 					continue;
 				}
 			}
 			*i = val;
+			if (clamped && table->procname)
+				pr_warn_ratelimited("\"%s\" was set out of range [%lu, %lu], clamped to %lu.\n",
+					table->procname, min ? *min : 0,
+					max ? *max : ULONG_MAX, val);
 		} else {
 			val = convdiv * (*i) / convmul;
 			if (!first) {
-- 
1.8.3.1

  parent reply	other threads:[~2018-04-27 21:00 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-27 21:00 [PATCH v6 0/8] ipc: Clamp *mni to the real IPCMNI limit & increase that limit Waiman Long
2018-04-27 21:00 ` [PATCH v6 1/8] sysctl: Add flags to support min/max range clamping Waiman Long
2018-04-27 21:00 ` [PATCH v6 2/8] proc/sysctl: Provide additional ctl_table.flags checks Waiman Long
2018-04-27 21:00 ` Waiman Long [this message]
2018-04-30 22:40   ` [PATCH v6 3/8] sysctl: Warn when a clamped sysctl parameter is set out of range Kees Cook
2018-05-01 13:41     ` Waiman Long
2018-04-27 21:00 ` [PATCH v6 4/8] ipc: Clamp msgmni and shmmni to the real IPCMNI limit Waiman Long
2018-04-27 21:00 ` [PATCH v6 5/8] ipc: Clamp semmni " Waiman Long
2018-04-27 21:00 ` [PATCH v6 6/8] test_sysctl: Add range clamping test Waiman Long
2018-04-27 21:00 ` [PATCH v6 7/8] ipc: Allow boot time extension of IPCMNI from 32k to 2M Waiman Long
2018-04-29 15:54   ` kbuild test robot
2018-04-27 21:00 ` [PATCH v6 8/8] ipc: Conserve sequence numbers in extended IPCMNI mode Waiman Long
2018-04-29 16:51   ` kbuild test robot
2018-05-02  2:18 ` [PATCH v6 0/8] ipc: Clamp *mni to the real IPCMNI limit & increase that limit Eric W. Biederman
2018-05-02 13:23   ` Waiman Long
2018-05-02 15:06     ` Eric W. Biederman
2018-05-07 19:14       ` 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=1524862838-8247-4-git-send-email-longman@redhat.com \
    --to=longman@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=corbet@lwn.net \
    --cc=ebiederm@xmission.com \
    --cc=keescook@chromium.org \
    --cc=linux-doc@vger.kernel.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;
as well as URLs for NNTP newsgroup(s).