blob: 0b7c6adb8661787f4f25485fb74dd2edce960549 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001// 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
khenaidood948f772021-08-11 17:49:24 -04005//go:build freebsd
khenaidooac637102019-01-14 15:44:34 -05006// +build freebsd
7
8package unix
9
10import (
11 "errors"
12 "fmt"
13)
14
15// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
16
17const (
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
24var (
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
31func capidxbit(right uint64) int {
32 return int((right >> 57) & 0x1f)
33}
34
35func 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
43func caprver(right uint64) int {
44 return int(right >> 62)
45}
46
47func capver(rights *CapRights) int {
48 return caprver(rights.Rights[0])
49}
50
51func caparsize(rights *CapRights) int {
52 return capver(rights) + 2
53}
54
55// CapRightsSet sets the permissions in setrights in rights.
56func 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.
91func 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.
126func 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
159func 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).
165func 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).
180func 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).
186func 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}