cap_freebsd.go raw

   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  //go: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