sysctl: fold sysctl_writes_strict checks into helper
authorLuis R. Rodriguez <mcgrof@kernel.org>
Wed, 12 Jul 2017 21:33:33 +0000 (14:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Jul 2017 23:26:00 +0000 (16:26 -0700)
The mode sysctl_writes_strict positional checks keep being copy and pasted
as we add new proc handlers.  Just add a helper to avoid code duplication.

Link: http://lkml.kernel.org/r/20170519033554.18592-4-mcgrof@kernel.org
Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
Suggested-by: Kees Cook <keescook@chromium.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/sysctl.c

index 02725178694a28d92f84e2aa126c81b21f385fe9..6f3bb1f099fa9ddb6363083fb9b8b057a93bd88a 100644 (file)
@@ -1970,6 +1970,32 @@ static void warn_sysctl_write(struct ctl_table *table)
                current->comm, table->procname);
 }
 
+/**
+ * proc_first_pos_non_zero_ignore - check if firs position is allowed
+ * @ppos: file position
+ * @table: the sysctl table
+ *
+ * Returns true if the first position is non-zero and the sysctl_writes_strict
+ * mode indicates this is not allowed for numeric input types. String proc
+ * hadlers can ignore the return value.
+ */
+static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
+                                          struct ctl_table *table)
+{
+       if (!*ppos)
+               return false;
+
+       switch (sysctl_writes_strict) {
+       case SYSCTL_WRITES_STRICT:
+               return true;
+       case SYSCTL_WRITES_WARN:
+               warn_sysctl_write(table);
+               return false;
+       default:
+               return false;
+       }
+}
+
 /**
  * proc_dostring - read a string sysctl
  * @table: the sysctl table
@@ -1990,8 +2016,8 @@ static void warn_sysctl_write(struct ctl_table *table)
 int proc_dostring(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN)
-               warn_sysctl_write(table);
+       if (write)
+               proc_first_pos_non_zero_ignore(ppos, table);
 
        return _proc_do_string((char *)(table->data), table->maxlen, write,
                               (char __user *)buffer, lenp, ppos);
@@ -2193,17 +2219,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                conv = do_proc_dointvec_conv;
 
        if (write) {
-               if (*ppos) {
-                       switch (sysctl_writes_strict) {
-                       case SYSCTL_WRITES_STRICT:
-                               goto out;
-                       case SYSCTL_WRITES_WARN:
-                               warn_sysctl_write(table);
-                               break;
-                       default:
-                               break;
-                       }
-               }
+               if (proc_first_pos_non_zero_ignore(ppos, table))
+                       goto out;
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
@@ -2468,17 +2485,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
        left = *lenp;
 
        if (write) {
-               if (*ppos) {
-                       switch (sysctl_writes_strict) {
-                       case SYSCTL_WRITES_STRICT:
-                               goto out;
-                       case SYSCTL_WRITES_WARN:
-                               warn_sysctl_write(table);
-                               break;
-                       default:
-                               break;
-                       }
-               }
+               if (proc_first_pos_non_zero_ignore(ppos, table))
+                       goto out;
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;