Bug 29109 - posix_spawn() always returns 1 (EPERM) on clone() failure
Summary: posix_spawn() always returns 1 (EPERM) on clone() failure
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.35
: P2 normal
Target Milestone: 2.36
Assignee: Adhemerval Zanella
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-05-01 14:52 UTC by Alexey Izbyshev
Modified: 2022-05-06 14:34 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Izbyshev 2022-05-01 14:52:30 UTC
The reproducer below uses time namespaces to easily trigger clone() failure (requires Linux >= 5.6).

$ cat test.c
#include <stdio.h>
#include <spawn.h>

#include <stdio.h>
#include <string.h>
#include <spawn.h>

int main(int argc, char *argv[], char *envp[]) {
  if (argc <= 1)
    return 1;
  int err = posix_spawn(0, argv[1], 0, 0, argv + 1, envp);
  if (err) {
    printf("posix_spawn: %d (%s)\n", err, strerror(err));
    return 127;
  }
  return 0;
}

$ gcc test.c
$ strace -e clone,clone3 unshare -UrT ./a.out /bin/true
clone3({flags=CLONE_VM|CLONE_VFORK, exit_signal=SIGCHLD, stack=0x7f322965f000, stack_size=0x9000}, 88) = -1 EINVAL (Invalid argument)
posix_spawn: 1 (Operation not permitted)
+++ exited with 127 +++

The bug is that while __clone_internal() reports errors via errno, __spawnix() treats it as a raw syscall[1], simply negating its return value (which is always -1 on error).

[1] https://sourceware.org/git?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/spawni.c;h=d703485e3fb898dc65986d3e1cd9c1e7b8593abe;hb=glibc-2.35#l412
Comment 1 Adhemerval Zanella 2022-05-02 13:30:57 UTC
I think the best option here is to make __clone_internal not change errno and just return the error as negative errno.
Comment 2 Alexey Izbyshev 2022-05-02 13:39:11 UTC
> I think the best option here is to make __clone_internal not change errno and just return the error as negative errno.

FWIW, all current code in glibc seems to use __clone_internal as a typical C function, i.e. expecting it return -1 and set errno on error. It's not clear to me why changing that would be the best option (compared to just fixing posix_spawn() to use errno instead of negating the return value).
Comment 3 Adhemerval Zanella 2022-05-02 13:46:45 UTC
Yes(In reply to Alexey Izbyshev from comment #2)
> > I think the best option here is to make __clone_internal not change errno and just return the error as negative errno.
> 
> FWIW, all current code in glibc seems to use __clone_internal as a typical C
> function, i.e. expecting it return -1 and set errno on error. It's not clear
> to me why changing that would be the best option (compared to just fixing
> posix_spawn() to use errno instead of negating the return value).

The only another usage is on pthread_create, but just using errno seems the simplest solution indeed.
Comment 4 Adhemerval Zanella 2022-05-06 14:09:03 UTC
Fixed on 2.36.
Comment 5 Sourceware Commits 2022-05-06 14:34:32 UTC
The release/2.35/master branch has been updated by Adhemerval Zanella <azanella@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=bbb017a2bb2983de297f3d443c59221fbff92e30

commit bbb017a2bb2983de297f3d443c59221fbff92e30
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Fri May 6 11:34:18 2022 -0300

    NEWS: Add a bug fix entry for BZ #29109