Commit c196e32a111b0ee356d67acceb938ae0b5e63ef0

Authored by Alexey Dobriyan
Committed by Linus Torvalds
1 parent a08aa355af

lib: add kstrto*_from_user()

There is quite a lot of code which does copy_from_user() + strict_strto*()
or simple_strto*() combo in slightly different ways.

Before doing conversions all over tree, let's get final API correct.

Enter kstrtoull_from_user() and friends.

Typical code which uses them looks very simple:

	TYPE val;
	int rv;

	rv = kstrtoTYPE_from_user(buf, count, 0, &val);
	if (rv < 0)
		return rv;
	[use val]
	return count;

There is a tiny semantic difference from the plain kstrto*() API -- the
latter allows any amount of leading zeroes, while the former copies data
into buffer on stack and thus allows leading zeroes as long as it fits
into buffer.

This shouldn't be a problem for typical usecase "echo 42 > /proc/x".

The point is to make reading one integer from userspace _very_ simple and
very bug free.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 57 additions and 0 deletions Side-by-side Diff

include/linux/kernel.h
... ... @@ -248,6 +248,37 @@
248 248 int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
249 249 int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
250 250  
  251 +int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
  252 +int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
  253 +int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
  254 +int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
  255 +int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
  256 +int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
  257 +int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
  258 +int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
  259 +int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
  260 +int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
  261 +
  262 +static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
  263 +{
  264 + return kstrtoull_from_user(s, count, base, res);
  265 +}
  266 +
  267 +static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
  268 +{
  269 + return kstrtoll_from_user(s, count, base, res);
  270 +}
  271 +
  272 +static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
  273 +{
  274 + return kstrtouint_from_user(s, count, base, res);
  275 +}
  276 +
  277 +static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
  278 +{
  279 + return kstrtoint_from_user(s, count, base, res);
  280 +}
  281 +
251 282 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
252 283 extern long simple_strtol(const char *,char **,unsigned int);
253 284 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
... ... @@ -17,6 +17,7 @@
17 17 #include <linux/math64.h>
18 18 #include <linux/module.h>
19 19 #include <linux/types.h>
  20 +#include <asm/uaccess.h>
20 21  
21 22 static inline char _tolower(const char c)
22 23 {
... ... @@ -222,4 +223,29 @@
222 223 return 0;
223 224 }
224 225 EXPORT_SYMBOL(kstrtos8);
  226 +
  227 +#define kstrto_from_user(f, g, type) \
  228 +int f(const char __user *s, size_t count, unsigned int base, type *res) \
  229 +{ \
  230 + /* sign, base 2 representation, newline, terminator */ \
  231 + char buf[1 + sizeof(type) * 8 + 1 + 1]; \
  232 + \
  233 + count = min(count, sizeof(buf) - 1); \
  234 + if (copy_from_user(buf, s, count)) \
  235 + return -EFAULT; \
  236 + buf[count] = '\0'; \
  237 + return g(buf, base, res); \
  238 +} \
  239 +EXPORT_SYMBOL(f)
  240 +
  241 +kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long);
  242 +kstrto_from_user(kstrtoll_from_user, kstrtoll, long long);
  243 +kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long);
  244 +kstrto_from_user(kstrtol_from_user, kstrtol, long);
  245 +kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int);
  246 +kstrto_from_user(kstrtoint_from_user, kstrtoint, int);
  247 +kstrto_from_user(kstrtou16_from_user, kstrtou16, u16);
  248 +kstrto_from_user(kstrtos16_from_user, kstrtos16, s16);
  249 +kstrto_from_user(kstrtou8_from_user, kstrtou8, u8);
  250 +kstrto_from_user(kstrtos8_from_user, kstrtos8, s8);