github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/syscalls/linux/sys_key.go (about)

     1  // Copyright 2023 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 linux
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  
    21  	"github.com/metacubex/gvisor/pkg/abi/linux"
    22  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    23  	"github.com/metacubex/gvisor/pkg/log"
    24  	"github.com/metacubex/gvisor/pkg/sentry/arch"
    25  	"github.com/metacubex/gvisor/pkg/sentry/kernel"
    26  	"github.com/metacubex/gvisor/pkg/sentry/kernel/auth"
    27  )
    28  
    29  // Keyctl implements Linux syscall keyctl(2).
    30  func Keyctl(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    31  	switch args[0].Int() {
    32  	case linux.KEYCTL_GET_KEYRING_ID:
    33  		return keyCtlGetKeyringID(t, args)
    34  	case linux.KEYCTL_DESCRIBE:
    35  		return keyctlDescribe(t, args)
    36  	case linux.KEYCTL_JOIN_SESSION_KEYRING:
    37  		return keyctlJoinSessionKeyring(t, args)
    38  	case linux.KEYCTL_SETPERM:
    39  		return keyctlSetPerm(t, args)
    40  	}
    41  	log.Debugf("Unimplemented keyctl operation: %d", args[0].Int())
    42  	kernel.IncrementUnimplementedSyscallCounter(sysno)
    43  	return 0, nil, linuxerr.ENOSYS
    44  }
    45  
    46  // keyCtlGetKeyringID implements keyctl(2) with operation
    47  // KEYCTL_GET_KEYRING_ID.
    48  func keyCtlGetKeyringID(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    49  	keyID := auth.KeySerial(args[1].Int())
    50  	var key *auth.Key
    51  	var err error
    52  	if keyID > 0 {
    53  		// Not a special key ID, so return as-is.
    54  		return uintptr(keyID), nil, nil
    55  	}
    56  	switch keyID {
    57  	case linux.KEY_SPEC_SESSION_KEYRING:
    58  		key, err = t.SessionKeyring()
    59  	default:
    60  		if keyID <= 0 {
    61  			// Other special key IDs are not implemented.
    62  			return 0, nil, linuxerr.ENOSYS
    63  		}
    64  		// For positive key IDs, KEYCTL_GET_KEYRING_ID can be used as an existence
    65  		// and permissions check.
    66  		key, err = t.LookupKey(keyID)
    67  	}
    68  	if err != nil {
    69  		return 0, nil, err
    70  	}
    71  	return uintptr(key.ID), nil, nil
    72  }
    73  
    74  // keyctlDescribe implements keyctl(2) with operation KEYCTL_DESCRIBE.
    75  func keyctlDescribe(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    76  	keyID := auth.KeySerial(args[1].Int())
    77  	bufPtr := args[2].Pointer()
    78  	bufSize := args[3].SizeT()
    79  
    80  	// Get address range to write to.
    81  	if bufSize > math.MaxInt32 {
    82  		bufSize = math.MaxInt32
    83  	}
    84  
    85  	var key *auth.Key
    86  	var err error
    87  	switch keyID {
    88  	case linux.KEY_SPEC_SESSION_KEYRING:
    89  		key, err = t.SessionKeyring()
    90  	default:
    91  		key, err = t.LookupKey(keyID)
    92  	}
    93  	if err != nil {
    94  		return 0, nil, err
    95  	}
    96  	uid := t.UserNamespace().MapFromKUID(key.KUID())
    97  	gid := t.UserNamespace().MapFromKGID(key.KGID())
    98  	keyDesc := fmt.Sprintf("%s;%d;%d;%08x;%s\x00", key.Type(), uid, gid, uint64(key.Permissions()), key.Description)
    99  	if bufSize > 0 {
   100  		toWrite := uint(len(keyDesc))
   101  		if toWrite > bufSize {
   102  			toWrite = bufSize
   103  		}
   104  		_, err = t.CopyOutBytes(bufPtr, []byte(keyDesc)[:toWrite])
   105  	}
   106  	// The KEYCTL_DESCRIBE operation returns the length of the full string,
   107  	// regardless of whether or not it was fully written out to userspace.
   108  	// It includes the zero byte at the end in the returned length.
   109  	return uintptr(len(keyDesc)), nil, err
   110  }
   111  
   112  // keyctlJoinSessionKeyring implements keyctl(2) with operation
   113  // KEYCTL_JOIN_SESSION_KEYRING.
   114  func keyctlJoinSessionKeyring(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   115  	keyDescPtr := args[1].Pointer()
   116  	var key *auth.Key
   117  	var err error
   118  	if keyDescPtr == 0 {
   119  		// Creating an anonymous keyring.
   120  		key, err = t.JoinSessionKeyring(nil)
   121  	} else {
   122  		// Joining a named keyring. Read in its description.
   123  		var keyringDesc string
   124  		keyringDesc, err = t.CopyInString(keyDescPtr, auth.MaxKeyDescSize)
   125  		if err != nil {
   126  			return 0, nil, err
   127  		}
   128  		key, err = t.JoinSessionKeyring(&keyringDesc)
   129  	}
   130  	if err != nil {
   131  		return 0, nil, err
   132  	}
   133  	return uintptr(key.ID), nil, nil
   134  }
   135  
   136  // keyctlSetPerm implements keyctl(2) with operation KEYCTL_SETPERM.
   137  func keyctlSetPerm(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   138  	keyID := auth.KeySerial(args[1].Int())
   139  	newPerms := auth.KeyPermissions(args[2].Uint64())
   140  	var key *auth.Key
   141  	var err error
   142  	switch keyID {
   143  	case linux.KEY_SPEC_SESSION_KEYRING:
   144  		key, err = t.SessionKeyring()
   145  	default:
   146  		key, err = t.UserNamespace().Keys.Lookup(keyID)
   147  	}
   148  	if err != nil {
   149  		return 0, nil, err
   150  	}
   151  	return 0, nil, t.SetPermsOnKey(key, newPerms)
   152  }