英文:
Is there a way to chroot/sandbox a go os.exec call (prevent rm -rf /)
问题
我想测试/自动化一些代码库,基本流程如下:
repos := []string{"repo 1", "repo 2", ...}
for r := range repos {
// 克隆代码库
// 进入代码库目录
// 运行测试
// 构建代码
// ...
}
我正在使用GO来实现这个过程,使用os.exec
调用一系列命令,类似于:
exec.Command("sh", "-c", "git clone project")
到目前为止一切顺利,但我想知道是否有一种方法可以防止在Makefile中出现类似rm -rf /
的错误写法,从而破坏我的主机。
基本上,我想使用系统库/工具,但限制/限定输出到特定的workdir
,这样我就可以避免预先构建chroot。
一个可行的解决方案是使用FreeBSD jail,但我想知道是否有一种替代/安全的方法,在不使用容器、虚拟机等的情况下,在基本的Mac OS X工作站上实现这一点,以便任何人都可以“安全地”运行和测试,而不用担心。
有什么想法吗?
英文:
I want to test/automate some repositories, the basic flow is something like:
repos := []string{"repo 1", "repo 2", ...}
for r := range repos {
// git clone the repo
// cd repo dir
// make test
// make build
// ...
}
I am doing this with GO using os.exec
to call the all the series of commands, something like:
exec.Command("sh", "-c", "git clone project")
So far so good, but I would like to know if there is a way to secure/protect against something miswriting on the Makefile that could be doing something like rm -rf /
. and break my host.
Basically I would like to use the system libraries/tools but restrict/chroot only the output to a specific workdir
, so that I can avoid pre-build a chroot for this.
A working solution is to use a FreeBSD jail, but I would like to know if there an alternative/secure way of doing this without the need of containers,virtualbox,etc; and using a basic Mac OS X workstation. so that anyone could "safely" run & test without worries.
Any ideas ?
答案1
得分: 1
你可以使用os.Setuid/os.Setgid来实现这个功能(example.go):
package main
import (
"log"
"flag"
"os"
"os/exec"
"syscall"
)
func main() {
var oUid = flag.Int("uid", 0, "Run with User ID")
var oGid = flag.Int("gid", 0, "Run with Group ID")
flag.Parse()
// 从参数中获取UID/GID
var uid = *oUid
var gid = *oGid
// 运行whoami命令
out, err := exec.Command("whoami").Output()
if err != nil {
log.Fatal(err)
return
}
// 输出whoami结果
log.Println("原始的UID/GID whoami:", string(out))
log.Println("设置UID/GID")
// 更改权限
err = syscall.Setgid(gid)
if err != nil {
log.Println("无法设置gid")
log.Fatal(err)
return
}
err = syscall.Setuid(uid)
if err != nil {
log.Println("无法设置uid")
log.Fatal(err)
return
}
// 再次执行whoami命令
out, err = exec.Command("whoami").Output()
if err != nil {
log.Fatal(err)
return
}
log.Println("更改后的UID/GID whoami:", string(out))
// 做一些危险的操作
log.Println("在/bin目录下创建一个可执行文件应该会失败...")
_, err = os.Create("/bin/should-fail")
if err == nil {
log.Println("警告:操作没有失败")
return
}
log.Println("一切正常", err)
}
我还建议你阅读关于正确设置gid/uid的内容(https://unix.stackexchange.com/questions/166817/using-the-setuid-bit-properly,使用C语言)。哦!需要先设置gid再设置uid,因为如果不这样做,示例会失败。
你应该以root权限执行example.go
,并使用-gid,-uid标志指定非特权的gid/uid命令。
sudo go run example.go -uid <非特权id> -gid <非特权id>
英文:
You should be fine using os.Setuid/os.Setgid (example.go):
package main
import (
"log"
"flag"
"os"
"os/exec"
"syscall"
)
func main() {
var oUid = flag.Int("uid", 0, "Run with User ID")
var oGid = flag.Int("gid", 0, "Run with Group ID")
flag.Parse()
// Get UID/GUID from args
var uid = *oUid
var gid = *oGid
// Run whoami
out, err := exec.Command("whoami").Output()
if err != nil {
log.Fatal(err)
return
}
// Output whoami
log.Println("Original UID/GID whoami:", string(out))
log.Println("Setting UID/GUID")
// Change privileges
err = syscall.Setgid(gid)
if err != nil {
log.Println("Cannot setgid")
log.Fatal(err)
return
}
err = syscall.Setuid(uid)
if err != nil {
log.Println("Cannot setuid")
log.Fatal(err)
return
}
// Execute whoami again
out, err = exec.Command("whoami").Output()
if err != nil {
log.Fatal(err)
return
}
log.Println("Changed UID/GID whoami:", string(out))
// Do some dangerous stuff
log.Println("Creating a executable file within /bin should fail...")
_, err = os.Create("/bin/should-fail")
if err == nil {
log.Println("Warning: operation did not fail")
return
}
log.Println("We are fine", err)
}
I would also recommend to read about setting gid/uid properly (https://unix.stackexchange.com/questions/166817/using-the-setuid-bit-properly, in C). Oh! its needed to set gid before uid, because the example fails if you don't do so.
You should execute example.go
with root privileges and specify unprivileged gid/uid to the command with flags -gid,-uid respectively.
sudo go run example.go -uid <unprivileged id> -gid <unprivileged id>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论