capabilities: Check ambient caps, last valid runtime cap.
Partners have expressed interest in using the 'capabilities' keyword
in init, so make the code more resilient:
-Check that ambient capabilities are supported by the kernel.
-Check that the last valid cap at runtime is not higher than what's in
kernel headers.
-Check that the user is not requesting a capability present in kernel
headers but not supported by the kernel at runtime.
-Don't attempt to drop bounding set capabilities not supported at
runtime.
This CL also fixes a small bug where < should have been used instead of
<=, and uses 'static' instead of anonymous namespaces.
Bug: 32438163
Test: Use a test service that uses capabilities.
Test: Apply in internal tree and test with angler and rild.
Change-Id: Ia271cc7eb389d1d526d61f897261e4bac4d19e5d
diff --git a/init/service.cpp b/init/service.cpp
index e967a7c..7cff348 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -312,13 +312,28 @@
bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
capabilities_ = 0;
+ if (!CapAmbientSupported()) {
+ *err = "capabilities requested but the kernel does not support ambient capabilities";
+ return false;
+ }
+
+ unsigned int last_valid_cap = GetLastValidCap();
+ if (last_valid_cap >= capabilities_.size()) {
+ LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
+ }
+
for (size_t i = 1; i < args.size(); i++) {
const std::string& arg = args[i];
- int cap = LookupCap(arg);
- if (cap == -1) {
+ int res = LookupCap(arg);
+ if (res < 0) {
*err = StringPrintf("invalid capability '%s'", arg.c_str());
return false;
}
+ unsigned int cap = static_cast<unsigned int>(res); // |res| is >= 0.
+ if (cap > last_valid_cap) {
+ *err = StringPrintf("capability '%s' not supported by the kernel", arg.c_str());
+ return false;
+ }
capabilities_[cap] = true;
}
return true;