mirror of
git://git.musl-libc.org/musl
synced 2025-03-06 20:48:29 +01:00
fix faccessat to support AT_EACCESS flag
this is another case of the kernel syscall failing to support flags where it needs to, leading to horrible workarounds in userspace. this time the workaround requires changing uid/gid, and that's not safe to do in the current process. in the worst case, kernel resource limits might prevent recovering the original values, and then there would be no way to safely return. so, use the safe but horribly inefficient alternative: forking. clone is used instead of fork to suppress signals from the child. fortunately this worst-case code is only needed when effective and real ids mismatch, which mainly happens in suid programs.
This commit is contained in:
parent
89384f78ce
commit
0a05eace16
1 changed files with 46 additions and 1 deletions
|
@ -1,7 +1,52 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "syscall.h"
|
||||
#include "pthread_impl.h"
|
||||
|
||||
struct ctx {
|
||||
int fd;
|
||||
const char *filename;
|
||||
int amode;
|
||||
int p;
|
||||
};
|
||||
|
||||
static int checker(void *p)
|
||||
{
|
||||
struct ctx *c = p;
|
||||
int ret;
|
||||
if (__syscall(SYS_setgid, __syscall(SYS_getegid))
|
||||
|| __syscall(SYS_setuid, __syscall(SYS_geteuid)))
|
||||
__syscall(SYS_exit, 1);
|
||||
ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
|
||||
__syscall(SYS_write, c->p, &ret, sizeof ret);
|
||||
__syscall(SYS_exit, 0);
|
||||
}
|
||||
|
||||
int faccessat(int fd, const char *filename, int amode, int flag)
|
||||
{
|
||||
return syscall(SYS_faccessat, fd, filename, amode, flag);
|
||||
if (!flag || (flag==AT_EACCESS && getuid()==geteuid() && getgid()==getegid()))
|
||||
return syscall(SYS_faccessat, fd, filename, amode, flag);
|
||||
|
||||
if (flag != AT_EACCESS)
|
||||
return __syscall_ret(-EINVAL);
|
||||
|
||||
char stack[1024];
|
||||
sigset_t set;
|
||||
int ret, p[2];
|
||||
|
||||
if (pipe(p)) return __syscall_ret(-EBUSY);
|
||||
struct ctx c = { .fd = fd, .filename = filename, .amode = amode, .p = p[1] };
|
||||
|
||||
__block_app_sigs(&set);
|
||||
|
||||
ret = __clone(checker, stack+sizeof stack, 0, &c);
|
||||
__syscall(SYS_close, p[1]);
|
||||
|
||||
if (ret<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
|
||||
ret = -EBUSY;
|
||||
__syscall(SYS_close, p[0]);
|
||||
|
||||
__restore_sigs(&set);
|
||||
|
||||
return __syscall_ret(ret);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue