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