From patchwork Wed Aug 16 12:52:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 9903721 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DA51A6038C for ; Wed, 16 Aug 2017 12:55:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CB3B9289CD for ; Wed, 16 Aug 2017 12:55:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BFE7A289E1; Wed, 16 Aug 2017 12:55:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id F1969289CD for ; Wed, 16 Aug 2017 12:55:20 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dhxpI-000302-Nl; Wed, 16 Aug 2017 12:53:36 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dhxpH-0002wN-MH for xen-devel@lists.xenproject.org; Wed, 16 Aug 2017 12:53:35 +0000 Received: from [193.109.254.147] by server-8.bemta-6.messagelabs.com id 0F/2F-09901-F4044995; Wed, 16 Aug 2017 12:53:35 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrELMWRWlGSWpSXmKPExsVyuP0Ov66fw5R Igzs9Ehbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8aKz0tZC3a6VVybcJq5gbFPv4uRk0NCwEji 7cR/TF2MXBxCAgsZJfYsmcIIkmATUJXYcP0UK4gtIqAkcW/VZLAiZoHHTBIzdi0Hcjg4hAUCJ U632YHUsADVn1+2ngXE5hUwkZh0aR0LxAJ5iY4Dk8FsTqD45A3HwGwhAWOJ7T2N7BMYuRcwMq xi1ChOLSpLLdI1stRLKspMzyjJTczM0TU0MNPLTS0uTkxPzUlMKtZLzs/dxAj0LwMQ7GA8sCj wEKMkB5OSKG+Q1pRIIb6k/JTKjMTijPii0pzU4kOMMhwcShK8kvZAOcGi1PTUirTMHGCgwaQl OHiURHjTbIHSvMUFibnFmekQqVOMuhyvJvz/xiTEkpeflyolznvLDqhIAKQoozQPbgQs6C8xy koJ8zICHSXEU5BalJtZgir/ilGcg1FJmFcC5BKezLwSuE2vgI5gAjriSvskkCNKEhFSUg2Mhv ovyucfnqyz4nqK9IGVc7nzTZMfzWISVHpa8rq1oqd8Ru1kxlU6Yr/PX69YwqDr+K748FMb71k vJmlMeLqicPElgx0/1l22VCzTPBix31GvJjL0nHXT6SPvjwUvuSksZv6FXaRh/ZlvDum//PZv vuLpF7n/eMM0M30NzzWTHswNdbgwUXmyhhJLcUaioRZzUXEiALUxAdp1AgAA X-Env-Sender: jgross@suse.com X-Msg-Ref: server-5.tower-27.messagelabs.com!1502888014!106580770!1 X-Originating-IP: [195.135.220.15] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 60299 invoked from network); 16 Aug 2017 12:53:34 -0000 Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by server-5.tower-27.messagelabs.com with DHE-RSA-CAMELLIA256-SHA encrypted SMTP; 16 Aug 2017 12:53:34 -0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id E61D9AE8B; Wed, 16 Aug 2017 12:52:33 +0000 (UTC) From: Juergen Gross To: xen-devel@lists.xenproject.org Date: Wed, 16 Aug 2017 14:52:06 +0200 Message-Id: <20170816125219.5255-40-jgross@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20170816125219.5255-1-jgross@suse.com> References: <20170816125219.5255-1-jgross@suse.com> Cc: Juergen Gross , Stefano Stabellini , Wei Liu , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Jan Beulich Subject: [Xen-devel] [PATCH v3 39/52] xen: check parameter validity when parsing command line X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Where possible check validity of parameters in _cmdline_parse() and issue a warning message in case of an error detected. In order to make sure a custom parameter parsing function really returns a value (error or success), don't use a void pointer for storing the function address, but a proper typed function pointer. Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu Signed-off-by: Juergen Gross --- V2: - replaced literal 8 by BITS_PER_BYTE (Wei Liu) - added test for empty string to parse_bool() V3: - use function pointer in struct kernel_param (Jan Beulich) - better range check in assign_integer_param() (Jan Beulich) - dont assign int values in case of overflow (Jan Beulich) - allow multiple handlers for a parameter (Jan Beulich) --- xen/common/kernel.c | 67 +++++++++++++++++++++++++++++++++++++------------ xen/include/xen/init.h | 30 +++++++++++++++++----- xen/include/xen/types.h | 3 +++ 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/xen/common/kernel.c b/xen/common/kernel.c index ce7cb8adb5..c629ffa11c 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -23,34 +23,43 @@ enum system_state system_state = SYS_STATE_early_boot; xen_commandline_t saved_cmdline; static const char __initconst opt_builtin_cmdline[] = CONFIG_CMDLINE; -static void __init assign_integer_param( +static int __init assign_integer_param( const struct kernel_param *param, uint64_t val) { switch ( param->len ) { case sizeof(uint8_t): - *(uint8_t *)param->var = val; + if ( val > UINT8_MAX && val < (uint64_t)INT8_MIN ) + return -EOVERFLOW; + *(uint8_t *)param->par.var = val; break; case sizeof(uint16_t): - *(uint16_t *)param->var = val; + if ( val > UINT16_MAX && val < (uint64_t)INT16_MIN ) + return -EOVERFLOW; + *(uint16_t *)param->par.var = val; break; case sizeof(uint32_t): - *(uint32_t *)param->var = val; + if ( val > UINT32_MAX && val < (uint64_t)INT32_MIN ) + return -EOVERFLOW; + *(uint32_t *)param->par.var = val; break; case sizeof(uint64_t): - *(uint64_t *)param->var = val; + *(uint64_t *)param->par.var = val; break; default: BUG(); } + + return 0; } static void __init _cmdline_parse(const char *cmdline) { char opt[128], *optval, *optkey, *q; - const char *p = cmdline; + const char *p = cmdline, *s, *key; const struct kernel_param *param; - int bool_assert; + int bool_assert, rctmp, rc; + bool found; for ( ; ; ) { @@ -84,10 +93,13 @@ static void __init _cmdline_parse(const char *cmdline) } /* Boolean parameters can be inverted with 'no-' prefix. */ + key = optkey; bool_assert = !!strncmp("no-", optkey, 3); if ( !bool_assert ) optkey += 3; + rc = 0; + found = false; for ( param = __setup_start; param < __setup_end; param++ ) { if ( strcmp(param->name, optkey) ) @@ -96,34 +108,48 @@ static void __init _cmdline_parse(const char *cmdline) strlen(param->name) == q + 1 - opt && !strncmp(param->name, opt, q + 1 - opt) ) { + found = true; optval[-1] = '='; - ((void (*)(const char *))param->var)(q); + rctmp = param->par.func(q); optval[-1] = '\0'; + if ( !rc ) + rc = rctmp; } continue; } + rctmp = 0; + found = true; switch ( param->type ) { case OPT_STR: - strlcpy(param->var, optval, param->len); + strlcpy(param->par.var, optval, param->len); break; case OPT_UINT: - assign_integer_param( + rctmp = assign_integer_param( param, - simple_strtoll(optval, NULL, 0)); + simple_strtoll(optval, &s, 0)); + if ( *s ) + rctmp = -EINVAL; break; case OPT_BOOL: - if ( !parse_bool(optval) ) + rctmp = parse_bool(optval); + if ( rctmp < 0 ) + break; + if ( !rctmp ) bool_assert = !bool_assert; + rctmp = 0; assign_integer_param(param, bool_assert); break; case OPT_SIZE: - assign_integer_param( + rctmp = assign_integer_param( param, - parse_size_and_unit(optval, NULL)); + parse_size_and_unit(optval, &s)); + if ( *s ) + rctmp = -EINVAL; break; case OPT_CUSTOM: + rctmp = -EINVAL; if ( !bool_assert ) { if ( *optval ) @@ -131,13 +157,21 @@ static void __init _cmdline_parse(const char *cmdline) safe_strcpy(opt, "no"); optval = opt; } - ((void (*)(const char *))param->var)(optval); + rctmp = param->par.func(optval); break; default: BUG(); break; } + + if ( !rc ) + rc = rctmp; } + + if ( rc ) + printk("parameter \"%s\" has invalid value \"%s\"!\n", key, optval); + if ( !found ) + printk("parameter \"%s\" unknown!\n", key); } } @@ -176,7 +210,8 @@ int __init parse_bool(const char *s) !strcmp("on", s) || !strcmp("true", s) || !strcmp("enable", s) || - !strcmp("1", s) ) + !strcmp("1", s) || + !*s ) return 1; return -1; diff --git a/xen/include/xen/init.h b/xen/include/xen/init.h index 25d2eef8dd..234ec25aae 100644 --- a/xen/include/xen/init.h +++ b/xen/include/xen/init.h @@ -83,7 +83,10 @@ struct kernel_param { OPT_CUSTOM } type; unsigned int len; - void *var; + union { + void *var; + int (*func)(const char *); + } par; }; extern const struct kernel_param __setup_start[], __setup_end[]; @@ -95,23 +98,38 @@ extern const struct kernel_param __setup_start[], __setup_end[]; #define custom_param(_name, _var) \ __setup_str __setup_str_##_var[] = _name; \ - __kparam __setup_##_var = { __setup_str_##_var, OPT_CUSTOM, 0, _var } + __kparam __setup_##_var = \ + { .name = __setup_str_##_var, \ + .type = OPT_CUSTOM, \ + .par.func = _var } #define boolean_param(_name, _var) \ __setup_str __setup_str_##_var[] = _name; \ __kparam __setup_##_var = \ - { __setup_str_##_var, OPT_BOOL, sizeof(_var), &_var } + { .name = __setup_str_##_var, \ + .type = OPT_BOOL, \ + .len = sizeof(_var), \ + .par.var = &_var } #define integer_param(_name, _var) \ __setup_str __setup_str_##_var[] = _name; \ __kparam __setup_##_var = \ - { __setup_str_##_var, OPT_UINT, sizeof(_var), &_var } + { .name = __setup_str_##_var, \ + .type = OPT_UINT, \ + .len = sizeof(_var), \ + .par.var = &_var } #define size_param(_name, _var) \ __setup_str __setup_str_##_var[] = _name; \ __kparam __setup_##_var = \ - { __setup_str_##_var, OPT_SIZE, sizeof(_var), &_var } + { .name = __setup_str_##_var, \ + .type = OPT_SIZE, \ + .len = sizeof(_var), \ + .par.var = &_var } #define string_param(_name, _var) \ __setup_str __setup_str_##_var[] = _name; \ __kparam __setup_##_var = \ - { __setup_str_##_var, OPT_STR, sizeof(_var), &_var } + { .name = __setup_str_##_var, \ + .type = OPT_STR, \ + .len = sizeof(_var), \ + .par.var = &_var } #endif /* __ASSEMBLY__ */ diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h index b1dbb8720a..03f0fe612e 100644 --- a/xen/include/xen/types.h +++ b/xen/include/xen/types.h @@ -14,12 +14,15 @@ #define NULL ((void*)0) #endif +#define INT8_MIN (-127-1) #define INT16_MIN (-32767-1) #define INT32_MIN (-2147483647-1) +#define INT8_MAX (127) #define INT16_MAX (32767) #define INT32_MAX (2147483647) +#define UINT8_MAX (255) #define UINT16_MAX (65535) #define UINT32_MAX (4294967295U)