Received: by 10.213.65.68 with SMTP id h4csp669922imn; Wed, 4 Apr 2018 05:24:24 -0700 (PDT) X-Google-Smtp-Source: AIpwx48zGrCI8iqSU1NwwmoUsPI+1IY5tHzguekpYDWN1+M5GOxguzEkYz25phIXsOhWhDGqk7BW X-Received: by 2002:a17:902:82cb:: with SMTP id u11-v6mr18300665plz.369.1522844664902; Wed, 04 Apr 2018 05:24:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522844664; cv=none; d=google.com; s=arc-20160816; b=a1KuRZaBqfaQ17P7yXNnONGnotFaGUZ/x/660+aL/0MPhidNIENiJ3SWsRNa/re3CN eok+KGcOagHMHzHaJk2SlhiuZLwR1EYPUcKXrYUoiD2H7FUwdLw1LQ3kPs0a+4cpNkuK KCflEy4abf+fij/Q4BFhGrNLokr7K6LkLz2XKWQxXauIvIpdy/PAXqur5QbbG1bWXpR5 CYmFC9M/npNVnBD3G2702aNEJ4tLQlctfEH0L2OujIzzEXETC+ev9zg6nMZeT4aCYtPG GBOsYMC1QTeHuqr2XV2aAq4KoHqDJ1gfJbwnphu8C6f2rbF6Mf/oP3JAK2KEtocgLflQ 3mGg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:cc:references:to:subject:arc-authentication-results; bh=+ejXlxK++LulCSKkvhfY3m5AXcgoyA29BjtkbLBoJek=; b=A9y789SdvXlMrnZ2faRNOfwxYs0DHSplzdVlNZb7sQ3eNtaf+0LbxF/mGZENFPurOp FSVq6C65FTHx16KW8O76E49PKKIJxCQ2C1RfQkNI+s8VLZETcxdc99+k0h76j+spHPg2 +XtVXhySAC9uXP8iOjXb3faJUxPqO2kYXfdIS1vMkixbJ1bW7y1bQuDlM0n5g5q08RiK a4DBzChTjvhDe3O3FJFKgEBgAQD1PKyYyiRcXBLwiALZPeJSECnFMwcSrdU0+1SDuob4 YCTqr0PNQG3+luUfSGrM0VE1EIiK8GaWXdN1c/7LN9dQ2PtbdV8HkUD23CvrSuRN3wKN khYA== 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i3-v6si2886518pld.241.2018.04.04.05.24.10; Wed, 04 Apr 2018 05:24:24 -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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751313AbeDDMVn (ORCPT + 99 others); Wed, 4 Apr 2018 08:21:43 -0400 Received: from www262.sakura.ne.jp ([202.181.97.72]:11235 "EHLO www262.sakura.ne.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751117AbeDDMVm (ORCPT ); Wed, 4 Apr 2018 08:21:42 -0400 Received: from fsav404.sakura.ne.jp (fsav404.sakura.ne.jp [133.242.250.103]) by www262.sakura.ne.jp (8.14.5/8.14.5) with ESMTP id w34CLebm055380; Wed, 4 Apr 2018 21:21:40 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) Received: from www262.sakura.ne.jp (202.181.97.72) by fsav404.sakura.ne.jp (F-Secure/fsigk_smtp/530/fsav404.sakura.ne.jp); Wed, 04 Apr 2018 21:21:40 +0900 (JST) X-Virus-Status: clean(F-Secure/fsigk_smtp/530/fsav404.sakura.ne.jp) Received: from [192.168.1.8] (softbank126099184120.bbtec.net [126.99.184.120]) (authenticated bits=0) by www262.sakura.ne.jp (8.14.5/8.14.5) with ESMTP id w34CLdk6055371 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 4 Apr 2018 21:21:40 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) Subject: Re: INFO: rcu detected stall in bitmap_parselist To: Yury Norov References: <000000000000edc3690568cc95eb@google.com> Cc: syzbot , cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, lizefan@huawei.com, syzkaller-bugs@googlegroups.com, Noam Camus , Rasmus Villemoes , Matthew Wilcox , Mauro Carvalho Chehab , Andrew Morton From: Tetsuo Handa Message-ID: Date: Wed, 4 Apr 2018 21:21:43 +0900 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <000000000000edc3690568cc95eb@google.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Yury, are you OK with this patch? From 7f21827cdfe9780b4949b22bcd19efa721b463d2 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 4 Apr 2018 21:12:10 +0900 Subject: [PATCH] lib/bitmap: Rewrite __bitmap_parselist(). syzbot is catching stalls at __bitmap_parselist() [1]. The trigger is unsigned long v = 0; bitmap_parselist("7:,", &v, BITS_PER_LONG); which results in hitting infinite loop at while (a <= b) { off = min(b - a + 1, used_size); bitmap_set(maskp, a, off); a += group_size; } due to used_size == group_size == 0. Current code is difficult to read due to too many flag variables. Let's rewrite it. My understanding of "range:used_size/group_size" is "start[-end[:used_size/group_size]]" format. Please check whether my understanding is correct... [1] https://syzkaller.appspot.com/bug?id=ad7e0351fbc90535558514a71cd3edc11681997a Signed-off-by: Tetsuo Handa Reported-by: syzbot Fixes: 0a5ce0831d04382a ("lib/bitmap.c: make bitmap_parselist() thread-safe and much faster") Cc: Yury Norov Cc: Noam Camus Cc: Rasmus Villemoes Cc: Matthew Wilcox Cc: Mauro Carvalho Chehab Cc: Andrew Morton --- lib/bitmap.c | 183 +++++++++++++++++++++++++---------------------------------- 1 file changed, 78 insertions(+), 105 deletions(-) diff --git a/lib/bitmap.c b/lib/bitmap.c index 9e498c7..9cef440 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -485,6 +485,58 @@ int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, } EXPORT_SYMBOL(bitmap_print_to_pagebuf); +static bool get_uint(const char **buf, unsigned int *res) +{ + const char *p = *buf; + + if (!isdigit(*p)) + return false; + *res = simple_strtoul(p, (char **) buf, 10); + return p < *buf; +} + +static int __bitmap_parse_one_chunk(const char *buf, unsigned long *maskp, + const unsigned int nmaskbits) +{ + unsigned int start; + unsigned int end; + unsigned int group_size; + unsigned int used_size; + + while (*buf && isspace(*buf)) + buf++; + if (!get_uint(&buf, &start)) + return -EINVAL; + if (*buf == '-') { + buf++; + if (!get_uint(&buf, &end) || start > end) + return -EINVAL; + if (*buf == ':') { + buf++; + if (!get_uint(&buf, &used_size) || *buf++ != '/' || + !get_uint(&buf, &group_size) || + used_size > group_size) + return -EINVAL; + } else { + group_size = used_size = end - start + 1; + } + } else { + end = start; + group_size = used_size = 1; + } + if (end >= nmaskbits) + return -ERANGE; + while (start <= end) { + const unsigned int bits = min(end - start + 1, used_size); + + bitmap_set(maskp, start, bits); + start += group_size; + } + while (*buf && isspace(*buf)) + buf++; + return *buf ? -EINVAL : 0; +} + /** * __bitmap_parselist - convert list format ASCII string to bitmap * @buf: read nul-terminated user string from this buffer @@ -511,113 +563,34 @@ int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, * - ``-ERANGE``: bit number specified too large for mask */ static int __bitmap_parselist(const char *buf, unsigned int buflen, - int is_user, unsigned long *maskp, - int nmaskbits) + const int is_user, unsigned long *maskp, + const int nmaskbits) { - unsigned int a, b, old_a, old_b; - unsigned int group_size, used_size, off; - int c, old_c, totaldigits, ndigits; - const char __user __force *ubuf = (const char __user __force *)buf; - int at_start, in_range, in_partial_range; - - totaldigits = c = 0; - old_a = old_b = 0; - group_size = used_size = 0; + int err = 0; bitmap_zero(maskp, nmaskbits); - do { - at_start = 1; - in_range = 0; - in_partial_range = 0; - a = b = 0; - ndigits = totaldigits; - - /* Get the next cpu# or a range of cpu#'s */ - while (buflen) { - old_c = c; - if (is_user) { - if (__get_user(c, ubuf++)) - return -EFAULT; - } else - c = *buf++; - buflen--; - if (isspace(c)) - continue; - - /* A '\0' or a ',' signal the end of a cpu# or range */ - if (c == '\0' || c == ',') - break; - /* - * whitespaces between digits are not allowed, - * but it's ok if whitespaces are on head or tail. - * when old_c is whilespace, - * if totaldigits == ndigits, whitespace is on head. - * if whitespace is on tail, it should not run here. - * as c was ',' or '\0', - * the last code line has broken the current loop. - */ - if ((totaldigits != ndigits) && isspace(old_c)) - return -EINVAL; - - if (c == '/') { - used_size = a; - at_start = 1; - in_range = 0; - a = b = 0; - continue; - } - - if (c == ':') { - old_a = a; - old_b = b; - at_start = 1; - in_range = 0; - in_partial_range = 1; - a = b = 0; - continue; - } - - if (c == '-') { - if (at_start || in_range) - return -EINVAL; - b = 0; - in_range = 1; - at_start = 1; - continue; - } - - if (!isdigit(c)) - return -EINVAL; - - b = b * 10 + (c - '0'); - if (!in_range) - a = b; - at_start = 0; - totaldigits++; - } - if (ndigits == totaldigits) - continue; - if (in_partial_range) { - group_size = a; - a = old_a; - b = old_b; - old_a = old_b = 0; - } else { - used_size = group_size = b - a + 1; - } - /* if no digit is after '-', it's wrong*/ - if (at_start && in_range) - return -EINVAL; - if (!(a <= b) || !(used_size <= group_size)) - return -EINVAL; - if (b >= nmaskbits) - return -ERANGE; - while (a <= b) { - off = min(b - a + 1, used_size); - bitmap_set(maskp, a, off); - a += group_size; - } - } while (buflen && c == ','); - return 0; + while (buflen && !err) { + char *cp; + char tmpbuf[256]; + unsigned int size = min(buflen, + (unsigned int) sizeof(tmpbuf) - 1); + + if (!is_user) + memcpy(tmpbuf, buf, size); + else if (copy_from_user(tmpbuf, (const char __user __force *) + buf, size)) + return -EFAULT; + tmpbuf[size] = '\0'; + cp = strchr(tmpbuf, ','); + if (cp) { + *cp = '\0'; + size = cp - tmpbuf + 1; + } else if (size != buflen) + return -EINVAL; /* Chunk too long. */ + buflen -= size; + buf += size; + err = __bitmap_parse_one_chunk(tmpbuf, maskp, nmaskbits); + } + return err; } int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) -- 1.8.3.1