Cherry-pick upstream fix for fcopy usage with private-lib
Closes: #973756
Reiner Herrmann
3 years ago
0 | From: smitsohu <smitsohu@gmail.com> | |
1 | Subject: [PATCH] add PATH_FCOPY to private-lib automatically | |
2 | Bug: https://github.com/netblue30/firejail/issues/3741 | |
3 | Bug-Debian: https://bugs.debian.org/973756 | |
4 | Origin: upstream, commits a274ad1 and 04cdc12 | |
5 | ||
6 | restore 45304621a6c600d8e30e98bfbef05149caaf56c5, but now run | |
7 | fldd as root user. This became necessary because in the meantime | |
8 | read permission on helper executables was removed. | |
9 | ||
10 | Puts infrastructure in place to add other helper binaries to | |
11 | private-lib as well, should the need arise. | |
12 | ||
13 | --- a/src/firejail/fs_lib.c | |
14 | +++ b/src/firejail/fs_lib.c | |
15 | @@ -28,6 +28,7 @@ | |
16 | #define MAXBUF 4096 | |
17 | ||
18 | extern void fslib_install_stdc(void); | |
19 | +extern void fslib_install_firejail(void); | |
20 | extern void fslib_install_system(void); | |
21 | ||
22 | static int lib_cnt = 0; | |
23 | @@ -137,33 +138,22 @@ | |
24 | lib_cnt++; | |
25 | } | |
26 | ||
27 | - | |
28 | // requires full path for lib | |
29 | // it could be a library or an executable | |
30 | // lib is not copied, only libraries used by it | |
31 | -void fslib_copy_libs(const char *full_path) { | |
32 | - assert(full_path); | |
33 | - if (arg_debug || arg_debug_private_lib) | |
34 | - printf(" fslib_copy_libs %s\n", full_path); | |
35 | - | |
36 | - // if library/executable does not exist or the user does not have read access to it | |
37 | - // print a warning and exit the function. | |
38 | - if (access(full_path, R_OK)) { | |
39 | - if (arg_debug || arg_debug_private_lib) | |
40 | - printf("cannot find %s for private-lib, skipping...\n", full_path); | |
41 | - return; | |
42 | - } | |
43 | - | |
44 | +static void fslib_copy_libs(const char *full_path, unsigned mask) { | |
45 | // create an empty RUN_LIB_FILE and allow the user to write to it | |
46 | unlink(RUN_LIB_FILE); // in case is there | |
47 | create_empty_file_as_root(RUN_LIB_FILE, 0644); | |
48 | - if (chown(RUN_LIB_FILE, getuid(), getgid())) | |
49 | - errExit("chown"); | |
50 | + if (mask & SBOX_USER) { | |
51 | + if (chown(RUN_LIB_FILE, getuid(), getgid())) | |
52 | + errExit("chown"); | |
53 | + } | |
54 | ||
55 | // run fldd to extract the list of files | |
56 | if (arg_debug || arg_debug_private_lib) | |
57 | printf(" running fldd %s\n", full_path); | |
58 | - sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); | |
59 | + sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); | |
60 | ||
61 | // open the list of libraries and install them on by one | |
62 | FILE *fp = fopen(RUN_LIB_FILE, "r"); | |
63 | @@ -182,6 +172,34 @@ | |
64 | unlink(RUN_LIB_FILE); | |
65 | } | |
66 | ||
67 | +void fslib_copy_libs_parse_as_root(const char *full_path) { | |
68 | + assert(full_path); | |
69 | + if (arg_debug || arg_debug_private_lib) | |
70 | + printf(" fslib_copy_libs_parse_as_root %s\n", full_path); | |
71 | + | |
72 | + struct stat s; | |
73 | + if (stat(full_path, &s)) { | |
74 | + if (arg_debug || arg_debug_private_lib) | |
75 | + printf("cannot find %s for private-lib, skipping...\n", full_path); | |
76 | + return; | |
77 | + } | |
78 | + fslib_copy_libs(full_path, SBOX_ROOT); | |
79 | +} | |
80 | + | |
81 | +// if library/executable does not exist or the user does not have read access to it | |
82 | +// print a warning and exit the function. | |
83 | +void fslib_copy_libs_parse_as_user(const char *full_path) { | |
84 | + assert(full_path); | |
85 | + if (arg_debug || arg_debug_private_lib) | |
86 | + printf(" fslib_copy_libs_parse_as_user %s\n", full_path); | |
87 | + | |
88 | + if (access(full_path, R_OK)) { | |
89 | + if (arg_debug || arg_debug_private_lib) | |
90 | + printf("cannot find %s for private-lib, skipping...\n", full_path); | |
91 | + return; | |
92 | + } | |
93 | + fslib_copy_libs(full_path, SBOX_USER); | |
94 | +} | |
95 | ||
96 | void fslib_copy_dir(const char *full_path) { | |
97 | assert(full_path); | |
98 | @@ -236,7 +254,7 @@ | |
99 | access(fname, X_OK) != 0) // don't duplicate executables, just install the libraries | |
100 | fslib_duplicate(fname); | |
101 | ||
102 | - fslib_copy_libs(fname); | |
103 | + fslib_copy_libs_parse_as_user(fname); | |
104 | } | |
105 | } | |
106 | } | |
107 | @@ -379,25 +397,12 @@ | |
108 | printf("Installing standard C library\n"); | |
109 | fslib_install_stdc(); | |
110 | ||
111 | - // start timetrace | |
112 | - timetrace_start(); | |
113 | - | |
114 | - // bring in firejail executable libraries in case we are redirected here by a firejail symlink from /usr/local/bin/firejail | |
115 | + // install other libraries needed by firejail | |
116 | if (arg_debug || arg_debug_private_lib) | |
117 | printf("Installing Firejail libraries\n"); | |
118 | - fslib_install_list(PATH_FIREJAIL); | |
119 | - | |
120 | - // bring in firejail directory | |
121 | - fslib_install_list(LIBDIR "/firejail"); | |
122 | - | |
123 | - // bring in dhclient libraries | |
124 | - if (any_dhcp()) { | |
125 | - if (arg_debug || arg_debug_private_lib) | |
126 | - printf("Installing dhclient libraries\n"); | |
127 | - fslib_install_list(RUN_MNT_DIR "/dhclient"); | |
128 | - } | |
129 | - fmessage("Firejail libraries installed in %0.2f ms\n", timetrace_end()); | |
130 | + fslib_install_firejail(); | |
131 | ||
132 | + // start timetrace | |
133 | timetrace_start(); | |
134 | ||
135 | // copy the libs in the new lib directory for the main exe | |
136 | --- a/src/firejail/fs_lib2.c | |
137 | +++ b/src/firejail/fs_lib2.c | |
138 | @@ -22,7 +22,8 @@ | |
139 | #include <sys/stat.h> | |
140 | ||
141 | extern void fslib_duplicate(const char *full_path); | |
142 | -extern void fslib_copy_libs(const char *full_path); | |
143 | +extern void fslib_copy_libs_parse_as_user(const char *full_path); | |
144 | +extern void fslib_copy_libs_parse_as_root(const char *full_path); | |
145 | extern void fslib_copy_dir(const char *full_path); | |
146 | ||
147 | //*************************************************************** | |
148 | @@ -123,6 +124,52 @@ | |
149 | fmessage("Standard C library installed in %0.2f ms\n", timetrace_end()); | |
150 | } | |
151 | ||
152 | +//*************************************************************** | |
153 | +// Firejail libraries | |
154 | +//*************************************************************** | |
155 | + | |
156 | +static void fdir(void) { | |
157 | + fslib_copy_dir(LIBDIR "/firejail"); | |
158 | + | |
159 | + // executables and libraries from firejail directory | |
160 | + static const char * const fbin[] = { | |
161 | + PATH_FCOPY, // currently sufficient to find all needed libraries | |
162 | + // PATH_FSECCOMP, | |
163 | + // PATH_FSEC_OPTIMIZE, | |
164 | + // PATH_FSEC_PRINT, | |
165 | + // RUN_FIREJAIL_LIB_DIR "/libtrace.so", | |
166 | + // RUN_FIREJAIL_LIB_DIR "/libtracelog.so", | |
167 | + // RUN_FIREJAIL_LIB_DIR "/libpostexecseccomp.so", | |
168 | + NULL, | |
169 | + }; | |
170 | + | |
171 | + // need to run fldd as root user, unprivileged users have no read permission on executables | |
172 | + int i; | |
173 | + for (i = 0; fbin[i]; i++) | |
174 | + fslib_copy_libs_parse_as_root(fbin[i]); | |
175 | +} | |
176 | + | |
177 | +void fslib_install_firejail(void) { | |
178 | + timetrace_start(); | |
179 | + // bring in firejail executable libraries, in case we are redirected here | |
180 | + // by a firejail symlink from /usr/local/bin/firejail | |
181 | + fslib_copy_libs_parse_as_user(PATH_FIREJAIL); | |
182 | + | |
183 | + // bring in firejail directory | |
184 | + fdir(); | |
185 | + | |
186 | + // bring in dhclient libraries | |
187 | + if (any_dhcp()) | |
188 | + fslib_copy_libs_parse_as_user(RUN_MNT_DIR "/dhclient"); | |
189 | + | |
190 | +#ifdef HAVE_X11 | |
191 | + // bring in xauth libraries | |
192 | + if (arg_x11_xorg) | |
193 | + fslib_copy_libs_parse_as_user("/usr/bin/xauth"); | |
194 | +#endif | |
195 | + | |
196 | + fmessage("Firejail libraries installed in %0.2f ms\n", timetrace_end()); | |
197 | +} | |
198 | ||
199 | //*************************************************************** | |
200 | // various system libraries | |
201 | @@ -268,7 +315,7 @@ | |
202 | if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir1) == -1) | |
203 | errExit("asprintf"); | |
204 | if (access(name, R_OK) == 0) { | |
205 | - fslib_copy_libs(name); | |
206 | + fslib_copy_libs_parse_as_user(name); | |
207 | fslib_copy_dir(name); | |
208 | } | |
209 | else { | |
210 | @@ -277,7 +324,7 @@ | |
211 | if (asprintf(&name, "/usr/lib64/%s", ptr->dir1) == -1) | |
212 | errExit("asprintf"); | |
213 | if (access(name, R_OK) == 0) { | |
214 | - fslib_copy_libs(name); | |
215 | + fslib_copy_libs_parse_as_user(name); | |
216 | fslib_copy_dir(name); | |
217 | } | |
218 | } | |
219 | @@ -288,7 +335,7 @@ | |
220 | if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir2) == -1) | |
221 | errExit("asprintf"); | |
222 | if (access(name, R_OK) == 0) { | |
223 | - fslib_copy_libs(name); | |
224 | + fslib_copy_libs_parse_as_user(name); | |
225 | fslib_copy_dir(name); | |
226 | } | |
227 | else { | |
228 | @@ -297,7 +344,7 @@ | |
229 | if (asprintf(&name, "/usr/lib64/%s", ptr->dir2) == -1) | |
230 | errExit("asprintf"); | |
231 | if (access(name, R_OK) == 0) { | |
232 | - fslib_copy_libs(name); | |
233 | + fslib_copy_libs_parse_as_user(name); | |
234 | fslib_copy_dir(name); | |
235 | } | |
236 | } | |
237 | --- a/src/firejail/sbox.c | |
238 | +++ b/src/firejail/sbox.c | |
239 | @@ -203,15 +203,16 @@ | |
240 | } | |
241 | } | |
242 | ||
243 | - if (filtermask & SBOX_ROOT) { | |
244 | + if (filtermask & SBOX_USER) | |
245 | + drop_privs(1); | |
246 | + else if (filtermask & SBOX_ROOT) { | |
247 | // elevate privileges in order to get grsecurity working | |
248 | if (setreuid(0, 0)) | |
249 | errExit("setreuid"); | |
250 | if (setregid(0, 0)) | |
251 | errExit("setregid"); | |
252 | } | |
253 | - else if (filtermask & SBOX_USER) | |
254 | - drop_privs(1); | |
255 | + else assert(0); | |
256 | ||
257 | if (arg[0]) { // get rid of scan-build warning | |
258 | int fd = open(arg[0], O_PATH | O_CLOEXEC); |