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は、root
通常のユーザーが実行しても結果でなければなりません。passwd
で実行すると、user1
実際には次のようになります。
$ ps -aux | grep passwd
root 4317 0.0 0.0 85940 2004 pts/0 S+ 10:24 0:00 passwd
しかし、脱出するとping
違いますuser1
。
$ ps -aux | grep ping
user1 4362 0.0 0.0 6500 632 pts/0 S+ 10:29 0:00 ping 192.168.8.1
root
最初のケースではプロセスのuidが0に設定され、2番目のケースでは0に設定されないのはなぜですか?
答え1
@rui-f-ribeiroの発言の一般的な意味は正しいですが、詳細はそうではありません。詳細は重要です。 Ubuntuは次のパッケージを使用します。
limit_capabilities
pingユーティリティは、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 呼び出しを介してユーザーのルートを削除する
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
ソケットを開いた後にルートが不要になったため、2番目のプロセスのuidがリセットされました。
確認するときは、passwd
ユーティリティにはまだroot権限が必要です。
これを確認するには、ソースコードを確認する必要があります。これは、uidのリセットが早すぎるため、リセットする前に他のユーザーがuidを確認する機会を提供できるためです。