diff options
Diffstat (limited to 'test/util')
-rw-r--r-- | test/util/BUILD | 12 | ||||
-rw-r--r-- | test/util/capability_util.h | 112 | ||||
-rw-r--r-- | test/util/fuchsia_capability_util.cc | 45 | ||||
-rw-r--r-- | test/util/fuchsia_capability_util.h | 41 | ||||
-rw-r--r-- | test/util/linux_capability_util.cc (renamed from test/util/capability_util.cc) | 2 | ||||
-rw-r--r-- | test/util/linux_capability_util.h | 128 |
6 files changed, 231 insertions, 109 deletions
diff --git a/test/util/BUILD b/test/util/BUILD index 4a4401ba8..3211546f5 100644 --- a/test/util/BUILD +++ b/test/util/BUILD @@ -8,13 +8,21 @@ package( cc_library( name = "capability_util", testonly = 1, - srcs = ["capability_util.cc"], - hdrs = ["capability_util.h"], + srcs = [ + "fuchsia_capability_util.cc", + "linux_capability_util.cc", + ], + hdrs = [ + "capability_util.h", + "fuchsia_capability_util.h", + "linux_capability_util.h", + ], deps = [ ":cleanup", ":memory_util", ":posix_error", ":save_util", + ":socket_util", ":test_util", "@com_google_absl//absl/strings", ], diff --git a/test/util/capability_util.h b/test/util/capability_util.h index c4b0feade..f5d622e2d 100644 --- a/test/util/capability_util.h +++ b/test/util/capability_util.h @@ -17,112 +17,12 @@ #ifndef GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_ #define GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_ -#ifdef __linux__ - -#include <errno.h> -#include <linux/capability.h> -#include <sys/syscall.h> -#include <unistd.h> - -#include "test/util/cleanup.h" -#include "test/util/posix_error.h" -#include "test/util/save_util.h" -#include "test/util/test_util.h" - -#ifndef _LINUX_CAPABILITY_VERSION_3 -#error Expecting _LINUX_CAPABILITY_VERSION_3 support +#if defined(__Fuchsia__) +#include "test/util/fuchsia_capability_util.h" +#elif defined(__linux__) +#include "test/util/linux_capability_util.h" +#else +#error "Unhandled platform" #endif -namespace gvisor { -namespace testing { - -// HaveCapability returns true if the process has the specified EFFECTIVE -// capability. -inline PosixErrorOr<bool> HaveCapability(int cap) { - if (!cap_valid(cap)) { - return PosixError(EINVAL, "Invalid capability"); - } - - struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; - struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; - RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); - MaybeSave(); - - return (caps[CAP_TO_INDEX(cap)].effective & CAP_TO_MASK(cap)) != 0; -} - -// SetCapability sets the specified EFFECTIVE capability. -inline PosixError SetCapability(int cap, bool set) { - if (!cap_valid(cap)) { - return PosixError(EINVAL, "Invalid capability"); - } - - struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; - struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; - RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); - MaybeSave(); - - if (set) { - caps[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap); - } else { - caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); - } - header = {_LINUX_CAPABILITY_VERSION_3, 0}; - RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); - MaybeSave(); - - return NoError(); -} - -// DropPermittedCapability drops the specified PERMITTED. The EFFECTIVE -// capabilities must be a subset of PERMITTED, so those are dropped as well. -inline PosixError DropPermittedCapability(int cap) { - if (!cap_valid(cap)) { - return PosixError(EINVAL, "Invalid capability"); - } - - struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; - struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; - RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); - MaybeSave(); - - caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); - caps[CAP_TO_INDEX(cap)].permitted &= ~CAP_TO_MASK(cap); - - header = {_LINUX_CAPABILITY_VERSION_3, 0}; - RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); - MaybeSave(); - - return NoError(); -} - -PosixErrorOr<bool> CanCreateUserNamespace(); - -class AutoCapability { - public: - AutoCapability(int cap, bool set) : cap_(cap), set_(set) { - const bool has = EXPECT_NO_ERRNO_AND_VALUE(HaveCapability(cap)); - if (set != has) { - EXPECT_NO_ERRNO(SetCapability(cap_, set_)); - applied_ = true; - } - } - - ~AutoCapability() { - if (applied_) { - EXPECT_NO_ERRNO(SetCapability(cap_, !set_)); - } - } - - private: - int cap_; - bool set_; - bool applied_ = false; -}; - -} // namespace testing -} // namespace gvisor - -#endif // __linux__ - #endif // GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_ diff --git a/test/util/fuchsia_capability_util.cc b/test/util/fuchsia_capability_util.cc new file mode 100644 index 000000000..43f60f20f --- /dev/null +++ b/test/util/fuchsia_capability_util.cc @@ -0,0 +1,45 @@ +// Copyright 2021 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifdef __Fuchsia__ + +#include "test/util/fuchsia_capability_util.h" + +#include <netinet/in.h> +#include <sys/socket.h> + +#include "test/util/socket_util.h" + +namespace gvisor { +namespace testing { + +PosixErrorOr<bool> HaveCapability(int cap) { + if (cap == CAP_NET_RAW) { + auto s = Socket(AF_INET, SOCK_RAW, IPPROTO_UDP); + if (s.ok()) { + return true; + } + if (s.error().errno_value() == EPERM) { + return false; + } + return s.error(); + } + + return false; +} + +} // namespace testing +} // namespace gvisor + +#endif // __Fuchsia__ diff --git a/test/util/fuchsia_capability_util.h b/test/util/fuchsia_capability_util.h new file mode 100644 index 000000000..87657d7e8 --- /dev/null +++ b/test/util/fuchsia_capability_util.h @@ -0,0 +1,41 @@ +// Copyright 2021 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Utilities for testing capabilities on Fuchsia. + +#ifndef GVISOR_TEST_UTIL_FUCHSIA_CAPABILITY_UTIL_H_ +#define GVISOR_TEST_UTIL_FUCHSIA_CAPABILITY_UTIL_H_ + +#ifdef __Fuchsia__ + +#include "test/util/posix_error.h" + +#ifdef CAP_NET_RAW +#error "Fuchsia should not define CAP_NET_RAW" +#endif // CAP_NET_RAW +#define CAP_NET_RAW 0 + +namespace gvisor { +namespace testing { + +// HaveCapability returns true if the process has the specified EFFECTIVE +// capability. +PosixErrorOr<bool> HaveCapability(int cap); + +} // namespace testing +} // namespace gvisor + +#endif // __Fuchsia__ + +#endif // GVISOR_TEST_UTIL_FUCHSIA_CAPABILITY_UTIL_H_ diff --git a/test/util/capability_util.cc b/test/util/linux_capability_util.cc index 3bf218128..958eb96f9 100644 --- a/test/util/capability_util.cc +++ b/test/util/linux_capability_util.cc @@ -14,7 +14,7 @@ #ifdef __linux__ -#include "test/util/capability_util.h" +#include "test/util/linux_capability_util.h" #include <linux/capability.h> #include <sched.h> diff --git a/test/util/linux_capability_util.h b/test/util/linux_capability_util.h new file mode 100644 index 000000000..be94ebd19 --- /dev/null +++ b/test/util/linux_capability_util.h @@ -0,0 +1,128 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Utilities for testing capabilities on Linux. + +#ifndef GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_ +#define GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_ + +#ifdef __linux__ + +#include <errno.h> +#include <linux/capability.h> +#include <sys/syscall.h> +#include <unistd.h> + +#include "test/util/cleanup.h" +#include "test/util/posix_error.h" +#include "test/util/save_util.h" +#include "test/util/test_util.h" + +#ifndef _LINUX_CAPABILITY_VERSION_3 +#error Expecting _LINUX_CAPABILITY_VERSION_3 support +#endif + +namespace gvisor { +namespace testing { + +// HaveCapability returns true if the process has the specified EFFECTIVE +// capability. +inline PosixErrorOr<bool> HaveCapability(int cap) { + if (!cap_valid(cap)) { + return PosixError(EINVAL, "Invalid capability"); + } + + struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; + struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; + RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); + MaybeSave(); + + return (caps[CAP_TO_INDEX(cap)].effective & CAP_TO_MASK(cap)) != 0; +} + +// SetCapability sets the specified EFFECTIVE capability. +inline PosixError SetCapability(int cap, bool set) { + if (!cap_valid(cap)) { + return PosixError(EINVAL, "Invalid capability"); + } + + struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; + struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; + RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); + MaybeSave(); + + if (set) { + caps[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap); + } else { + caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); + } + header = {_LINUX_CAPABILITY_VERSION_3, 0}; + RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); + MaybeSave(); + + return NoError(); +} + +// DropPermittedCapability drops the specified PERMITTED. The EFFECTIVE +// capabilities must be a subset of PERMITTED, so those are dropped as well. +inline PosixError DropPermittedCapability(int cap) { + if (!cap_valid(cap)) { + return PosixError(EINVAL, "Invalid capability"); + } + + struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0}; + struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {}; + RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps)); + MaybeSave(); + + caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); + caps[CAP_TO_INDEX(cap)].permitted &= ~CAP_TO_MASK(cap); + + header = {_LINUX_CAPABILITY_VERSION_3, 0}; + RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps)); + MaybeSave(); + + return NoError(); +} + +PosixErrorOr<bool> CanCreateUserNamespace(); + +class AutoCapability { + public: + AutoCapability(int cap, bool set) : cap_(cap), set_(set) { + const bool has = EXPECT_NO_ERRNO_AND_VALUE(HaveCapability(cap)); + if (set != has) { + EXPECT_NO_ERRNO(SetCapability(cap_, set_)); + applied_ = true; + } + } + + ~AutoCapability() { + if (applied_) { + EXPECT_NO_ERRNO(SetCapability(cap_, !set_)); + } + } + + private: + int cap_; + bool set_; + bool applied_ = false; +}; + +} // namespace testing +} // namespace gvisor + +#endif // __linux__ + +#endif // GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_ |