Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Docker 为什么将setuid放在alpine容器中的execve上?_Docker_Security_Rust_System Calls_Busybox - Fatal编程技术网

Docker 为什么将setuid放在alpine容器中的execve上?

Docker 为什么将setuid放在alpine容器中的execve上?,docker,security,rust,system-calls,busybox,Docker,Security,Rust,System Calls,Busybox,仅在alpine容器中:当运行启动其他可执行文件(execve(2))的setuid二进制文件时,内核[1]BusyBox似乎会放弃setuid获得的特权。我认为这可能是出于安全考虑而设计的 问题:我想了解为什么会发生这种情况,是什么原因造成的 我正在开发一款名为Write inrust的一次性setuid runnerkamikaze是一个非常简单的二进制文件,它本身就是一个二进制文件,然后使用and启动一个新进程 主要组成部分包括: :实现取消链接(2)和进程生成 使用std::env; 使

仅在alpine容器中:当运行启动其他可执行文件(
execve(2)
)的setuid二进制文件时,内核[1]BusyBox似乎会放弃setuid获得的特权。我认为这可能是出于安全考虑而设计的

问题:我想了解为什么会发生这种情况,是什么原因造成的

我正在开发一款名为Write in
rust
的一次性setuid runner
kamikaze
是一个非常简单的二进制文件,它本身就是一个二进制文件,然后使用and启动一个新进程

主要组成部分包括:

:实现
取消链接(2)
和进程生成

使用std::env;
使用std::fs;
使用std::process::{Command,exit};
fn用法(){
println!(“用法:kamikaze:一个简单的安装程序,它下载
kamikaze
,将所有权更改为
root
,并设置setuid位

!/usr/bin/env sh
设置-euo管道故障
REPO=“Enteee/kamikaze”
INSTALL=“INSTALL-m 755-o root kamikaze下载kamikaze&&chmod u+s kamikaze”
旋度-s“https://api.github.com/repos/${REPO}/releases/latest“\
|grep“浏览器\下载\ url”\
|切割-d''-f 4\
|xargs-n1 curl-s-L——输出kamikaze下载
陷阱“rm kamikaze下载”退出
如果[[$(id-u)-ne 0]];则
sudo sh-c“${INSTALL}”
其他的
评估“${INSTALL}”
fi
当我在容器外运行
kamikaze
时[2]:

$curlhttps://raw.githubusercontent.com/Enteee/kamikaze/master/install.sh |嘘
美元/神风ps-f
UID PID PPID C TIME TTY TIME CMD
根32239587 0 08:17分/0 00:00:00./kamikaze ps-f
根3224323008:17分/0 00:00:00秒-f
我获得了预期的行为。子进程(
PID=3224
)作为
根运行。另一方面,在容器[2]中:


$docker build-t kamikaze-BusyBox在alpine中实现了
ps
命令,它通过将有效用户id设置为真实用户id来删除setuid获得的权限

:

:定义
BB\u SUID\u DROP

//                 APPLET_NOEXEC:name    main location    suid_type     help
//applet:IF_PS(    APPLET_NOEXEC(ps,     ps,  BB_DIR_BIN, BB_SUID_DROP, ps))
//applet:IF_MINIPS(APPLET_NOEXEC(minips, ps,  BB_DIR_BIN, BB_SUID_DROP, ps))
解决方法很简单。
kamikaze
只需在
execve(2)
之前将真实用户id设置为有效用户id即可

:


也许值得一提:我最初认为权限降级发生在
fork(2)
上,但我实现了,并且看到了相同的行为。也许手册页的这部分可以解释:如果设置的用户ID位是在文件名指向的程序文件上设置的,而基础文件系统没有装载NOSUD(挂载的MS_NOSUID标志(2)),并且调用进程未被ptrace,则调用进程的有效用户ID将更改为程序文件所有者的ID。类似地,当设置程序文件的set group ID位时,调用进程的有效组ID将设置为程序文件的组。谢谢。据我所知,该部分手册页的第页解释了setuid的工作原理。这正是我在容器外部看到的,而不是在容器内部看到的。或者我遗漏了什么?也可能值得注意:docker挂载根文件系统时没有nosuid标志:
$docker run-ti alpine sh-c'mount | grep-I“on/”
生成
overlay on/type overlay(rw、relatime、lowerdir=/var/lib/docker/overlay2/l/GXDHPBDM7TSYZS5OP43RJVSOWM:/var/lib/docker/overlay2/l/C57Dorpgimsueof6YYSBNATK、upperdir=/var/lib/docker/overlay2/c9f27caebcbff131d58137067feb75b941b5d7ad4d5677a8140334dce75ad576/diff、workdir=/var/lib/docr/docr/docr/docker/docker/overlay2/C9F27CACBFF131D75757D757AD757D757D757D757D757D757D757D777D7D7D7D7D7D7D7D7D7D
这里为setuid的工作指定了3个条件。您应该检查这些条件在常规环境和容器之间是否不同。具体来说,最有可能的是装载参数。
//                 APPLET_NOEXEC:name    main location    suid_type     help
//applet:IF_PS(    APPLET_NOEXEC(ps,     ps,  BB_DIR_BIN, BB_SUID_DROP, ps))
//applet:IF_MINIPS(APPLET_NOEXEC(minips, ps,  BB_DIR_BIN, BB_SUID_DROP, ps))
extern crate exec;
extern crate users;

use std::env;

use std::fs;

use std::process::exit;

use users::{get_effective_uid, get_effective_gid};
use users::switch::{set_current_uid, set_current_gid};

fn usage() {
    println!("usage: kamikaze <command> <arguments>");
}

fn main() {

    // Kill myself
    fs::remove_file(
        env::current_exe().expect("failed to get path to executable")
    ).expect("kamikaze failed");

    set_current_uid(
        get_effective_uid()
    ).expect("failed setting current uid");

    set_current_gid(
        get_effective_gid()
    ).expect("failed setting current gid");

    let mut args: Vec<String> = env::args().collect();
    match args.len() {
        0 => usage(),
        1 => usage(),
        _ => {
            args.remove(0);
            let err = exec::Command::new(args.remove(0))
                .args(&args)
                .exec();
            println!("Error: {}", err);
        },
    }
    // Should never get here
    exit(1);
}