|
|
Message-ID: <20180130213353.GM1627@brightrain.aerifal.cx>
Date: Tue, 30 Jan 2018 16:33:53 -0500
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: [PATCH] faccessat: fix error code on setreXid failure
On Tue, Jan 30, 2018 at 11:32:37PM +0300, Alexander Monakov wrote:
> Commit 316d6741b68b485205d7233c98bd6c795bb80370 changed one use of
> SYS_exit in 'checker' without changing another just three lines above,
> and then commit f9fb20b42da0e755d93de229a5a737d79a0e8f60 changed the
> meaning of return value, causing EACCES to be reported instead of EBUSY
> if preparatory setregid/setreuid fail.
This looks right.
> This is the minimal fix for the issue, but it appears there's another:
> collecting checker's exit code and reaping the zombie is implemented as
>
> int status;
> do {
> __syscall(SYS_wait4, pid, &status, __WCLONE, 0);
> } while (!WIFEXITED(status) && !WIFSIGNALED(status));
>
> but I don't understand why this retry loop is required and correct:
AFAIK wait4 can also return due to Stopped status or trace-related
reasons, not just exit. That was the motivation I think.
> - if another thread won the race to collect the zombie by doing something
> like waitpid(-1, 0, __WALL), it fails to check syscall's return value and
> uses uninitialized 'status', possibly causing an infinite loop or OOB access
> in the parent;
Yes, I think that should be fixed even though I think it's broken
usage.
> - the code seems to assume that the zombie will not be auto-collected even if
> SIGCHLD disposition is set to SIG_IGN; this sounds logical, but not explicitly
> documented as far as I can tell;
Indeed, I'm not sure, but I don't know any good fix.
> - if the two problems above don't arise, I don't see how the test in while ()
> condition can fail; we have signals blocked, so waitpid can only return when
> the child no longer exists.
>
> Plus, using CLONE_VM | CLONE_VFORK would help conserve resources.
I'm not sure if it's safe -- having tasks sharing vm with different
permissions is usually a very bad thing. It might be ok here but I'm
not sure.
>
> Alexander
>
> src/unistd/faccessat.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
> index 33478959..954cbdb4 100644
> --- a/src/unistd/faccessat.c
> +++ b/src/unistd/faccessat.c
> @@ -25,7 +25,7 @@ static int checker(void *p)
> int i;
> if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1)
> || __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1))
> - __syscall(SYS_exit, 1);
> + return sizeof errors/sizeof *errors - 1;
> ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
> for (i=0; i < sizeof errors/sizeof *errors - 1 && ret!=errors[i]; i++);
> return i;
Looks ok except it encodes an assumption that EBUSY is last. It might
make more sense to goto the errno-searching loop.
Rich
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.