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  }