fix(native): a spawn whose dup2 source close-from closed fails with EBADF

This commit is contained in:
Kurt Himebauch committed 2026-11-09 13:23:10 -05:00
1 parent 436e99e02b
commit 107cefbf46
2 files changed
+25 -6

No files matched your search

+5 -2
View File
@@ -878,13 +878,16 @@ static int ddnatv_posix_spawn(pid_t *pid, const char *path,
return ret;
}
static void apply_closefrom(posix_spawn_file_actions_t *actions);
static int apply_closefrom(posix_spawn_file_actions_t *actions);
int posix_spawn(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *attrp,
char *const argv[], char *const envp[]) {
if (file_actions) apply_closefrom((posix_spawn_file_actions_t *)file_actions);
if (file_actions) {
int bad = apply_closefrom((posix_spawn_file_actions_t *)file_actions);
if (bad) return bad;
}
posix_spawnattr_t sanitized;
return ddnatv_posix_spawn(pid, path, file_actions, spawn_attr_for_android(attrp, &sanitized), argv, envp, 0);
}
+20 -4
View File
@@ -49,6 +49,7 @@ static struct closefrom_entry {
int nkeep;
int keep[CLOSEFROM_KEEP];
int closed_to; // the descriptors up to this one are closed by actions already added
int bad_source; // a dup2 after close-from duplicates a descriptor it closed: glibc's EBADF
} g_closefrom[CLOSEFROM_SLOTS];
static pthread_mutex_t g_closefrom_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -101,7 +102,17 @@ int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *actions, int fd
static int (*orig)(posix_spawn_file_actions_t *, int, int) = NULL;
if (!orig) orig = (int (*)(posix_spawn_file_actions_t *, int, int))dlsym(RTLD_NEXT, "posix_spawn_file_actions_adddup2");
int ret = orig ? orig(actions, fd, newfd) : ENOSYS;
if (ret == 0) closefrom_note_target(actions, newfd);
if (ret == 0) {
pthread_mutex_lock(&g_closefrom_lock);
struct closefrom_entry *e = closefrom_entry(actions, 0);
if (e && e->from >= 0 && fd >= e->from) {
int reopened = 0;
for (int k = 0; k < e->nkeep; k++) reopened |= e->keep[k] == fd;
if (!reopened) e->bad_source = 1;
}
pthread_mutex_unlock(&g_closefrom_lock);
closefrom_note_target(actions, newfd);
}
return ret;
}
@@ -125,12 +136,16 @@ int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *actions) {
return orig ? orig(actions) : ENOSYS;
}
static void apply_closefrom(posix_spawn_file_actions_t *actions) {
static int apply_closefrom(posix_spawn_file_actions_t *actions) {
pthread_mutex_lock(&g_closefrom_lock);
struct closefrom_entry *e = closefrom_entry(actions, 0);
if (!e || e->from < 0) {
pthread_mutex_unlock(&g_closefrom_lock);
return;
return 0;
}
if (e->bad_source) {
pthread_mutex_unlock(&g_closefrom_lock);
return EBADF;
}
int highest = e->highest;
DIR *dir = opendir("/proc/self/fd");
@@ -152,7 +167,8 @@ static void apply_closefrom(posix_spawn_file_actions_t *actions) {
e->closed_to = fd;
}
pthread_mutex_unlock(&g_closefrom_lock);
return 0;
}
#else
static void apply_closefrom(posix_spawn_file_actions_t *actions) { (void)actions; }
static int apply_closefrom(posix_spawn_file_actions_t *actions) { (void)actions; return 0; }
#endif