196 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			196 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2017 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// +build freebsd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package unix
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									// This is the version of CapRights this package understands. See C implementation for parallels.
							 | 
						||
| 
								 | 
							
									capRightsGoVersion = CAP_RIGHTS_VERSION_00
							 | 
						||
| 
								 | 
							
									capArSizeMin       = CAP_RIGHTS_VERSION_00 + 2
							 | 
						||
| 
								 | 
							
									capArSizeMax       = capRightsGoVersion + 2
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									bit2idx = []int{
							 | 
						||
| 
								 | 
							
										-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
							 | 
						||
| 
								 | 
							
										4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func capidxbit(right uint64) int {
							 | 
						||
| 
								 | 
							
									return int((right >> 57) & 0x1f)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func rightToIndex(right uint64) (int, error) {
							 | 
						||
| 
								 | 
							
									idx := capidxbit(right)
							 | 
						||
| 
								 | 
							
									if idx < 0 || idx >= len(bit2idx) {
							 | 
						||
| 
								 | 
							
										return -2, fmt.Errorf("index for right 0x%x out of range", right)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return bit2idx[idx], nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func caprver(right uint64) int {
							 | 
						||
| 
								 | 
							
									return int(right >> 62)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func capver(rights *CapRights) int {
							 | 
						||
| 
								 | 
							
									return caprver(rights.Rights[0])
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func caparsize(rights *CapRights) int {
							 | 
						||
| 
								 | 
							
									return capver(rights) + 2
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsSet sets the permissions in setrights in rights.
							 | 
						||
| 
								 | 
							
								func CapRightsSet(rights *CapRights, setrights []uint64) error {
							 | 
						||
| 
								 | 
							
									// This is essentially a copy of cap_rights_vset()
							 | 
						||
| 
								 | 
							
									if capver(rights) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("bad rights version %d", capver(rights))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n := caparsize(rights)
							 | 
						||
| 
								 | 
							
									if n < capArSizeMin || n > capArSizeMax {
							 | 
						||
| 
								 | 
							
										return errors.New("bad rights size")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for _, right := range setrights {
							 | 
						||
| 
								 | 
							
										if caprver(right) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
											return errors.New("bad right version")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i, err := rightToIndex(right)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if i >= n {
							 | 
						||
| 
								 | 
							
											return errors.New("index overflow")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if capidxbit(rights.Rights[i]) != capidxbit(right) {
							 | 
						||
| 
								 | 
							
											return errors.New("index mismatch")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										rights.Rights[i] |= right
							 | 
						||
| 
								 | 
							
										if capidxbit(rights.Rights[i]) != capidxbit(right) {
							 | 
						||
| 
								 | 
							
											return errors.New("index mismatch (after assign)")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsClear clears the permissions in clearrights from rights.
							 | 
						||
| 
								 | 
							
								func CapRightsClear(rights *CapRights, clearrights []uint64) error {
							 | 
						||
| 
								 | 
							
									// This is essentially a copy of cap_rights_vclear()
							 | 
						||
| 
								 | 
							
									if capver(rights) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("bad rights version %d", capver(rights))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n := caparsize(rights)
							 | 
						||
| 
								 | 
							
									if n < capArSizeMin || n > capArSizeMax {
							 | 
						||
| 
								 | 
							
										return errors.New("bad rights size")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for _, right := range clearrights {
							 | 
						||
| 
								 | 
							
										if caprver(right) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
											return errors.New("bad right version")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i, err := rightToIndex(right)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if i >= n {
							 | 
						||
| 
								 | 
							
											return errors.New("index overflow")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if capidxbit(rights.Rights[i]) != capidxbit(right) {
							 | 
						||
| 
								 | 
							
											return errors.New("index mismatch")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
							 | 
						||
| 
								 | 
							
										if capidxbit(rights.Rights[i]) != capidxbit(right) {
							 | 
						||
| 
								 | 
							
											return errors.New("index mismatch (after assign)")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
							 | 
						||
| 
								 | 
							
								func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
							 | 
						||
| 
								 | 
							
									// This is essentially a copy of cap_rights_is_vset()
							 | 
						||
| 
								 | 
							
									if capver(rights) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
										return false, fmt.Errorf("bad rights version %d", capver(rights))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n := caparsize(rights)
							 | 
						||
| 
								 | 
							
									if n < capArSizeMin || n > capArSizeMax {
							 | 
						||
| 
								 | 
							
										return false, errors.New("bad rights size")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for _, right := range setrights {
							 | 
						||
| 
								 | 
							
										if caprver(right) != CAP_RIGHTS_VERSION_00 {
							 | 
						||
| 
								 | 
							
											return false, errors.New("bad right version")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i, err := rightToIndex(right)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return false, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if i >= n {
							 | 
						||
| 
								 | 
							
											return false, errors.New("index overflow")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if capidxbit(rights.Rights[i]) != capidxbit(right) {
							 | 
						||
| 
								 | 
							
											return false, errors.New("index mismatch")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (rights.Rights[i] & right) != right {
							 | 
						||
| 
								 | 
							
											return false, nil
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return true, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func capright(idx uint64, bit uint64) uint64 {
							 | 
						||
| 
								 | 
							
									return ((1 << (57 + idx)) | bit)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
							 | 
						||
| 
								 | 
							
								// See man cap_rights_init(3) and rights(4).
							 | 
						||
| 
								 | 
							
								func CapRightsInit(rights []uint64) (*CapRights, error) {
							 | 
						||
| 
								 | 
							
									var r CapRights
							 | 
						||
| 
								 | 
							
									r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
							 | 
						||
| 
								 | 
							
									r.Rights[1] = capright(1, 0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err := CapRightsSet(&r, rights)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &r, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
							 | 
						||
| 
								 | 
							
								// The capability rights on fd can never be increased by CapRightsLimit.
							 | 
						||
| 
								 | 
							
								// See man cap_rights_limit(2) and rights(4).
							 | 
						||
| 
								 | 
							
								func CapRightsLimit(fd uintptr, rights *CapRights) error {
							 | 
						||
| 
								 | 
							
									return capRightsLimit(int(fd), rights)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
							 | 
						||
| 
								 | 
							
								// See man cap_rights_get(3) and rights(4).
							 | 
						||
| 
								 | 
							
								func CapRightsGet(fd uintptr) (*CapRights, error) {
							 | 
						||
| 
								 | 
							
									r, err := CapRightsInit(nil)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									err = capRightsGet(capRightsGoVersion, int(fd), r)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return r, nil
							 | 
						||
| 
								 | 
							
								}
							 |