Только в альпийском контейнере: при запуске двоичного файла setuid, запускающего другой исполняемый файл (execve(2)
), ядро [1] Кажется, что BusyBox отбрасывает привилегии, полученные setuid , Я думаю, что это может быть сделано из-за соображений безопасности.
Вопрос : Я хотел бы понять, почему это происходит и что за это отвечает?
Я работаю над одноразовым бегуном по сетуиду под названием kamikaze
, написанным на rust
. kamikaze
- это очень простой двоичный файл, который unlink(2)
сам по себе и затем запускает новый процесс, используя fork(2)
и execve(2)
.
Основные компоненты:
src/main.rs
[a47dedc] : Реализация unlink(2)
и процесс появления.
use std::env;
use std::fs;
use std::process::{Command, exit};
fn usage() {
println!("usage: kamikaze <command> <arguments>");
exit(1);
}
fn main() {
// Kill myself
fs::remove_file(
env::current_exe().expect("failed to get path to executable")
).expect("kamikaze failed");
let mut args: Vec<String> = env::args().collect();
match args.len() {
0 => usage(),
1 => usage(),
_ => {
args.remove(0);
let mut child = Command::new(args.remove(0))
.args(&args)
.spawn()
.expect("failed to execute process");
exit(
child
.wait()
.expect("wait failed")
.code().unwrap()
);
},
}
}
install.sh
[a47dedc] : простой установщик, который загружает kamikaze
, меняет владельца на root
и устанавливает бит setuid.
#!/usr/bin/env sh
set -euo pipefail
REPO="Enteee/kamikaze"
INSTALL="install -m 755 -o root kamikaze-download kamikaze && chmod u+s kamikaze"
curl -s "https://api.github.com/repos/${REPO}/releases/latest" \
| grep "browser_download_url" \
| cut -d '"' -f 4 \
| xargs -n1 curl -s -L --output kamikaze-download
trap 'rm kamikaze-download' EXIT
if [[ $(id -u) -ne 0 ]]; then
sudo sh -c "${INSTALL}"
else
eval "${INSTALL}"
fi
Когда я запускаю kamikaze
вне контейнера [2] :
$ curl https://raw.githubusercontent.com/Enteee/kamikaze/master/install.sh | sh
$ ./kamikaze ps -f
UID PID PPID C STIME TTY TIME CMD
root 3223 9587 0 08:17 pts/0 00:00:00 ./kamikaze ps -f
root 3224 3223 0 08:17 pts/0 00:00:00 ps -f
Я получаю ожидаемое поведение. Дочерний процесс (PID=3224
) запускается как root
. С другой стороны, внутри контейнера [2] :
$ docker build -t kamikaze - <<EOF
FROM alpine
RUN set -exuo pipefail \
&& apk add curl \
&& curl https://raw.githubusercontent.com/Enteee/kamikaze/master/install.sh | sh
USER nobody
CMD ["/kamikaze", "ps"]
EOF
$ docker run kamikaze
PID USER TIME COMMAND
1 root 0:00 /kamikaze ps
6 nobody 0:00 ps
ps
работает как nobody
.
[1] Сначала я подумал, что это из-за некоторого механизма безопасности, реализованного в Docker и ядре Linux. Но после глубокого погружения в Docker Security , NO_NEW_PRIVILEGES
и seccomp(2)
я наконец понял, что BusyBox просто отбрасывает привилегии.
[2] kamikaze [1.0.0]
исправлено и изменено это поведение. Поэтому этот пример больше не работает. Для воспроизведения примера используйте релиз kamikaze
[0.0.0] .