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.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
new file mode 100644
index 000000000..a658173eb
--- /dev/null
+++ b/src/firejail/appimage.c
@@ -0,0 +1,176 @@
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
34const char *appimage_getdir(void) {
35 return mntdir;
36}
37
38void appimage_set(const char *appimage_path) {
39 assert(appimage_path);
40 assert(devloop == NULL); // don't call this twice!
41 EUID_ASSERT();
42
43#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h
44 // check appimage_path
45 if (access(appimage_path, R_OK) == -1) {
46 fprintf(stderr, "Error: cannot access AppImage file\n");
47 exit(1);
48 }
49
50 // get appimage type and ELF size
51 // a value of 0 means we are dealing with a type1 appimage
52 long unsigned int size = appimage2_size(appimage_path);
53 if (arg_debug)
54 printf("AppImage ELF size %lu\n", size);
55
56 // open as user to prevent race condition
57 int ffd = open(appimage_path, O_RDONLY|O_CLOEXEC);
58 if (ffd == -1) {
59 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n");
60 exit(1);
61 }
62
63 // find or allocate a free loop device to use
64 EUID_ROOT();
65 int cfd = open("/dev/loop-control", O_RDWR);
66 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE);
67 if (devnr == -1) {
68 fprintf(stderr, "Error: cannot allocate a new loopback device\n");
69 exit(1);
70 }
71 close(cfd);
72 if (asprintf(&devloop, "/dev/loop%d", devnr) == -1)
73 errExit("asprintf");
74
75 int lfd = open(devloop, O_RDONLY);
76 if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) {
77 fprintf(stderr, "Error: cannot configure the loopback device\n");
78 exit(1);
79 }
80
81 if (size) {
82 struct loop_info64 info;
83 memset(&info, 0, sizeof(struct loop_info64));
84 info.lo_offset = size;
85 if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1)
86 errExit("configure appimage offset");
87 }
88
89 close(lfd);
90 close(ffd);
91 EUID_USER();
92
93 // creates appimage mount point perms 0700
94 if (asprintf(&mntdir, "%s/.appimage-%u", RUN_FIREJAIL_APPIMAGE_DIR, getpid()) == -1)
95 errExit("asprintf");
96 EUID_ROOT();
97 mkdir_attr(mntdir, 0700, getuid(), getgid());
98 EUID_USER();
99
100 // mount
101 char *mode;
102 if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1)
103 errExit("asprintf");
104 EUID_ROOT();
105
106 if (size == 0) {
107 if (mount(devloop, mntdir, "iso9660",MS_MGC_VAL|MS_RDONLY, mode) < 0)
108 errExit("mounting appimage");
109 }
110 else {
111 if (mount(devloop, mntdir, "squashfs",MS_MGC_VAL|MS_RDONLY, mode) < 0)
112 errExit("mounting appimage");
113 }
114
115 if (arg_debug)
116 printf("appimage mounted on %s\n", mntdir);
117 EUID_USER();
118
119 // set environment
120 if (appimage_path && setenv("APPIMAGE", appimage_path, 1) < 0)
121 errExit("setenv");
122 if (mntdir && setenv("APPDIR", mntdir, 1) < 0)
123 errExit("setenv");
124
125 // build new command line
126 if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1)
127 errExit("asprintf");
128
129 free(mode);
130#ifdef HAVE_GCOV
131 __gcov_flush();
132#endif
133#else
134 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n");
135 exit(1);
136#endif
137}
138
139void appimage_clear(void) {
140 int rv;
141
142 EUID_ROOT();
143 if (mntdir) {
144 int i;
145 int rv = 0;
146 for (i = 0; i < 5; i++) {
147 rv = umount2(mntdir, MNT_FORCE);
148 if (rv == 0)
149 break;
150 if (rv == -1 && errno == EBUSY) {
151 if (!arg_quiet)
152 printf("Warning: EBUSY error trying to unmount %s\n", mntdir);
153 sleep(2);
154 continue;
155 }
156
157 // rv = -1
158 if (!arg_quiet) {
159 printf("Warning: error trying to unmount %s\n", mntdir);
160 perror("umount");
161 }
162 }
163
164 if (rv == 0) {
165 rmdir(mntdir);
166 free(mntdir);
167 }
168 }
169
170 if (devloop) {
171 int lfd = open(devloop, O_RDONLY);
172 rv = ioctl(lfd, LOOP_CLR_FD, 0);
173 (void) rv;
174 close(lfd);
175 }
176}