1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * Squashfs - a compressed read only filesystem for Linux
4   *
5   * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
6   * Phillip Lougher <phillip@squashfs.org.uk>
7   *
8   * id.c
9   */
10  
11  /*
12   * This file implements code to handle uids and gids.
13   *
14   * For space efficiency regular files store uid and gid indexes, which are
15   * converted to 32-bit uids/gids using an id look up table.  This table is
16   * stored compressed into metadata blocks.  A second index table is used to
17   * locate these.  This second index table for speed of access (and because it
18   * is small) is read at mount time and cached in memory.
19   */
20  
21  #include <linux/fs.h>
22  #include <linux/vfs.h>
23  #include <linux/slab.h>
24  
25  #include "squashfs_fs.h"
26  #include "squashfs_fs_sb.h"
27  #include "squashfs.h"
28  
29  /*
30   * Map uid/gid index into real 32-bit uid/gid using the id look up table
31   */
squashfs_get_id(struct super_block * sb,unsigned int index,unsigned int * id)32  int squashfs_get_id(struct super_block *sb, unsigned int index,
33  					unsigned int *id)
34  {
35  	struct squashfs_sb_info *msblk = sb->s_fs_info;
36  	int block = SQUASHFS_ID_BLOCK(index);
37  	int offset = SQUASHFS_ID_BLOCK_OFFSET(index);
38  	u64 start_block;
39  	__le32 disk_id;
40  	int err;
41  
42  	if (index >= msblk->ids)
43  		return -EINVAL;
44  
45  	start_block = le64_to_cpu(msblk->id_table[block]);
46  
47  	err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset,
48  							sizeof(disk_id));
49  	if (err < 0)
50  		return err;
51  
52  	*id = le32_to_cpu(disk_id);
53  	return 0;
54  }
55  
56  
57  /*
58   * Read uncompressed id lookup table indexes from disk into memory
59   */
squashfs_read_id_index_table(struct super_block * sb,u64 id_table_start,u64 next_table,unsigned short no_ids)60  __le64 *squashfs_read_id_index_table(struct super_block *sb,
61  		u64 id_table_start, u64 next_table, unsigned short no_ids)
62  {
63  	unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
64  	unsigned int indexes = SQUASHFS_ID_BLOCKS(no_ids);
65  	int n;
66  	__le64 *table;
67  	u64 start, end;
68  
69  	TRACE("In read_id_index_table, length %d\n", length);
70  
71  	/* Sanity check values */
72  
73  	/* there should always be at least one id */
74  	if (no_ids == 0)
75  		return ERR_PTR(-EINVAL);
76  
77  	/*
78  	 * The computed size of the index table (length bytes) should exactly
79  	 * match the table start and end points
80  	 */
81  	if (length != (next_table - id_table_start))
82  		return ERR_PTR(-EINVAL);
83  
84  	table = squashfs_read_table(sb, id_table_start, length);
85  	if (IS_ERR(table))
86  		return table;
87  
88  	/*
89  	 * table[0], table[1], ... table[indexes - 1] store the locations
90  	 * of the compressed id blocks.   Each entry should be less than
91  	 * the next (i.e. table[0] < table[1]), and the difference between them
92  	 * should be SQUASHFS_METADATA_SIZE or less.  table[indexes - 1]
93  	 * should be less than id_table_start, and again the difference
94  	 * should be SQUASHFS_METADATA_SIZE or less
95  	 */
96  	for (n = 0; n < (indexes - 1); n++) {
97  		start = le64_to_cpu(table[n]);
98  		end = le64_to_cpu(table[n + 1]);
99  
100  		if (start >= end || (end - start) >
101  				(SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) {
102  			kfree(table);
103  			return ERR_PTR(-EINVAL);
104  		}
105  	}
106  
107  	start = le64_to_cpu(table[indexes - 1]);
108  	if (start >= id_table_start || (id_table_start - start) >
109  				(SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) {
110  		kfree(table);
111  		return ERR_PTR(-EINVAL);
112  	}
113  
114  	return table;
115  }
116