gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/linux_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 on Linux.
    16  
    17  #ifndef GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_
    18  #define GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_
    19  
    20  #ifdef __linux__
    21  
    22  #include <errno.h>
    23  #include <linux/capability.h>
    24  #include <sys/syscall.h>
    25  #include <unistd.h>
    26  
    27  #include "test/util/cleanup.h"
    28  #include "test/util/posix_error.h"
    29  #include "test/util/save_util.h"
    30  #include "test/util/test_util.h"
    31  
    32  #ifndef _LINUX_CAPABILITY_VERSION_3
    33  #error Expecting _LINUX_CAPABILITY_VERSION_3 support
    34  #endif
    35  
    36  namespace gvisor {
    37  namespace testing {
    38  
    39  // HaveCapability returns true if the process has the specified EFFECTIVE
    40  // capability.
    41  inline PosixErrorOr<bool> HaveCapability(int cap) {
    42    if (!cap_valid(cap)) {
    43      return PosixError(EINVAL, "Invalid capability");
    44    }
    45  
    46    struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0};
    47    struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {};
    48    RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps));
    49    MaybeSave();
    50  
    51    return (caps[CAP_TO_INDEX(cap)].effective & CAP_TO_MASK(cap)) != 0;
    52  }
    53  
    54  // SetCapability sets the specified EFFECTIVE capability.
    55  inline PosixError SetCapability(int cap, bool set) {
    56    if (!cap_valid(cap)) {
    57      return PosixError(EINVAL, "Invalid capability");
    58    }
    59  
    60    struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0};
    61    struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {};
    62    RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps));
    63    MaybeSave();
    64  
    65    if (set) {
    66      caps[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap);
    67    } else {
    68      caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap);
    69    }
    70    header = {_LINUX_CAPABILITY_VERSION_3, 0};
    71    RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps));
    72    MaybeSave();
    73  
    74    return NoError();
    75  }
    76  
    77  // DropPermittedCapability drops the specified PERMITTED. The EFFECTIVE
    78  // capabilities must be a subset of PERMITTED, so those are dropped as well.
    79  inline PosixError DropPermittedCapability(int cap) {
    80    if (!cap_valid(cap)) {
    81      return PosixError(EINVAL, "Invalid capability");
    82    }
    83  
    84    struct __user_cap_header_struct header = {_LINUX_CAPABILITY_VERSION_3, 0};
    85    struct __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3] = {};
    86    RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capget, &header, &caps));
    87    MaybeSave();
    88  
    89    caps[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap);
    90    caps[CAP_TO_INDEX(cap)].permitted &= ~CAP_TO_MASK(cap);
    91  
    92    header = {_LINUX_CAPABILITY_VERSION_3, 0};
    93    RETURN_ERROR_IF_SYSCALL_FAIL(syscall(__NR_capset, &header, &caps));
    94    MaybeSave();
    95  
    96    return NoError();
    97  }
    98  
    99  PosixErrorOr<bool> CanCreateUserNamespace();
   100  
   101  class AutoCapability {
   102   public:
   103    AutoCapability(int cap, bool set) : cap_(cap), set_(set) {
   104      const bool has = EXPECT_NO_ERRNO_AND_VALUE(HaveCapability(cap));
   105      if (set != has) {
   106        EXPECT_NO_ERRNO(SetCapability(cap_, set_));
   107        applied_ = true;
   108      }
   109    }
   110  
   111    ~AutoCapability() {
   112      if (applied_) {
   113        EXPECT_NO_ERRNO(SetCapability(cap_, !set_));
   114      }
   115    }
   116  
   117   private:
   118    int cap_;
   119    bool set_;
   120    bool applied_ = false;
   121  };
   122  
   123  }  // namespace testing
   124  }  // namespace gvisor
   125  
   126  #endif  // __linux__
   127  
   128  #endif  // GVISOR_TEST_UTIL_LINUX_CAPABILITY_UTIL_H_