Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp4146941pxb; Mon, 27 Sep 2021 10:20:22 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzcyCUG67t8O1vNAEGXDpSYENjiUB7iJL+ZcGSCX9sOR3vuYrvUYILkD+yaG/5IVR/dA52K X-Received: by 2002:aa7:9dda:0:b0:443:6dc4:701e with SMTP id g26-20020aa79dda000000b004436dc4701emr777198pfq.69.1632763222485; Mon, 27 Sep 2021 10:20:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632763222; cv=none; d=google.com; s=arc-20160816; b=Znxd38w/fyBKoVBMy+scy2wCjEKQpOi7MbkPTZNwwDD9HDqr7/MHXerHiCzjVK9/HS 04CEJT26n24WsbuEwtVONw2CnftkdXTZPL7osN0rsoz8MegAQ2dLouJMBS/35czpX3ux FltejTUSecVueMjmfuggv3GWO9jHtKZOFheK/ZVMn4Qm+QC4i+JUZcFum0zsGXWEPxEk U5uTcAKsVuK/TOGIwO+UJqX7IrWciTgYOwWl0jte7jxIdYiYXmGIFadIRln0xkR0xz6x WoKnq+VzEg7G6Vof6jyfw6BNDrRKjpyBYod7jmlmiuuw38at1BLxlV/K7aLLVQDHbtQp chbg== 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=L6xjDVlGguElUm+oMnYcDB6U2QW7gk5Qe4IwGviAmxE=; b=HNEkFKbHNavHbQuMcyQXkW77QcYPN2PppJi1RuJz5gcHfQ9vuJW/H/JDek7f9Z97O1 ZL9rObS/d6G2V3ghfY3+QULK6sQi49i4uWMbyWfEh38nBT6SoRp1fcn2Ujk/zAo8BONT Roh4yyeIm/ECE5tjRhupBJ82MERkGN3JBoIrv8mF2aOe6/82IwSb0v5Dwk57xXoe1kSd FAUVgG14i3Huvv65eQ7xY+rl9HnZ+fEzKrD4rT/zQSq66B5QQpREwtGliY1wNnf43A4E cBJ6dKKG/i2HE9jX76N2H1yOZezrBt9pfhq0AX0gtTmXn2BqUoc6J4iOiGGvb1AAT8uy 5/ig== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=sEj6UZKf; 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 z19si22190675pgj.281.2021.09.27.10.20.06; Mon, 27 Sep 2021 10:20: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=sEj6UZKf; 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 S236926AbhI0RTk (ORCPT + 99 others); Mon, 27 Sep 2021 13:19:40 -0400 Received: from mail.kernel.org ([198.145.29.99]:55390 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236670AbhI0RPO (ORCPT ); Mon, 27 Sep 2021 13:15:14 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 140FC6136F; Mon, 27 Sep 2021 17:10:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632762646; bh=04kIWPn05Hq1DT9FgELgq24nOOVbuN6zG7jDb7g0c10=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sEj6UZKfqnXmSratjaTl+PK0/brdGV1omQqJbLflWb1UAmZLmmhtDXtTwJuYfituv Gi8Pw8yi5+iBXjS9fQwVi7bTSAvdshOeTyGW1SdXjwtMF7dllcosHaip97ZjbKdHCT BpZAoVwMEh2jGebtSpj6G8R7hnDKFPxEFjiJGgD8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Linus Torvalds , Arnd Bergmann Subject: [PATCH 5.10 103/103] qnx4: work around gcc false positive warning bug Date: Mon, 27 Sep 2021 19:03:15 +0200 Message-Id: <20210927170229.335388953@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 commit d5f6545934c47e97c0b48a645418e877b452a992 upstream. In commit b7213ffa0e58 ("qnx4: avoid stringop-overread errors") I tried to teach gcc about how the directory entry structure can be two different things depending on a status flag. It made the code clearer, and it seemed to make gcc happy. However, Arnd points to a gcc bug, where despite using two different members of a union, gcc then gets confused, and uses the size of one of the members to decide if a string overrun happens. And not necessarily the rigth one. End result: with some configurations, gcc-11 will still complain about the source buffer size being overread: fs/qnx4/dir.c: In function 'qnx4_readdir': fs/qnx4/dir.c:76:32: error: 'strnlen' specified bound [16, 48] exceeds source size 1 [-Werror=stringop-overread] 76 | size = strnlen(name, size); | ^~~~~~~~~~~~~~~~~~~ fs/qnx4/dir.c:26:22: note: source object declared here 26 | char de_name; | ^~~~~~~ because gcc will get confused about which union member entry is actually getting accessed, even when the source code is very clear about it. Gcc internally will have combined two "redundant" pointers (pointing to different union elements that are at the same offset), and takes the size checking from one or the other - not necessarily the right one. This is clearly a gcc bug, but we can work around it fairly easily. The biggest thing here is the big honking comment about why we do what we do. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 Reported-and-tested-by: Arnd Bergmann Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/qnx4/dir.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -20,12 +20,33 @@ * 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. + * + * Also, due to a bug in gcc, we don't want to use the + * real (differently sized) name arrays in the inode and + * link entries, but always the 'de_name[]' one in the + * fake struct entry. + * + * See + * + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 + * + * for details, but basically gcc will take the size of the + * 'name' array from one of the used union entries randomly. + * + * This use of 'de_name[]' (48 bytes) avoids the false positive + * warnings that would happen if gcc decides to use 'inode.di_name' + * (16 bytes) even when the pointer and size were to come from + * 'link.dl_name' (48 bytes). + * + * In all cases the actual name pointer itself is the same, it's + * only the gcc internal 'what is the size of this field' logic + * that can get confused. */ union qnx4_directory_entry { struct { - char de_name; - char de_pad[62]; - char de_status; + const char de_name[48]; + u8 de_pad[15]; + u8 de_status; }; struct qnx4_inode_entry inode; struct qnx4_link_info link; @@ -53,29 +74,26 @@ static int qnx4_readdir(struct file *fil 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 = (union qnx4_directory_entry *) (bh->b_data + offset); - if (!de->de_name) + if (!de->de_name[0]) continue; if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) continue; 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 { 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 + de->link.dl_inode_ndx; } - size = strnlen(name, size); + size = strnlen(de->de_name, size); QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name)); - if (!dir_emit(ctx, name, size, ino, DT_UNKNOWN)) { + if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) { brelse(bh); return 0; }