Question

In POSIX, there are the well-known functions getuid() and geteuid() for fetching the real and effective uid of the process. However, it is often useful to check the saved uid also (on platforms supporting POSIX saved uids, which is every current OS).

For example, in the classic guide "Setuid Demystified" (Chen, Dean, Wagner 2002) the authors recommend checking that the real, effective and saved uids are all as expected immediately after any call to the setuid() function. In their implementation guidelines however, they do not explain how to check the saved uid on all platforms.

How can I retrieve my process's saved uid?

Was it helpful?

Solution

The following snippet implements a getsuid() function. Tested to work on Linux 2.6+, FreeBSD 8+, Solaris 8+, AIX 5.3+, HP-UX 11.00+, MacOS 10.6+. Will probably work on older versions too.

#include <unistd.h>
#include <stdio.h>
#ifdef _AIX
#include <sys/id.h>
#elif defined(__sun)
#include <fcntl.h>
#include <procfs.h>
#elif defined(__hpux)
#include <dlfcn.h>
#include <sys/pstat.h>
#elif defined(__APPLE__)
#include <sys/sysctl.h>
#endif

#if defined(__linux) || defined(__FreeBSD__)
static int getsuid(uid_t* suid) {
  uid_t ruid, euid;
  return getresuid(&ruid, &euid, suid);
}

#elif defined(_AIX)
static int getsuid(uid_t* suid) {
  *suid = getuidx(ID_SAVED);
  return *suid == (uid_t)-1 ? -1 : 0;
}

#elif defined(__sun)
static int getsuid(uid_t* suid) {
  int fd = open("/proc/self/cred", O_RDONLY);
  if (fd < 0) return -1;
  prcred_t prcred;
  int n = read(fd, &prcred, sizeof(prcred));
  close(fd);
  if (n != sizeof(prcred)) return -1;
  *suid = prcred.pr_suid;
  return 0;
}

#elif defined(__hpux)
static int getsuid(uid_t* suid)
{
  // HP-UX does have getresuid, but only on 11.11 onwards.
  void* handle;
  int (*getresuid_)(uid_t*,uid_t*,uid_t*);
  struct pst_status pst;
  int i;

  if ((handle = dlopen("libc.sl", RTLD_LAZY | RTLD_GLOBAL)) &&
      (getresuid_ = dlsym(handle, "getresuid")))
  {
    uid_t dummy1, dummy2, result;
    if ((*getresuid_)(&dummy1, &dummy2, &result))
      return -1;
    *suid = result;
    dlclose(handle);
    return 0; 
  }
  if (handle) dlclose(handle);

  for (i = 0; pstat_getproc(&pst, sizeof(pst), 1, i); ++i) {
    if (pst.pst_pid != getpid())
      continue;
    *suid = pst.pst_suid;
    return 0;
  }
  return -1;
}

#elif defined(__APPLE__)
static int getsuid(uid_t* suid)
{
  int ctl[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
  struct kinfo_proc kip;
  size_t len = sizeof(kip);
  if (sysctl(ctl, 4, &kip, &len, 0, 0) < 0)
    return -1;
  *suid = kip.kp_eproc.e_pcred.p_svuid;
  return 0;
}

#else
#error getsuid() not implemented for this platform
#endif

#ifdef TEST_CODE
int main() {
  uid_t ruid, euid, suid;
  ruid = getuid();
  euid = geteuid();
  if (getsuid(&suid) < 0) {
    perror("getsuid failure");
    return -1;
  }
  printf("uid: %ld, euid: %ld, suid: %ld\n",
         (long)ruid, (long)euid, (long)suid);
}
#endif
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top