1

我编译了这个示例 set-root-id 程序:

  #define _GNU_SOURCE

  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>


  void print_ids()
     {
     uid_t ruid, euid, suid, rgid, egid, sgid;

     getresuid(&ruid, &euid, &suid);
     printf("\nruid=%d, euid=%d, suid=%d\n", ruid, euid, suid);

     getresgid(&rgid, &egid, &sgid);
     printf("rgid=%d, egid=%d, sgid=%d\n\n", rgid, egid, sgid);
     }


  void main(int argc, char *argv[])
     {
     print_ids();
     seteuid(1000); printf("seteuid(1000): %s\n", strerror(errno));
     print_ids();
     seteuid(1001); printf("seteuid(1001): %s\n", strerror(errno));
     print_ids();
     seteuid(0);    printf("seteuid(0): %s\n",    strerror(errno));   
     print_ids();
     }

调用 seteuid(0) 有效,但显示错误消息:“不允许操作”:

$ gcc -Wall ./p3.c -o p3
./p3.c:32: warning: return type of ‘main’ is not ‘int’
$ su -c "chown root:root ./p3 ; chmod 4755 ./p3"
Password: ****
$ ls -l ./p3
-rwsr-xr-x 1 root root 7697  2 gen 19.21 ./p3
$ ./p3

ruid=1000, euid=0, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(1000): Success

ruid=1000, euid=1000, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(1001): Operation not permitted

ruid=1000, euid=1000, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(0): Operation not permitted

ruid=1000, euid=0, suid=0
rgid=1000, egid=1000, sgid=1000

$

为什么 seteuid(0) 有效但显示错误消息?我注意到省略对 seteuid(1001) 的调用或对 seteuid(1000) 的调用没有出现错误消息。

谢谢

(我在 Debian 6 上工作,gcc 版本 4.4.5)

4

1 回答 1

2

EPERM的仍然errno来自上一个电话。成功的系统调用不设置errno为 0;你必须自己做。

通常,您不需要设置errno为 0。您检查系统调用的返回值,然后如果表明失败,则检查errno更多详细信息。errno 不会告诉你事失败了——它会告诉你某事是如何失败的。

对于返回值中没有明显错误指示符的函数,此一般规则有一个例外,例如strtoul,但seteuid不是其中之一。它有一个干净的返回值。如果它返回 0,则根本不应该打印错误消息。

并且依靠strerror(0)产生“成功消息”也不干净 - 在当前的 glibc 中它说"Success"但我仍然记得什么时候strerror(0)"Unknown error 0". 也许它仍然在某个地方。

于 2014-01-02T18:46:14.630 回答