Set-uid 可执行文件和生成的进程用户

Set-uid 可执行文件和生成的进程用户

在 Ubuntu 14.04 中,passwd可执行文件是

-rwsr-xr-x 1 root root 47032 gen 27 01:50 /usr/bin/passwd

可执行文件ping

-rwsr-xr-x 1 root root 44168 mag  7  2014 /bin/ping

因此(对于两者)运行进程的 uid 应该是 result root,即使它们是从普通用户运行的。如果我passwd从运行user1,事实上,我得到

$ ps -aux | grep passwd
root      4317  0.0  0.0  85940  2004 pts/0    S+   10:24   0:00 passwd

但如果我逃避pinguser1就不一样了:

$ ps -aux | grep ping
user1    4362  0.0  0.0   6500   632 pts/0    S+   10:29   0:00 ping 192.168.8.1

为什么进程的 uidroot在第一种情况下被设置为而不是在第二种情况下?

答案1

@rui-f-ribeiro 言论的大体意义是正确的,但细节则不然。细节很重要。 Ubuntu 使用这些软件包:

ping 实用程序重置名为 的函数中的权限limit_capabilities,该函数由 ping 和 ping6 共享。相关的代码块如下所示:

        if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
                perror("ping: prctl");
                exit(-1);
        }

        if (setuid(getuid()) < 0) {
                perror("setuid");
                exit(-1);
        }

        if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
                perror("ping: prctl");
                exit(-1);
        }

        cap_free(cap_p);
        cap_free(cap_cur_p);
#endif
        uid = getuid();
        euid = geteuid();
#ifndef CAPABILITIES
        if (seteuid(uid)) {
                perror("ping: setuid");
                exit(-1);
        }
#endif

也就是说(阅读源代码),ping执行多个特权操作并放弃特权 - 但可以将其构建为根据个人喜好以不同的方式运行。

有趣的是,变更日志指出:

iputils (3:20121221-2) unstable; urgency=low

  * Enable the CAP_NET_RAW capability and strip the setuid bit on ping and
    ping6 binaries if possible.

故事passwd相似,但细节不同。它是阴影工具套件,可能会删除以下权限change_root

    /* Drop privileges */
    if (   (setregid (getgid (), getgid ()) != 0)
        || (setreuid (getuid (), getuid ()) != 0)) {
            fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
                     Prog, strerror (errno));
            exit (EXIT_FAILURE);
    }

但它只在特殊情况下才会这样做:

/*
 * process_root_flag - chroot if given the --root option
 *
 * This shall be called before accessing the passwd, group, shadow,
 * gshadow, useradd's default, login.defs files (non exhaustive list)
 * or authenticating the caller.
 *
 * The audit, syslog, or locale files shall be open before
 */

在通常情况下,它确保它拥有特权并且不会删除它们(因为没有其他不需要特权的事情可做):

    if (setuid (0) != 0) {
            (void) fputs (_("Cannot change ID to root.\n"), stderr);
            SYSLOG ((LOG_ERR, "can't setuid(0)"));
            closelog ();
            exit (E_NOPERM);
    }

大多数实用程序不会重置 setuid/setgid 行为,假定它们未安装这些权限。

答案2

正如 @schily 所说,在 ping 实用程序(和其他实用程序)中,root 权限在不再需要后会被删除。这样做是出于安全原因。

从 ping.c - main() - 通过 getuid 和 setuid 调用删除用户 root。

getuid() 获取当前用户,root 执行 setuid() 将更改进程的 uid。

/*
 * Pull this stuff up front so we can drop root if desired.
 */
if (!(proto = getprotobyname("icmp"))) {
    (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
    exit(2);
}
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
    if (errno==EPERM) {
        fprintf(stderr, "ping: ping must run as root\n");
    }
    else perror("ping: socket");
    exit(2);
}

#ifdef SAFE_TO_DROP_ROOT    
    setuid(getuid());       /* HERE RETURNING TO THE USER */
#endif

答案3

第二个进程的 uid 已被重置,因为在打开套接字后不再需要 root。

当您检查时,该passwd实用程序仍然需要 root 权限。

如果您想验证这一点,则需要检查源代码,因为 uid 的重置可能完成得太快,以至于其他人有机会在重置之前验证 uid。

相关内容