// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build freebsd package unix import ( "errors" "fmt" ) // Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c const ( // This is the version of CapRights this package understands. See C implementation for parallels. capRightsGoVersion = CAP_RIGHTS_VERSION_00 capArSizeMin = CAP_RIGHTS_VERSION_00 + 2 capArSizeMax = capRightsGoVersion + 2 ) var ( bit2idx = []int{ -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, } ) func capidxbit(right uint64) int { return int((right >> 57) & 0x1f) } func rightToIndex(right uint64) (int, error) { idx := capidxbit(right) if idx < 0 || idx >= len(bit2idx) { return -2, fmt.Errorf("index for right 0x%x out of range", right) } return bit2idx[idx], nil } func caprver(right uint64) int { return int(right >> 62) } func capver(rights *CapRights) int { return caprver(rights.Rights[0]) } func caparsize(rights *CapRights) int { return capver(rights) + 2 } // CapRightsSet sets the permissions in setrights in rights. func CapRightsSet(rights *CapRights, setrights []uint64) error { // This is essentially a copy of cap_rights_vset() if capver(rights) != CAP_RIGHTS_VERSION_00 { return fmt.Errorf("bad rights version %d", capver(rights)) } n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { return errors.New("bad rights size") } for _, right := range setrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { return errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return err } if i >= n { return errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { return errors.New("index mismatch") } rights.Rights[i] |= right if capidxbit(rights.Rights[i]) != capidxbit(right) { return errors.New("index mismatch (after assign)") } } return nil } // CapRightsClear clears the permissions in clearrights from rights. func CapRightsClear(rights *CapRights, clearrights []uint64) error { // This is essentially a copy of cap_rights_vclear() if capver(rights) != CAP_RIGHTS_VERSION_00 { return fmt.Errorf("bad rights version %d", capver(rights)) } n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { return errors.New("bad rights size") } for _, right := range clearrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { return errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return err } if i >= n { return errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { return errors.New("index mismatch") } rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF) if capidxbit(rights.Rights[i]) != capidxbit(right) { return errors.New("index mismatch (after assign)") } } return nil } // CapRightsIsSet checks whether all the permissions in setrights are present in rights. func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) { // This is essentially a copy of cap_rights_is_vset() if capver(rights) != CAP_RIGHTS_VERSION_00 { return false, fmt.Errorf("bad rights version %d", capver(rights)) } n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { return false, errors.New("bad rights size") } for _, right := range setrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { return false, errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return false, err } if i >= n { return false, errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { return false, errors.New("index mismatch") } if (rights.Rights[i] & right) != right { return false, nil } } return true, nil } func capright(idx uint64, bit uint64) uint64 { return ((1 << (57 + idx)) | bit) } // CapRightsInit returns a pointer to an initialised CapRights structure filled with rights. // See man cap_rights_init(3) and rights(4). func CapRightsInit(rights []uint64) (*CapRights, error) { var r CapRights r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0) r.Rights[1] = capright(1, 0) err := CapRightsSet(&r, rights) if err != nil { return nil, err } return &r, nil } // CapRightsLimit reduces the operations permitted on fd to at most those contained in rights. // The capability rights on fd can never be increased by CapRightsLimit. // See man cap_rights_limit(2) and rights(4). func CapRightsLimit(fd uintptr, rights *CapRights) error { return capRightsLimit(int(fd), rights) } // CapRightsGet returns a CapRights structure containing the operations permitted on fd. // See man cap_rights_get(3) and rights(4). func CapRightsGet(fd uintptr) (*CapRights, error) { r, err := CapRightsInit(nil) if err != nil { return nil, err } err = capRightsGet(capRightsGoVersion, int(fd), r) if err != nil { return nil, err } return r, nil }