Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp4146112pxb; Mon, 27 Sep 2021 10:19:17 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxmoWFTvEWoo1wPU8hkIpqqQO+NFXTvJMaOdPlLAr8OsaCqqzgwdhwa7v4K12IFM3QFF1I6 X-Received: by 2002:a17:90a:1a02:: with SMTP id 2mr264544pjk.6.1632763157737; Mon, 27 Sep 2021 10:19:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632763157; cv=none; d=google.com; s=arc-20160816; b=oAFRyy8kzXuaBY0nh2Lt5LfSRffAh4/ar4Qu8UalHbxxeSDLvnDsUtYJDBgmNwl318 u6hQW+GCwoEGJQZ7BOrcX+5Yz/6HEURowkZNFkx5md6tbAYzZFki0oR6w7ef96obfEpc iOZ0hpHSUAhKooDaKUkgC8WLFFkzA+WZ3Hw/ug48D/nmd/mTjtj8++hnkHqKI2EuUOUj 7BZUXs3FZtXjdhjAbn//n6P/3wgYO/sKikmQyB2aKblv+lRIqthamprjL2Fx7YrcFwsa kX1jkam+mrH7FAUbfbPbdJfFWlpY5y3W4OmYD2E0xAO8+J8lKv55XNBRKpAdBvPDFVoX hLSw== 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=iGcuavZjmDZH1LuNxEkxX5XUvYPzDK34I096gFx1ZEkhTiuh3NB684UX1V8hrUX5Bl MNdOIQiATNZkIshE6Igrzfw7I2YSEPzqOGgbZztiSsD/Vy2psnQSJSRAv6q1HOZwweQH WQ+t9CPtCxTV8aZJUdIaFRPq0wc+s+YXqRB+CQ4PLkdVl+2MXIorIT9XNclZVe7OUxKO awQv+x77JnaQW01LQh10md2nR4a4jcLoq30QTefAcJf36jwTUYr5QGICpZVUMMt75lIs LS18y7MylYgnK898fgn0xAajBDUj+WxW0INnHN45bjF5uI6EumxpmsMsxUFriz8ZS6A1 KegQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=twNCCZZZ; 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 v11si22911203pgr.56.2021.09.27.10.19.04; Mon, 27 Sep 2021 10:19:17 -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=twNCCZZZ; 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 S236142AbhI0RTw (ORCPT + 99 others); Mon, 27 Sep 2021 13:19:52 -0400 Received: from mail.kernel.org ([198.145.29.99]:55534 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236686AbhI0RPQ (ORCPT ); Mon, 27 Sep 2021 13:15:16 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5EA9161374; Mon, 27 Sep 2021 17:10:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632762648; bh=2x/8C7RGicmM784+vbWKsqQcHRNQFf3C1wuczzZL2ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=twNCCZZZr99L0i6zgf3+Mk4UN3zCgf1htMuNo7Bz1sb69qbjn2Aq+kBFkGiAJrxJh 4G8s6e5f7R7yriP/wiKnehKANpHjcZwtcdrBLVV1R3IuD2r292Sv1MTJ3KqNxf+M7K i8Wu047HS7VR5zB9xHrhYxL8HqiK7zgUOC7g3Ie8= 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.10 092/103] qnx4: avoid stringop-overread errors Date: Mon, 27 Sep 2021 19:03:04 +0200 Message-Id: <20210927170228.953995670@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210927170225.702078779@linuxfoundation.org> References: <20210927170225.702078779@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