diff options
-rw-r--r-- | etc/gedit.profile | 3 | ||||
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs_bin.c | 36 | ||||
-rw-r--r-- | src/firejail/fs_lib.c | 171 | ||||
-rw-r--r-- | src/lib/ldd_utils.c | 8 |
5 files changed, 95 insertions, 125 deletions
diff --git a/etc/gedit.profile b/etc/gedit.profile index 62c923f6b..d7ac6d36c 100644 --- a/etc/gedit.profile +++ b/etc/gedit.profile | |||
@@ -38,8 +38,7 @@ tracelog | |||
38 | # private-bin gedit | 38 | # private-bin gedit |
39 | private-dev | 39 | private-dev |
40 | # private-etc fonts | 40 | # private-etc fonts |
41 | # private-lib temporarily disabled pending code fixes | 41 | private-lib /usr/bin/gedit,libtinfo.so.5,libreadline.so.7,gedit,libgspell-1.so.1,gconv,aspell |
42 | #private-lib gedit,libgspell-1.so.1,gconv,aspell | ||
43 | private-tmp | 42 | private-tmp |
44 | 43 | ||
45 | noexec ${HOME} | 44 | noexec ${HOME} |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index d873a36f5..f988dc114 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -53,7 +53,6 @@ | |||
53 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" | 53 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" |
54 | #define RUN_LIB_DIR "/run/firejail/mnt/lib" | 54 | #define RUN_LIB_DIR "/run/firejail/mnt/lib" |
55 | #define RUN_LIB_FILE "/run/firejail/mnt/libfiles" | 55 | #define RUN_LIB_FILE "/run/firejail/mnt/libfiles" |
56 | #define RUN_LIB_BIN "/run/firejail/mnt/binfiles" | ||
57 | #define RUN_DNS_ETC "/run/firejail/mnt/dns-etc" | 56 | #define RUN_DNS_ETC "/run/firejail/mnt/dns-etc" |
58 | 57 | ||
59 | 58 | ||
@@ -224,6 +223,7 @@ typedef struct config_t { | |||
224 | char *opt_private_keep; // keep list for private opt directory | 223 | char *opt_private_keep; // keep list for private opt directory |
225 | char *srv_private_keep; // keep list for private srv directory | 224 | char *srv_private_keep; // keep list for private srv directory |
226 | char *bin_private_keep; // keep list for private bin directory | 225 | char *bin_private_keep; // keep list for private bin directory |
226 | char *bin_private_lib; // executable list sent by private-bin to private-lib | ||
227 | char *lib_private_keep; // keep list for private bin directory | 227 | char *lib_private_keep; // keep list for private bin directory |
228 | char *cwd; // current working directory | 228 | char *cwd; // current working directory |
229 | char *overlay_dir; | 229 | char *overlay_dir; |
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index b0ad35299..5625ed356 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c | |||
@@ -148,7 +148,7 @@ static void report_duplication(const char *fname) { | |||
148 | } | 148 | } |
149 | } | 149 | } |
150 | 150 | ||
151 | static void duplicate(char *fname, FILE *fplist) { | 151 | static void duplicate(char *fname) { |
152 | assert(fname); | 152 | assert(fname); |
153 | 153 | ||
154 | if (*fname == '~' || strstr(fname, "..")) { | 154 | if (*fname == '~' || strstr(fname, "..")) { |
@@ -182,8 +182,18 @@ static void duplicate(char *fname, FILE *fplist) { | |||
182 | errExit("asprintf"); | 182 | errExit("asprintf"); |
183 | } | 183 | } |
184 | 184 | ||
185 | if (fplist) | 185 | // add to private-lib list |
186 | fprintf(fplist, "%s\n", full_path); | 186 | if (cfg.bin_private_lib == NULL) { |
187 | if (asprintf(&cfg.bin_private_lib, "%s,%s",fname, full_path) == -1) | ||
188 | errExit("asprinf"); | ||
189 | } | ||
190 | else { | ||
191 | char *tmp; | ||
192 | if (asprintf(&tmp, "%s,%s,%s", cfg.bin_private_lib, fname, full_path) == -1) | ||
193 | errExit("asprinf"); | ||
194 | free(cfg.bin_private_lib); | ||
195 | cfg.bin_private_lib = tmp; | ||
196 | } | ||
187 | 197 | ||
188 | // if full_path is symlink, and the link is in our path, copy both the file and the symlink | 198 | // if full_path is symlink, and the link is in our path, copy both the file and the symlink |
189 | if (is_link(full_path)) { | 199 | if (is_link(full_path)) { |
@@ -209,14 +219,14 @@ static void duplicate(char *fname, FILE *fplist) { | |||
209 | report_duplication(fname); | 219 | report_duplication(fname); |
210 | } | 220 | } |
211 | 221 | ||
212 | static void globbing(char *fname, FILE *fplist) { | 222 | static void globbing(char *fname) { |
213 | assert(fname); | 223 | assert(fname); |
214 | 224 | ||
215 | // go directly to duplicate() if no globbing char is present - see man 7 glob | 225 | // go directly to duplicate() if no globbing char is present - see man 7 glob |
216 | if (strrchr(fname, '*') == NULL && | 226 | if (strrchr(fname, '*') == NULL && |
217 | strrchr(fname, '[') == NULL && | 227 | strrchr(fname, '[') == NULL && |
218 | strrchr(fname, '?') == NULL) | 228 | strrchr(fname, '?') == NULL) |
219 | return duplicate(fname, fplist); | 229 | return duplicate(fname); |
220 | 230 | ||
221 | // loop through paths[] | 231 | // loop through paths[] |
222 | int i = 0; | 232 | int i = 0; |
@@ -247,7 +257,7 @@ static void globbing(char *fname, FILE *fplist) { | |||
247 | if (strcmp(globbuf.gl_pathv[j], pattern) == 0) | 257 | if (strcmp(globbuf.gl_pathv[j], pattern) == 0) |
248 | continue; | 258 | continue; |
249 | 259 | ||
250 | duplicate(globbuf.gl_pathv[j], fplist); | 260 | duplicate(globbuf.gl_pathv[j]); |
251 | } | 261 | } |
252 | 262 | ||
253 | globfree(&globbuf); | 263 | globfree(&globbuf); |
@@ -274,22 +284,12 @@ void fs_private_bin_list(void) { | |||
274 | if (!dlist) | 284 | if (!dlist) |
275 | errExit("strdup"); | 285 | errExit("strdup"); |
276 | 286 | ||
277 | // save a list of private-bin files in order to bring in private-libs later | ||
278 | FILE *fplist = NULL; | ||
279 | if (arg_private_lib) { | ||
280 | fplist = fopen(RUN_LIB_BIN, "w"); | ||
281 | if (!fplist) | ||
282 | errExit("fopen"); | ||
283 | } | ||
284 | |||
285 | char *ptr = strtok(dlist, ","); | 287 | char *ptr = strtok(dlist, ","); |
286 | globbing(ptr, fplist); | 288 | globbing(ptr); |
287 | while ((ptr = strtok(NULL, ",")) != NULL) | 289 | while ((ptr = strtok(NULL, ",")) != NULL) |
288 | globbing(ptr, fplist); | 290 | globbing(ptr); |
289 | free(dlist); | 291 | free(dlist); |
290 | fs_logger_print(); | 292 | fs_logger_print(); |
291 | if (fplist) | ||
292 | fclose(fplist); | ||
293 | 293 | ||
294 | // mount-bind | 294 | // mount-bind |
295 | int i = 0; | 295 | int i = 0; |
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index 4f8a98fe4..ec12ff01b 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -83,7 +83,7 @@ void fslib_duplicate(const char *full_path) { | |||
83 | free(name); | 83 | free(name); |
84 | 84 | ||
85 | if (arg_debug || arg_debug_private_lib) | 85 | if (arg_debug || arg_debug_private_lib) |
86 | printf("copying %s to private %s\n", full_path, dest_dir); | 86 | printf(" copying %s to private %s\n", full_path, dest_dir); |
87 | 87 | ||
88 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", full_path, dest_dir); | 88 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", full_path, dest_dir); |
89 | report_duplication(full_path); | 89 | report_duplication(full_path); |
@@ -97,7 +97,7 @@ void fslib_duplicate(const char *full_path) { | |||
97 | void fslib_copy_libs(const char *full_path) { | 97 | void fslib_copy_libs(const char *full_path) { |
98 | assert(full_path); | 98 | assert(full_path); |
99 | if (arg_debug || arg_debug_private_lib) | 99 | if (arg_debug || arg_debug_private_lib) |
100 | printf("fslib_copy_libs %s\n", full_path); | 100 | printf(" fslib_copy_libs %s\n", full_path); |
101 | 101 | ||
102 | // if library/executable does not exist or the user does not have read access to it | 102 | // if library/executable does not exist or the user does not have read access to it |
103 | // print a warning and exit the function. | 103 | // print a warning and exit the function. |
@@ -115,7 +115,7 @@ void fslib_copy_libs(const char *full_path) { | |||
115 | 115 | ||
116 | // run fldd to extact the list of files | 116 | // run fldd to extact the list of files |
117 | if (arg_debug || arg_debug_private_lib) | 117 | if (arg_debug || arg_debug_private_lib) |
118 | printf("running fldd %s\n", full_path); | 118 | printf(" running fldd %s\n", full_path); |
119 | sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); | 119 | sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); |
120 | 120 | ||
121 | // open the list of libraries and install them on by one | 121 | // open the list of libraries and install them on by one |
@@ -138,7 +138,7 @@ void fslib_copy_libs(const char *full_path) { | |||
138 | void fslib_copy_dir(const char *full_path) { | 138 | void fslib_copy_dir(const char *full_path) { |
139 | assert(full_path); | 139 | assert(full_path); |
140 | if (arg_debug || arg_debug_private_lib) | 140 | if (arg_debug || arg_debug_private_lib) |
141 | printf("fslib_copy_dir %s\n", full_path); | 141 | printf(" fslib_copy_dir %s\n", full_path); |
142 | 142 | ||
143 | // do nothing if the directory does not exist or is not owned by root | 143 | // do nothing if the directory does not exist or is not owned by root |
144 | struct stat s; | 144 | struct stat s; |
@@ -172,8 +172,10 @@ void fslib_copy_dir(const char *full_path) { | |||
172 | } | 172 | } |
173 | 173 | ||
174 | 174 | ||
175 | // return 1 if the file is valid | 175 | |
176 | static char *valid_file(const char *lib) { | 176 | static void install_list_entry(const char *lib) { |
177 | char *fname = NULL; | ||
178 | |||
177 | // filename check | 179 | // filename check |
178 | int len = strlen(lib); | 180 | int len = strlen(lib); |
179 | if (strcspn(lib, "\\&!?\"'<>%^(){}[];,*") != (size_t)len || | 181 | if (strcspn(lib, "\\&!?\"'<>%^(){}[];,*") != (size_t)len || |
@@ -182,31 +184,68 @@ static char *valid_file(const char *lib) { | |||
182 | exit(1); | 184 | exit(1); |
183 | } | 185 | } |
184 | 186 | ||
187 | // if this is a full path, use it as is | ||
188 | if (*lib == '/') { | ||
189 | fname = strdup(lib); | ||
190 | goto load_library; | ||
191 | } | ||
192 | |||
193 | |||
185 | // find the library | 194 | // find the library |
186 | int i; | 195 | int i; |
187 | for (i = 0; default_lib_paths[i]; i++) { | 196 | for (i = 0; default_lib_paths[i]; i++) { |
188 | char *fname; | ||
189 | if (asprintf(&fname, "%s/%s", default_lib_paths[i], lib) == -1) | 197 | if (asprintf(&fname, "%s/%s", default_lib_paths[i], lib) == -1) |
190 | errExit("asprintf"); | 198 | errExit("asprintf"); |
191 | 199 | ||
192 | // existing file owned by root, read access | 200 | // existing file owned by root, read access |
193 | struct stat s; | 201 | struct stat s; |
194 | if (stat(fname, &s) == 0 && s.st_uid == 0 && !access(fname, R_OK)) { | 202 | if (stat(fname, &s) == 0 && s.st_uid == 0 && !access(fname, R_OK)) { |
195 | if (is_dir(fname)) | 203 | // load directories and regular 64 bit libraries |
196 | return fname; | 204 | if (is_dir(fname) || is_lib_64(fname)) |
197 | // for regular libraries check if it is 64bit | 205 | goto load_library; |
198 | if (is_lib_64(fname)) | ||
199 | return fname; | ||
200 | // if not 64bit, continue searching | 206 | // if not 64bit, continue searching |
201 | } | 207 | } |
202 | free(fname); | 208 | free(fname); |
203 | } | 209 | } |
204 | 210 | ||
205 | fwarning("%s library not found, skipping...\n", lib); | 211 | // fwarning("%s library not found, skipping...\n", lib); |
206 | return NULL; | 212 | return; |
213 | |||
214 | load_library: | ||
215 | if (fname) { | ||
216 | if (is_dir(fname)) | ||
217 | fslib_copy_dir(fname); | ||
218 | else { | ||
219 | if (strstr(fname, ".so") || | ||
220 | access(fname, X_OK) != 0) // don't duplicate executables | ||
221 | fslib_duplicate(fname); | ||
222 | |||
223 | fslib_copy_libs(fname); | ||
224 | } | ||
225 | free(fname); | ||
226 | } | ||
207 | } | 227 | } |
208 | 228 | ||
209 | 229 | ||
230 | void fslib_install_list(const char *lib_list) { | ||
231 | if (arg_debug || arg_debug_private_lib) | ||
232 | printf(" fslib_install_list %s\n", lib_list); | ||
233 | |||
234 | char *dlist = strdup(lib_list); | ||
235 | if (!dlist) | ||
236 | errExit("strdup"); | ||
237 | |||
238 | char *ptr = strtok(dlist, ","); | ||
239 | install_list_entry(ptr); | ||
240 | |||
241 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
242 | install_list_entry(ptr); | ||
243 | free(dlist); | ||
244 | fs_logger_print(); | ||
245 | } | ||
246 | |||
247 | |||
248 | |||
210 | static void mount_directories(void) { | 249 | static void mount_directories(void) { |
211 | if (arg_debug || arg_debug_private_lib) | 250 | if (arg_debug || arg_debug_private_lib) |
212 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); | 251 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); |
@@ -264,7 +303,7 @@ void fs_private_lib(void) { | |||
264 | 303 | ||
265 | // install standard C libraries | 304 | // install standard C libraries |
266 | if (arg_debug || arg_debug_private_lib) | 305 | if (arg_debug || arg_debug_private_lib) |
267 | printf("*** Installing standard C library\n"); | 306 | printf("Installing standard C library\n"); |
268 | fslib_install_stdc(); | 307 | fslib_install_stdc(); |
269 | 308 | ||
270 | // start timetrace | 309 | // start timetrace |
@@ -273,116 +312,48 @@ void fs_private_lib(void) { | |||
273 | // copy the libs in the new lib directory for the main exe | 312 | // copy the libs in the new lib directory for the main exe |
274 | if (cfg.original_program_index > 0) { | 313 | if (cfg.original_program_index > 0) { |
275 | if (arg_debug || arg_debug_private_lib) | 314 | if (arg_debug || arg_debug_private_lib) |
276 | printf("*** Installing sandboxed program libraries\n"); | 315 | printf("Installing sandboxed program libraries\n"); |
277 | fslib_copy_libs(cfg.original_argv[cfg.original_program_index]); | 316 | fslib_install_list(cfg.original_argv[cfg.original_program_index]); |
278 | } | 317 | } |
279 | 318 | ||
280 | // for the shell | 319 | // for the shell |
281 | if (!arg_shell_none) { | 320 | if (!arg_shell_none) { |
282 | if (arg_debug || arg_debug_private_lib) | 321 | if (arg_debug || arg_debug_private_lib) |
283 | printf("*** Installing shell libraries\n"); | 322 | printf("Installing shell libraries\n"); |
284 | fslib_copy_libs(cfg.shell); | 323 | |
285 | // a shell is useless without ls command | 324 | fslib_install_list(cfg.shell); |
286 | fslib_copy_libs("/bin/ls"); | 325 | // a shell is useless without some basic commands |
326 | fslib_install_list("/bin/ls,/bin/cat,/bin/mv,/bin/rm"); | ||
327 | |||
287 | } | 328 | } |
288 | 329 | ||
289 | // for the listed libs and directories | 330 | // for the listed libs and directories |
290 | if (private_list && *private_list != '\0') { | 331 | if (private_list && *private_list != '\0') { |
291 | if (arg_debug || arg_debug_private_lib) | 332 | if (arg_debug || arg_debug_private_lib) |
292 | printf("*** Processing private-lib files (%s)\n", private_list); | 333 | printf("Processing private-lib files\n"); |
293 | 334 | fslib_install_list(private_list); | |
294 | char *dlist = strdup(private_list); | ||
295 | if (!dlist) | ||
296 | errExit("strdup"); | ||
297 | |||
298 | char *ptr = strtok(dlist, ","); | ||
299 | char *lib = valid_file(ptr); | ||
300 | if (lib) { | ||
301 | if (is_dir(lib)) | ||
302 | fslib_copy_dir(lib); | ||
303 | else { | ||
304 | fslib_duplicate(lib); | ||
305 | fslib_copy_libs(lib); | ||
306 | } | ||
307 | free(lib); | ||
308 | } | ||
309 | |||
310 | while ((ptr = strtok(NULL, ",")) != NULL) { | ||
311 | lib = valid_file(ptr); | ||
312 | if (lib) { | ||
313 | if (is_dir(lib)) | ||
314 | fslib_copy_dir(lib); | ||
315 | else { | ||
316 | fslib_duplicate(lib); | ||
317 | fslib_copy_libs(lib); | ||
318 | } | ||
319 | free(lib); | ||
320 | } | ||
321 | } | ||
322 | free(dlist); | ||
323 | fs_logger_print(); | ||
324 | } | 335 | } |
325 | 336 | ||
326 | // for private-bin files | 337 | // for private-bin files |
327 | if (arg_private_bin) { | 338 | if (arg_private_bin) { |
328 | if (arg_debug || arg_debug_private_lib) | 339 | if (arg_debug || arg_debug_private_lib) |
329 | printf("*** Processing private-bin files\n"); | 340 | printf("Processing private-bin files\n"); |
330 | FILE *fp = fopen(RUN_LIB_BIN, "r"); | 341 | fslib_install_list(cfg.bin_private_lib); |
331 | if (fp) { | ||
332 | char buf[MAXBUF]; | ||
333 | while (fgets(buf, MAXBUF, fp)) { | ||
334 | // remove \n | ||
335 | char *ptr = strchr(buf, '\n'); | ||
336 | if (ptr) | ||
337 | *ptr = '\0'; | ||
338 | |||
339 | // copy libraries for this program | ||
340 | fslib_copy_libs(buf); | ||
341 | |||
342 | // load program data from /usr/lib/program or from /usr/lib/x86_64-linux-gnu | ||
343 | ptr = strrchr(buf, '/'); | ||
344 | if (ptr && *(ptr + 1) != '\0') { | ||
345 | ptr++; | ||
346 | |||
347 | // /usr/lib/program | ||
348 | char *name; | ||
349 | if (asprintf(&name, "/usr/lib/%s", ptr) == -1) | ||
350 | errExit("asprintf"); | ||
351 | if (is_dir(name)) | ||
352 | fslib_copy_dir(name); | ||
353 | free(name); | ||
354 | |||
355 | // /usr/lib/x86_linux-gnu - debian & friends | ||
356 | if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr) == -1) | ||
357 | errExit("asprintf"); | ||
358 | if (is_dir(name)) | ||
359 | fslib_copy_dir(name); | ||
360 | free(name); | ||
361 | |||
362 | // /usr/lib64 - CentOS, Fedora | ||
363 | if (asprintf(&name, "/usr/lib64/%s", ptr) == -1) | ||
364 | errExit("asprintf"); | ||
365 | if (is_dir(name)) | ||
366 | fslib_copy_dir(name); | ||
367 | free(name); | ||
368 | } | ||
369 | } | ||
370 | fclose(fp); | ||
371 | } | ||
372 | } | 342 | } |
373 | fmessage("Program libraries installed in %0.2f ms\n", timetrace_end()); | 343 | fmessage("Program libraries installed in %0.2f ms\n", timetrace_end()); |
374 | 344 | ||
375 | // install the reset of the system libraries | 345 | // install the reset of the system libraries |
376 | if (arg_debug || arg_debug_private_lib) | 346 | if (arg_debug || arg_debug_private_lib) |
377 | printf("*** Installing system libraries\n"); | 347 | printf("Installing system libraries\n"); |
378 | fslib_install_system(); | 348 | fslib_install_system(); |
379 | 349 | ||
350 | // bring in firejail directory for --trace and seccomp post exec | ||
351 | // bring in firejail executable libraries in case we are redirected here by a firejail symlink from /usr/local/bin/firejail | ||
352 | fslib_install_list("/usr/bin/firejail,firejail"); // todo: use the installed path for the executable | ||
353 | |||
380 | fmessage("Installed %d %s and %d %s\n", lib_cnt, (lib_cnt == 1)? "library": "libraries", | 354 | fmessage("Installed %d %s and %d %s\n", lib_cnt, (lib_cnt == 1)? "library": "libraries", |
381 | dir_cnt, (dir_cnt == 1)? "directory": "directories"); | 355 | dir_cnt, (dir_cnt == 1)? "directory": "directories"); |
382 | 356 | ||
383 | // bring in firejail directory for --trace and seccomp post exec | ||
384 | fslib_copy_dir(LIBDIR "/firejail"); | ||
385 | |||
386 | // mount lib filesystem | 357 | // mount lib filesystem |
387 | mount_directories(); | 358 | mount_directories(); |
388 | } | 359 | } |
diff --git a/src/lib/ldd_utils.c b/src/lib/ldd_utils.c index 556fb02eb..b8a7aeed2 100644 --- a/src/lib/ldd_utils.c +++ b/src/lib/ldd_utils.c | |||
@@ -24,11 +24,11 @@ | |||
24 | #include <fcntl.h> | 24 | #include <fcntl.h> |
25 | 25 | ||
26 | const char * const default_lib_paths[] = { | 26 | const char * const default_lib_paths[] = { |
27 | "/usr/lib/x86_64-linux-gnu", // Debian & friends | ||
28 | "/lib/x86_64-linux-gnu", // CentOS, Fedora | ||
29 | "/usr/lib", | ||
27 | "/lib", | 30 | "/lib", |
28 | "/lib/x86_64-linux-gnu", | ||
29 | "/lib64", | 31 | "/lib64", |
30 | "/usr/lib", | ||
31 | "/usr/lib/x86_64-linux-gnu", | ||
32 | LIBDIR, | 32 | LIBDIR, |
33 | "/usr/local/lib", | 33 | "/usr/local/lib", |
34 | "/usr/lib/x86_64-linux-gnu/mesa", // libGL.so is sometimes a symlink into this directory | 34 | "/usr/lib/x86_64-linux-gnu/mesa", // libGL.so is sometimes a symlink into this directory |
@@ -43,7 +43,7 @@ int is_lib_64(const char *exe) { | |||
43 | int fd = open(exe, O_RDONLY); | 43 | int fd = open(exe, O_RDONLY); |
44 | if (fd < 0) | 44 | if (fd < 0) |
45 | return 0; | 45 | return 0; |
46 | 46 | ||
47 | unsigned char buf[EI_NIDENT]; | 47 | unsigned char buf[EI_NIDENT]; |
48 | ssize_t len = 0; | 48 | ssize_t len = 0; |
49 | while (len < EI_NIDENT) { | 49 | while (len < EI_NIDENT) { |