mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Move user home detection to its own library.
PiperOrigin-RevId: 307977689
This commit is contained in:
committed by
gVisor bot
parent
0c586946ea
commit
e69a871c7b
@@ -0,0 +1,34 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "user",
|
||||
srcs = ["user.go"],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/fspath",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "user_test",
|
||||
size = "small",
|
||||
srcs = ["user_test.go"],
|
||||
library = ":user",
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/fs/tmpfs",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/contexttest",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
)
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boot
|
||||
package user
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -136,10 +136,10 @@ func getExecUserHomeVFS2(ctx context.Context, mns *vfs.MountNamespace, uid auth.
|
||||
return homeDir, nil
|
||||
}
|
||||
|
||||
// maybeAddExecUserHome returns a new slice with the HOME enviroment variable
|
||||
// MaybeAddExecUserHome returns a new slice with the HOME enviroment variable
|
||||
// set if the slice does not already contain it, otherwise it returns the
|
||||
// original slice unmodified.
|
||||
func maybeAddExecUserHome(ctx context.Context, mns *fs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
|
||||
func MaybeAddExecUserHome(ctx context.Context, mns *fs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
|
||||
// Check if the envv already contains HOME.
|
||||
for _, env := range envv {
|
||||
if strings.HasPrefix(env, "HOME=") {
|
||||
@@ -159,7 +159,10 @@ func maybeAddExecUserHome(ctx context.Context, mns *fs.MountNamespace, uid auth.
|
||||
return append(envv, "HOME="+homeDir), nil
|
||||
}
|
||||
|
||||
func maybeAddExecUserHomeVFS2(ctx context.Context, vmns *vfs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
|
||||
// MaybeAddExecUserHomeVFS2 returns a new slice with the HOME enviroment
|
||||
// variable set if the slice does not already contain it, otherwise it returns
|
||||
// the original slice unmodified.
|
||||
func MaybeAddExecUserHomeVFS2(ctx context.Context, vmns *vfs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
|
||||
// Check if the envv already contains HOME.
|
||||
for _, env := range envv {
|
||||
if strings.HasPrefix(env, "HOME=") {
|
||||
@@ -12,167 +12,111 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boot
|
||||
package user
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"gvisor.dev/gvisor/pkg/sentry/contexttest"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/tmpfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/contexttest"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
func setupTempDir() (string, error) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "exec-user-test")
|
||||
if err != nil {
|
||||
return "", err
|
||||
// createEtcPasswd creates /etc/passwd with the given contents and mode. If
|
||||
// mode is empty, then no file will be created. If mode is not a regular file
|
||||
// mode, then contents is ignored.
|
||||
func createEtcPasswd(ctx context.Context, root *fs.Dirent, contents string, mode linux.FileMode) error {
|
||||
if err := root.CreateDirectory(ctx, root, "etc", fs.FilePermsFromMode(0755)); err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpDir, nil
|
||||
}
|
||||
|
||||
func setupPasswd(contents string, perms os.FileMode) func() (string, error) {
|
||||
return func() (string, error) {
|
||||
tmpDir, err := setupTempDir()
|
||||
etc, err := root.Walk(ctx, root, "etc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer etc.DecRef()
|
||||
switch mode.FileType() {
|
||||
case 0:
|
||||
// Don't create anything.
|
||||
return nil
|
||||
case linux.S_IFREG:
|
||||
passwd, err := etc.Create(ctx, root, "passwd", fs.FileFlags{Write: true}, fs.FilePermsFromMode(mode))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "etc"), 0777); err != nil {
|
||||
return "", err
|
||||
defer passwd.DecRef()
|
||||
if _, err := passwd.Writev(ctx, usermem.BytesIOSequence([]byte(contents))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(tmpDir, "etc", "passwd"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(contents)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = f.Chmod(perms)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmpDir, nil
|
||||
return nil
|
||||
case linux.S_IFDIR:
|
||||
return etc.CreateDirectory(ctx, root, "passwd", fs.FilePermsFromMode(mode))
|
||||
case linux.S_IFIFO:
|
||||
return etc.CreateFifo(ctx, root, "passwd", fs.FilePermsFromMode(mode))
|
||||
default:
|
||||
return fmt.Errorf("unknown file type %x", mode.FileType())
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetExecUserHome tests the getExecUserHome function.
|
||||
func TestGetExecUserHome(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
uid auth.KUID
|
||||
createRoot func() (string, error)
|
||||
expected string
|
||||
uid auth.KUID
|
||||
passwdContents string
|
||||
passwdMode linux.FileMode
|
||||
expected string
|
||||
}{
|
||||
"success": {
|
||||
uid: 1000,
|
||||
createRoot: setupPasswd("adin::1000:1111::/home/adin:/bin/sh", 0666),
|
||||
expected: "/home/adin",
|
||||
},
|
||||
"no_passwd": {
|
||||
uid: 1000,
|
||||
createRoot: setupTempDir,
|
||||
expected: "/",
|
||||
uid: 1000,
|
||||
passwdContents: "adin::1000:1111::/home/adin:/bin/sh",
|
||||
passwdMode: linux.S_IFREG | 0666,
|
||||
expected: "/home/adin",
|
||||
},
|
||||
"no_perms": {
|
||||
uid: 1000,
|
||||
createRoot: setupPasswd("adin::1000:1111::/home/adin:/bin/sh", 0000),
|
||||
expected: "/",
|
||||
uid: 1000,
|
||||
passwdContents: "adin::1000:1111::/home/adin:/bin/sh",
|
||||
passwdMode: linux.S_IFREG,
|
||||
expected: "/",
|
||||
},
|
||||
"no_passwd": {
|
||||
uid: 1000,
|
||||
expected: "/",
|
||||
},
|
||||
"directory": {
|
||||
uid: 1000,
|
||||
createRoot: func() (string, error) {
|
||||
tmpDir, err := setupTempDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "etc"), 0777); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := syscall.Mkdir(filepath.Join(tmpDir, "etc", "passwd"), 0666); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tmpDir, nil
|
||||
},
|
||||
expected: "/",
|
||||
uid: 1000,
|
||||
passwdMode: linux.S_IFDIR | 0666,
|
||||
expected: "/",
|
||||
},
|
||||
// Currently we don't allow named pipes.
|
||||
"named_pipe": {
|
||||
uid: 1000,
|
||||
createRoot: func() (string, error) {
|
||||
tmpDir, err := setupTempDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "etc"), 0777); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := syscall.Mkfifo(filepath.Join(tmpDir, "etc", "passwd"), 0666); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tmpDir, nil
|
||||
},
|
||||
expected: "/",
|
||||
uid: 1000,
|
||||
passwdMode: linux.S_IFIFO | 0666,
|
||||
expected: "/",
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
tmpDir, err := tc.createRoot()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create root dir: %v", err)
|
||||
}
|
||||
|
||||
sandEnd, cleanup, err := startGofer(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create gofer: %v", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
ctx := contexttest.Context(t)
|
||||
conf := &Config{
|
||||
RootDir: "unused_root_dir",
|
||||
Network: NetworkNone,
|
||||
DisableSeccomp: true,
|
||||
}
|
||||
msrc := fs.NewPseudoMountSource(ctx)
|
||||
rootInode := tmpfs.NewDir(ctx, nil, fs.RootOwner, fs.FilePermsFromMode(0777), msrc)
|
||||
|
||||
spec := &specs.Spec{
|
||||
Root: &specs.Root{
|
||||
Path: tmpDir,
|
||||
Readonly: true,
|
||||
},
|
||||
// Add /proc mount as tmpfs to avoid needing a kernel.
|
||||
Mounts: []specs.Mount{
|
||||
{
|
||||
Destination: "/proc",
|
||||
Type: "tmpfs",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mntr := newContainerMounter(spec, []int{sandEnd}, nil, &podMountHints{})
|
||||
mns, err := mntr.createMountNamespace(ctx, conf)
|
||||
mns, err := fs.NewMountNamespace(ctx, rootInode)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create mount namespace: %v", err)
|
||||
t.Fatalf("NewMountNamespace failed: %v", err)
|
||||
}
|
||||
ctx = fs.WithRoot(ctx, mns.Root())
|
||||
if err := mntr.mountSubmounts(ctx, conf, mns); err != nil {
|
||||
t.Fatalf("failed to create mount namespace: %v", err)
|
||||
defer mns.DecRef()
|
||||
root := mns.Root()
|
||||
defer root.DecRef()
|
||||
ctx = fs.WithRoot(ctx, root)
|
||||
|
||||
if err := createEtcPasswd(ctx, root, tc.passwdContents, tc.passwdMode); err != nil {
|
||||
t.Fatalf("createEtcPasswd failed: %v", err)
|
||||
}
|
||||
|
||||
got, err := getExecUserHome(ctx, mns, tc.uid)
|
||||
+1
-4
@@ -20,7 +20,6 @@ go_library(
|
||||
"loader_arm64.go",
|
||||
"network.go",
|
||||
"strace.go",
|
||||
"user.go",
|
||||
"vfs.go",
|
||||
],
|
||||
visibility = [
|
||||
@@ -52,6 +51,7 @@ go_library(
|
||||
"//pkg/sentry/fs/sys",
|
||||
"//pkg/sentry/fs/tmpfs",
|
||||
"//pkg/sentry/fs/tty",
|
||||
"//pkg/sentry/fs/user",
|
||||
"//pkg/sentry/fsimpl/devtmpfs",
|
||||
"//pkg/sentry/fsimpl/gofer",
|
||||
"//pkg/sentry/fsimpl/host",
|
||||
@@ -97,7 +97,6 @@ go_library(
|
||||
"//pkg/tcpip/transport/tcp",
|
||||
"//pkg/tcpip/transport/udp",
|
||||
"//pkg/urpc",
|
||||
"//pkg/usermem",
|
||||
"//runsc/boot/filter",
|
||||
"//runsc/boot/platforms",
|
||||
"//runsc/boot/pprof",
|
||||
@@ -115,7 +114,6 @@ go_test(
|
||||
"compat_test.go",
|
||||
"fs_test.go",
|
||||
"loader_test.go",
|
||||
"user_test.go",
|
||||
],
|
||||
library = ":boot",
|
||||
deps = [
|
||||
@@ -125,7 +123,6 @@ go_test(
|
||||
"//pkg/sentry/contexttest",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sync",
|
||||
"//pkg/unet",
|
||||
"//runsc/fsgofer",
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/control"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/host"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/user"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -550,11 +551,11 @@ func (l *Loader) run() error {
|
||||
// Add the HOME enviroment variable if it is not already set.
|
||||
var envv []string
|
||||
if kernel.VFS2Enabled {
|
||||
envv, err = maybeAddExecUserHomeVFS2(ctx, l.rootProcArgs.MountNamespaceVFS2,
|
||||
envv, err = user.MaybeAddExecUserHomeVFS2(ctx, l.rootProcArgs.MountNamespaceVFS2,
|
||||
l.rootProcArgs.Credentials.RealKUID, l.rootProcArgs.Envv)
|
||||
|
||||
} else {
|
||||
envv, err = maybeAddExecUserHome(ctx, l.rootProcArgs.MountNamespace,
|
||||
envv, err = user.MaybeAddExecUserHome(ctx, l.rootProcArgs.MountNamespace,
|
||||
l.rootProcArgs.Credentials.RealKUID, l.rootProcArgs.Envv)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -860,7 +861,7 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
|
||||
root := args.MountNamespace.Root()
|
||||
defer root.DecRef()
|
||||
ctx := fs.WithRoot(l.k.SupervisorContext(), root)
|
||||
envv, err := maybeAddExecUserHome(ctx, args.MountNamespace, args.KUID, args.Envv)
|
||||
envv, err := user.MaybeAddExecUserHome(ctx, args.MountNamespace, args.KUID, args.Envv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user