aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReinette Chatre <reinette.chatre@linux.intel.com>2006-10-11 04:21:55 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-11 14:14:22 -0400
commit01a3ee2b203e511e20f98b85a9172fd32c53e87c (patch)
tree0dd90d81dc86f231828af23bdb97522405b06cab
parent39484e53bb00f55b6303a908070db133608ef2a5 (diff)
[PATCH] bitmap: parse input from kernel and user buffers
lib/bitmap.c:bitmap_parse() is a library function that received as input a user buffer. This seemed to have originated from the way the write_proc function of the /proc filesystem operates. This has been reworked to not use kmalloc and eliminates a lot of get_user() overhead by performing one access_ok before using __get_user(). We need to test if we are in kernel or user space (is_user) and access the buffer differently. We cannot use __get_user() to access kernel addresses in all cases, for example in architectures with separate address space for kernel and user. This function will be useful for other uses as well; for example, taking input for /sysfs instead of /proc, so it was changed to accept kernel buffers. We have this use for the Linux UWB project, as part as the upcoming bandwidth allocator code. Only a few routines used this function and they were changed too. Signed-off-by: Reinette Chatre <reinette.chatre@linux.intel.com> Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> Cc: Paul Jackson <pj@sgi.com> Cc: Joe Korty <joe.korty@ccur.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/bitmap.h13
-rw-r--r--include/linux/cpumask.h14
-rw-r--r--include/linux/nodemask.h14
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/profile.c2
-rw-r--r--lib/bitmap.c54
6 files changed, 70 insertions, 29 deletions
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index dcc5de7cc48..64b4641904f 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -46,7 +46,8 @@
46 * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) 46 * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
47 * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) 47 * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
48 * bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf 48 * bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf
49 * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf 49 * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf
50 * bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
50 * bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf 51 * bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf
51 * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list 52 * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list
52 * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region 53 * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region
@@ -106,7 +107,9 @@ extern int __bitmap_weight(const unsigned long *bitmap, int bits);
106 107
107extern int bitmap_scnprintf(char *buf, unsigned int len, 108extern int bitmap_scnprintf(char *buf, unsigned int len,
108 const unsigned long *src, int nbits); 109 const unsigned long *src, int nbits);
109extern int bitmap_parse(const char __user *ubuf, unsigned int ulen, 110extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
111 unsigned long *dst, int nbits);
112extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
110 unsigned long *dst, int nbits); 113 unsigned long *dst, int nbits);
111extern int bitmap_scnlistprintf(char *buf, unsigned int len, 114extern int bitmap_scnlistprintf(char *buf, unsigned int len,
112 const unsigned long *src, int nbits); 115 const unsigned long *src, int nbits);
@@ -270,6 +273,12 @@ static inline void bitmap_shift_left(unsigned long *dst,
270 __bitmap_shift_left(dst, src, n, nbits); 273 __bitmap_shift_left(dst, src, n, nbits);
271} 274}
272 275
276static inline int bitmap_parse(const char *buf, unsigned int buflen,
277 unsigned long *maskp, int nmaskbits)
278{
279 return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
280}
281
273#endif /* __ASSEMBLY__ */ 282#endif /* __ASSEMBLY__ */
274 283
275#endif /* __LINUX_BITMAP_H */ 284#endif /* __LINUX_BITMAP_H */
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index b268a3c0c37..d0e8c8b0e34 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -8,8 +8,8 @@
8 * See detailed comments in the file linux/bitmap.h describing the 8 * See detailed comments in the file linux/bitmap.h describing the
9 * data type on which these cpumasks are based. 9 * data type on which these cpumasks are based.
10 * 10 *
11 * For details of cpumask_scnprintf() and cpumask_parse(), 11 * For details of cpumask_scnprintf() and cpumask_parse_user(),
12 * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c. 12 * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
13 * For details of cpulist_scnprintf() and cpulist_parse(), see 13 * For details of cpulist_scnprintf() and cpulist_parse(), see
14 * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c. 14 * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
15 * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c 15 * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
@@ -49,7 +49,7 @@
49 * unsigned long *cpus_addr(mask) Array of unsigned long's in mask 49 * unsigned long *cpus_addr(mask) Array of unsigned long's in mask
50 * 50 *
51 * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing 51 * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
52 * int cpumask_parse(ubuf, ulen, mask) Parse ascii string as cpumask 52 * int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask
53 * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing 53 * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
54 * int cpulist_parse(buf, map) Parse ascii string as cpulist 54 * int cpulist_parse(buf, map) Parse ascii string as cpulist
55 * int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit) 55 * int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
@@ -273,12 +273,12 @@ static inline int __cpumask_scnprintf(char *buf, int len,
273 return bitmap_scnprintf(buf, len, srcp->bits, nbits); 273 return bitmap_scnprintf(buf, len, srcp->bits, nbits);
274} 274}
275 275
276#define cpumask_parse(ubuf, ulen, dst) \ 276#define cpumask_parse_user(ubuf, ulen, dst) \
277 __cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS) 277 __cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS)
278static inline int __cpumask_parse(const char __user *buf, int len, 278static inline int __cpumask_parse_user(const char __user *buf, int len,
279 cpumask_t *dstp, int nbits) 279 cpumask_t *dstp, int nbits)
280{ 280{
281 return bitmap_parse(buf, len, dstp->bits, nbits); 281 return bitmap_parse_user(buf, len, dstp->bits, nbits);
282} 282}
283 283
284#define cpulist_scnprintf(buf, len, src) \ 284#define cpulist_scnprintf(buf, len, src) \
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 5dce5c21822..b1063e9cdb1 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -8,8 +8,8 @@
8 * See detailed comments in the file linux/bitmap.h describing the 8 * See detailed comments in the file linux/bitmap.h describing the
9 * data type on which these nodemasks are based. 9 * data type on which these nodemasks are based.
10 * 10 *
11 * For details of nodemask_scnprintf() and nodemask_parse(), 11 * For details of nodemask_scnprintf() and nodemask_parse_user(),
12 * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c. 12 * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
13 * For details of nodelist_scnprintf() and nodelist_parse(), see 13 * For details of nodelist_scnprintf() and nodelist_parse(), see
14 * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c. 14 * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
15 * For details of node_remap(), see bitmap_bitremap in lib/bitmap.c. 15 * For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
@@ -51,7 +51,7 @@
51 * unsigned long *nodes_addr(mask) Array of unsigned long's in mask 51 * unsigned long *nodes_addr(mask) Array of unsigned long's in mask
52 * 52 *
53 * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing 53 * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
54 * int nodemask_parse(ubuf, ulen, mask) Parse ascii string as nodemask 54 * int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask
55 * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing 55 * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
56 * int nodelist_parse(buf, map) Parse ascii string as nodelist 56 * int nodelist_parse(buf, map) Parse ascii string as nodelist
57 * int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit) 57 * int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
@@ -288,12 +288,12 @@ static inline int __nodemask_scnprintf(char *buf, int len,
288 return bitmap_scnprintf(buf, len, srcp->bits, nbits); 288 return bitmap_scnprintf(buf, len, srcp->bits, nbits);
289} 289}
290 290
291#define nodemask_parse(ubuf, ulen, dst) \ 291#define nodemask_parse_user(ubuf, ulen, dst) \
292 __nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES) 292 __nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES)
293static inline int __nodemask_parse(const char __user *buf, int len, 293static inline int __nodemask_parse_user(const char __user *buf, int len,
294 nodemask_t *dstp, int nbits) 294 nodemask_t *dstp, int nbits)
295{ 295{
296 return bitmap_parse(buf, len, dstp->bits, nbits); 296 return bitmap_parse_user(buf, len, dstp->bits, nbits);
297} 297}
298 298
299#define nodelist_scnprintf(buf, len, src) \ 299#define nodelist_scnprintf(buf, len, src) \
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 607c7809ad0..9a352667007 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -57,7 +57,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
57 if (!irq_desc[irq].chip->set_affinity || no_irq_affinity) 57 if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
58 return -EIO; 58 return -EIO;
59 59
60 err = cpumask_parse(buffer, count, new_value); 60 err = cpumask_parse_user(buffer, count, new_value);
61 if (err) 61 if (err)
62 return err; 62 return err;
63 63
diff --git a/kernel/profile.c b/kernel/profile.c
index 857300a2afe..f940b462eec 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -399,7 +399,7 @@ static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffe
399 unsigned long full_count = count, err; 399 unsigned long full_count = count, err;
400 cpumask_t new_value; 400 cpumask_t new_value;
401 401
402 err = cpumask_parse(buffer, count, new_value); 402 err = cpumask_parse_user(buffer, count, new_value);
403 if (err) 403 if (err)
404 return err; 404 return err;
405 405
diff --git a/lib/bitmap.c b/lib/bitmap.c
index d71e38c54ea..037fa9aa2ed 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -316,10 +316,11 @@ int bitmap_scnprintf(char *buf, unsigned int buflen,
316EXPORT_SYMBOL(bitmap_scnprintf); 316EXPORT_SYMBOL(bitmap_scnprintf);
317 317
318/** 318/**
319 * bitmap_parse - convert an ASCII hex string into a bitmap. 319 * __bitmap_parse - convert an ASCII hex string into a bitmap.
320 * @ubuf: pointer to buffer in user space containing string. 320 * @buf: pointer to buffer containing string.
321 * @ubuflen: buffer size in bytes. If string is smaller than this 321 * @buflen: buffer size in bytes. If string is smaller than this
322 * then it must be terminated with a \0. 322 * then it must be terminated with a \0.
323 * @is_user: location of buffer, 0 indicates kernel space
323 * @maskp: pointer to bitmap array that will contain result. 324 * @maskp: pointer to bitmap array that will contain result.
324 * @nmaskbits: size of bitmap, in bits. 325 * @nmaskbits: size of bitmap, in bits.
325 * 326 *
@@ -330,11 +331,13 @@ EXPORT_SYMBOL(bitmap_scnprintf);
330 * characters and for grouping errors such as "1,,5", ",44", "," and "". 331 * characters and for grouping errors such as "1,,5", ",44", "," and "".
331 * Leading and trailing whitespace accepted, but not embedded whitespace. 332 * Leading and trailing whitespace accepted, but not embedded whitespace.
332 */ 333 */
333int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, 334int __bitmap_parse(const char *buf, unsigned int buflen,
334 unsigned long *maskp, int nmaskbits) 335 int is_user, unsigned long *maskp,
336 int nmaskbits)
335{ 337{
336 int c, old_c, totaldigits, ndigits, nchunks, nbits; 338 int c, old_c, totaldigits, ndigits, nchunks, nbits;
337 u32 chunk; 339 u32 chunk;
340 const char __user *ubuf = buf;
338 341
339 bitmap_zero(maskp, nmaskbits); 342 bitmap_zero(maskp, nmaskbits);
340 343
@@ -343,11 +346,15 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
343 chunk = ndigits = 0; 346 chunk = ndigits = 0;
344 347
345 /* Get the next chunk of the bitmap */ 348 /* Get the next chunk of the bitmap */
346 while (ubuflen) { 349 while (buflen) {
347 old_c = c; 350 old_c = c;
348 if (get_user(c, ubuf++)) 351 if (is_user) {
349 return -EFAULT; 352 if (__get_user(c, ubuf++))
350 ubuflen--; 353 return -EFAULT;
354 }
355 else
356 c = *buf++;
357 buflen--;
351 if (isspace(c)) 358 if (isspace(c))
352 continue; 359 continue;
353 360
@@ -388,11 +395,36 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
388 nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; 395 nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
389 if (nbits > nmaskbits) 396 if (nbits > nmaskbits)
390 return -EOVERFLOW; 397 return -EOVERFLOW;
391 } while (ubuflen && c == ','); 398 } while (buflen && c == ',');
392 399
393 return 0; 400 return 0;
394} 401}
395EXPORT_SYMBOL(bitmap_parse); 402EXPORT_SYMBOL(__bitmap_parse);
403
404/**
405 * bitmap_parse_user()
406 *
407 * @ubuf: pointer to user buffer containing string.
408 * @ulen: buffer size in bytes. If string is smaller than this
409 * then it must be terminated with a \0.
410 * @maskp: pointer to bitmap array that will contain result.
411 * @nmaskbits: size of bitmap, in bits.
412 *
413 * Wrapper for __bitmap_parse(), providing it with user buffer.
414 *
415 * We cannot have this as an inline function in bitmap.h because it needs
416 * linux/uaccess.h to get the access_ok() declaration and this causes
417 * cyclic dependencies.
418 */
419int bitmap_parse_user(const char __user *ubuf,
420 unsigned int ulen, unsigned long *maskp,
421 int nmaskbits)
422{
423 if (!access_ok(VERIFY_READ, ubuf, ulen))
424 return -EFAULT;
425 return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits);
426}
427EXPORT_SYMBOL(bitmap_parse_user);
396 428
397/* 429/*
398 * bscnl_emit(buf, buflen, rbot, rtop, bp) 430 * bscnl_emit(buf, buflen, rbot, rtop, bp)