summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-08-14 15:22:17 +0100
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-08-20 08:52:32 +0100
commit4b4c208d99358941cfe886bc1a87e38c2390f0bd (patch)
tree07f1aa535981c3da041b5cea6d25a2fcf2023b9a
parentcef058c48b21c6effed8d6580876632b4344ec7f (diff)
ecore - don't do anything with heap between fork and exec
this avoids a possibgle deadlock if a malloc impl is holding a lock and has not released it at the time we fork. @fix
-rw-r--r--src/lib/ecore/ecore_exe_posix.c31
-rw-r--r--src/lib/ecore/efl_exe.c79
-rw-r--r--src/lib/eina/eina_file.c220
3 files changed, 271 insertions, 59 deletions
diff --git a/src/lib/ecore/ecore_exe_posix.c b/src/lib/ecore/ecore_exe_posix.c
index f88f0ca15b..895875c8c3 100644
--- a/src/lib/ecore/ecore_exe_posix.c
+++ b/src/lib/ecore/ecore_exe_posix.c
@@ -218,6 +218,13 @@ _impl_ecore_exe_run_priority_get(void)
218 return run_pri; 218 return run_pri;
219} 219}
220 220
221#if defined (__FreeBSD__) || defined (__OpenBSD__)
222# include <dlfcn.h>
223static char ***_dl_environ;
224#else
225extern char **environ;
226#endif
227
221Eo * 228Eo *
222_impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe) 229_impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
223{ 230{
@@ -294,7 +301,29 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe)
294 else if (pid == 0) /* child */ 301 else if (pid == 0) /* child */
295 { 302 {
296#ifdef HAVE_SYSTEMD 303#ifdef HAVE_SYSTEMD
297 unsetenv("NOTIFY_SOCKET"); 304 char **env = NULL, **e;
305
306# if defined (__FreeBSD__) || defined (__OpenBSD__)
307 _dl_environ = dlsym(NULL, "environ");
308 env = *_dl_environ;
309# else
310 env = environ;
311# endif
312 // find NOTIFY_SOCKET env var and remove it without any heap work
313 if (env)
314 {
315 Eina_Bool shuffle = EINA_FALSE;
316
317 for (e = env; *e; e++)
318 {
319 if (!shuffle)
320 {
321 if (!strncmp(e[0], "NOTIFY_SOCKET=", 14))
322 shuffle = EINA_TRUE;
323 }
324 if (shuffle) e[0] = e[1];
325 }
326 }
298#endif 327#endif
299 if (run_pri != ECORE_EXE_PRIORITY_INHERIT) 328 if (run_pri != ECORE_EXE_PRIORITY_INHERIT)
300 { 329 {
diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c
index c5a2f57343..a0fd7d4608 100644
--- a/src/lib/ecore/efl_exe.c
+++ b/src/lib/ecore/efl_exe.c
@@ -357,8 +357,10 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
357 return EINA_FALSE; 357 return EINA_FALSE;
358#else 358#else
359 Eo *loop; 359 Eo *loop;
360 Efl_Task_Data *tdl, *td = efl_data_scope_get(obj, EFL_TASK_CLASS); 360 Efl_Task_Data *tdl = NULL, *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
361 Eina_Iterator *itr = NULL, *itr2 = NULL;
361 const char *cmd; 362 const char *cmd;
363 char **newenv, **env = NULL, **e;
362 int devnull; 364 int devnull;
363 int pipe_stdin[2]; 365 int pipe_stdin[2];
364 int pipe_stdout[2]; 366 int pipe_stdout[2];
@@ -428,9 +430,17 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
428 } 430 }
429 431
430 _ecore_signal_pid_lock(); 432 _ecore_signal_pid_lock();
433 // get these before the fork to avoid heap malloc deadlocks
434 loop = efl_provider_find(obj, EFL_LOOP_CLASS);
435 if (loop) tdl = efl_data_scope_get(loop, EFL_TASK_CLASS);
436 if (pd->env) itr = efl_core_env_content_get(pd->env);
437 if (pd->env) itr2 = efl_core_env_content_get(pd->env);
431 pd->pid = fork(); 438 pd->pid = fork();
439
432 if (pd->pid != 0) 440 if (pd->pid != 0)
433 { 441 {
442 if (itr) eina_iterator_free(itr);
443 if (itr2) eina_iterator_free(itr2);
434 // parent process is here inside this if block 444 // parent process is here inside this if block
435 if (td->flags & EFL_TASK_FLAGS_USE_STDIN) close(pipe_stdin[0]); 445 if (td->flags & EFL_TASK_FLAGS_USE_STDIN) close(pipe_stdin[0]);
436 if (td->flags & EFL_TASK_FLAGS_USE_STDOUT) close(pipe_stdout[1]); 446 if (td->flags & EFL_TASK_FLAGS_USE_STDOUT) close(pipe_stdout[1]);
@@ -513,58 +523,77 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
513 close(devnull); 523 close(devnull);
514 } 524 }
515 525
516 if (!(loop = efl_provider_find(obj, EFL_LOOP_CLASS))) exit(1); 526 if (!tdl) exit(1);
517
518 if (!(tdl = efl_data_scope_get(loop, EFL_TASK_CLASS))) exit(1);
519 527
520 // clear systemd notify socket... only relevant for systemd world, 528 // clear systemd notify socket... only relevant for systemd world,
521 // otherwise shouldn't be trouble 529 // otherwise shouldn't be trouble
522 putenv("NOTIFY_SOCKET="); 530# if defined (__FreeBSD__) || defined (__OpenBSD__)
531 _dl_environ = dlsym(NULL, "environ");
532 if (_dl_environ) env = *_dl_environ;
533# else
534 env = environ;
535# endif
536 if (env)
537 {
538 Eina_Bool shuffle = EINA_FALSE;
539
540 for (e = env; *e; e++)
541 {
542 if (!shuffle)
543 {
544 if (!strncmp(e[0], "NOTIFY_SOCKET=", 14))
545 shuffle = EINA_TRUE;
546 }
547 if (shuffle) e[0] = e[1];
548 }
549 }
523 550
524 // actually setenv the env object (clear what was there before so it is 551 // actually setenv the env object (clear what was there before so it is
525 // the only env there) 552 // the only env there)
526 if (pd->env) 553 if (pd->env)
527 { 554 {
528 Eina_Iterator *itr;
529 const char *key; 555 const char *key;
556 int count = 0, i = 0;
530 557
531# ifdef HAVE_CLEARENV 558 // use 2nd throw-away itr to count
532 clearenv(); 559 EINA_ITERATOR_FOREACH(itr2, key)
533# else 560 {
534# if defined (__FreeBSD__) || defined (__OpenBSD__) 561 count++;
535 _dl_environ = dlsym(NULL, "environ"); 562 }
536 if (_dl_environ) *_dl_environ = NULL; 563 // object which we don't free (sitting in hash table in env obj)
537 else ERR("Can't find envrion symbol"); 564 newenv = alloca(sizeof(char *) * (count + 1));
538# else 565 // use 2st iter to walk and fill new env
539 environ = NULL;
540# endif
541# endif
542 itr = efl_core_env_content_get(pd->env);
543
544 EINA_ITERATOR_FOREACH(itr, key) 566 EINA_ITERATOR_FOREACH(itr, key)
545 { 567 {
546 setenv(key, efl_core_env_get(pd->env, key) , 1); 568 newenv[i] = (char *)efl_core_env_get(pd->env, key);
569 i++;
547 } 570 }
548 efl_unref(pd->env); 571 // yes - we dont free itr or itr2 - we're going to exec below or exit
549 pd->env = NULL; 572 // also put newenv array on stack pointign to the strings in the env
573# if defined (__FreeBSD__) || defined (__OpenBSD__)
574 if (_dl_environ) *_dl_environ = newenv;
575 else ERR("Can't find envrion symbol");
576# else
577 environ = newenv;
578# endif
550 } 579 }
551 580
552 // close all fd's other than the first 3 (0, 1, 2) and exited write fd 581 // close all fd's other than the first 3 (0, 1, 2) and exited write fd
553 int except[2] = { 0, -1 }; 582 int except[2] = { 0, -1 };
554 except[0] = pd->fd.exited_write; 583 except[0] = pd->fd.exited_write;
555 eina_file_close_from(3, except); 584 eina_file_close_from(3, except);
556#ifdef HAVE_PRCTL 585# ifdef HAVE_PRCTL
557 if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT)) 586 if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT))
558 { 587 {
559 prctl(PR_SET_PDEATHSIG, SIGTERM); 588 prctl(PR_SET_PDEATHSIG, SIGTERM);
560 } 589 }
561#elif defined(HAVE_PROCCTL) 590# elif defined(HAVE_PROCCTL)
562 if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT)) 591 if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT))
563 { 592 {
564 int sig = SIGTERM; 593 int sig = SIGTERM;
565 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig); 594 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);
566 } 595 }
567#endif 596# endif
568 // actually execute! 597 // actually execute!
569 _exec(cmd, pd->flags, td->flags); 598 _exec(cmd, pd->flags, td->flags);
570 // we couldn't exec... uh oh. HAAAAAAAALP! 599 // we couldn't exec... uh oh. HAAAAAAAALP!
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index c8abe6d39a..e38bf5bfbb 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -21,6 +21,10 @@
21# include "config.h" 21# include "config.h"
22#endif 22#endif
23 23
24#ifndef _GNU_SOURCE
25# define _GNU_SOURCE
26#endif
27
24#include <stdlib.h> 28#include <stdlib.h>
25#include <string.h> 29#include <string.h>
26#include <stddef.h> 30#include <stddef.h>
@@ -1252,6 +1256,47 @@ eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
1252 return 0; 1256 return 0;
1253} 1257}
1254 1258
1259///////////////////////////////////////////////////////////////////////////
1260// this below is funky avoiding opendir to avoid heap allocations thus
1261// getdents and all the os specific stuff as this is intendedf for use
1262// between fork and exec normally ... this is important
1263#if defined(__FreeBSD__)
1264# define do_getdents(fd, buf, size) getdents(fd, buf, size)
1265typedef struct
1266{
1267 ino_t d_ino;
1268 off_t d_off;
1269 unsigned short d_reclen;
1270 unsigned char d_type;
1271 unsigned char ____pad0;
1272 unsigned short d_namlen;
1273 unsigned short ____pad1;
1274 char d_name[4096];
1275} Dirent;
1276#elif defined(__OpenBSD__)
1277# define do_getdents(fd, buf, size) getdents(fd, buf, size)
1278typedef struct
1279{
1280 __ino_t d_ino;
1281 __off_t d_off;
1282 unsigned short d_reclen;
1283 unsigned char d_type;
1284 unsigned char d_namlen;
1285 unsigned char ____pad[4];
1286 char d_name[4096];
1287} Dirent;
1288#elif defined(__linux__)
1289# define do_getdents(fd, buf, size) getdents64(fd, buf, size)
1290typedef struct
1291{
1292 ino64_t d_ino;
1293 off64_t d_off;
1294 unsigned short d_reclen;
1295 unsigned char d_type;
1296 char d_name[4096];
1297} Dirent;
1298#endif
1299
1255EAPI void 1300EAPI void
1256eina_file_close_from(int fd, int *except_fd) 1301eina_file_close_from(int fd, int *except_fd)
1257{ 1302{
@@ -1259,62 +1304,171 @@ eina_file_close_from(int fd, int *except_fd)
1259 // XXX: what do to here? anything? 1304 // XXX: what do to here? anything?
1260#else 1305#else
1261#ifdef HAVE_DIRENT_H 1306#ifdef HAVE_DIRENT_H
1307//# if 0
1308# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
1309 int dirfd;
1310 Dirent *d;
1311 char buf[4096];
1312 int *closes = NULL;
1313 int num_closes = 0, i, j, clo, num;
1314 const char *fname;
1315 ssize_t pos, ret;
1316 Eina_Bool do_read;
1317
1318 dirfd = open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
1319 if (dirfd < 0) dirfd = open("/dev/fd", O_RDONLY | O_DIRECTORY);
1320 if (dirfd >= 0)
1321 {
1322 // count # of closes - the dir list should/will not change as its
1323 // the fd's we have open so we can read it twice with no changes
1324 // to it
1325 do_read = EINA_TRUE;
1326 for (;;)
1327 {
1328skip:
1329 if (do_read)
1330 {
1331 pos = 0;
1332 ret = do_getdents(dirfd, buf, sizeof(buf));
1333 if (ret <= 0) break;
1334 do_read = EINA_FALSE;
1335 }
1336 d = (Dirent *)(buf + pos);
1337 fname = d->d_name;
1338 pos += d->d_reclen;
1339 if (pos >= ret) do_read = EINA_TRUE;
1340 if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
1341 num = atoi(fname);
1342 if (num < fd) continue;
1343 if (except_fd)
1344 {
1345 for (j = 0; except_fd[j] >= 0; j++)
1346 {
1347 if (except_fd[j] == num) goto skip;
1348 }
1349 }
1350 num_closes++;
1351 }
1352 // alloc closes list and walk again to fill it - on stack to avoid
1353 // heap allocs
1354 closes = alloca(num_closes * sizeof(int));
1355 if ((closes) && (num_closes > 0))
1356 {
1357 clo = 0;
1358 lseek(dirfd, 0, SEEK_SET);
1359 do_read = EINA_TRUE;
1360 for (;;)
1361 {
1362skip2:
1363 if (do_read)
1364 {
1365 pos = 0;
1366 ret = do_getdents(dirfd, buf, sizeof(buf));
1367 if (ret <= 0) break;
1368 do_read = EINA_FALSE;
1369 }
1370 d = (Dirent *)(buf + pos);
1371 fname = d->d_name;
1372 pos += d->d_reclen;
1373 if (pos >= ret) do_read = EINA_TRUE;
1374 if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
1375 num = atoi(fname);
1376 if (num < fd) continue;
1377 if (except_fd)
1378 {
1379 for (j = 0; except_fd[j] >= 0; j++)
1380 {
1381 if (except_fd[j] == num) goto skip2;
1382 }
1383 }
1384 if (clo < num_closes) closes[clo] = num;
1385 clo++;
1386 }
1387 }
1388 close(dirfd);
1389 // now go close all those fd's - some may be invalide like the dir
1390 // reading fd above... that's ok.
1391 for (i = 0; i < num_closes; i++)
1392 {
1393 close(closes[i]);
1394 }
1395 return;
1396 }
1397# else
1262 DIR *dir; 1398 DIR *dir;
1399 int *closes = NULL;
1400 int num_closes = 0, i, j, clo, num;
1401 struct dirent *dp;
1402 const char *fname;
1263 1403
1264 dir = opendir("/proc/self/fd"); 1404 dir = opendir("/proc/self/fd");
1265 if (!dir) dir = opendir("/dev/fd"); 1405 if (!dir) dir = opendir("/dev/fd");
1266 if (dir) 1406 if (dir)
1267 { 1407 {
1268 struct dirent *dp; 1408 // count # of closes - the dir list should/will not change as its
1269 const char *fname; 1409 // the fd's we have open so we can read it twice with no changes
1270 int *closes = NULL; 1410 // to it
1271 int num_closes = 0, i;
1272
1273 for (;;) 1411 for (;;)
1274 { 1412 {
1275skip: 1413skip:
1276 dp = readdir(dir); 1414 if (!(dp = readdir(dir))) break;
1277 if (!dp) break;
1278 fname = dp->d_name; 1415 fname = dp->d_name;
1279 1416 if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
1280 if ((fname[0] >= '0') && (fname[0] <= '9')) 1417 num = atoi(fname);
1418 if (num < fd) continue;
1419 if (except_fd)
1281 { 1420 {
1282 int num = atoi(fname); 1421 for (j = 0; except_fd[j] >= 0; j++)
1283 if (num >= fd)
1284 { 1422 {
1285 if (except_fd) 1423 if (except_fd[j] == num) goto skip;
1286 { 1424 }
1287 int j; 1425 }
1288 1426 num_closes++;
1289 for (j = 0; except_fd[j] >= 0; j++) 1427 }
1290 { 1428 // alloc closes list and walk again to fill it - on stack to avoid
1291 if (except_fd[j] == num) goto skip; 1429 // heap allocs
1292 } 1430 closes = alloca(num_closes * sizeof(int));
1293 } 1431 if ((closes) && (num_closes > 0))
1294 num_closes++; 1432 {
1295 int *tmp = realloc(closes, num_closes * sizeof(int)); 1433 clo = 0;
1296 if (!tmp) num_closes--; 1434 seekdir(dir, 0);
1297 else 1435 for (;;)
1436 {
1437skip2:
1438 if (!(dp = readdir(dir))) break;
1439 fname = dp->d_name;
1440 if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
1441 num = atoi(fname);
1442 if (num < fd) continue;
1443 if (except_fd)
1444 {
1445 for (j = 0; except_fd[j] >= 0; j++)
1298 { 1446 {
1299 closes = tmp; 1447 if (except_fd[j] == num) goto skip2;
1300 closes[num_closes - 1] = num;
1301 } 1448 }
1302 } 1449 }
1450 if (clo < num_closes) closes[clo] = num;
1451 clo++;
1303 } 1452 }
1304 } 1453 }
1305 closedir(dir); 1454 closedir(dir);
1306 for (i = 0; i < num_closes; i++) close(closes[i]); 1455 // now go close all those fd's - some may be invalide like the dir
1307 free(closes); 1456 // reading fd above... that's ok.
1457 for (i = 0; i < num_closes; i++)
1458 {
1459 close(closes[i]);
1460 }
1308 return; 1461 return;
1309 } 1462 }
1463# endif
1310#endif 1464#endif
1311 int i, max = 1024; 1465 int max = 1024;
1312 1466
1313# ifdef HAVE_SYS_RESOURCE_H 1467#ifdef HAVE_SYS_RESOURCE_H
1314 struct rlimit lim; 1468 struct rlimit lim;
1315 if (getrlimit(RLIMIT_NOFILE, &lim) < 0) return; 1469 if (getrlimit(RLIMIT_NOFILE, &lim) < 0) return;
1316 max = lim.rlim_max; 1470 max = lim.rlim_max;
1317# endif 1471#endif
1318 for (i = fd; i < max;) 1472 for (i = fd; i < max;)
1319 { 1473 {
1320 if (except_fd) 1474 if (except_fd)
@@ -1323,11 +1477,11 @@ skip:
1323 1477
1324 for (j = 0; except_fd[j] >= 0; j++) 1478 for (j = 0; except_fd[j] >= 0; j++)
1325 { 1479 {
1326 if (except_fd[j] == i) goto skip2; 1480 if (except_fd[j] == i) goto skip3;
1327 } 1481 }
1328 } 1482 }
1329 close(i); 1483 close(i);
1330skip2: 1484skip3:
1331 i++; 1485 i++;
1332 } 1486 }
1333#endif 1487#endif