On Mon, 7 Nov 2022, Mouse wrote:

used in new code".  But I must be missing something, because I can't
see any way to exploit the functionality described there, including the
saved IDs, to get the effect I want...short of creating an executable


I don't use seteuid(), but, it looks like you can just re-swap the
(uid, euid) in a child binary and regain the parent's privileges.

Compile with and without -DRELINQUISH.

```
cc -o /tmp/x x.c
cc -o /tmp/y y.c
sudo sh -c 'chown root:wheel /tmp/x; chmod 4555 /tmp/x'
/tmp/x
```

---START x.c---
#include <err.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char* argv[])
{
        uid_t uid, euid;

        uid = getuid();
        euid = geteuid();
        if (uid == euid)
                errx(1, "UID == EUID--won't proceed.");
        printf("%s: UID=%d, EUID=%d\n", *argv, uid, euid);

        if (setreuid(euid, uid) != 0)
                err(1, "setreuid(%d, %d) failed", euid, uid);
        printf("%s: UID=%d, EUID=%d\n", *argv, getuid(), geteuid());

#ifdef RELINQUISH
        /*
         *  Need to do this to safely execute any binary,
         */
#if defined(__FreeBSD__) || defined(__OpenBSD__)
        /*
         *  This works only on FreeBSD (13.1-RELEASE-p3) and
         *  OpenBSD (6.9).
         */
        if (setuid(uid) != 0)
                err(1, "setuid(%d) failed", uid);
#else
        /*
         *  On NetBSD (9.99.106), setuid() fails.
         *  On Linux (5.0.0-38), the call succeeds, but has no effect.
         *  So, we use setreuid().
         */
        if (setreuid(uid, uid) != 0)
                err(1, "setreuid(%d, %d) failed", uid, uid);
#endif
#endif
        execl("/tmp/y", "y", NULL);
        err(1, "execl(/tmp/y) failed");
}
---END x.c---

---START y.c---
#include <err.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char* argv[])
{
        uid_t uid, euid;

        uid = getuid();
        euid = geteuid();
        printf("%s: UID=%d, EUID=%d\n", *argv, uid, euid);
        fflush(stdout);

        if (setreuid(uid, uid) != 0)
                err(1, "setreuid(%d, %d) failed", uid, uid);

        printf("%s: UID=%d, EUID=%d\n", *argv, getuid(), geteuid());

        return 0;
}
---END y.c---

-RVP

Reply via email to