Merge tag 'tty-5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[linux-2.6-microblaze.git] / kernel / sysctl.c
index 14f30b4..e5da394 100644 (file)
@@ -67,6 +67,8 @@
 #include <linux/bpf.h>
 #include <linux/mount.h>
 
+#include "../lib/kstrtox.h"
+
 #include <linux/uaccess.h>
 #include <asm/processor.h>
 
@@ -127,6 +129,7 @@ static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
 static int __maybe_unused four = 4;
 static unsigned long one_ul = 1;
+static unsigned long long_max = LONG_MAX;
 static int one_hundred = 100;
 static int one_thousand = 1000;
 #ifdef CONFIG_PRINTK
@@ -1747,6 +1750,8 @@ static struct ctl_table fs_table[] = {
                .maxlen         = sizeof(files_stat.max_files),
                .mode           = 0644,
                .proc_handler   = proc_doulongvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &long_max,
        },
        {
                .procname       = "nr_open",
@@ -2117,6 +2122,41 @@ static void proc_skip_char(char **buf, size_t *size, const char v)
        }
 }
 
+/**
+ * strtoul_lenient - parse an ASCII formatted integer from a buffer and only
+ *                   fail on overflow
+ *
+ * @cp: kernel buffer containing the string to parse
+ * @endp: pointer to store the trailing characters
+ * @base: the base to use
+ * @res: where the parsed integer will be stored
+ *
+ * In case of success 0 is returned and @res will contain the parsed integer,
+ * @endp will hold any trailing characters.
+ * This function will fail the parse on overflow. If there wasn't an overflow
+ * the function will defer the decision what characters count as invalid to the
+ * caller.
+ */
+static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
+                          unsigned long *res)
+{
+       unsigned long long result;
+       unsigned int rv;
+
+       cp = _parse_integer_fixup_radix(cp, &base);
+       rv = _parse_integer(cp, base, &result);
+       if ((rv & KSTRTOX_OVERFLOW) || (result != (unsigned long)result))
+               return -ERANGE;
+
+       cp += rv;
+
+       if (endp)
+               *endp = (char *)cp;
+
+       *res = (unsigned long)result;
+       return 0;
+}
+
 #define TMPBUFLEN 22
 /**
  * proc_get_long - reads an ASCII formatted integer from a user buffer
@@ -2160,7 +2200,8 @@ static int proc_get_long(char **buf, size_t *size,
        if (!isdigit(*p))
                return -EINVAL;
 
-       *val = simple_strtoul(p, &p, 0);
+       if (strtoul_lenient(p, &p, 0, val))
+               return -EINVAL;
 
        len = p - tmp;
 
@@ -2602,23 +2643,25 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
                                        int *valp,
                                        int write, void *data)
 {
+       int tmp, ret;
        struct do_proc_dointvec_minmax_conv_param *param = data;
+       /*
+        * If writing, first do so via a temporary local int so we can
+        * bounds-check it before touching *valp.
+        */
+       int *ip = write ? &tmp : valp;
+
+       ret = do_proc_dointvec_conv(negp, lvalp, ip, write, data);
+       if (ret)
+               return ret;
+
        if (write) {
-               int val = *negp ? -*lvalp : *lvalp;
-               if ((param->min && *param->min > val) ||
-                   (param->max && *param->max < val))
+               if ((param->min && *param->min > tmp) ||
+                   (param->max && *param->max < tmp))
                        return -EINVAL;
-               *valp = val;
-       } else {
-               int val = *valp;
-               if (val < 0) {
-                       *negp = true;
-                       *lvalp = -(unsigned long)val;
-               } else {
-                       *negp = false;
-                       *lvalp = (unsigned long)val;
-               }
+               *valp = tmp;
        }
+
        return 0;
 }
 
@@ -2667,22 +2710,22 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
                                         unsigned int *valp,
                                         int write, void *data)
 {
+       int ret;
+       unsigned int tmp;
        struct do_proc_douintvec_minmax_conv_param *param = data;
+       /* write via temporary local uint for bounds-checking */
+       unsigned int *up = write ? &tmp : valp;
 
-       if (write) {
-               unsigned int val = *lvalp;
+       ret = do_proc_douintvec_conv(lvalp, up, write, data);
+       if (ret)
+               return ret;
 
-               if (*lvalp > UINT_MAX)
-                       return -EINVAL;
-
-               if ((param->min && *param->min > val) ||
-                   (param->max && *param->max < val))
+       if (write) {
+               if ((param->min && *param->min > tmp) ||
+                   (param->max && *param->max < tmp))
                        return -ERANGE;
 
-               *valp = val;
-       } else {
-               unsigned int val = *valp;
-               *lvalp = (unsigned long) val;
+               *valp = tmp;
        }
 
        return 0;
@@ -3285,7 +3328,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
 
 #endif /* CONFIG_PROC_SYSCTL */
 
-#ifdef CONFIG_BPF_SYSCALL
+#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_SYSCTL)
 static int proc_dointvec_minmax_bpf_stats(struct ctl_table *table, int write,
                                          void __user *buffer, size_t *lenp,
                                          loff_t *ppos)