/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_LinuxCapabilities_h #define mozilla_LinuxCapabilities_h #include #include #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/PodOperations.h" // This class is a relatively simple interface to manipulating the // capabilities of a Linux process/thread; see the capabilities(7) man // page for background information. // Unfortunately, Android's kernel headers omit some definitions // needed for the low-level capability interface. They're part of the // stable syscall ABI, so it's safe to include them here. #ifndef _LINUX_CAPABILITY_VERSION_3 # define _LINUX_CAPABILITY_VERSION_3 0x20080522 # define _LINUX_CAPABILITY_U32S_3 2 #endif #ifndef CAP_TO_INDEX # define CAP_TO_INDEX(x) ((x) >> 5) # define CAP_TO_MASK(x) (1 << ((x) & 31)) #endif namespace mozilla { class LinuxCapabilities final { public: // A class to represent a bit within the capability sets as an lvalue. class BitRef { __u32& mWord; __u32 mMask; friend class LinuxCapabilities; BitRef(__u32& aWord, uint32_t aMask) : mWord(aWord), mMask(aMask) {} BitRef(const BitRef& aBit) = default; public: MOZ_IMPLICIT operator bool() const { return mWord & mMask; } BitRef& operator=(bool aSetTo) { if (aSetTo) { mWord |= mMask; } else { mWord &= mMask; } return *this; } }; // The default value is the empty set. LinuxCapabilities() { PodArrayZero(mBits); } // Get the current thread's capability sets and assign them to this // object. Returns whether it succeeded and sets errno on failure. // Shouldn't fail unless the kernel is very old. bool GetCurrent(); // Try to set the current thread's capability sets to those // specified in this object. Returns whether it succeeded and sets // errno on failure. bool SetCurrentRaw() const; // The capability model requires that the permitted set always be a // superset of the effective and inheritable sets. This method // expands the permitted set as needed and then sets the current // thread's capabilities, as described above. bool SetCurrent() { Normalize(); return SetCurrentRaw(); } void Normalize() { for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; ++i) { mBits[i].permitted |= mBits[i].effective | mBits[i].inheritable; } } bool AnyEffective() const { for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; ++i) { if (mBits[i].effective != 0) { return true; } } return false; } // These three methods expose individual bits in the three // capability sets as objects that can be used as bool lvalues. // The argument is the capability number, as defined in // the header. BitRef Effective(unsigned aCap) { return GenericBitRef(&__user_cap_data_struct::effective, aCap); } BitRef Permitted(unsigned aCap) { return GenericBitRef(&__user_cap_data_struct::permitted, aCap); } BitRef Inheritable(unsigned aCap) { return GenericBitRef(&__user_cap_data_struct::inheritable, aCap); } private: __user_cap_data_struct mBits[_LINUX_CAPABILITY_U32S_3]; BitRef GenericBitRef(__u32 __user_cap_data_struct::*aField, unsigned aCap) { // Please don't pass untrusted data as the capability number. MOZ_ASSERT(CAP_TO_INDEX(aCap) < _LINUX_CAPABILITY_U32S_3); return BitRef(mBits[CAP_TO_INDEX(aCap)].*aField, CAP_TO_MASK(aCap)); } }; } // namespace mozilla #endif // mozilla_LinuxCapabilities_h