Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp4154884pxb; Mon, 27 Sep 2021 10:30:22 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwJBt5bTlLQCx7hL42vHSgfi7PhPIYmkJ+TOj4dG7YfnfUAPgbo2UmoqssfplyCVXFKA1fX X-Received: by 2002:a17:90a:10c1:: with SMTP id b1mr329448pje.42.1632763822053; Mon, 27 Sep 2021 10:30:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632763822; cv=none; d=google.com; s=arc-20160816; b=aLy9L2Afc2ZDSkeTH2KT8AnbOAc2Nh8vgtnm8g7UNC3G33N0mlLEvUSj4PGj8J4/Y1 GTLPdL6JXezBsx0/HzN0PfhuZg90WD8ghqMRGbEL+6bdfaPR9iRsnDtwCkqf2YirEjNb SU/zAvRGr5tpc7JGgD/+GLqjL1RbPTEBMRHaqtRsakq9q7cUSwbgl3zkuR7sjOXdiods axNt6Bp2RhUsipIscc0Ee1FEIgH+uJuDwGqrmoISK/X2AV7EUGsFh5w4c6PaBE+yvH3o wxZcKsUpYn5X14bsOPUbez+YKgtp8mVoIWHjWF8Swb9RjgVcIDWHkimOiuxTuzHLfKUo Yu6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=EWo5MbJLUk4gEf41Iu2aMcBRLjQGGLmecKMniOIRfFQ=; b=Nu9Ji3MXIqYxNDqw9y0Dpk+im+nWr7TYcBW9i3t5e9K0mWOKlJTnMKh7WpbXsRLm6l ZT+ZXmFJ9Fbvs31t/4vNB3Ze4kxgtmElTuLOc4c1mqyNam8Qw/iq8JB/9iid39o+fkZC vwtFj0EPe/iJsTRA08xouH/8tR47pcEN9LWf58WuhOcy5hD5tXHbHgT4yLacBKFeR9EG YusUlDdK6lO1SxwzNSZ3ie5W4Ix1Y8kkz5e5tV/iOMPrBf+oEKy321KFjElq3bmN9z8X QaZ1Zp+sg5ChQLdj/jSZi1j6NekApvmfMEqmkTK/zgXKqSdjZqJgbBiAcU5J2bF+++X+ QC7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=ek3myY1d; 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=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v1si25668471plg.230.2021.09.27.10.30.07; Mon, 27 Sep 2021 10:30:22 -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=@linuxfoundation.org header.s=korg header.b=ek3myY1d; 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=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237010AbhI0RaW (ORCPT + 99 others); Mon, 27 Sep 2021 13:30:22 -0400 Received: from mail.kernel.org ([198.145.29.99]:43266 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236741AbhI0R1l (ORCPT ); Mon, 27 Sep 2021 13:27:41 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 9906061391; Mon, 27 Sep 2021 17:16:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632763020; bh=2x/8C7RGicmM784+vbWKsqQcHRNQFf3C1wuczzZL2ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ek3myY1dDFrFzGVvDJT2XvMluxUqbq7wZqbguuZImyzh//5GwRGSiaLN3xiH7FOy0 HJ8+Th7UZ8YaEz6K9KFHc5ph9bdK4LPGD3a4Qi1wbEioY/QSNqv2B6I6OhZZgKy9n+ pnnbu4ABaLpg/xmRe76FWz+YvvLEPSuRxHFrYbpw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Linus Torvalds , Sasha Levin Subject: [PATCH 5.14 138/162] qnx4: avoid stringop-overread errors Date: Mon, 27 Sep 2021 19:03:04 +0200 Message-Id: <20210927170238.202093428@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210927170233.453060397@linuxfoundation.org> References: <20210927170233.453060397@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Linus Torvalds [ Upstream commit b7213ffa0e585feb1aee3e7173e965e66ee0abaa ] The qnx4 directory entries are 64-byte blocks that have different contents depending on the a status byte that is in the last byte of the block. In particular, a directory entry can be either a "link info" entry with a 48-byte name and pointers to the real inode information, or an "inode entry" with a smaller 16-byte name and the full inode information. But the code was written to always just treat the directory name as if it was part of that "inode entry", and just extend the name to the longer case if the status byte said it was a link entry. That work just fine and gives the right results, but now that gcc is tracking data structure accesses much more, the code can trigger a compiler error about using up to 48 bytes (the long name) in a structure that only has that shorter name in it: fs/qnx4/dir.c: In function ‘qnx4_readdir’: fs/qnx4/dir.c:51:32: error: ‘strnlen’ specified bound 48 exceeds source size 16 [-Werror=stringop-overread] 51 | size = strnlen(de->di_fname, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from fs/qnx4/qnx4.h:3, from fs/qnx4/dir.c:16: include/uapi/linux/qnx4_fs.h:45:25: note: source object declared here 45 | char di_fname[QNX4_SHORT_NAME_MAX]; | ^~~~~~~~ which is because the source code doesn't really make this whole "one of two different types" explicit. Fix this by introducing a very explicit union of the two types, and basically explaining to the compiler what is really going on. Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/qnx4/dir.c | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index a6ee23aadd28..2a66844b7ff8 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -15,13 +15,27 @@ #include #include "qnx4.h" +/* + * A qnx4 directory entry is an inode entry or link info + * depending on the status field in the last byte. The + * first byte is where the name start either way, and a + * zero means it's empty. + */ +union qnx4_directory_entry { + struct { + char de_name; + char de_pad[62]; + char de_status; + }; + struct qnx4_inode_entry inode; + struct qnx4_link_info link; +}; + static int qnx4_readdir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); unsigned int offset; struct buffer_head *bh; - struct qnx4_inode_entry *de; - struct qnx4_link_info *le; unsigned long blknum; int ix, ino; int size; @@ -38,27 +52,30 @@ static int qnx4_readdir(struct file *file, struct dir_context *ctx) } ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK; for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) { + union qnx4_directory_entry *de; + const char *name; + offset = ix * QNX4_DIR_ENTRY_SIZE; - de = (struct qnx4_inode_entry *) (bh->b_data + offset); - if (!de->di_fname[0]) + de = (union qnx4_directory_entry *) (bh->b_data + offset); + + if (!de->de_name) continue; - if (!(de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) + if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) continue; - if (!(de->di_status & QNX4_FILE_LINK)) - size = QNX4_SHORT_NAME_MAX; - else - size = QNX4_NAME_MAX; - size = strnlen(de->di_fname, size); - QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, de->di_fname)); - if (!(de->di_status & QNX4_FILE_LINK)) + if (!(de->de_status & QNX4_FILE_LINK)) { + size = sizeof(de->inode.di_fname); + name = de->inode.di_fname; ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; - else { - le = (struct qnx4_link_info*)de; - ino = ( le32_to_cpu(le->dl_inode_blk) - 1 ) * + } else { + size = sizeof(de->link.dl_fname); + name = de->link.dl_fname; + ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) * QNX4_INODES_PER_BLOCK + - le->dl_inode_ndx; + de->link.dl_inode_ndx; } - if (!dir_emit(ctx, de->di_fname, size, ino, DT_UNKNOWN)) { + size = strnlen(name, size); + QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name)); + if (!dir_emit(ctx, name, size, ino, DT_UNKNOWN)) { brelse(bh); return 0; } -- 2.33.0