From patchwork Wed Dec 15 22:11:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Campbell Suter X-Patchwork-Id: 1568828 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=Eo8FZcia; 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 4JDqGH111sz9sVq for ; Thu, 16 Dec 2021 09:11:32 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 9472880F90; Wed, 15 Dec 2021 23:11:23 +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="Eo8FZcia"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9B98080379; Wed, 15 Dec 2021 23:11:21 +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-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) (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 B644280379 for ; Wed, 15 Dec 2021 23:11:16 +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-x62b.google.com with SMTP id u17so17726644plg.9 for ; Wed, 15 Dec 2021 14:11:16 -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=C3xmcUrwGZebN7H5HvdMywbnmgSYqbyFzUDHVymYuBU=; b=Eo8FZciabQrPhF/ItWzcHh9Ub47wiPiMwzHrgF3nMdiUy+zNkK7csQNhw4ET+ysDD0 fJMHa7P956csFiU35DZmG2o8PK3XQqH3fHzwWrEtGGrA/+7Tsy/5nEWfl04pUCDRCAIJ nsERTrazvDs3QFX8KcKeqzUeRVlhHCM5KH0gU= 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=C3xmcUrwGZebN7H5HvdMywbnmgSYqbyFzUDHVymYuBU=; b=X49k1B2/ijO03V1wXMQIhXUwp9zhBZkcpTAhyqh4Bb3o5X8VwuPV6gv8zBLkjXn+/T KZaEwyvzcdwzZs0wcKjyl/BE77SSCqRIIJu65RCBHOv9DKqh7leinC59PtNJr0uQD2cL RQzx1BA+Ky36Z1sMjzywGOQ2htZc7mSeBxG4cHG9NOZmIT5WehRHtOOOK+E4Dz9vDurg tuybVrXbJ4ucCy1hVjOw0FuCer8TR+HHTdCZa818zCw/wSfj+/T+W4hsrQ67pduz+hp7 EGBqBTTrfa0GjJC8YIGTelsjIh5nTHrDvXAVxFC5U+Tr2eaEXSjdENBy4S/5E+Xt5/vs uzXg== X-Gm-Message-State: AOAM530l02y7fXHz5vaDeNOVq743DqP/UAMeAtntkLMYTLXChXsT8a8z 8Ycbm86xQJiw0KF3ME+KJSDR0prwb5Qjhvf4olSrjtKjGhdhwUF8VBIvVGQeC1GiefzPe01lGkl nojeQ14nBftTyfYLjJnyrwhscoWhFVKhG8Pda7LtIpGXBpwkPGPHt4etEZIC0NL6aGCv7XQ== X-Google-Smtp-Source: ABdhPJwi0+d1GXkH6IRYJdVCW52IbQy24aupGuYP9Gubkgf3POYx52BrLOItMiWfJlStexxguI52JQ== X-Received: by 2002:a17:902:f687:b0:141:cf6b:fee7 with SMTP id l7-20020a170902f68700b00141cf6bfee7mr12849727plg.75.1639606274658; Wed, 15 Dec 2021 14:11:14 -0800 (PST) Received: from ?IPV6:2406:e002:b405:9901:2677:4b6b:643:ad5f? ([2406:e002:b405:9901:2677:4b6b:643:ad5f]) by smtp.gmail.com with ESMTPSA id r16sm3160686pgk.45.2021.12.15.14.11.12 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 15 Dec 2021 14:11:14 -0800 (PST) Message-ID: <6b273159-fea1-27df-6b21-a86eb9642af8@snapit.group> Date: Thu, 16 Dec 2021 11:11:10 +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 v2] squashfs: Fix file lookups on appended images 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. V2 of this patch fixes sqfs_opendir directly accessing an inode field, and instead uses the unaligned access function as it should. [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..5c05ddca38 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, (int)get_unaligned_le32(&root_inode->inode_number)); if (ret) goto out;