如何检索我的进程已保存的uid?

时间:2014-01-22 10:57:16

标签: security unix cross-platform posix setuid

在POSIX中,有众所周知的函数getuid()geteuid()用于获取进程的真实有效uid。但是,检查保存的uid通常也很有用(在支持POSIX保存的uid的平台上,这是每个当前的操作系统)。

例如,在经典指南"Setuid Demystified" (Chen, Dean, Wagner 2002)中,作者建议在调用setuid()函数后立即检查真实,有效和保存的uid是否符合预期。但是,在他们的实施指南中,他们没有解释如何在所有平台上检查已保存的uid。

如何检索我的进程已保存的uid?

1 个答案:

答案 0 :(得分:1)

以下代码段实现了getsuid()功能。经测试适用于Linux 2.6 +,FreeBSD 8 +,Solaris 8 +,AIX 5.3 +,HP-UX 11.00+,MacOS 10.6+。也可能适用于旧版本。

#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