Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp2385912pxb; Mon, 20 Sep 2021 21:00:11 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxJsCE1NYbFCB65DQ6aGx/dcHF19OZBX4egWdn2edHZ6M2Zk1Ouj+wFzH9eJOn6BUAQ7CD4 X-Received: by 2002:a02:cc22:: with SMTP id o2mr9136769jap.128.1632196810999; Mon, 20 Sep 2021 21:00:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632196810; cv=none; d=google.com; s=arc-20160816; b=y+/uz7gtdA/tJaQ1i7m1ykgCDmr+/4NOyFBDZM/dIMYpI5z0AB/LAa1F6yr0uXKGle TYsVMpdSZ55s9rB6U/i7p8TC+IGk7P4+O79ntaWxOJP0WHcOmkgWNzWrYJyEyA81sEAC G26P5Dp6cfLDv1e0wvv2LTxFRu/WrlPKJ2Z1B4L4yXa1GwqxSy3cqrj8t5iKMhUzICQN Ah4dty+zH3yedzhn4+AW/5Qc1QlvJJyXAbYyjsOQ6bJV9SZYXhbSmIj7rVeNnB9Ya6/3 odRdvE0eXE1yMw7El64HQYPipH+8ambkTb8q577y/Sfgqh7Y72NowouMNfDfZMW8e8vd 1IPg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:mime-version:message-id:date :dkim-signature; bh=pguml3paj2LeB5heWrEsmrwhMCMlKDyRkBgZeHcvxlM=; b=PhsOxXIoRyAWOMm59aP7D1Zi3thUXlEzc8PgmaNrjspG5FbKtxEdhrSyKogOo94gBs qxLRYpfGLbX5morjYF/SqxiPgOVrYgXMjK+Y5EAuf9LwheRYY6q0R9gwBq+Jp5kacirQ LxQdvoAOqfrDkPPgydK0Tc461HwVRp3qOKBQFZIBWvL7N4yxJr6QTV86gtWag7GGxNqj Md/K7Lr/i8+mELrqLfQYafURhJnB07vDqCJyIa0qnwiF2RDHEl4PMYgKwJOdjjuAi6i0 vI3NjHDiEPDh+mRPjTICPsJRLEhjPJ+5Odo1X64eRoBrQbKvHRhJeXpn7ttl767ncTH5 RqyQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QZvWuxoH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id r2si13172293ila.178.2021.09.20.20.59.59; Mon, 20 Sep 2021 21:00:10 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QZvWuxoH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236603AbhIUCJC (ORCPT + 99 others); Mon, 20 Sep 2021 22:09:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34096 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237164AbhIUBwr (ORCPT ); Mon, 20 Sep 2021 21:52:47 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CF928C0363F9 for ; Mon, 20 Sep 2021 16:25:47 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id m10-20020a05620a290a00b004334bcdf1f4so30180185qkp.2 for ; Mon, 20 Sep 2021 16:25:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:message-id:mime-version:subject:from:to:cc; bh=pguml3paj2LeB5heWrEsmrwhMCMlKDyRkBgZeHcvxlM=; b=QZvWuxoHRNl58kiylK3SiDmPeerQVYX1bUDQBZvz+VKz1OMGl/VnuqM0ABNzQDb6Ks /8L5utuNlUXChpYBFhNF2j+HVg1mUtaSM1C++icVmp55GCqaiFMAekzxaXp7yLULEBqL B2M3VblthoUdv+c424XdVu3PIbqROYvkP6q636u4C/xksk7EMrpPw9C629VarSo0IUgj bWWo3JG1sp5xNKkdMuAr9md9rg4qE/dxFKhz5Si/8nKiCl82o2FbENB0TMZLhDtZZBD8 bjh175RLHfVQLJIWq9UxDARd2i3adArN3u2WB+UH6d3D2QhVW5wM6mD6Cm5Gc74zLwbI Zclw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=pguml3paj2LeB5heWrEsmrwhMCMlKDyRkBgZeHcvxlM=; b=28gwxrulBhFtlaLWCZwdtWIunAUcvalnEeJ03kD/DVwh0f7TZrE0d0gMWB0nAnOvvc Zzvr8zYdvNDB0eCa6tykVufZmktnf3eHqPj9F7jGVWhRcD+VQKFOWdUjv3oRvpcrWoY5 PrVmrgIGNh/mliiK8HiE8oz+9p2nPtFWpjO3eS80WwJYq6QM7kw1kbRD3y+UQs8+1b6m qS6v3+jGbO5sMv9S+HfAt/8qHNp9jPwgf8TuwFzBvf9HXaFb+ztOIqC/a/80T0CDAc9v WBGiXpnvChHS8LHaJb4Oqq7XKBA79Kq4uU/F9UVShgaLMRcINyc6V1AvKXxaN7Gqd2lG qFCQ== X-Gm-Message-State: AOAM530a5O0L/rePaafBxPccquubyZAjKx+LedlGWDUj8DJRyOtwtuCq LjxnrB2Y6BTSsn34KO8EqZJhoDiCUkRC0Y/neVw= X-Received: from ndesaulniers1.mtv.corp.google.com ([2620:15c:211:202:5f32:153:b2ea:296d]) (user=ndesaulniers job=sendgmr) by 2002:a25:1388:: with SMTP id 130mr33364420ybt.58.1632180346968; Mon, 20 Sep 2021 16:25:46 -0700 (PDT) Date: Mon, 20 Sep 2021 16:25:33 -0700 Message-Id: <20210920232533.4092046-1-ndesaulniers@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.33.0.464.g1972c5931b-goog Subject: [PATCH] nbd: use shifts rather than multiplies From: Nick Desaulniers To: Josef Bacik Cc: Greg Kroah-Hartman , Nick Desaulniers , stable@vger.kernel.org, Arnd Bergmann , Rasmus Villemoes , Naresh Kamboju , Nathan Chancellor , Stephen Rothwell , Kees Cook , Linus Torvalds , Pavel Machek , Jens Axboe , linux-block@vger.kernel.org, nbd@other.debian.org, linux-kernel@vger.kernel.org, llvm@lists.linux.dev Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org commit fad7cd3310db ("nbd: add the check to prevent overflow in __nbd_ioctl()") raised an issue from the fallback helpers added in commit f0907827a8a9 ("compiler.h: enable builtin overflow checkers and add fallback code") ERROR: modpost: "__divdi3" [drivers/block/nbd.ko] undefined! As Stephen Rothwell notes: The added check_mul_overflow() call is being passed 64 bit values. COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW is not set for this build (see include/linux/overflow.h). Specifically, the helpers for checking whether the results of a multiplication overflowed (__unsigned_mul_overflow, __signed_add_overflow) use the division operator when !COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW. This is problematic for 64b operands on 32b hosts. This was fixed upstream by commit 76ae847497bc ("Documentation: raise minimum supported version of GCC to 5.1") which is not suitable to be backported to stable. Further, __builtin_mul_overflow() would emit a libcall to a compiler-rt-only symbol when compiling with clang < 14 for 32b targets. ld.lld: error: undefined symbol: __mulodi4 In order to keep stable buildable with GCC 4.9 and clang < 14, modify struct nbd_config to instead track the number of bits of the block size; reconstructing the block size using runtime checked shifts that are not problematic for those compilers and in a ways that can be backported to stable. In nbd_set_size, we do validate that the value of blksize must be a power of two (POT) and is in the range of [512, PAGE_SIZE] (both inclusive). This does modify the debugfs interface. Cc: stable@vger.kernel.org Cc: Arnd Bergmann Cc: Rasmus Villemoes Link: https://github.com/ClangBuiltLinux/linux/issues/1438 Link: https://lore.kernel.org/all/20210909182525.372ee687@canb.auug.org.au/ Link: https://lore.kernel.org/stable/CAHk-=whiQBofgis_rkniz8GBP9wZtSZdcDEffgSLO62BUGV3gg@mail.gmail.com/ Reported-by: Naresh Kamboju Reported-by: Nathan Chancellor Reported-by: Stephen Rothwell Suggested-by: Kees Cook Suggested-by: Linus Torvalds Suggested-by: Pavel Machek Signed-off-by: Nick Desaulniers --- This patch is kind of a v3 for solving this problem. v2: https://lore.kernel.org/stable/20210914002318.2298583-1-ndesaulniers@google.com/ v1: https://lore.kernel.org/stable/20210913203201.1844253-1-ndesaulniers@google.com/ But is quite different in approach. Instead of trying to fix up the overflow routines in stable, we amend the code in nbd.c as per Linus (against mainline) with fixes from Kees to use the named overflow checker. drivers/block/nbd.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 5170a630778d..1183f7872b71 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -97,13 +97,18 @@ struct nbd_config { atomic_t recv_threads; wait_queue_head_t recv_wq; - loff_t blksize; + unsigned int blksize_bits; loff_t bytesize; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbg_dir; #endif }; +static inline unsigned int nbd_blksize(struct nbd_config *config) +{ + return 1u << config->blksize_bits; +} + struct nbd_device { struct blk_mq_tag_set tag_set; @@ -146,7 +151,7 @@ static struct dentry *nbd_dbg_dir; #define NBD_MAGIC 0x68797548 -#define NBD_DEF_BLKSIZE 1024 +#define NBD_DEF_BLKSIZE_BITS 10 static unsigned int nbds_max = 16; static int max_part = 16; @@ -317,12 +322,12 @@ static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize, loff_t blksize) { if (!blksize) - blksize = NBD_DEF_BLKSIZE; + blksize = 1u << NBD_DEF_BLKSIZE_BITS; if (blksize < 512 || blksize > PAGE_SIZE || !is_power_of_2(blksize)) return -EINVAL; nbd->config->bytesize = bytesize; - nbd->config->blksize = blksize; + nbd->config->blksize_bits = __ffs(blksize); if (!nbd->task_recv) return 0; @@ -1337,7 +1342,7 @@ static int nbd_start_device(struct nbd_device *nbd) args->index = i; queue_work(nbd->recv_workq, &args->work); } - return nbd_set_size(nbd, config->bytesize, config->blksize); + return nbd_set_size(nbd, config->bytesize, nbd_blksize(config)); } static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *bdev) @@ -1406,11 +1411,11 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, case NBD_SET_BLKSIZE: return nbd_set_size(nbd, config->bytesize, arg); case NBD_SET_SIZE: - return nbd_set_size(nbd, arg, config->blksize); + return nbd_set_size(nbd, arg, nbd_blksize(config)); case NBD_SET_SIZE_BLOCKS: - if (check_mul_overflow((loff_t)arg, config->blksize, &bytesize)) + if (check_shl_overflow(arg, config->blksize_bits, &bytesize)) return -EINVAL; - return nbd_set_size(nbd, bytesize, config->blksize); + return nbd_set_size(nbd, bytesize, nbd_blksize(config)); case NBD_SET_TIMEOUT: nbd_set_cmd_timeout(nbd, arg); return 0; @@ -1476,7 +1481,7 @@ static struct nbd_config *nbd_alloc_config(void) atomic_set(&config->recv_threads, 0); init_waitqueue_head(&config->recv_wq); init_waitqueue_head(&config->conn_wait); - config->blksize = NBD_DEF_BLKSIZE; + config->blksize_bits = NBD_DEF_BLKSIZE_BITS; atomic_set(&config->live_connections, 0); try_module_get(THIS_MODULE); return config; @@ -1604,7 +1609,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd) debugfs_create_file("tasks", 0444, dir, nbd, &nbd_dbg_tasks_fops); debugfs_create_u64("size_bytes", 0444, dir, &config->bytesize); debugfs_create_u32("timeout", 0444, dir, &nbd->tag_set.timeout); - debugfs_create_u64("blocksize", 0444, dir, &config->blksize); + debugfs_create_u32("blocksize_bits", 0444, dir, &config->blksize_bits); debugfs_create_file("flags", 0444, dir, nbd, &nbd_dbg_flags_fops); return 0; @@ -1826,7 +1831,7 @@ nbd_device_policy[NBD_DEVICE_ATTR_MAX + 1] = { static int nbd_genl_size_set(struct genl_info *info, struct nbd_device *nbd) { struct nbd_config *config = nbd->config; - u64 bsize = config->blksize; + u64 bsize = nbd_blksize(config); u64 bytes = config->bytesize; if (info->attrs[NBD_ATTR_SIZE_BYTES]) @@ -1835,7 +1840,7 @@ static int nbd_genl_size_set(struct genl_info *info, struct nbd_device *nbd) if (info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]) bsize = nla_get_u64(info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]); - if (bytes != config->bytesize || bsize != config->blksize) + if (bytes != config->bytesize || bsize != nbd_blksize(config)) return nbd_set_size(nbd, bytes, bsize); return 0; } base-commit: 4c17ca27923c16fd73bbb9ad033c7d749c3bcfcc -- 2.33.0.464.g1972c5931b-goog