From patchwork Wed Dec 15 01:38:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Campbell Suter X-Patchwork-Id: 1567982 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=snapit.group header.i=@snapit.group header.a=rsa-sha256 header.s=shd header.b=Jsx2VeTU; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JDJ993WfSz9sVq for ; Wed, 15 Dec 2021 12:50:19 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0B12F80FF4; Wed, 15 Dec 2021 02:50:09 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=snapit.group Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=snapit.group header.i=@snapit.group header.b="Jsx2VeTU"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 3D90180FF4; Wed, 15 Dec 2021 02:38:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 229CD80FF4 for ; Wed, 15 Dec 2021 02:38:45 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=snapit.group Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=campbell@snapit.group Received: by mail-pl1-x62c.google.com with SMTP id y7so15095268plp.0 for ; Tue, 14 Dec 2021 17:38:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=snapit.group; s=shd; h=message-id:date:mime-version:user-agent:content-language:to:cc:from :subject:content-transfer-encoding; bh=srVzwsL6FRvR9xCy4MsNjkEJLxsIruGBpVaAjpduvFQ=; b=Jsx2VeTU0oJn85wqsBpCPl/81zgJbWib8j4OvH/y4NXZtY06psqbVxEEwnZcEuAlf1 UC121xTgWRI7ToBeIZDmWuaFrWH3sfP5aJFP9U9xC/0dI782X3zbKRDV+qU1YCZ6uD0b 8ugsCBLrpZCdGbUaLxjGQC0xInGketf8mvsJ0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent :content-language:to:cc:from:subject:content-transfer-encoding; bh=srVzwsL6FRvR9xCy4MsNjkEJLxsIruGBpVaAjpduvFQ=; b=EhhnQ84XxAjl3uuFpdEPRTbTV/0KTfk5eKqGJphLiYbvb8AGhyBMWWxV1uKRjOG5Ul cXfkaLw+jBtQUlbX/MVx65xc22x1akhTUgzJSUR5kxi/1G7cM3V/EWsTi1FGQEjb4OM9 Y20bCdpgDt0tc6/1BTIpy2hIIRI6ifIYuRY3J+6bdpqqjqvSsECZHSBK37k9yH2MjaS5 P3qMpzB65IV/qSXTwv6pJalGpKo1pSYgHj7ZHdy8tr8vbOZ2UIvM/h+GzBuHjnI98iHX OFg2rfqWfF7N6S2lXB7vdjGEsU1o/C9cdMyzX/f2xPZDIlPUBlJIQ5zNAVT7K/8PTC6b A4Mw== X-Gm-Message-State: AOAM530rsZspSo071R1bG/QFztoczgPY7MjRrNLTI+kZ8o8G3sVKn93G hUJXPABoy4TXh4SFlyh7qr5oCKqaqSM6oc/ylD23gWGsUT7zaJIJq3Flq8NUe1eCmc1QtjFO4LV mvsDg9y14Zuu4VYYa+VHB05955fsBTYvQ2oqqF2/qYzVp8Ov84uCaMh+zsqc074WwULuXTw== X-Google-Smtp-Source: ABdhPJzWF4b/xlAm1zswy3WVw5nNIAGUGEuv7CKcj7Hz6wkcb6+rHER+Fo2HQvHIeC9Z/ugEEZjnOg== X-Received: by 2002:a17:902:a587:b0:148:aa3a:2aac with SMTP id az7-20020a170902a58700b00148aa3a2aacmr105246plb.73.1639532322747; Tue, 14 Dec 2021 17:38:42 -0800 (PST) Received: from ?IPV6:2406:e002:b403:e201:4fe5:a777:7604:98b? ([2406:e002:b403:e201:4fe5:a777:7604:98b]) by smtp.gmail.com with ESMTPSA id h13sm320201pfv.84.2021.12.14.17.38.40 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 14 Dec 2021 17:38:42 -0800 (PST) Message-ID: <7e247ec7-34ba-c1f7-01a4-ea7790b0c7c0@snapit.group> Date: Wed, 15 Dec 2021 14:38:38 +1300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.3.0 Content-Language: en-GB To: u-boot@lists.denx.de Cc: Joao Marcos Costa , Miquel Raynal , Thomas Petazzoni From: Campbell Suter Subject: [PATCH] squashfs: Fix file lookups on appended images X-Mailman-Approved-At: Wed, 15 Dec 2021 02:50:07 +0100 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.38 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Previously, sqfs_search_dir assumed that the root inode has the highest available ID. Unfortunately, this fails on appended images (those where you run mksquashfs multiple times) since the inodes there are arranged differently to those on a regular image. The squashfs format does contain a reference to the root inode. Unfortunately, it's stored as it's compressed block address and a byte offset into that block[1]. The only place we have access to that information is in sqfs_read_inode_table, so while it's ugly we find the root inode there and pass it back for later use. [1] In https://github.com/plougher/squashfs-tools/tree/b6f80b53: squashfs-tools/squashfs_fs.h line 154 squashfs-tools/read_fs.c line 950 Signed-off-by: Campbell Suter --- fs/squashfs/sqfs.c | 65 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/fs/squashfs/sqfs.c b/fs/squashfs/sqfs.c index e2d91c654c..d8014a7a79 100644 --- a/fs/squashfs/sqfs.c +++ b/fs/squashfs/sqfs.c @@ -442,7 +442,7 @@ static char *sqfs_resolve_symlink(struct squashfs_symlink_inode *sym, * table. */ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list, - int token_count, u32 *m_list, int m_count) + int token_count, u32 *m_list, int m_count, int root_inode) { struct squashfs_super_block *sblk = ctxt.sblk; char *path, *target, **sym_tokens, *res, *rem; @@ -463,7 +463,7 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list, dirsp = (struct fs_dir_stream *)dirs; /* Start by root inode */ - table = sqfs_find_inode(dirs->inode_table, le32_to_cpu(sblk->inodes), + table = sqfs_find_inode(dirs->inode_table, root_inode, sblk->inodes, sblk->block_size); dir = (struct squashfs_dir_inode *)table; @@ -576,7 +576,7 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list, dirs->entry = NULL; ret = sqfs_search_dir(dirs, sym_tokens, token_count, - m_list, m_count); + m_list, m_count, root_inode); goto out; } else if (!sqfs_is_dir(get_unaligned_le16(&dir->inode_type))) { printf("** Cannot find directory. **\n"); @@ -684,15 +684,17 @@ static int sqfs_get_metablk_pos(u32 *pos_list, void *table, u32 offset, return ret; } -static int sqfs_read_inode_table(unsigned char **inode_table) +static int sqfs_read_inode_table(unsigned char **inode_table, + const struct squashfs_base_inode **root_inode) { struct squashfs_super_block *sblk = ctxt.sblk; - u64 start, n_blks, table_offset, table_size; + u64 start, n_blks, table_offset, src_table_pos = 0, table_size; int j, ret = 0, metablks_count; unsigned char *src_table, *itb; u32 src_len, dest_offset = 0; unsigned long dest_len = 0; bool compressed; + u64 root_inode_block, root_inode_offset; table_size = get_unaligned_le64(&sblk->directory_table_start) - get_unaligned_le64(&sblk->inode_table_start); @@ -701,6 +703,13 @@ static int sqfs_read_inode_table(unsigned char **inode_table) n_blks = sqfs_calc_n_blks(sblk->inode_table_start, sblk->directory_table_start, &table_offset); + /* + * Value to indicate 'not found' - set it here so that it's not unset + * in case of an error. + */ + if (root_inode) + *root_inode = NULL; + /* Allocate a proper sized buffer (itb) to store the inode table */ itb = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz); if (!itb) @@ -733,8 +742,34 @@ static int sqfs_read_inode_table(unsigned char **inode_table) src_table = itb + table_offset + SQFS_HEADER_SIZE; + /* + * While we're here, find the root inode. It's specified by an on-disk + * block position and offset, which we can't look up anywhere else if + * the metadata is compressed. Thus find it's inode index, which can + * later be used to look it up. + * + * Note that while directory entries also have these offset + * parameters, they also include the inode number which is what this + * implementation uses to look them up. + */ + root_inode_block = (u64)le64_to_cpu(sblk->root_inode) >> 16; + root_inode_offset = (u64)le64_to_cpu(sblk->root_inode) & 0xffff; + /* Extract compressed Inode table */ for (j = 0; j < metablks_count; j++) { + /* + * Check if we're at the raw block offset the root inode is + * specified to live at, and if so point the root inode to + * where it's about to end up. + * + * Note we're doing this now, before dest_offset has been + * pointed to the next block. + */ + if (src_table_pos == root_inode_block && root_inode) { + *root_inode = (const struct squashfs_base_inode *) + (*inode_table + dest_offset + root_inode_offset); + } + sqfs_read_metablock(itb, table_offset, &compressed, &src_len); if (compressed) { dest_len = SQFS_METADATA_BLOCK_SIZE; @@ -749,8 +784,8 @@ static int sqfs_read_inode_table(unsigned char **inode_table) dest_offset += dest_len; } else { - memcpy(*inode_table + (j * SQFS_METADATA_BLOCK_SIZE), - src_table, src_len); + memcpy(*inode_table + dest_offset, src_table, src_len); + dest_offset += SQFS_METADATA_BLOCK_SIZE; } /* @@ -760,6 +795,17 @@ static int sqfs_read_inode_table(unsigned char **inode_table) table_offset += src_len + SQFS_HEADER_SIZE; src_table += src_len + SQFS_HEADER_SIZE; + src_table_pos += src_len + SQFS_HEADER_SIZE; + } + + /* + * If we couldn't find the inode, return an error to reduce the chance + * someone will try to index this null pointer. + */ + if (root_inode && !*root_inode) { + printf("Failed to locate root squashfs inode.\n"); + ret = -ENOENT; + goto free_itb; } free_itb: @@ -875,6 +921,7 @@ int sqfs_opendir(const char *filename, struct fs_dir_stream **dirsp) struct squashfs_dir_stream *dirs; char **token_list = NULL, *path = NULL; u32 *pos_list = NULL; + const struct squashfs_base_inode *root_inode = NULL; dirs = calloc(1, sizeof(*dirs)); if (!dirs) @@ -887,7 +934,7 @@ int sqfs_opendir(const char *filename, struct fs_dir_stream **dirsp) dirs->inode_table = NULL; dirs->dir_table = NULL; - ret = sqfs_read_inode_table(&inode_table); + ret = sqfs_read_inode_table(&inode_table, &root_inode); if (ret) { ret = -EINVAL; goto out; @@ -929,7 +976,7 @@ int sqfs_opendir(const char *filename, struct fs_dir_stream **dirsp) dirs->inode_table = inode_table; dirs->dir_table = dir_table; ret = sqfs_search_dir(dirs, token_list, token_count, pos_list, - metablks_count); + metablks_count, root_inode->inode_number); if (ret) goto out;