mirror of git://git.musl-libc.org/musl
revert regression in faccessat AT_EACCESS robustness
commit f9fb20b42d
switched from using a
pipe for the result to conveying it via the child process exit status.
Alexander Monakov pointed out that the latter could fail if the
application is not expecting faccessat to produce a child and performs
a wait operation with __WCLONE or __WALL, and that it is not clear
whether it's guaranteed to work when SIGCHLD's disposition has been
set to SIG_IGN.
in addition, that commit introduced a bug that caused EACCES to be
produced instead of EBUSY due to an exit path that was overlooked when
the error channel was changed, and introduced a spurious retry loop
around the wait operation.
This commit is contained in:
parent
7c709f2d4f
commit
cd0ae687de
|
@ -1,6 +1,5 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "pthread_impl.h"
|
#include "pthread_impl.h"
|
||||||
|
@ -9,26 +8,19 @@ struct ctx {
|
||||||
int fd;
|
int fd;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
int amode;
|
int amode;
|
||||||
};
|
int p;
|
||||||
|
|
||||||
static const int errors[] = {
|
|
||||||
0, -EACCES, -ELOOP, -ENAMETOOLONG, -ENOENT, -ENOTDIR,
|
|
||||||
-EROFS, -EBADF, -EINVAL, -ETXTBSY,
|
|
||||||
-EFAULT, -EIO, -ENOMEM,
|
|
||||||
-EBUSY
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int checker(void *p)
|
static int checker(void *p)
|
||||||
{
|
{
|
||||||
struct ctx *c = p;
|
struct ctx *c = p;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
|
||||||
if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1)
|
if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1)
|
||||||
|| __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1))
|
|| __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1))
|
||||||
__syscall(SYS_exit, 1);
|
__syscall(SYS_exit, 1);
|
||||||
ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
|
ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
|
||||||
for (i=0; i < sizeof errors/sizeof *errors - 1 && ret!=errors[i]; i++);
|
__syscall(SYS_write, c->p, &ret, sizeof ret);
|
||||||
return i;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int faccessat(int fd, const char *filename, int amode, int flag)
|
int faccessat(int fd, const char *filename, int amode, int flag)
|
||||||
|
@ -42,20 +34,21 @@ int faccessat(int fd, const char *filename, int amode, int flag)
|
||||||
char stack[1024];
|
char stack[1024];
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int ret = -EBUSY;
|
int status;
|
||||||
struct ctx c = { .fd = fd, .filename = filename, .amode = amode };
|
int ret, p[2];
|
||||||
|
|
||||||
|
if (pipe2(p, O_CLOEXEC)) return __syscall_ret(-EBUSY);
|
||||||
|
struct ctx c = { .fd = fd, .filename = filename, .amode = amode, .p = p[1] };
|
||||||
|
|
||||||
__block_all_sigs(&set);
|
__block_all_sigs(&set);
|
||||||
|
|
||||||
pid = __clone(checker, stack+sizeof stack, 0, &c);
|
pid = __clone(checker, stack+sizeof stack, 0, &c);
|
||||||
if (pid > 0) {
|
__syscall(SYS_close, p[1]);
|
||||||
int status;
|
|
||||||
do {
|
if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
|
||||||
__syscall(SYS_wait4, pid, &status, __WCLONE, 0);
|
ret = -EBUSY;
|
||||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
__syscall(SYS_close, p[0]);
|
||||||
if (WIFEXITED(status))
|
__syscall(SYS_wait4, pid, &status, __WCLONE, 0);
|
||||||
ret = errors[WEXITSTATUS(status)];
|
|
||||||
}
|
|
||||||
|
|
||||||
__restore_sigs(&set);
|
__restore_sigs(&set);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue