Received: by 2002:ac0:bc90:0:0:0:0:0 with SMTP id a16csp4108150img; Tue, 26 Mar 2019 03:12:05 -0700 (PDT) X-Google-Smtp-Source: APXvYqyDi2NqWmKafkOMY/c1M0skJdm8C+WuFXlGzj2YP0ejWCIv9Y6XaCausmApS52iHKXVdsC6 X-Received: by 2002:a63:4750:: with SMTP id w16mr28646156pgk.256.1553595125546; Tue, 26 Mar 2019 03:12:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1553595125; cv=none; d=google.com; s=arc-20160816; b=ts8WbDy7W/Khz8RzYmJELi8kT9I4BUpGM6USjeiQYf6nh/v/92QRJe8ExOGzS4m7B6 PdAnkhiHlCF4ty2tHfzk9ThO0/+0WRLb+VAvNi/oNK2V+qEqq8pQaQFskKw6DOd011MN A7ABM5Gqkfya2gdjHwF3ldnI3xAyGFkfjG0dVCAZDqZy3fQvEvyS15R2ERgfOE2+RjG2 tmFcc4I/LcgKLe86RBhETffB8Rgml3+pW/SMXcXPqwjLVkxY7oK95j0BF5jq1jy++aX1 yckUl7iGEG8ODOV5jQQEM4T8PK10grnnRikgzQDh2DaaVDo8Ky62+uIbxO1HI22DLaIH fLew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:organization:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date; bh=/w6s0d5KLfjlrB7cewGj4aK0X9ZCQZT8LLdePywJWso=; b=K2J8EmRIF8dSy/USh1Qxt7JEAuVN51Rjfj9g5c3a0n1sPZ/L3yANkitrLfG7w1/kDS KpDdR/EnxLNEDgCMfi/EigODMT85aqf2MzaSDIaLkw5SBCN1EkSdVAJNhJwLPqlvAXaj vTn3A5HUcXngxWkyLQ74WFJCfp/1BLzWb5tw9dZmGjI1cA1Pp2b0KDw+dS6eZQLSUAwk GLwDtBBK8/Jf+BBcm6t5+sEA/3MKtugAEZqPGKgQE1YO59Y/EnFhYMNi0LBTGlBIZa3u FScRyi7rFqPp06i+5rJFHlJTz3oFnOz2KGUcPwkl8BUCMRmGYBmb3n14StQIsddAQAk5 hBfw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m3si15149611pgp.263.2019.03.26.03.11.50; Tue, 26 Mar 2019 03:12:05 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731003AbfCZKKu (ORCPT + 99 others); Tue, 26 Mar 2019 06:10:50 -0400 Received: from mga11.intel.com ([192.55.52.93]:20984 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725535AbfCZKKu (ORCPT ); Tue, 26 Mar 2019 06:10:50 -0400 X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Mar 2019 03:10:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,271,1549958400"; d="scan'208";a="130239543" Received: from smile.fi.intel.com (HELO smile) ([10.237.72.86]) by orsmga006.jf.intel.com with ESMTP; 26 Mar 2019 03:10:46 -0700 Received: from andy by smile with local (Exim 4.92) (envelope-from ) id 1h8j2b-00018w-6r; Tue, 26 Mar 2019 12:10:45 +0200 Date: Tue, 26 Mar 2019 12:10:45 +0200 From: Andy Shevchenko To: Yury Norov Cc: Andrew Morton , Rasmus Villemoes , Arnd Bergmann , Kees Cook , Matthew Wilcox , Tetsuo Handa , Yury Norov , linux-kernel@vger.kernel.org Subject: Re: [PATCH 3/6] bitmap_parselist: rework input string parser Message-ID: <20190326101045.GT9224@smile.fi.intel.com> References: <20190325210748.6571-1-ynorov@marvell.com> <20190325210748.6571-4-ynorov@marvell.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20190325210748.6571-4-ynorov@marvell.com> Organization: Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo User-Agent: Mutt/1.10.1 (2018-07-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Mar 26, 2019 at 12:07:45AM +0300, Yury Norov wrote: > The requirement for this rework is to keep the __bitmap_parselist() > copy-less and single-pass but make it more readable and maintainable by > splitting into logical parts and removing explicit nested cycles and > opaque local variables. > > __bitmap_parselist() can parse userspace inputs and therefore we cannot > use simple_strtoul() to parse numbers. > +static long get_char(char *c, const char *str, int is_user) > +{ > + if (unlikely(is_user)) Can is_user be boolean? Can we name it from_user or is_from_user? > + return __get_user(*c, (const char __force __user *)str); > + > + *c = *str; > + return 0; > +} > + > +static const char *bitmap_getnum(unsigned int *num, const char *str, > + const char *const end, int is_user) > +{ > + unsigned int n = 0; > + const char *_str; > + long ret; > + char c; > + > + for (_str = str, *num = 0; _str <= end; _str++) { > + ret = get_char(&c, _str, is_user); > + if (ret) > + return ERR_PTR(ret); > + > + if (!isdigit(c)) { > + if (_str == str) > + return ERR_PTR(-EINVAL); > + > + return _str; > + } > + > + *num = *num * 10 + (c - '0'); > + if (*num < n) > + return ERR_PTR(-EOVERFLOW); > + > + n = *num; > + } Can't we do other way around, i.e. move the loop body to a helper and do something like this: if (is_from_user) { for (...) { __get_user(...); helper1(); helper2(); } } else { for (...) { *c = *str; helper1(); helper2() } } Each branch can be optimized more I think. > + > + return _str; > +} > + > +static const char *bitmap_find_region(const char *str, > + const char *const end, int is_user) > +{ > + long ret; > + char c; > + > + for (; str <= end; str++) { > + ret = get_char(&c, str, is_user); > + if (ret) > + return ERR_PTR(ret); > + > + /* Unexpected end of line. */ > + if (c == 0 || c == '\n') > + return NULL; > + > + /* > + * The format allows commas and whitespases > + * at the beginning of the region, so skip it. > + */ > + if (!isspace(c) && c != ',') > + break; > + } > + > + return str <= end ? str : NULL; > +} > + > +static const char *bitmap_parse_region(struct region *r, const char *str, > + const char *const end, int is_user) > +{ > + long ret; > + char c; > + > + str = bitmap_getnum(&r->start, str, end, is_user); > + if (IS_ERR(str)) > + return str; > + > + ret = get_char(&c, str, is_user); > + if (ret) > + return (char *)ret; > + > + if (c == 0 || c == '\n') { > + str = end + 1; > + goto no_end; > + } > + > + if (isspace(c) || c == ',') > + goto no_end; > + > + if (c != '-') > + return ERR_PTR(-EINVAL); > + > + str = bitmap_getnum(&r->end, str + 1, end, is_user); > + if (IS_ERR(str)) > + return str; > + > + ret = get_char(&c, str, is_user); > + if (ret) > + return ERR_PTR(ret); > + > + if (c == 0 || c == '\n') { > + str = end + 1; > + goto no_pattern; > + } > + > + if (isspace(c) || c == ',') > + goto no_pattern; > + > + if (c != ':') > + return ERR_PTR(-EINVAL); > + > + str = bitmap_getnum(&r->off, str + 1, end, is_user); > + if (IS_ERR(str)) > + return str; > + > + ret = get_char(&c, str, is_user); > + if (ret) > + return (char *)ret; > + > + if (c != '/') > + return ERR_PTR(-EINVAL); > + > + str = bitmap_getnum(&r->grlen, str + 1, end, is_user); > + > + return str; return bitmap_getnum(...); > + > +no_end: > + r->end = r->start; > +no_pattern: > + r->off = r->end + 1; > + r->grlen = r->end + 1; > + > + return str; > +} > + So, all above depends to what memory we access kernel / user space. Perhaps we can get copy of memory of a given size and then parse it in kernel space always? -- With Best Regards, Andy Shevchenko