Received: by 2002:a05:6a10:d5a5:0:0:0:0 with SMTP id gn37csp3729408pxb; Mon, 4 Oct 2021 08:23:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwPxEFP0x0QmHxUS4EhUlkL1DhOXvb22FZIP3Fj/6Mb5McPBBP1NtuHDWtkW+cLScdj2kXC X-Received: by 2002:a17:902:d353:b0:13e:a87e:f2e with SMTP id l19-20020a170902d35300b0013ea87e0f2emr273635plk.64.1633361016874; Mon, 04 Oct 2021 08:23:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633361016; cv=none; d=google.com; s=arc-20160816; b=SVoO1nr/9s45snsWjr98KTS5DIje1NOPAcjseyYoUwarfbqAj38NamIjsuDkLX2Nd6 nPURQSLIGGpgPjTk+IYU4l6p/+IL8ISw7KTKqoNtvoi7rvEk51SZ3jz/jHU1LM4Gyjkz 7pwz3hiNLbgk3T0YVKB57ylAE5q2GcD+/N3MAxa1V0HhZA7vcDdK2q52IOSAA6bC6zy0 DRriuoqgyArjpOKeMofn/L53DEc6Z9Up8Nq2RD1geo1TNE8vSKBuP4D3HBKEcS2qey77 bil4ewzC1zoHJUbESv6M56PZhfCnSzWAkN6iS9f2aWmpqxBPoev+yJVEJfSUzEO7AT8q 67OQ== 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=totJ7bpjuBKXMOkEEa7i0kpDRF/JKavEFavIesTUW7p29bKkXnv+OSLD+RcdQ/I1RH X9ffd8mdLmYGR3SBc9J06F0t3u8lj7XCnxT9CjQ/8XwGm/yQjMsTDFx7LanCwBnS0BLf u+TBSGAIfq0//5IwoK5+c181UYJdlFK+Uq4PWkcbd577ITN7ExalvYmcZPqK0nUywAzE GTm62WztCKlAchpc+DD7scpInClfZhoece3ht9nsSWEjFnEE7clfGmneoCvQMjYjufIV 0yK6Pw6kHp7KxJeer3LWdpMJO0puITtJtr4BrYEXywOFsN7p27THTBKDDZlNNIhNDxJQ KshA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="on2y/91O"; 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 n3si17869607pjh.74.2021.10.04.08.23.08; Mon, 04 Oct 2021 08:23:36 -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="on2y/91O"; 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 S235630AbhJDNL3 (ORCPT + 99 others); Mon, 4 Oct 2021 09:11:29 -0400 Received: from mail.kernel.org ([198.145.29.99]:45614 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234633AbhJDNJA (ORCPT ); Mon, 4 Oct 2021 09:09:00 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 8DC6D613D5; Mon, 4 Oct 2021 13:03:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1633352581; bh=2x/8C7RGicmM784+vbWKsqQcHRNQFf3C1wuczzZL2ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=on2y/91Oh/GH13yqGkiSwhACJy9jZk3TaaJCSlg4iKG16HlyWcZ+mTfJgddD3Y0Ok p1yywyjxR1gcrRG/KwuJLkYSY7kEPNP+Gx1xCSPziKOGUTazXIIJi1ZR/TxoYLaLqL zgv8tDJWxat3YWBvAAFOPJXyAKbYohoZQCxI0XGU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Linus Torvalds , Sasha Levin Subject: [PATCH 4.19 41/95] qnx4: avoid stringop-overread errors Date: Mon, 4 Oct 2021 14:52:11 +0200 Message-Id: <20211004125034.921083317@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211004125033.572932188@linuxfoundation.org> References: <20211004125033.572932188@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