gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/kernel/auth/capability_set_test.go (about)

     1  // Copyright 2024 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 auth
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"gvisor.dev/gvisor/pkg/abi/linux"
    22  	"gvisor.dev/gvisor/pkg/errors/linuxerr"
    23  )
    24  
    25  // capsEquals returns trun when the given creds' capabilities match the given caps.
    26  func capsEquals(creds *Credentials, caps TaskCapabilities) bool {
    27  	return creds.PermittedCaps == caps.PermittedCaps &&
    28  		creds.InheritableCaps == caps.InheritableCaps &&
    29  		creds.EffectiveCaps == caps.EffectiveCaps &&
    30  		creds.BoundingCaps == caps.BoundingCaps
    31  }
    32  
    33  // credentialsWithCaps returns a copy of creds with the given capabilities.
    34  func credentialsWithCaps(creds *Credentials, permittedCaps, inheritableCaps, effectiveCaps, boundingCaps CapabilitySet) *Credentials {
    35  	newCreds := creds.Fork()
    36  	newCreds.PermittedCaps = permittedCaps
    37  	newCreds.InheritableCaps = inheritableCaps
    38  	newCreds.EffectiveCaps = effectiveCaps
    39  	newCreds.BoundingCaps = boundingCaps
    40  	return newCreds
    41  }
    42  
    43  func TestCapsFromVfsCaps(t *testing.T) {
    44  	for _, tst := range []struct {
    45  		name     string
    46  		capData  VfsCapData
    47  		creds    *Credentials
    48  		wantCaps TaskCapabilities
    49  		wantErr  error
    50  	}{
    51  		{
    52  			name: "TestRootCredential",
    53  			capData: VfsCapData{
    54  				MagicEtc:    0x2000001,
    55  				Permitted:   CapabilitySetOf(linux.CAP_NET_ADMIN),
    56  				Inheritable: CapabilitySetOf(linux.CAP_NET_ADMIN),
    57  			},
    58  			creds: credentialsWithCaps(NewRootCredentials(NewRootUserNamespace()), AllCapabilities, CapabilitySetOf(linux.CAP_NET_RAW), AllCapabilities, CapabilitySetOf(linux.CAP_SYSLOG)),
    59  			wantCaps: TaskCapabilities{
    60  				PermittedCaps:   AllCapabilities,
    61  				InheritableCaps: CapabilitySetOf(linux.CAP_NET_RAW),
    62  				EffectiveCaps:   AllCapabilities,
    63  				BoundingCaps:    CapabilitySetOf(linux.CAP_SYSLOG),
    64  			},
    65  			wantErr: nil,
    66  		},
    67  		{
    68  			name: "TestPermittedAndInheritableCaps",
    69  			capData: VfsCapData{
    70  				MagicEtc:    0x2000001,
    71  				Permitted:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID}),
    72  				Inheritable: CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETGID}),
    73  			},
    74  			creds: credentialsWithCaps(
    75  				NewUserCredentials(123, 321, nil, nil, NewRootUserNamespace()),
    76  				AllCapabilities,
    77  				AllCapabilities,
    78  				AllCapabilities,
    79  				AllCapabilities),
    80  			wantCaps: TaskCapabilities{
    81  				PermittedCaps:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID, linux.CAP_SETGID}),
    82  				InheritableCaps: AllCapabilities,
    83  				EffectiveCaps:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID, linux.CAP_SETGID}),
    84  				BoundingCaps:    AllCapabilities,
    85  			},
    86  			wantErr: nil,
    87  		},
    88  		{
    89  			name: "TestEffectiveBitOff",
    90  			capData: VfsCapData{
    91  				MagicEtc:    0x2000000,
    92  				Permitted:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID}),
    93  				Inheritable: CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETGID}),
    94  			},
    95  			creds: credentialsWithCaps(
    96  				NewUserCredentials(123, 321, nil, nil, NewRootUserNamespace()),
    97  				AllCapabilities,
    98  				AllCapabilities,
    99  				AllCapabilities,
   100  				AllCapabilities),
   101  			wantCaps: TaskCapabilities{
   102  				PermittedCaps:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID, linux.CAP_SETGID}),
   103  				InheritableCaps: AllCapabilities,
   104  				EffectiveCaps:   0,
   105  				BoundingCaps:    AllCapabilities,
   106  			},
   107  			wantErr: nil,
   108  		},
   109  		{
   110  			name: "TestInsufficientCaps",
   111  			capData: VfsCapData{
   112  				MagicEtc:    0x2000001,
   113  				Permitted:   CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN, linux.CAP_SETUID}),
   114  				Inheritable: CapabilitySetOfMany([]linux.Capability{linux.CAP_CHOWN}),
   115  			},
   116  			creds: credentialsWithCaps(
   117  				NewUserCredentials(123, 321, nil, nil, NewRootUserNamespace()),
   118  				AllCapabilities,
   119  				AllCapabilities,
   120  				AllCapabilities,
   121  				CapabilitySetOf(linux.CAP_CHOWN)),
   122  			wantCaps: TaskCapabilities{},
   123  			wantErr:  linuxerr.EPERM,
   124  		},
   125  	} {
   126  		t.Run(tst.name, func(t *testing.T) {
   127  			newCreds, err := CapsFromVfsCaps(tst.capData, tst.creds)
   128  			if err == nil {
   129  				if tst.wantErr != nil {
   130  					t.Errorf("CapsFromVfsCaps(%v, %v) returned unexpected error %v", tst.capData, tst.creds, tst.wantErr)
   131  				}
   132  				if !capsEquals(newCreds, tst.wantCaps) {
   133  					t.Errorf("CapsFromVfsCaps(%v, %v) returned capabilities: %v, want capabilities: %v",
   134  						tst.capData, tst.creds,
   135  						TaskCapabilities{
   136  							PermittedCaps:   newCreds.PermittedCaps,
   137  							InheritableCaps: newCreds.InheritableCaps,
   138  							EffectiveCaps:   newCreds.EffectiveCaps,
   139  							BoundingCaps:    newCreds.BoundingCaps,
   140  						}, tst.wantCaps)
   141  				}
   142  			} else if tst.wantErr == nil || tst.wantErr.Error() != err.Error() {
   143  				t.Errorf("CapsFromVfsCaps(%v, %v) returned error %v, wantErr: %v", tst.capData, tst.creds, err, tst.wantErr)
   144  			}
   145  		})
   146  	}
   147  }
   148  
   149  func TestVfsCapData(t *testing.T) {
   150  	for _, tst := range []struct {
   151  		name    string
   152  		data    []byte
   153  		capData VfsCapData
   154  		wantErr error
   155  	}{
   156  		{
   157  			name:    "VfsCapRevision1",
   158  			data:    []byte{0, 0, 0, 1, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   159  			capData: VfsCapData{},
   160  			wantErr: fmt.Errorf("VFS_CAP_REVISION_%v with cap data size %v is not supported", 0x1000000, 20),
   161  		},
   162  		{
   163  			name: "VfsCapRevision2",
   164  			data: []byte{1, 0, 0, 2, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0},
   165  			capData: VfsCapData{
   166  				MagicEtc:    0x2000001,
   167  				Permitted:   CapabilitySetOf(linux.CAP_NET_RAW),
   168  				Inheritable: CapabilitySetOf(linux.CAP_SYSLOG),
   169  			},
   170  			wantErr: nil,
   171  		},
   172  		{
   173  			name: "VfsCapRevision3",
   174  			data: []byte{0, 0, 0, 3, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
   175  			capData: VfsCapData{
   176  				MagicEtc:    0x3000000,
   177  				RootID:      1,
   178  				Permitted:   CapabilitySetOf(linux.CAP_SYSLOG),
   179  				Inheritable: CapabilitySetOf(linux.CAP_NET_ADMIN),
   180  			},
   181  			wantErr: nil,
   182  		},
   183  		{
   184  			name:    "VfsCapRevisionNotSupported",
   185  			data:    []byte{0, 0, 0, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0},
   186  			capData: VfsCapData{},
   187  			wantErr: fmt.Errorf("VFS_CAP_REVISION_%v with cap data size %v is not supported", 0xf000000, 20),
   188  		},
   189  		{
   190  			name:    "VfsInvalidInput",
   191  			data:    []byte{0, 0, 0, 0},
   192  			capData: VfsCapData{},
   193  			wantErr: fmt.Errorf("the size of security.capability is too small, actual size: %v", 4),
   194  		},
   195  	} {
   196  		t.Run(tst.name, func(t *testing.T) {
   197  			capData, err := VfsCapDataOf(tst.data)
   198  			if err == nil {
   199  				if tst.wantErr != nil {
   200  					t.Errorf("VfsCapDataOf(%v) returned unexpected error %v", tst.data, tst.wantErr)
   201  				}
   202  				if tst.capData != capData {
   203  					t.Errorf("VfsCapDataOf(%v) = %v, want %v", tst.data, capData, tst.capData)
   204  				}
   205  			} else if tst.wantErr == nil || tst.wantErr.Error() != err.Error() {
   206  				t.Errorf("VfsCapDataOf(%v) returned error %v, wantErr: %v", tst.data, err, tst.wantErr)
   207  			}
   208  		})
   209  	}
   210  }