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