1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2021 Joerg Vehlow <joerg.vehlow@aox-tech.de>
4 */
5
6 /*\
7 * [Description]
8 *
9 * Kernel commits
10 *
11 * - f37aa4c7366 (squashfs: add more sanity checks in id lookup)
12 * - eabac19e40c (squashfs: add more sanity checks in inode lookup)
13 * - 506220d2ba2 (squashfs: add more sanity checks in xattr id lookup)
14 *
15 * added some sanity checks, that verify the size of
16 * inode lookup, id (uid/gid) and xattr blocks in the squashfs,
17 * but broke mounting filesystems with completely filled blocks.
18 * A block has a max size of 8192.
19 * An inode lookup entry has an uncompressed size of 8 bytes,
20 * an id block 4 bytes and an xattr block 16 bytes.
21 *
22 *
23 * To fill up at least one block for each of the three tables,
24 * 2048 files with unique uid/gid and xattr are created.
25 *
26 *
27 * The bugs are fixed in kernel commits
28 *
29 * - c1b2028315c (squashfs: fix inode lookup sanity checks)
30 * - 8b44ca2b634 (squashfs: fix xattr id and id lookup sanity checks)
31 */
32
33 #include <stdio.h>
34 #include <sys/mount.h>
35
36 #include "tst_test.h"
37 #include "tst_safe_macros.h"
38
39 static const char *MOUNT_DIR = "mnt";
40 static const char *DATA_DIR = "data";
41
42 static int mounted;
43
cleanup(void)44 static void cleanup(void)
45 {
46 if (mounted)
47 SAFE_UMOUNT("mnt");
48 }
49
setup(void)50 static void setup(void)
51 {
52 int i;
53
54 tst_res(TINFO, "Test squashfs sanity check regressions");
55
56 SAFE_MKDIR(DATA_DIR, 0777);
57
58 for (i = 0; i < 2048; ++i) {
59 int fd;
60 char name[20];
61
62 sprintf(name, "%s/%d", DATA_DIR, i);
63 fd = SAFE_OPEN(name, O_CREAT | O_EXCL, 0666);
64 SAFE_FCHOWN(fd, i, i);
65
66 /* This must be either "security", "user" or "trusted" namespace,
67 * because squashfs cannot store other namespaces.
68 * Since the files are most likely created on a tmpfs,
69 * "user" namespace is not possible, because it is not allowed.
70 */
71 SAFE_FSETXATTR(fd, "security.x", &i, sizeof(i), 0);
72 close(fd);
73 }
74
75 /* Create squashfs without any compression.
76 * This allows reasoning about block sizes.
77 * Redirect stdout, to get rid of undefined uid messages
78 */
79 const char *argv[] = {
80 "mksquashfs", DATA_DIR, tst_device->dev,
81 "-noappend", "-noI", "-noD", "-noX", "-noF", NULL
82 };
83 tst_cmd(argv, "/dev/null", NULL, 0);
84
85 SAFE_MKDIR(MOUNT_DIR, 0777);
86 }
87
run(void)88 static void run(void)
89 {
90 if (mount(tst_device->dev, MOUNT_DIR, "squashfs", 0, NULL) != 0)
91 tst_brk(TFAIL | TERRNO, "Mount failed");
92 mounted = 1;
93
94 SAFE_UMOUNT("mnt");
95 mounted = 0;
96
97 tst_res(TPASS, "Regression not detected");
98 }
99
100 static struct tst_test test = {
101 .test_all = run,
102 .cleanup = cleanup,
103 .setup = setup,
104 .needs_root = 1,
105 .needs_device = 1,
106 .dev_min_size = 1,
107 .needs_cmds = (const char *const []) {
108 "mksquashfs",
109 NULL
110 },
111 .needs_drivers = (const char *const []) {
112 "squashfs",
113 NULL
114 },
115 .tags = (const struct tst_tag[]) {
116 {"linux-git", "c1b2028315c"},
117 {"linux-git", "8b44ca2b634"},
118 {}
119 },
120 };
121