github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/util/capability_util.h (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Utilities for testing capabilities. 16 17 #ifndef GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_ 18 #define GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_ 19 20 #include <errno.h> 21 #include <linux/capability.h> 22 #include <sys/syscall.h> 23 #include <unistd.h> 24 25 #include "test/util/cleanup.h" 26 #include "test/util/posix_error.h" 27 #include "test/util/save_util.h" 28 #include "test/util/test_util.h" 29 30 #ifndef _LINUX_CAPABILITY_VERSION_3 31 #error Expecting _LINUX_CAPABILITY_VERSION_3 support 32 #endif 33 34 namespace gvisor { 35 namespace testing { 36 37 // HaveCapability returns true if the process has the specified EFFECTIVE 38 // capability. 39 inline PosixErrorOr<bool> HaveCapability(int cap) { 40 if (!cap_valid(cap)) { 41 return PosixError(EINVAL, "Invalid capability"); 42 } 43 44 struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; 45 struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; 46 RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); 47 MaybeSave(); 48 49 return (caps[CAP_TO_INDEX(cap)].effective & CAP_TO_MASK(cap)) != 0; 50 } 51 52 // SetCapability sets the specified EFFECTIVE capability. 53 inline PosixError SetCapability(int cap, bool set) { 54 if (!cap_valid(cap)) { 55 return PosixError(EINVAL, "Invalid capability"); 56 } 57 58 struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; 59 struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; 60 RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); 61 MaybeSave(); 62 63 if (set) { 64 caps[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap); 65 } else { 66 caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); 67 } 68 header = {_LINUX_CAPABILITY_VERSION_3, 0}; 69 RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); 70 MaybeSave(); 71 72 return NoError(); 73 } 74 75 // DropPermittedCapability drops the specified PERMITTED. The EFFECTIVE 76 // capabilities must be a subset of PERMITTED, so those are dropped as well. 77 inline PosixError DropPermittedCapability(int cap) { 78 if (!cap_valid(cap)) { 79 return PosixError(EINVAL, "Invalid capability"); 80 } 81 82 struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; 83 struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; 84 RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); 85 MaybeSave(); 86 87 caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); 88 caps[CAP_TO_INDEX(cap)].permitted &= ~CAP_TO_MASK(cap); 89 90 header = {_LINUX_CAPABILITY_VERSION_3, 0}; 91 RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); 92 MaybeSave(); 93 94 return NoError(); 95 } 96 97 PosixErrorOr<bool> CanCreateUserNamespace(); 98 99 class AutoCapability { 100 public: 101 AutoCapability(int cap, bool set) : cap_(cap), set_(set) { 102 const bool has = EXPECT_NO_ERRNO_AND_VALUE(HaveCapability(cap)); 103 if (set != has) { 104 EXPECT_NO_ERRNO(SetCapability(cap_, set_)); 105 applied_ = true; 106 } 107 } 108 109 ~AutoCapability() { 110 if (applied_) { 111 EXPECT_NO_ERRNO(SetCapability(cap_, !set_)); 112 } 113 } 114 115 private: 116 int cap_; 117 bool set_; 118 bool applied_ = false; 119 }; 120 121 } // namespace testing 122 } // namespace gvisor 123 #endif // GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_