Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp4137795pxb; Mon, 27 Sep 2021 10:09:11 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz38+JY1SUEG/Up3a5YXItm1NYm4L/t7dnbwyMZr6eBkE353qsZaOzUgrSUZAMiE/Cnj5V6 X-Received: by 2002:a17:90a:7:: with SMTP id 7mr213101pja.0.1632762551191; Mon, 27 Sep 2021 10:09:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632762551; cv=none; d=google.com; s=arc-20160816; b=i6oo39iwxNfL3e/TBII3sdSetAsZMsIMCd7jzN5WveX1rzYwENZnLKt9GMJOdfhCNc fjKiRoLoyg6bgqhoencgBX3cJmJ7iufzAFOyMa26aHCfkp4svUHDwdmqQx6w7oyLxN5D Lg6VCqm11KRC+SG8k7qylYwDuSgjy9oT/7Qlsyd5wfOAS9Q0uTULpdCxRVh91ApkAnZl eE4201ZqXiglSIKAqcteY9pBPImF2ncQ4SNcliI+7LS4imcjt2e166/YsPe1WxcaLEUZ ssFfWLQymNe5ThQzm40IulNjGCccMB0ANNQxhN8HWrdrhjhnrdvhelrKjUzNyWlalZ7g MbcQ== 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=waS1UG1EoDm0HfZMvsQ2ubk6oiyL6csy0apZ4hQ1bixQQLEW78VqFl5ra8OtjKnYc0 oPajR7sGrB0LLKIMqMytywezXvc2td6qqGV1cjRKHJp4vYzrhv3UvkckOHEczB/rwboT oz5X0AGR07IGiIheW0fx9ZiQjrG9pUHg5J2RkovL5gOkK22RCZho3/wTQm0uSKcA8qqs cXD5g3E/eA/uT4BwC3C/2dxLBl58y08EHtf9B00HysV1r7X5mc1V4IR5xjXceYY9xwhw CG6EaUj5Arm5jZNmW37iVO+ugGcpxFNEGgZCrs7K3SVCX/ewv8S9RVyAVZJVnf2qZoYe yrqw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=pMIl64iF; 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 x66si18103149pfx.208.2021.09.27.10.08.58; Mon, 27 Sep 2021 10:09:11 -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=pMIl64iF; 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 S236001AbhI0RId (ORCPT + 99 others); Mon, 27 Sep 2021 13:08:33 -0400 Received: from mail.kernel.org ([198.145.29.99]:46362 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236206AbhI0RHa (ORCPT ); Mon, 27 Sep 2021 13:07:30 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id ED70960F70; Mon, 27 Sep 2021 17:05:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632762352; bh=2x/8C7RGicmM784+vbWKsqQcHRNQFf3C1wuczzZL2ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pMIl64iFp+7fJp1I8qfsVBIGeTDnHA7E0GzD6wPYa3UA/QmN7k0ESCg9B4U3REmnO JePbXheSBwgYc56NNZTATwFu8z6SITLAyd0tlztAMO/M4NTck6oy6QIuQIgXKFF9Zk c+1DFdBeECCTb9KD4IW3CKrdyiiQmNg9a/GGVH9o= 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.4 58/68] qnx4: avoid stringop-overread errors Date: Mon, 27 Sep 2021 19:02:54 +0200 Message-Id: <20210927170221.973392903@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210927170219.901812470@linuxfoundation.org> References: <20210927170219.901812470@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