aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/appimage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/appimage.c')
-rw-r--r--src/firejail/appimage.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
new file mode 100644
index 000000000..0d1f8cb4d
--- /dev/null
+++ b/src/firejail/appimage.c
@@ -0,0 +1,184 @@
1/*
2 * Copyright (C) 2014-2016 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20// http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=770fe30a46a12b6fb6b63fbe1737654d28e84844
21// sudo mount -o loop krita-3.0-x86_64.appimage mnt
22
23#include "firejail.h"
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/mount.h>
27#include <fcntl.h>
28#include <linux/loop.h>
29#include <errno.h>
30
31static char *devloop = NULL; // device file
32static char *mntdir = NULL; // mount point in /tmp directory
33
34void appimage_set(const char *appimage) {
35 assert(appimage);
36 assert(devloop == NULL); // don't call this twice!
37 EUID_ASSERT();
38
39#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h
40 // check appimage file
41 invalid_filename(appimage);
42 if (access(appimage, R_OK) == -1) {
43 fprintf(stderr, "Error: cannot access AppImage file\n");
44 exit(1);
45 }
46
47 // get appimage type and ELF size
48 // a value of 0 means we are dealing with a type1 appimage
49 long unsigned int size = appimage2_size(appimage);
50 if (arg_debug)
51 printf("AppImage ELF size %lu\n", size);
52
53 // open appimage file
54 /* coverity[toctou] */
55 int ffd = open(appimage, O_RDONLY|O_CLOEXEC);
56 if (ffd == -1) {
57 fprintf(stderr, "Error: cannot open AppImage file\n");
58 exit(1);
59 }
60
61 // find or allocate a free loop device to use
62 EUID_ROOT();
63 int cfd = open("/dev/loop-control", O_RDWR);
64 if (cfd == -1) {
65 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n");
66 exit(1);
67 }
68 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE);
69 if (devnr == -1) {
70 fprintf(stderr, "Error: cannot allocate a new loopback device\n");
71 exit(1);
72 }
73 close(cfd);
74 if (asprintf(&devloop, "/dev/loop%d", devnr) == -1)
75 errExit("asprintf");
76
77 int lfd = open(devloop, O_RDONLY);
78 if (lfd == -1) {
79 fprintf(stderr, "Error: cannot open %s\n", devloop);
80 exit(1);
81 }
82 if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) {
83 fprintf(stderr, "Error: cannot configure the loopback device\n");
84 exit(1);
85 }
86
87 if (size) {
88 struct loop_info64 info;
89 memset(&info, 0, sizeof(struct loop_info64));
90 info.lo_offset = size;
91 if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1)
92 errExit("configure appimage offset");
93 }
94
95 close(lfd);
96 close(ffd);
97 EUID_USER();
98
99 // creates appimage mount point perms 0700
100 if (asprintf(&mntdir, "%s/.appimage-%u", RUN_FIREJAIL_APPIMAGE_DIR, getpid()) == -1)
101 errExit("asprintf");
102 EUID_ROOT();
103 mkdir_attr(mntdir, 0700, getuid(), getgid());
104 EUID_USER();
105
106 // mount
107 char *mode;
108 if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1)
109 errExit("asprintf");
110 EUID_ROOT();
111
112 if (size == 0) {
113 if (mount(devloop, mntdir, "iso9660",MS_MGC_VAL|MS_RDONLY, mode) < 0)
114 errExit("mounting appimage");
115 }
116 else {
117 if (mount(devloop, mntdir, "squashfs",MS_MGC_VAL|MS_RDONLY, mode) < 0)
118 errExit("mounting appimage");
119 }
120
121 if (arg_debug)
122 printf("appimage mounted on %s\n", mntdir);
123 EUID_USER();
124
125 // set environment
126 if (setenv("APPIMAGE", appimage, 1) < 0)
127 errExit("setenv");
128 if (mntdir && setenv("APPDIR", mntdir, 1) < 0)
129 errExit("setenv");
130
131 // build new command line
132 if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1)
133 errExit("asprintf");
134
135 free(mode);
136#ifdef HAVE_GCOV
137 __gcov_flush();
138#endif
139#else
140 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n");
141 exit(1);
142#endif
143}
144
145void appimage_clear(void) {
146 int rv;
147
148 EUID_ROOT();
149 if (mntdir) {
150 int i;
151 int rv = 0;
152 for (i = 0; i < 5; i++) {
153 rv = umount2(mntdir, MNT_FORCE);
154 if (rv == 0)
155 break;
156 if (rv == -1 && errno == EBUSY) {
157 if (!arg_quiet)
158 printf("Warning: EBUSY error trying to unmount %s\n", mntdir);
159 sleep(2);
160 continue;
161 }
162
163 // rv = -1
164 if (!arg_quiet) {
165 printf("Warning: error trying to unmount %s\n", mntdir);
166 perror("umount");
167 }
168 }
169
170 if (rv == 0) {
171 rmdir(mntdir);
172 free(mntdir);
173 }
174 }
175
176 if (devloop) {
177 int lfd = open(devloop, O_RDONLY);
178 if (lfd != -1) {
179 rv = ioctl(lfd, LOOP_CLR_FD, 0);
180 (void) rv;
181 close(lfd);
182 }
183 }
184}