Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=06b2a76d25d3cfbd14680021c1d356c91be6904e
Commit:     06b2a76d25d3cfbd14680021c1d356c91be6904e
Parent:     10e6f32bdf02448f787d78647e75cf98a02f19a4
Author:     Yi Yang <[EMAIL PROTECTED]>
AuthorDate: Fri Feb 8 04:21:57 2008 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Fri Feb 8 09:22:41 2008 -0800

    Add new string functions strict_strto* and convert kernel params to use them
    
    Currently, for every sysfs node, the callers will be responsible for
    implementing store operation, so many many callers are doing duplicate
    things to validate input, they have the same mistakes because they are
    calling simple_strtol/ul/ll/uul, especially for module params, they are
    just numeric, but you can echo such values as 0x1234xxx, 07777888 and
    1234aaa, for these cases, module params store operation just ignores
    succesive invalid char and converts prefix part to a numeric although input
    is acctually invalid.
    
    This patch tries to fix the aforementioned issues and implements
    strict_strtox serial functions, kernel/params.c uses them to strictly
    validate input, so module params will reject such values as 0x1234xxxx and
    returns an error:
    
    write error: Invalid argument
    
    Any modules which export numeric sysfs node can use strict_strtox instead of
    simple_strtox to reject any invalid input.
    
    Here are some test results:
    
    Before applying this patch:
    
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000g > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000gggggggg > 
/sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 010000 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0100008 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 010000aaaaa > 
/sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]#
    
    After applying this patch:
    
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000g > /sys/module/e1000/parameters/copybreak
    -bash: echo: write error: Invalid argument
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo 0x1000gggggggg > 
/sys/module/e1000/parameters/copybreak
    -bash: echo: write error: Invalid argument
    [EMAIL PROTECTED] /]# echo 010000 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# echo 0100008 > /sys/module/e1000/parameters/copybreak
    -bash: echo: write error: Invalid argument
    [EMAIL PROTECTED] /]# echo 010000aaaaa > 
/sys/module/e1000/parameters/copybreak
    -bash: echo: write error: Invalid argument
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]# echo -n 4096 > /sys/module/e1000/parameters/copybreak
    [EMAIL PROTECTED] /]# cat /sys/module/e1000/parameters/copybreak
    4096
    [EMAIL PROTECTED] /]#
    
    [EMAIL PROTECTED]: fix compiler warnings]
    [EMAIL PROTECTED]: fix off-by-one found by [EMAIL PROTECTED]
    Signed-off-by: Yi Yang <[EMAIL PROTECTED]>
    Cc: Greg KH <[EMAIL PROTECTED]>
    Cc: "Randy.Dunlap" <[EMAIL PROTECTED]>
    Cc: Takashi Iwai <[EMAIL PROTECTED]>
    Cc: Hugh Dickins <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 include/linux/kernel.h |    4 ++
 kernel/params.c        |   20 ++++----
 lib/vsprintf.c         |  123 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 10 deletions(-)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8f28d35..2df44e7 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -141,6 +141,10 @@ extern unsigned long simple_strtoul(const char *,char 
**,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
 extern long long simple_strtoll(const char *,char **,unsigned int);
+extern int strict_strtoul(const char *, unsigned int, unsigned long *);
+extern int strict_strtol(const char *, unsigned int, long *);
+extern int strict_strtoull(const char *, unsigned int, unsigned long long *);
+extern int strict_strtoll(const char *, unsigned int, long long *);
 extern int sprintf(char * buf, const char * fmt, ...)
        __attribute__ ((format (printf, 2, 3)));
 extern int vsprintf(char *buf, const char *, va_list)
diff --git a/kernel/params.c b/kernel/params.c
index e28c706..afc46a2 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -180,12 +180,12 @@ int parse_args(const char *name,
 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)              
\
        int param_set_##name(const char *val, struct kernel_param *kp)  \
        {                                                               \
-               char *endp;                                             \
                tmptype l;                                              \
+               int ret;                                                \
                                                                        \
                if (!val) return -EINVAL;                               \
-               l = strtolfn(val, &endp, 0);                            \
-               if (endp == val || ((type)l != l))                      \
+               ret = strtolfn(val, 0, &l);                             \
+               if (ret == -EINVAL || ((type)l != l))                   \
                        return -EINVAL;                                 \
                *((type *)kp->arg) = l;                                 \
                return 0;                                               \
@@ -195,13 +195,13 @@ int parse_args(const char *name,
                return sprintf(buffer, format, *((type *)kp->arg));     \
        }
 
-STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, simple_strtoul);
-STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
-STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, 
simple_strtoul);
-STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
-STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, simple_strtoul);
-STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
-STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
+STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
+STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
+STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, 
strict_strtoul);
+STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
+STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
+STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
+STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
 
 int param_set_charp(const char *val, struct kernel_param *kp)
 {
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 7b481ce..419993f 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -126,6 +126,129 @@ long long simple_strtoll(const char *cp,char 
**endp,unsigned int base)
        return simple_strtoull(cp,endp,base);
 }
 
+
+/**
+ * strict_strtoul - convert a string to an unsigned long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoul converts a string to an unsigned long only if the
+ * string is really an unsigned long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ *     echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * simple_strtoul just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ */
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
+
+/**
+ * strict_strtol - convert a string to a long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtol is similiar to strict_strtoul, but it allows the first
+ * character of a string is '-'.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ */
+int strict_strtol(const char *cp, unsigned int base, long *res);
+
+/**
+ * strict_strtoull - convert a string to an unsigned long long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoull converts a string to an unsigned long long only if the
+ * string is really an unsigned long long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ *     echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail of the string.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * simple_strtoull just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ */
+int strict_strtoull(const char *cp, unsigned int base, unsigned long long 
*res);
+
+/**
+ * strict_strtoll - convert a string to a long long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoll is similiar to strict_strtoull, but it allows the first
+ * character of a string is '-'.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ */
+int strict_strtoll(const char *cp, unsigned int base, long long *res);
+
+#define define_strict_strtoux(type, valtype)                           \
+int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\
+{                                                                      \
+       char *tail;                                                     \
+       valtype val;                                                    \
+       size_t len;                                                     \
+                                                                       \
+       *res = 0;                                                       \
+       len = strlen(cp);                                               \
+       if (len == 0)                                                   \
+               return -EINVAL;                                         \
+                                                                       \
+       val = simple_strtoul(cp, &tail, base);                          \
+       if ((*tail == '\0') ||                                          \
+               ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
+               *res = val;                                             \
+               return 0;                                               \
+       }                                                               \
+                                                                       \
+       return -EINVAL;                                                 \
+}                                                                      \
+
+#define define_strict_strtox(type, valtype)                            \
+int strict_strto##type(const char *cp, unsigned int base, valtype *res)        
\
+{                                                                      \
+       int ret;                                                        \
+       if (*cp == '-') {                                               \
+               ret = strict_strtou##type(cp+1, base, res);             \
+               if (ret != 0)                                           \
+                       *res = -(*res);                                 \
+       } else                                                          \
+               ret = strict_strtou##type(cp, base, res);               \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+
+define_strict_strtoux(l, unsigned long)
+define_strict_strtox(l, long)
+define_strict_strtoux(ll, unsigned long long)
+define_strict_strtox(ll, long long)
+
+EXPORT_SYMBOL(strict_strtoul);
+EXPORT_SYMBOL(strict_strtol);
+EXPORT_SYMBOL(strict_strtoll);
+EXPORT_SYMBOL(strict_strtoull);
+
 static int skip_atoi(const char **s)
 {
        int i=0;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to