Skip to content

Commit 32dfa04

Browse files
authored
Drop --offset=4096 & improve error messages (#14)
- Drop `--offset=4096` support since it leads to races on Linux <4.8. - Make `squashfs-mount arg1 arg2 --version` early exit for version instead of executing `--version`. - Replace "failed to mount" with actual error from libmount - Use more non-portable `err` and `errx`
1 parent afb254e commit 32dfa04

File tree

1 file changed

+46
-46
lines changed

1 file changed

+46
-46
lines changed

squashfs-mount.c

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,47 @@
1717

1818
#include <libmount/libmount.h>
1919

20-
#define exit_with_error(str) \
20+
#define exit_with_error(...) \
2121
do { \
22-
fputs(str, stderr); \
22+
fprintf(stderr, __VA_ARGS__); \
2323
exit(EXIT_FAILURE); \
2424
} while (0)
2525

2626
static void help(char const *argv0) {
27-
fputs("Usage: ", stderr);
28-
fputs(argv0, stderr);
29-
fputs(" <squashfs file> <mountpoint> [--offset=4096] <command> [args...]\n\n "
30-
" The --offset=4096 option "
31-
"translates to an offset=4096 mount option.\n",
32-
stderr);
33-
exit(EXIT_FAILURE);
27+
exit_with_error(
28+
"Usage: %s <squashfs file> <mountpoint> <command> [args...]\n", argv0);
3429
}
3530

3631
int main(int argc, char **argv) {
3732
struct libmnt_context *cxt;
3833
uid_t uid = getuid();
3934
char *program = argv[0];
40-
int has_offset = 0;
4135
struct stat mnt_stat;
4236

4337
argv++;
4438
argc--;
4539

46-
// Only parse flags up to position 3, we don't want to do arg parsing of the
47-
// command that is going to be executed.
48-
for (int i = 0; i < argc && i < 3; ++i) {
49-
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
40+
// Early exit for -h, --help, -v, --version.
41+
for (int i = 0, num_positional = 0; i < argc && num_positional <= 2; ++i) {
42+
char const *arg = argv[i];
43+
// Skip positional args.
44+
if (arg[0] != '-' || arg[1] == '\0') {
45+
++num_positional;
46+
continue;
47+
}
48+
// Early exit on -h, --help, -v, --version
49+
++arg;
50+
if (strcmp(arg, "h") == 0 || strcmp(arg, "-help") == 0)
5051
help(program);
51-
} else if (strcmp(argv[i], "-v") == 0 ||
52-
strcmp(argv[i], "--version") == 0) {
52+
if (strcmp(arg, "v") == 0 || strcmp(arg, "-version") == 0) {
5353
puts(VERSION);
5454
exit(EXIT_SUCCESS);
5555
}
56+
// Error on unrecognized flags.
57+
errx(EXIT_FAILURE, "Unknown flag %s", argv[i]);
5658
}
5759

58-
// We need at least 3 args
60+
// We need [squashfs_file] [mountpoint] [command]
5961
if (argc < 3)
6062
help(program);
6163

@@ -65,72 +67,70 @@ int main(int argc, char **argv) {
6567
char *mountpoint = *argv++;
6668
argc--;
6769

68-
// The optional offset toggle.
69-
if (strcmp(*argv, "--offset=4096") == 0) {
70-
has_offset = 1;
71-
argv++;
72-
argc--;
73-
}
74-
75-
if (argc == 0)
76-
help(program);
77-
7870
// Check that the mount point exists.
7971
int mnt_status = stat(mountpoint, &mnt_stat);
8072
if (mnt_status)
8173
err(EXIT_FAILURE, "Invalid mount point \"%s\"", mountpoint);
8274
if (!S_ISDIR(mnt_stat.st_mode))
83-
errx(EXIT_FAILURE, "Invalid mount point \"%s\" is not a directory", mountpoint);
75+
errx(EXIT_FAILURE, "Invalid mount point \"%s\" is not a directory",
76+
mountpoint);
8477

8578
// Check that the input squashfs file exists.
8679
int sqsh_status = stat(squashfs_file, &mnt_stat);
8780
if (sqsh_status)
8881
err(EXIT_FAILURE, "Invalid squashfs image file \"%s\"", squashfs_file);
8982
if (!S_ISREG(mnt_stat.st_mode))
90-
errx(EXIT_FAILURE, "Requested squashfs image \"%s\" is not a file", squashfs_file);
83+
errx(EXIT_FAILURE, "Requested squashfs image \"%s\" is not a file",
84+
squashfs_file);
9185

9286
if (unshare(CLONE_NEWNS) != 0)
93-
exit_with_error("Failed to unshare the mount namespace\n");
87+
err(EXIT_FAILURE, "Failed to unshare the mount namespace");
9488

9589
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) != 0)
96-
exit_with_error("Failed to remount \"/\" with MS_SLAVE\n");
90+
err(EXIT_FAILURE, "Failed to remount \"/\" with MS_SLAVE");
9791

9892
// Set real user to root before creating the mount context, otherwise it
9993
// fails.
10094
if (setreuid(0, 0) != 0)
101-
exit_with_error("Failed to setreuid\n");
95+
err(EXIT_FAILURE, "Failed to setreuid\n");
10296

97+
// Configure the mount
10398
// Makes LIBMOUNT_DEBUG=... work.
10499
mnt_init_debug(0);
105100

106101
cxt = mnt_new_context();
107102

108103
if (mnt_context_disable_mtab(cxt, 1) != 0)
109-
exit_with_error("Failed to disable mtab\n");
104+
errx(EXIT_FAILURE, "Failed to disable mtab");
110105

111106
if (mnt_context_set_fstype(cxt, "squashfs") != 0)
112-
exit_with_error("Failed to set fstype to squashfs\n");
113-
114-
char const *mount_options =
115-
has_offset ? "loop,nosuid,nodev,ro,offset=4096" : "loop,nosuid,nodev,ro";
107+
errx(EXIT_FAILURE, "Failed to set fstype to squashfs");
116108

117-
if (mnt_context_append_options(cxt, mount_options) != 0)
118-
exit_with_error("Failed to set mount options\n");
109+
if (mnt_context_append_options(cxt, "loop,nosuid,nodev,ro") != 0)
110+
errx(EXIT_FAILURE, "Failed to set mount options");
119111

120112
if (mnt_context_set_source(cxt, squashfs_file) != 0)
121-
exit_with_error("Failed to set source\n");
113+
errx(EXIT_FAILURE, "Failed to set source");
122114

123115
if (mnt_context_set_target(cxt, mountpoint) != 0)
124-
exit_with_error("Failed to set target\n");
125-
126-
if (mnt_context_mount(cxt) != 0)
127-
exit_with_error("Failed to mount\n");
116+
errx(EXIT_FAILURE, "Failed to set target");
117+
118+
// Attempt to mount
119+
int mount_exit_code = mnt_context_mount(cxt);
120+
if (mount_exit_code != 0) {
121+
char err_buf[BUFSIZ] = {0};
122+
mnt_context_get_excode(cxt, mount_exit_code, err_buf, sizeof(err_buf));
123+
const char *tgt = mnt_context_get_target(cxt);
124+
if (*err_buf != '\0' && tgt != NULL)
125+
exit_with_error("%s: %s\n", tgt, err_buf);
126+
errx(EXIT_FAILURE, "Failed to mount");
127+
}
128128

129129
if (setresuid(uid, uid, uid) != 0)
130-
exit_with_error("setresuid failed\n");
130+
errx(EXIT_FAILURE, "setresuid failed");
131131

132132
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)
133-
exit_with_error("PR_SET_NO_NEW_PRIVS failed\n");
133+
err(EXIT_FAILURE, "PR_SET_NO_NEW_PRIVS failed");
134134

135135
return execvp(argv[0], argv);
136136
}

0 commit comments

Comments
 (0)