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_