Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pkg/cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ func ExecOnContainer(args []string) error {
EnvAll bool
PassEnv wrapper.StringFlags
Dir string
User string
contName string
)

f.BoolVar(&help, "help", false, "show this help message")
f.BoolVar(&EnvAll, "env-all", false, "send all enviroment variables to container")
f.StringVar(&Dir, "dir", "", "working directory")
f.StringVar(&User, "user", "", "work user")

f.Var(&PassEnv, "env-pass", "pass only requested enviroment variables to container")

// Allocate variable locations
Expand Down Expand Up @@ -90,7 +93,10 @@ func ExecOnContainer(args []string) error {
}
}

exitCode, err = cruntime.Exec(childArgs, "")
if User == "" {
User = c.User
}
exitCode, err = cruntime.Exec(childArgs, "", User)
if err != nil && strings.Contains(err.Error(), "exit status") {
err = nil
}
Expand Down
25 changes: 18 additions & 7 deletions pkg/container/cruntime/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import (
"golang.org/x/sys/unix"
)

func runCommands(c []string, chroot string) {
func runCommands(c []string, chroot string, user string) {
for _, command := range c {
Exec(cmdline.Parse(command), chroot)
Exec(cmdline.Parse(command), chroot, user)
}
}

// Execute under container chroot
func Exec(c []string, chroot string) (exitCode int, err error) {
func Exec(c []string, chroot string, user string) (exitCode int, err error) {
var (
cmd *exec.Cmd
mainRoot *os.File
Expand Down Expand Up @@ -70,13 +70,24 @@ func Exec(c []string, chroot string) (exitCode int, err error) {
// Cloneflags: unix.CLONE_NEWUTS,
}

if chroot != "" {
cmd.SysProcAttr = &unix.SysProcAttr{
// Cloneflags: unix.CLONE_NEWUTS,
Chroot: chroot,
if user != "" {
u, err2 := getUser(user)
if err2 != nil {
err = err2
return
}

cmd.SysProcAttr.Credential = u.Credential
if u.User != nil && u.User.HomeDir != "" {
cmd.Dir = u.User.HomeDir
cmd.Env = append([]string{"HOME=" + u.User.HomeDir}, cmd.Env...)
}
}

if chroot != "" {
cmd.SysProcAttr.Chroot = chroot
}

err = cmd.Run()

if err != nil && err.Error() == "waitid: no child processes" {
Expand Down
11 changes: 8 additions & 3 deletions pkg/container/cruntime/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ func ContainerInitProc() {
if err != nil {
return err
}
runCommands(c.RunPrePivot, "/.old_root/")
// do not execute pre commands as defined user
runCommands(c.RunPrePivot, "/.old_root/", "")
purgeOldRoot(c)
runCommands(c.RunPreExec, "")
runCommands(c.RunPreExec, "", "")

if len(c.ContArgs) == 0 {
return fmt.Errorf("no container arg providen, malformed container file")
Expand All @@ -127,7 +128,11 @@ func ContainerInitProc() {
os.Chdir(c.Dir)
}

err = switchUser(c.User)
user, err := getUser(c.User)
if err != nil {
return err
}
err = switchUser(user)
if err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/container/cruntime/namespace/allocate.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package namespace

func (ns *NamespaceConf) defaults() {

if ns.UserValue == nil {
temp := ""
ns.UserValue = &temp
}

switch *ns.UserValue {
case "host":
ns.IsHost = true
Expand Down
74 changes: 55 additions & 19 deletions pkg/container/cruntime/user.go
Original file line number Diff line number Diff line change
@@ -1,54 +1,90 @@
package cruntime

import (
"os"
os_user "os/user"
"strconv"
"strings"
"syscall"
)

func switchUser(user string) (err error) {
type User struct {
Credential *syscall.Credential
User *os_user.User
}

if user == "" {
return nil
func getUser(ug string) (User User, err error) {
if ug == "" {
return
}

var (
uid int
gid int
uid uint64
gid uint64
)
credential := strings.Split(user, ":")
user_group := strings.Split(ug, ":")

if uid, err = strconv.Atoi(credential[0]); err != nil {
user, err := os_user.Lookup(credential[0])
if uid, err = strconv.ParseUint(user_group[0], 10, 32); err != nil {
User.User, err = os_user.Lookup(user_group[0])
if err == nil {
uid, _ = strconv.Atoi(user.Uid)
uid, _ = strconv.ParseUint(User.User.Uid, 10, 32)
// if usergroup is not presented, try gid info from user information

if len(credential) == 1 && user.Gid != "" {
credential = append(credential, user.Gid)
if len(user_group) == 1 && User.User.Gid != "" {
user_group = append(user_group, User.User.Gid)
}
} else {
return err
return
}

}

// if usergroup is not presented, set group name identical to username
if len(credential) == 1 {
credential = append(credential, credential[0])
if len(user_group) == 1 {
user_group = append(user_group, user_group[0])
}

if gid, err = strconv.Atoi(credential[1]); err != nil {
group, err := os_user.LookupGroup(credential[1])
if gid, err = strconv.ParseUint(user_group[1], 10, 32); err != nil {
group, err := os_user.LookupGroup(user_group[1])
if err == nil {
gid, _ = strconv.Atoi(group.Gid)
gid, _ = strconv.ParseUint(group.Gid, 10, 32)
}
}

err = syscall.Setgid(gid)
User.Credential = &syscall.Credential{}
User.Credential.Uid = uint32(uid)
User.Credential.Gid = uint32(gid)

return
}

func switchUser(user User) error {
err := switchCredential(user.Credential)
if err != nil {
return err
}
err = syscall.Setuid(uid)

if user.User == nil {
return nil
}

if user.User.HomeDir != "" {
os.Chdir(user.User.HomeDir)
}

return nil
}

func switchCredential(Credential *syscall.Credential) (err error) {
if Credential == nil {
return
}
err = syscall.Setgid(int(Credential.Gid))
if err != nil {
return
}

err = syscall.Setuid(int(Credential.Uid))

return
}
Loading