Skip to content

Commit

Permalink
no longer constantly run as root
Browse files Browse the repository at this point in the history
no more possible security vulnerabilities 😔
  • Loading branch information
axtloss committed Aug 10, 2024
1 parent ff825a3 commit 7997529
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
2 changes: 1 addition & 1 deletion cmd/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func compileCommand(cmd *cobra.Command, args []string) error {
runtime = detectedRuntime
}

err := core.CompileRecipe(recipePath, runtime)
err := core.CompileRecipe(recipePath, runtime, IsRoot, OrigGID, OrigUID)
if err != nil {
return err
}
Expand Down
33 changes: 33 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package cmd

import (
"fmt"
"os"
"path/filepath"
"strconv"
"syscall"

"github.com/spf13/cobra"
)

var Version = "0.7.4"
var IsRoot = false
var OrigUID = 1000
var OrigGID = 1000
var OrigUser = "user"

var rootCmd = &cobra.Command{
Use: "vib",
Expand All @@ -20,5 +30,28 @@ func init() {
}

func Execute() error {
if os.Getuid() == 0 {
IsRoot = true
gid, err := strconv.Atoi(os.Getenv("SUDO_GID"))
if err != nil {
return fmt.Errorf("failed to get user uid through SUDO_UID: %s", err.Error())
}
OrigGID = gid // go moment??
uid, err := strconv.Atoi(os.Getenv("SUDO_UID"))
if err != nil {
return fmt.Errorf("failed to get user uid through SUDO_GID: %s", err.Error())
}
OrigUID = uid
user := os.Getenv("SUDO_USER")
os.Setenv("HOME", filepath.Join("/home", user))
err = syscall.Seteuid(OrigUID)
if err != nil {
fmt.Println("WARN: Failed to drop root privileges")
}
err = syscall.Setgid(OrigGID)
if err != nil {
fmt.Println("WARN: Failed to drop root privileges")
}
}
return rootCmd.Execute()
}
21 changes: 15 additions & 6 deletions core/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,29 @@ import (
"fmt"
"os"
"os/exec"
"syscall"

"github.com/mitchellh/mapstructure"
"github.com/vanilla-os/vib/api"
)

// CompileRecipe compiles a recipe into a runnable image.
func CompileRecipe(recipePath string, runtime string) error {
func CompileRecipe(recipePath string, runtime string, isRoot bool, origGid int, origUid int) error {
recipe, err := BuildRecipe(recipePath)
if err != nil {
return err
}

syscall.Seteuid(0)
syscall.Setegid(0)
switch runtime {
case "docker":
err = compileDocker(recipe)
err = compileDocker(recipe, origGid, origUid)
if err != nil {
return err
}
case "podman":
err = compilePodman(recipe)
err = compilePodman(recipe, origGid, origUid)
if err != nil {
return err
}
Expand All @@ -32,6 +35,8 @@ func CompileRecipe(recipePath string, runtime string) error {
default:
return fmt.Errorf("no runtime specified and the prometheus library is not implemented yet")
}
syscall.Seteuid(origUid)
syscall.Setegid(origGid)

for _, finalizeInterface := range recipe.Finalize {
var module Finalize
Expand All @@ -40,7 +45,7 @@ func CompileRecipe(recipePath string, runtime string) error {
if err != nil {
return err
}
err = LoadFinalizePlugin(module.Type, finalizeInterface, &recipe, runtime)
err = LoadFinalizePlugin(module.Type, finalizeInterface, &recipe, runtime, isRoot, origGid, origUid)
if err != nil {
return err
}
Expand All @@ -51,7 +56,7 @@ func CompileRecipe(recipePath string, runtime string) error {
return nil
}

func compileDocker(recipe api.Recipe) error {
func compileDocker(recipe api.Recipe, gid int, uid int) error {
docker, err := exec.LookPath("docker")
if err != nil {
return err
Expand All @@ -66,11 +71,13 @@ func compileDocker(recipe api.Recipe) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = recipe.ParentPath
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an integer with architecture-dependent bit size from
strconv.Atoi
to a lower bit size type uint32 without an upper bound check.

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an integer with architecture-dependent bit size from
strconv.Atoi
to a lower bit size type uint32 without an upper bound check.

return cmd.Run()
}

func compilePodman(recipe api.Recipe) error {
func compilePodman(recipe api.Recipe, gid int, uid int) error {
podman, err := exec.LookPath("podman")
if err != nil {
return err
Expand All @@ -85,6 +92,8 @@ func compilePodman(recipe api.Recipe) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = recipe.ParentPath
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an integer with architecture-dependent bit size from
strconv.Atoi
to a lower bit size type uint32 without an upper bound check.

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an integer with architecture-dependent bit size from
strconv.Atoi
to a lower bit size type uint32 without an upper bound check.

return cmd.Run()
}
13 changes: 11 additions & 2 deletions core/plugins.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
)
import (
"os"
"syscall"
)

var openedBuildPlugins map[string]Plugin
Expand All @@ -21,7 +22,7 @@ func LoadPlugin(name string, plugintype api.PluginType, recipe *api.Recipe) (uin

localPluginPath := fmt.Sprintf("%s/%s.so", recipe.PluginPath, name)

globalPluginPath := fmt.Sprintf("%INSTALLPREFIX%/share/vib/plugins/%s.so", name)
globalPluginPath := fmt.Sprintf("%INSTALLPREFIX%/share/vib/plugins/%s.so", name)

// Prefer local plugins before global ones
var loadedPlugin uintptr
Expand Down Expand Up @@ -106,7 +107,7 @@ func LoadBuildPlugin(name string, module interface{}, recipe *api.Recipe) (strin
}
}

func LoadFinalizePlugin(name string, module interface{}, recipe *api.Recipe, runtime string) error {
func LoadFinalizePlugin(name string, module interface{}, recipe *api.Recipe, runtime string, isRoot bool, origGid int, origUid int) error {
if openedFinalizePlugins == nil {
openedFinalizePlugins = make(map[string]Plugin)
}
Expand All @@ -127,6 +128,9 @@ func LoadFinalizePlugin(name string, module interface{}, recipe *api.Recipe, run
}
fmt.Printf("Using Finalize plugin: %s\n", finalizeModule.Name)

syscall.Seteuid(0)
syscall.Setegid(0)

var getPluginScope func() int32
purego.RegisterLibFunc(&getPluginScope, finalizeModule.LoadedPlugin, "PluginScope")
scope := getPluginScope()
Expand All @@ -153,6 +157,9 @@ func LoadFinalizePlugin(name string, module interface{}, recipe *api.Recipe, run
scopedata.Runtime = runtime
}
if scope&api.FS == api.FS {
if !isRoot {
return fmt.Errorf("Plugin %s requires scope api.FS, which requires vib to run as root", finalizeModule.Name)
}
imageID, err := GetImageID(imageName, containerStorage)
if err != nil {
return err
Expand All @@ -172,6 +179,8 @@ func LoadFinalizePlugin(name string, module interface{}, recipe *api.Recipe, run
return err
}
res := finalizeModule.BuildFunc(C.CString(string(moduleJson)), C.CString(string(scopeJson)))
syscall.Seteuid(origGid)
syscall.Setegid(origUid)
if strings.HasPrefix(res, "ERROR:") {
return fmt.Errorf("%s", strings.Replace(res, "ERROR: ", "", 1))
} else {
Expand Down

0 comments on commit 7997529

Please sign in to comment.