Home | History | Annotate | Download | only in unix
      1 // Copyright 2017 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // +build freebsd
      6 
      7 package unix
      8 
      9 import (
     10 	"errors"
     11 	"fmt"
     12 )
     13 
     14 // Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
     15 
     16 const (
     17 	// This is the version of CapRights this package understands. See C implementation for parallels.
     18 	capRightsGoVersion = CAP_RIGHTS_VERSION_00
     19 	capArSizeMin       = CAP_RIGHTS_VERSION_00 + 2
     20 	capArSizeMax       = capRightsGoVersion + 2
     21 )
     22 
     23 var (
     24 	bit2idx = []int{
     25 		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
     26 		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     27 	}
     28 )
     29 
     30 func capidxbit(right uint64) int {
     31 	return int((right >> 57) & 0x1f)
     32 }
     33 
     34 func rightToIndex(right uint64) (int, error) {
     35 	idx := capidxbit(right)
     36 	if idx < 0 || idx >= len(bit2idx) {
     37 		return -2, fmt.Errorf("index for right 0x%x out of range", right)
     38 	}
     39 	return bit2idx[idx], nil
     40 }
     41 
     42 func caprver(right uint64) int {
     43 	return int(right >> 62)
     44 }
     45 
     46 func capver(rights *CapRights) int {
     47 	return caprver(rights.Rights[0])
     48 }
     49 
     50 func caparsize(rights *CapRights) int {
     51 	return capver(rights) + 2
     52 }
     53 
     54 // CapRightsSet sets the permissions in setrights in rights.
     55 func CapRightsSet(rights *CapRights, setrights []uint64) error {
     56 	// This is essentially a copy of cap_rights_vset()
     57 	if capver(rights) != CAP_RIGHTS_VERSION_00 {
     58 		return fmt.Errorf("bad rights version %d", capver(rights))
     59 	}
     60 
     61 	n := caparsize(rights)
     62 	if n < capArSizeMin || n > capArSizeMax {
     63 		return errors.New("bad rights size")
     64 	}
     65 
     66 	for _, right := range setrights {
     67 		if caprver(right) != CAP_RIGHTS_VERSION_00 {
     68 			return errors.New("bad right version")
     69 		}
     70 		i, err := rightToIndex(right)
     71 		if err != nil {
     72 			return err
     73 		}
     74 		if i >= n {
     75 			return errors.New("index overflow")
     76 		}
     77 		if capidxbit(rights.Rights[i]) != capidxbit(right) {
     78 			return errors.New("index mismatch")
     79 		}
     80 		rights.Rights[i] |= right
     81 		if capidxbit(rights.Rights[i]) != capidxbit(right) {
     82 			return errors.New("index mismatch (after assign)")
     83 		}
     84 	}
     85 
     86 	return nil
     87 }
     88 
     89 // CapRightsClear clears the permissions in clearrights from rights.
     90 func CapRightsClear(rights *CapRights, clearrights []uint64) error {
     91 	// This is essentially a copy of cap_rights_vclear()
     92 	if capver(rights) != CAP_RIGHTS_VERSION_00 {
     93 		return fmt.Errorf("bad rights version %d", capver(rights))
     94 	}
     95 
     96 	n := caparsize(rights)
     97 	if n < capArSizeMin || n > capArSizeMax {
     98 		return errors.New("bad rights size")
     99 	}
    100 
    101 	for _, right := range clearrights {
    102 		if caprver(right) != CAP_RIGHTS_VERSION_00 {
    103 			return errors.New("bad right version")
    104 		}
    105 		i, err := rightToIndex(right)
    106 		if err != nil {
    107 			return err
    108 		}
    109 		if i >= n {
    110 			return errors.New("index overflow")
    111 		}
    112 		if capidxbit(rights.Rights[i]) != capidxbit(right) {
    113 			return errors.New("index mismatch")
    114 		}
    115 		rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
    116 		if capidxbit(rights.Rights[i]) != capidxbit(right) {
    117 			return errors.New("index mismatch (after assign)")
    118 		}
    119 	}
    120 
    121 	return nil
    122 }
    123 
    124 // CapRightsIsSet checks whether all the permissions in setrights are present in rights.
    125 func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
    126 	// This is essentially a copy of cap_rights_is_vset()
    127 	if capver(rights) != CAP_RIGHTS_VERSION_00 {
    128 		return false, fmt.Errorf("bad rights version %d", capver(rights))
    129 	}
    130 
    131 	n := caparsize(rights)
    132 	if n < capArSizeMin || n > capArSizeMax {
    133 		return false, errors.New("bad rights size")
    134 	}
    135 
    136 	for _, right := range setrights {
    137 		if caprver(right) != CAP_RIGHTS_VERSION_00 {
    138 			return false, errors.New("bad right version")
    139 		}
    140 		i, err := rightToIndex(right)
    141 		if err != nil {
    142 			return false, err
    143 		}
    144 		if i >= n {
    145 			return false, errors.New("index overflow")
    146 		}
    147 		if capidxbit(rights.Rights[i]) != capidxbit(right) {
    148 			return false, errors.New("index mismatch")
    149 		}
    150 		if (rights.Rights[i] & right) != right {
    151 			return false, nil
    152 		}
    153 	}
    154 
    155 	return true, nil
    156 }
    157 
    158 func capright(idx uint64, bit uint64) uint64 {
    159 	return ((1 << (57 + idx)) | bit)
    160 }
    161 
    162 // CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
    163 // See man cap_rights_init(3) and rights(4).
    164 func CapRightsInit(rights []uint64) (*CapRights, error) {
    165 	var r CapRights
    166 	r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
    167 	r.Rights[1] = capright(1, 0)
    168 
    169 	err := CapRightsSet(&r, rights)
    170 	if err != nil {
    171 		return nil, err
    172 	}
    173 	return &r, nil
    174 }
    175 
    176 // CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
    177 // The capability rights on fd can never be increased by CapRightsLimit.
    178 // See man cap_rights_limit(2) and rights(4).
    179 func CapRightsLimit(fd uintptr, rights *CapRights) error {
    180 	return capRightsLimit(int(fd), rights)
    181 }
    182 
    183 // CapRightsGet returns a CapRights structure containing the operations permitted on fd.
    184 // See man cap_rights_get(3) and rights(4).
    185 func CapRightsGet(fd uintptr) (*CapRights, error) {
    186 	r, err := CapRightsInit(nil)
    187 	if err != nil {
    188 		return nil, err
    189 	}
    190 	err = capRightsGet(capRightsGoVersion, int(fd), r)
    191 	if err != nil {
    192 		return nil, err
    193 	}
    194 	return r, nil
    195 }
    196