gvisor/pkg/sentry/syscalls/linux/sys_capability.go

150 lines
4.5 KiB
Go
Raw Normal View History

// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package linux
import (
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
func lookupCaps(t *kernel.Task, tid kernel.ThreadID) (permitted, inheritable, effective auth.CapabilitySet, err error) {
if tid < 0 {
err = syserror.EINVAL
return
}
if tid > 0 {
t = t.PIDNamespace().TaskWithID(tid)
}
if t == nil {
err = syserror.ESRCH
return
}
creds := t.Credentials()
permitted, inheritable, effective = creds.PermittedCaps, creds.InheritableCaps, creds.EffectiveCaps
return
}
// Capget implements Linux syscall capget.
func Capget(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
hdrAddr := args[0].Pointer()
dataAddr := args[1].Pointer()
var hdr linux.CapUserHeader
if _, err := t.CopyIn(hdrAddr, &hdr); err != nil {
return 0, nil, err
}
// hdr.Pid doesn't need to be valid if this capget() is a "version probe"
// (hdr.Version is unrecognized and dataAddr is null), so we can't do the
// lookup yet.
switch hdr.Version {
case linux.LINUX_CAPABILITY_VERSION_1:
if dataAddr == 0 {
return 0, nil, nil
}
p, i, e, err := lookupCaps(t, kernel.ThreadID(hdr.Pid))
if err != nil {
return 0, nil, err
}
data := linux.CapUserData{
Effective: uint32(e),
Permitted: uint32(p),
Inheritable: uint32(i),
}
_, err = t.CopyOut(dataAddr, &data)
return 0, nil, err
case linux.LINUX_CAPABILITY_VERSION_2, linux.LINUX_CAPABILITY_VERSION_3:
if dataAddr == 0 {
return 0, nil, nil
}
p, i, e, err := lookupCaps(t, kernel.ThreadID(hdr.Pid))
if err != nil {
return 0, nil, err
}
data := [2]linux.CapUserData{
{
Effective: uint32(e),
Permitted: uint32(p),
Inheritable: uint32(i),
},
{
Effective: uint32(e >> 32),
Permitted: uint32(p >> 32),
Inheritable: uint32(i >> 32),
},
}
_, err = t.CopyOut(dataAddr, &data)
return 0, nil, err
default:
hdr.Version = linux.HighestCapabilityVersion
if _, err := t.CopyOut(hdrAddr, &hdr); err != nil {
return 0, nil, err
}
if dataAddr != 0 {
return 0, nil, syserror.EINVAL
}
return 0, nil, nil
}
}
// Capset implements Linux syscall capset.
func Capset(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
hdrAddr := args[0].Pointer()
dataAddr := args[1].Pointer()
var hdr linux.CapUserHeader
if _, err := t.CopyIn(hdrAddr, &hdr); err != nil {
return 0, nil, err
}
switch hdr.Version {
case linux.LINUX_CAPABILITY_VERSION_1:
if tid := kernel.ThreadID(hdr.Pid); tid != 0 && tid != t.ThreadID() {
return 0, nil, syserror.EPERM
}
var data linux.CapUserData
if _, err := t.CopyIn(dataAddr, &data); err != nil {
return 0, nil, err
}
p := auth.CapabilitySet(data.Permitted) & auth.AllCapabilities
i := auth.CapabilitySet(data.Inheritable) & auth.AllCapabilities
e := auth.CapabilitySet(data.Effective) & auth.AllCapabilities
return 0, nil, t.SetCapabilitySets(p, i, e)
case linux.LINUX_CAPABILITY_VERSION_2, linux.LINUX_CAPABILITY_VERSION_3:
if tid := kernel.ThreadID(hdr.Pid); tid != 0 && tid != t.ThreadID() {
return 0, nil, syserror.EPERM
}
var data [2]linux.CapUserData
if _, err := t.CopyIn(dataAddr, &data); err != nil {
return 0, nil, err
}
p := (auth.CapabilitySet(data[0].Permitted) | (auth.CapabilitySet(data[1].Permitted) << 32)) & auth.AllCapabilities
i := (auth.CapabilitySet(data[0].Inheritable) | (auth.CapabilitySet(data[1].Inheritable) << 32)) & auth.AllCapabilities
e := (auth.CapabilitySet(data[0].Effective) | (auth.CapabilitySet(data[1].Effective) << 32)) & auth.AllCapabilities
return 0, nil, t.SetCapabilitySets(p, i, e)
default:
hdr.Version = linux.HighestCapabilityVersion
if _, err := t.CopyOut(hdrAddr, &hdr); err != nil {
return 0, nil, err
}
return 0, nil, syserror.EINVAL
}
}