summaryrefslogtreecommitdiffstats
path: root/kernel/params.c
diff options
context:
space:
mode:
authorJean Delvare <jdelvare@suse.de>2017-10-03 19:16:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-10-03 20:54:26 -0400
commit96802e6b1dbf29d3012b39503c5dd6d9d8e82955 (patch)
tree8c4c37a6c544b8e4983fd705604845187968b67b /kernel/params.c
parent90ceb2a3ad868f800eb1c9f4ede650daddd94b77 (diff)
kernel/params.c: fix an overflow in param_attr_show
Function param_attr_show could overflow the buffer it is operating on. The buffer size is PAGE_SIZE, and the string returned by attribute->param->ops->get is generated by scnprintf(buffer, PAGE_SIZE, ...) so it could be PAGE_SIZE - 1 long, with the terminating '\0' at the very end of the buffer. Calling strcat(..., "\n") on this isn't safe, as the '\0' will be replaced by '\n' (OK) and then another '\0' will be added past the end of the buffer (not OK.) Simply add the trailing '\n' when writing the attribute contents to the buffer originally. This is safe, and also faster. Credits to Teradata for discovering this issue. Link: http://lkml.kernel.org/r/20170928162602.60c379c7@endymion Signed-off-by: Jean Delvare <jdelvare@suse.de> Acked-by: Ingo Molnar <mingo@kernel.org> Cc: Baoquan He <bhe@redhat.com> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/params.c')
-rw-r--r--kernel/params.c17
1 files changed, 7 insertions, 10 deletions
diff --git a/kernel/params.c b/kernel/params.c
index 8283ba045f4f..0cca488263dd 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -224,7 +224,7 @@ char *parse_args(const char *doing,
224 } \ 224 } \
225 int param_get_##name(char *buffer, const struct kernel_param *kp) \ 225 int param_get_##name(char *buffer, const struct kernel_param *kp) \
226 { \ 226 { \
227 return scnprintf(buffer, PAGE_SIZE, format, \ 227 return scnprintf(buffer, PAGE_SIZE, format "\n", \
228 *((type *)kp->arg)); \ 228 *((type *)kp->arg)); \
229 } \ 229 } \
230 const struct kernel_param_ops param_ops_##name = { \ 230 const struct kernel_param_ops param_ops_##name = { \
@@ -270,7 +270,7 @@ EXPORT_SYMBOL(param_set_charp);
270 270
271int param_get_charp(char *buffer, const struct kernel_param *kp) 271int param_get_charp(char *buffer, const struct kernel_param *kp)
272{ 272{
273 return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg)); 273 return scnprintf(buffer, PAGE_SIZE, "%s\n", *((char **)kp->arg));
274} 274}
275EXPORT_SYMBOL(param_get_charp); 275EXPORT_SYMBOL(param_get_charp);
276 276
@@ -301,7 +301,7 @@ EXPORT_SYMBOL(param_set_bool);
301int param_get_bool(char *buffer, const struct kernel_param *kp) 301int param_get_bool(char *buffer, const struct kernel_param *kp)
302{ 302{
303 /* Y and N chosen as being relatively non-coder friendly */ 303 /* Y and N chosen as being relatively non-coder friendly */
304 return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N'); 304 return sprintf(buffer, "%c\n", *(bool *)kp->arg ? 'Y' : 'N');
305} 305}
306EXPORT_SYMBOL(param_get_bool); 306EXPORT_SYMBOL(param_get_bool);
307 307
@@ -360,7 +360,7 @@ EXPORT_SYMBOL(param_set_invbool);
360 360
361int param_get_invbool(char *buffer, const struct kernel_param *kp) 361int param_get_invbool(char *buffer, const struct kernel_param *kp)
362{ 362{
363 return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y'); 363 return sprintf(buffer, "%c\n", (*(bool *)kp->arg) ? 'N' : 'Y');
364} 364}
365EXPORT_SYMBOL(param_get_invbool); 365EXPORT_SYMBOL(param_get_invbool);
366 366
@@ -460,8 +460,9 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
460 struct kernel_param p = *kp; 460 struct kernel_param p = *kp;
461 461
462 for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) { 462 for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
463 /* Replace \n with comma */
463 if (i) 464 if (i)
464 buffer[off++] = ','; 465 buffer[off - 1] = ',';
465 p.arg = arr->elem + arr->elemsize * i; 466 p.arg = arr->elem + arr->elemsize * i;
466 check_kparam_locked(p.mod); 467 check_kparam_locked(p.mod);
467 ret = arr->ops->get(buffer + off, &p); 468 ret = arr->ops->get(buffer + off, &p);
@@ -507,7 +508,7 @@ EXPORT_SYMBOL(param_set_copystring);
507int param_get_string(char *buffer, const struct kernel_param *kp) 508int param_get_string(char *buffer, const struct kernel_param *kp)
508{ 509{
509 const struct kparam_string *kps = kp->str; 510 const struct kparam_string *kps = kp->str;
510 return strlcpy(buffer, kps->string, PAGE_SIZE); 511 return scnprintf(buffer, PAGE_SIZE, "%s\n", kps->string);
511} 512}
512EXPORT_SYMBOL(param_get_string); 513EXPORT_SYMBOL(param_get_string);
513 514
@@ -549,10 +550,6 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
549 kernel_param_lock(mk->mod); 550 kernel_param_lock(mk->mod);
550 count = attribute->param->ops->get(buf, attribute->param); 551 count = attribute->param->ops->get(buf, attribute->param);
551 kernel_param_unlock(mk->mod); 552 kernel_param_unlock(mk->mod);
552 if (count > 0) {
553 strcat(buf, "\n");
554 ++count;
555 }
556 return count; 553 return count;
557} 554}
558 555