gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/cmd/exec_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "os" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cmp/cmp/cmpopts" 23 specs "github.com/opencontainers/runtime-spec/specs-go" 24 "gvisor.dev/gvisor/pkg/abi/linux" 25 "gvisor.dev/gvisor/pkg/sentry/control" 26 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 27 ) 28 29 func TestUser(t *testing.T) { 30 testCases := []struct { 31 input string 32 want user 33 wantErr bool 34 }{ 35 {input: "0", want: user{kuid: 0, kgid: 0}}, 36 {input: "7", want: user{kuid: 7, kgid: 0}}, 37 {input: "49:343", want: user{kuid: 49, kgid: 343}}, 38 {input: "0:2401", want: user{kuid: 0, kgid: 2401}}, 39 {input: "", wantErr: true}, 40 {input: "foo", wantErr: true}, 41 {input: ":123", wantErr: true}, 42 {input: "1:2:3", wantErr: true}, 43 } 44 45 for _, tc := range testCases { 46 var u user 47 if err := u.Set(tc.input); err != nil && tc.wantErr { 48 // We got an error and wanted one. 49 continue 50 } else if err == nil && tc.wantErr { 51 t.Errorf("user.Set(%s): got no error, but wanted one", tc.input) 52 } else if err != nil && !tc.wantErr { 53 t.Errorf("user.Set(%s): got error %v, but wanted none", tc.input, err) 54 } else if u != tc.want { 55 t.Errorf("user.Set(%s): got %+v, but wanted %+v", tc.input, u, tc.want) 56 } 57 } 58 } 59 60 func TestCLIArgs(t *testing.T) { 61 testCases := []struct { 62 ex Exec 63 argv []string 64 expected control.ExecArgs 65 }{ 66 { 67 ex: Exec{ 68 cwd: "/foo/bar", 69 user: user{kuid: 0, kgid: 0}, 70 extraKGIDs: []string{"1", "2", "3"}, 71 caps: []string{"CAP_DAC_OVERRIDE"}, 72 processPath: "", 73 }, 74 argv: []string{"ls", "/"}, 75 expected: control.ExecArgs{ 76 Argv: []string{"ls", "/"}, 77 WorkingDirectory: "/foo/bar", 78 FilePayload: control.NewFilePayload(map[int]*os.File{ 79 0: os.Stdin, 80 1: os.Stdout, 81 2: os.Stderr, 82 }, nil), 83 KUID: 0, 84 KGID: 0, 85 ExtraKGIDs: []auth.KGID{1, 2, 3}, 86 Capabilities: &auth.TaskCapabilities{ 87 BoundingCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 88 EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 89 InheritableCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 90 PermittedCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 91 }, 92 }, 93 }, 94 } 95 96 for _, tc := range testCases { 97 e, err := tc.ex.argsFromCLI(tc.argv, true) 98 if err != nil { 99 t.Errorf("argsFromCLI(%+v): got error: %+v", tc.ex, err) 100 } else if !cmp.Equal(*e, tc.expected, cmpopts.IgnoreUnexported(os.File{})) { 101 t.Errorf("argsFromCLI(%+v): got %+v, but expected %+v", tc.ex, *e, tc.expected) 102 } 103 } 104 } 105 106 func TestJSONArgs(t *testing.T) { 107 testCases := []struct { 108 // ex is provided to make sure it is overridden by p. 109 ex Exec 110 p specs.Process 111 expected control.ExecArgs 112 }{ 113 { 114 ex: Exec{ 115 cwd: "/baz/quux", 116 user: user{kuid: 1, kgid: 1}, 117 extraKGIDs: []string{"4", "5", "6"}, 118 caps: []string{"CAP_SETGID"}, 119 processPath: "/bin/foo", 120 }, 121 p: specs.Process{ 122 User: specs.User{UID: 0, GID: 0, AdditionalGids: []uint32{1, 2, 3}}, 123 Args: []string{"ls", "/"}, 124 Cwd: "/foo/bar", 125 Capabilities: &specs.LinuxCapabilities{ 126 Bounding: []string{"CAP_DAC_OVERRIDE"}, 127 Effective: []string{"CAP_DAC_OVERRIDE"}, 128 Inheritable: []string{"CAP_DAC_OVERRIDE"}, 129 Permitted: []string{"CAP_DAC_OVERRIDE"}, 130 }, 131 }, 132 expected: control.ExecArgs{ 133 Argv: []string{"ls", "/"}, 134 WorkingDirectory: "/foo/bar", 135 FilePayload: control.NewFilePayload(map[int]*os.File{ 136 0: os.Stdin, 137 1: os.Stdout, 138 2: os.Stderr, 139 }, nil), 140 KUID: 0, 141 KGID: 0, 142 ExtraKGIDs: []auth.KGID{1, 2, 3}, 143 Capabilities: &auth.TaskCapabilities{ 144 BoundingCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 145 EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 146 InheritableCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 147 PermittedCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE), 148 }, 149 }, 150 }, 151 } 152 153 for _, tc := range testCases { 154 e, err := argsFromProcess(&tc.p, true) 155 if err != nil { 156 t.Errorf("argsFromProcess(%+v): got error: %+v", tc.p, err) 157 } else if !cmp.Equal(*e, tc.expected, cmpopts.IgnoreUnexported(os.File{})) { 158 t.Errorf("argsFromProcess(%+v): got %+v, but expected %+v", tc.p, *e, tc.expected) 159 } 160 } 161 }