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 ?
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>