diff options
author | 2021-03-14 16:55:36 -0500 | |
---|---|---|
committer | 2021-03-14 16:55:36 -0500 | |
commit | 07f65ab2e53de569a42b2927377a40d89fb8d1af (patch) | |
tree | 432311feee38fb5a06f52366e0ee900fc61d9d9f /src/firejail | |
parent | Merge pull request #4094 from pirate486743186/patch-11 (diff) | |
parent | appimage: calculate elf offset from file descriptor (diff) | |
download | firejail-07f65ab2e53de569a42b2927377a40d89fb8d1af.tar.gz firejail-07f65ab2e53de569a42b2927377a40d89fb8d1af.tar.zst firejail-07f65ab2e53de569a42b2927377a40d89fb8d1af.zip |
Merge pull request #4095 from smitsohu/appimage
make appimage mounts private to sandbox
Diffstat (limited to 'src/firejail')
-rw-r--r-- | src/firejail/appimage.c | 129 | ||||
-rw-r--r-- | src/firejail/appimage_size.c | 22 | ||||
-rw-r--r-- | src/firejail/cmdline.c | 16 | ||||
-rw-r--r-- | src/firejail/firejail.h | 6 | ||||
-rw-r--r-- | src/firejail/fs.c | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 2 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 2 |
7 files changed, 60 insertions, 119 deletions
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index 40e53f44d..59758bf2d 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <errno.h> | 29 | #include <errno.h> |
30 | 30 | ||
31 | static char *devloop = NULL; // device file | 31 | static char *devloop = NULL; // device file |
32 | static char *mntdir = NULL; // mount point in /tmp directory | 32 | static long unsigned size = 0; // offset into appimage file |
33 | 33 | ||
34 | #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h | 34 | #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h |
35 | static void err_loop(void) { | 35 | static void err_loop(void) { |
@@ -44,27 +44,27 @@ void appimage_set(const char *appimage) { | |||
44 | EUID_ASSERT(); | 44 | EUID_ASSERT(); |
45 | 45 | ||
46 | #ifdef LOOP_CTL_GET_FREE | 46 | #ifdef LOOP_CTL_GET_FREE |
47 | // check appimage file | 47 | // open appimage file |
48 | invalid_filename(appimage, 0); // no globbing | 48 | invalid_filename(appimage, 0); // no globbing |
49 | if (access(appimage, R_OK) == -1) { | 49 | int ffd = open(appimage, O_RDONLY|O_CLOEXEC); |
50 | fprintf(stderr, "Error: cannot access AppImage file\n"); | 50 | if (ffd == -1) { |
51 | fprintf(stderr, "Error: cannot read AppImage file\n"); | ||
52 | exit(1); | ||
53 | } | ||
54 | struct stat s; | ||
55 | if (fstat(ffd, &s) == -1) | ||
56 | errExit("fstat"); | ||
57 | if (!S_ISREG(s.st_mode)) { | ||
58 | fprintf(stderr, "Error: invalid AppImage file\n"); | ||
51 | exit(1); | 59 | exit(1); |
52 | } | 60 | } |
53 | 61 | ||
54 | // get appimage type and ELF size | 62 | // get appimage type and ELF size |
55 | // a value of 0 means we are dealing with a type1 appimage | 63 | // a value of 0 means we are dealing with a type1 appimage |
56 | long unsigned int size = appimage2_size(appimage); | 64 | size = appimage2_size(ffd); |
57 | if (arg_debug) | 65 | if (arg_debug) |
58 | printf("AppImage ELF size %lu\n", size); | 66 | printf("AppImage ELF size %lu\n", size); |
59 | 67 | ||
60 | // open appimage file | ||
61 | /* coverity[toctou] */ | ||
62 | int ffd = open(appimage, O_RDONLY|O_CLOEXEC); | ||
63 | if (ffd == -1) { | ||
64 | fprintf(stderr, "Error: cannot open AppImage file\n"); | ||
65 | exit(1); | ||
66 | } | ||
67 | |||
68 | // find or allocate a free loop device to use | 68 | // find or allocate a free loop device to use |
69 | EUID_ROOT(); | 69 | EUID_ROOT(); |
70 | int cfd = open("/dev/loop-control", O_RDWR); | 70 | int cfd = open("/dev/loop-control", O_RDWR); |
@@ -77,6 +77,7 @@ void appimage_set(const char *appimage) { | |||
77 | if (asprintf(&devloop, "/dev/loop%d", devnr) == -1) | 77 | if (asprintf(&devloop, "/dev/loop%d", devnr) == -1) |
78 | errExit("asprintf"); | 78 | errExit("asprintf"); |
79 | 79 | ||
80 | // associate loop device with appimage | ||
80 | int lfd = open(devloop, O_RDONLY); | 81 | int lfd = open(devloop, O_RDONLY); |
81 | if (lfd == -1) | 82 | if (lfd == -1) |
82 | err_loop(); | 83 | err_loop(); |
@@ -90,64 +91,24 @@ void appimage_set(const char *appimage) { | |||
90 | if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1) | 91 | if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1) |
91 | err_loop(); | 92 | err_loop(); |
92 | } | 93 | } |
93 | |||
94 | close(lfd); | 94 | close(lfd); |
95 | close(ffd); | 95 | close(ffd); |
96 | EUID_USER(); | 96 | EUID_USER(); |
97 | 97 | ||
98 | // creates appimage mount point perms 0700 | 98 | // set environment |
99 | if (asprintf(&mntdir, "%s/.appimage-%u", RUN_FIREJAIL_APPIMAGE_DIR, getpid()) == -1) | ||
100 | errExit("asprintf"); | ||
101 | EUID_ROOT(); | ||
102 | mkdir_attr(mntdir, 0700, getuid(), getgid()); | ||
103 | EUID_USER(); | ||
104 | |||
105 | // mount | ||
106 | char *mode; | ||
107 | if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1) | ||
108 | errExit("asprintf"); | ||
109 | unsigned long flags = MS_MGC_VAL|MS_RDONLY; | ||
110 | if (getuid()) | ||
111 | flags |= MS_NODEV|MS_NOSUID; | ||
112 | |||
113 | EUID_ROOT(); | ||
114 | if (size == 0) { | ||
115 | fmessage("Mounting appimage type 1\n"); | ||
116 | if (mount(devloop, mntdir, "iso9660", flags, mode) < 0) | ||
117 | errExit("mounting appimage"); | ||
118 | } | ||
119 | else { | ||
120 | fmessage("Mounting appimage type 2\n"); | ||
121 | if (mount(devloop, mntdir, "squashfs", flags, NULL) < 0) | ||
122 | errExit("mounting appimage"); | ||
123 | } | ||
124 | |||
125 | if (arg_debug) | ||
126 | printf("appimage mounted on %s\n", mntdir); | ||
127 | EUID_USER(); | ||
128 | |||
129 | char* abspath = realpath(appimage, NULL); | 99 | char* abspath = realpath(appimage, NULL); |
130 | if (abspath == NULL) | 100 | if (abspath == NULL) |
131 | errExit("Failed to obtain absolute path"); | 101 | errExit("Failed to obtain absolute path"); |
132 | |||
133 | // set environment | ||
134 | env_store_name_val("APPIMAGE", abspath, SETENV); | 102 | env_store_name_val("APPIMAGE", abspath, SETENV); |
103 | free(abspath); | ||
135 | 104 | ||
136 | if (mntdir) | 105 | env_store_name_val("APPDIR", RUN_FIREJAIL_APPIMAGE_DIR, SETENV); |
137 | env_store_name_val("APPDIR", mntdir, SETENV); | ||
138 | 106 | ||
139 | if (size != 0) | 107 | if (size != 0) |
140 | env_store_name_val("ARGV0", appimage, SETENV); | 108 | env_store_name_val("ARGV0", appimage, SETENV); |
141 | 109 | ||
142 | if (cfg.cwd) | 110 | if (cfg.cwd) |
143 | env_store_name_val("OWD", cfg.cwd, SETENV); | 111 | env_store_name_val("OWD", cfg.cwd, SETENV); |
144 | |||
145 | // build new command line | ||
146 | if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1) | ||
147 | errExit("asprintf"); | ||
148 | |||
149 | free(abspath); | ||
150 | free(mode); | ||
151 | #ifdef HAVE_GCOV | 112 | #ifdef HAVE_GCOV |
152 | __gcov_flush(); | 113 | __gcov_flush(); |
153 | #endif | 114 | #endif |
@@ -157,44 +118,38 @@ void appimage_set(const char *appimage) { | |||
157 | #endif | 118 | #endif |
158 | } | 119 | } |
159 | 120 | ||
160 | void appimage_clear(void) { | 121 | // mount appimage into sandbox file system |
161 | int rv; | 122 | void appimage_mount(void) { |
123 | if (!devloop) | ||
124 | return; | ||
162 | 125 | ||
163 | EUID_ROOT(); | 126 | unsigned long flags = MS_MGC_VAL|MS_RDONLY; |
164 | if (mntdir) { | 127 | if (getuid()) |
165 | int i; | 128 | flags |= MS_NODEV|MS_NOSUID; |
166 | int rv = 0; | ||
167 | for (i = 0; i < 5; i++) { | ||
168 | rv = umount2(mntdir, MNT_FORCE); | ||
169 | if (rv == 0) { | ||
170 | fmessage("AppImage unmounted\n"); | ||
171 | |||
172 | break; | ||
173 | } | ||
174 | if (rv == -1 && errno == EBUSY) { | ||
175 | fwarning("EBUSY error trying to unmount %s\n", mntdir); | ||
176 | sleep(2); | ||
177 | continue; | ||
178 | } | ||
179 | |||
180 | // rv = -1 | ||
181 | if (!arg_quiet) { | ||
182 | fwarning("error trying to unmount %s\n", mntdir); | ||
183 | perror("umount"); | ||
184 | } | ||
185 | } | ||
186 | 129 | ||
187 | if (rv == 0) { | 130 | if (size == 0) { |
188 | rmdir(mntdir); | 131 | fmessage("Mounting appimage type 1\n"); |
189 | free(mntdir); | 132 | char *mode; |
190 | } | 133 | if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1) |
134 | errExit("asprintf"); | ||
135 | if (mount(devloop, RUN_FIREJAIL_APPIMAGE_DIR, "iso9660", flags, mode) < 0) | ||
136 | errExit("mounting appimage"); | ||
137 | free(mode); | ||
191 | } | 138 | } |
139 | else { | ||
140 | fmessage("Mounting appimage type 2\n"); | ||
141 | if (mount(devloop, RUN_FIREJAIL_APPIMAGE_DIR, "squashfs", flags, NULL) < 0) | ||
142 | errExit("mounting appimage"); | ||
143 | } | ||
144 | } | ||
192 | 145 | ||
146 | void appimage_clear(void) { | ||
147 | EUID_ROOT(); | ||
193 | if (devloop) { | 148 | if (devloop) { |
194 | int lfd = open(devloop, O_RDONLY); | 149 | int lfd = open(devloop, O_RDONLY); |
195 | if (lfd != -1) { | 150 | if (lfd != -1) { |
196 | rv = ioctl(lfd, LOOP_CLR_FD, 0); | 151 | if (ioctl(lfd, LOOP_CLR_FD, 0) != -1) |
197 | (void) rv; | 152 | fmessage("AppImage detached\n"); |
198 | close(lfd); | 153 | close(lfd); |
199 | } | 154 | } |
200 | } | 155 | } |
diff --git a/src/firejail/appimage_size.c b/src/firejail/appimage_size.c index 4640cb8a5..43ca501da 100644 --- a/src/firejail/appimage_size.c +++ b/src/firejail/appimage_size.c | |||
@@ -132,22 +132,20 @@ static long unsigned int read_elf64(int fd) { | |||
132 | 132 | ||
133 | // return 0 if error | 133 | // return 0 if error |
134 | // return 0 if this is not an appimgage2 file | 134 | // return 0 if this is not an appimgage2 file |
135 | long unsigned int appimage2_size(const char *fname) { | 135 | long unsigned int appimage2_size(int fd) { |
136 | ssize_t ret; | 136 | ssize_t ret; |
137 | int fd; | ||
138 | long unsigned int size = 0; | 137 | long unsigned int size = 0; |
139 | 138 | ||
140 | fd = open(fname, O_RDONLY); | ||
141 | if (fd < 0) | 139 | if (fd < 0) |
142 | return 0; | 140 | return 0; |
143 | 141 | ||
144 | ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0); | 142 | ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0); |
145 | if (ret != EI_NIDENT) | 143 | if (ret != EI_NIDENT) |
146 | goto getout; | 144 | return 0; |
147 | 145 | ||
148 | if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && | 146 | if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && |
149 | (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) | 147 | (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) |
150 | goto getout; | 148 | return 0; |
151 | 149 | ||
152 | if(ehdr.e_ident[EI_CLASS] == ELFCLASS32) { | 150 | if(ehdr.e_ident[EI_CLASS] == ELFCLASS32) { |
153 | size = read_elf32(fd); | 151 | size = read_elf32(fd); |
@@ -156,23 +154,19 @@ long unsigned int appimage2_size(const char *fname) { | |||
156 | size = read_elf64(fd); | 154 | size = read_elf64(fd); |
157 | } | 155 | } |
158 | else { | 156 | else { |
159 | goto getout; | 157 | return 0; |
160 | } | 158 | } |
161 | if (size == 0) | 159 | if (size == 0) |
162 | goto getout; | 160 | return 0; |
163 | 161 | ||
164 | 162 | ||
165 | // look for a LZMA header at this location | 163 | // look for a LZMA header at this location |
166 | unsigned char buf[4]; | 164 | unsigned char buf[4]; |
167 | ret = pread(fd, buf, 4, size); | 165 | ret = pread(fd, buf, 4, size); |
168 | if (ret != 4) { | 166 | if (ret != 4) |
169 | size = 0; | 167 | return 0; |
170 | goto getout; | ||
171 | } | ||
172 | if (memcmp(buf, "hsqs", 4) != 0) | 168 | if (memcmp(buf, "hsqs", 4) != 0) |
173 | size = 0; | 169 | return 0; |
174 | 170 | ||
175 | getout: | ||
176 | close(fd); | ||
177 | return size; | 171 | return size; |
178 | } | 172 | } |
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c index 0cdcb32bf..f902c4e1c 100644 --- a/src/firejail/cmdline.c +++ b/src/firejail/cmdline.c | |||
@@ -161,18 +161,16 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar | |||
161 | assert(*window_title); | 161 | assert(*window_title); |
162 | } | 162 | } |
163 | 163 | ||
164 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, char *apprun_path) { | 164 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { |
165 | // index == -1 could happen if we have --shell=none and no program was specified | 165 | // index == -1 could happen if we have --shell=none and no program was specified |
166 | // the program should exit with an error before entering this function | 166 | // the program should exit with an error before entering this function |
167 | assert(index != -1); | 167 | assert(index != -1); |
168 | 168 | ||
169 | if (arg_debug) | 169 | char *apprun_path = RUN_FIREJAIL_APPIMAGE_DIR "/AppRun"; |
170 | printf("Building AppImage command line: %s\n", *command_line); | ||
171 | |||
172 | 170 | ||
173 | int len1 = cmdline_length(argc, argv, index); // length of argv w/o changes | 171 | int len1 = cmdline_length(argc, argv, index); // length of argv w/o changes |
174 | int len2 = cmdline_length(1, &argv[index], 0); // apptest.AppImage | 172 | int len2 = cmdline_length(1, &argv[index], 0); // apptest.AppImage |
175 | int len3 = cmdline_length(1, &apprun_path, 0); // /run/firejail/appimage/.appimage-23304/AppRun | 173 | int len3 = cmdline_length(1, &apprun_path, 0); // /run/firejail/appimage/AppRun |
176 | int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun | 174 | int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun |
177 | 175 | ||
178 | if (len4 > ARG_MAX) { | 176 | if (len4 > ARG_MAX) { |
@@ -180,11 +178,6 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
180 | errExit("cmdline_length"); | 178 | errExit("cmdline_length"); |
181 | } | 179 | } |
182 | 180 | ||
183 | // save created apprun in cfg.command_line | ||
184 | char *tmp1 = strdup(*command_line); | ||
185 | if (!tmp1) | ||
186 | errExit("strdup"); | ||
187 | |||
188 | // TODO: deal with extra allocated memory. | 181 | // TODO: deal with extra allocated memory. |
189 | char *command_line_tmp = malloc(len1 + len3 + 1); | 182 | char *command_line_tmp = malloc(len1 + len3 + 1); |
190 | if (!command_line_tmp) | 183 | if (!command_line_tmp) |
@@ -200,13 +193,12 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
200 | assert(*window_title); | 193 | assert(*window_title); |
201 | 194 | ||
202 | // 'fix' command_line now | 195 | // 'fix' command_line now |
203 | if (asprintf(command_line, "'%s' %s", tmp1, command_line_tmp + len2) == -1) | 196 | if (asprintf(command_line, "'%s' %s", apprun_path, command_line_tmp + len2) == -1) |
204 | errExit("asprintf"); | 197 | errExit("asprintf"); |
205 | 198 | ||
206 | if (arg_debug) | 199 | if (arg_debug) |
207 | printf("AppImage quoted command line: %s\n", *command_line); | 200 | printf("AppImage quoted command line: %s\n", *command_line); |
208 | 201 | ||
209 | // free strdup | 202 | // free strdup |
210 | free(tmp1); | ||
211 | free(command_line_tmp); | 203 | free(command_line_tmp); |
212 | } | 204 | } |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index b21b5bef6..ca4c988fa 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -798,15 +798,15 @@ void print_compiletime_support(void); | |||
798 | 798 | ||
799 | // appimage.c | 799 | // appimage.c |
800 | void appimage_set(const char *appimage_path); | 800 | void appimage_set(const char *appimage_path); |
801 | void appimage_mount(void); | ||
801 | void appimage_clear(void); | 802 | void appimage_clear(void); |
802 | const char *appimage_getdir(void); | ||
803 | 803 | ||
804 | // appimage_size.c | 804 | // appimage_size.c |
805 | long unsigned int appimage2_size(const char *fname); | 805 | long unsigned int appimage2_size(int fd); |
806 | 806 | ||
807 | // cmdline.c | 807 | // cmdline.c |
808 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); | 808 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); |
809 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, char *apprun_path); | 809 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); |
810 | 810 | ||
811 | // sbox.c | 811 | // sbox.c |
812 | // programs | 812 | // programs |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 8b7e49611..fc67a15f3 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -801,8 +801,6 @@ void disable_config(void) { | |||
801 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); | 801 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); |
802 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) | 802 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) |
803 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); | 803 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); |
804 | if (!arg_appimage && stat(RUN_FIREJAIL_APPIMAGE_DIR, &s) == 0) | ||
805 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_APPIMAGE_DIR); | ||
806 | } | 804 | } |
807 | 805 | ||
808 | 806 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 9705c2436..b3524fcf5 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -2790,7 +2790,7 @@ int main(int argc, char **argv, char **envp) { | |||
2790 | if (arg_debug) | 2790 | if (arg_debug) |
2791 | printf("Configuring appimage environment\n"); | 2791 | printf("Configuring appimage environment\n"); |
2792 | appimage_set(cfg.command_name); | 2792 | appimage_set(cfg.command_name); |
2793 | build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, cfg.command_line); | 2793 | build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
2794 | } | 2794 | } |
2795 | else { | 2795 | else { |
2796 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 2796 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 36a54d6fe..60c097cf2 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -630,6 +630,8 @@ int sandbox(void* sandbox_arg) { | |||
630 | errExit("mounting " RUN_FIREJAIL_LIB_DIR); | 630 | errExit("mounting " RUN_FIREJAIL_LIB_DIR); |
631 | // keep a copy of dhclient executable before the filesystem is modified | 631 | // keep a copy of dhclient executable before the filesystem is modified |
632 | dhcp_store_exec(); | 632 | dhcp_store_exec(); |
633 | // mount appimage before the filesystem is modified | ||
634 | appimage_mount(); | ||
633 | 635 | ||
634 | //**************************** | 636 | //**************************** |
635 | // log sandbox data | 637 | // log sandbox data |