golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/cap_freebsd.go (about)

     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  }