blob: e0fc61a1ec50280c5e5a1088f5b0a900db707821 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <err.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/capability.h>
#include <linux/prctl.h>
namespace {
bool HasCapabilityEffective(int cap) {
__user_cap_header_struct header;
memset(&header, 0, sizeof(header));
header.version = _LINUX_CAPABILITY_VERSION_3;
__user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
if (syscall(SYS_capget, &header, &caps) != 0) {
err(EXIT_FAILURE, "capget");
}
return caps[CAP_TO_INDEX(cap)].effective & CAP_TO_MASK(cap);
}
bool HasCapabilityPermitted(int cap) {
__user_cap_header_struct header;
memset(&header, 0, sizeof(header));
header.version = _LINUX_CAPABILITY_VERSION_3;
__user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
if (syscall(SYS_capget, &header, &caps) != 0) {
err(EXIT_FAILURE, "capget");
}
return caps[CAP_TO_INDEX(cap)].permitted & CAP_TO_MASK(cap);
}
bool HasCapabilityInheritable(int cap) {
__user_cap_header_struct header;
memset(&header, 0, sizeof(header));
header.version = _LINUX_CAPABILITY_VERSION_3;
__user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
if (syscall(SYS_capget, &header, &caps) != 0) {
err(EXIT_FAILURE, "capget");
}
return caps[CAP_TO_INDEX(cap)].inheritable & CAP_TO_MASK(cap);
}
bool HasCapabilityAmbient(int cap) {
int res = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0);
if (res == -1) {
err(EXIT_FAILURE, "prctl PR_CAP_AMBIENT");
}
return res == 1;
}
bool HasCapabilityBounding(int cap) {
int res = prctl(PR_CAPBSET_READ, cap, 0, 0, 0);
if (res == -1) {
err(EXIT_FAILURE, "prctl PR_CAPBSET_READ");
}
return res == 1;
}
int b2d(bool value) { return value ? 1 : 0; }
int MaxCapabilitySupported() {
FILE* fp = fopen("/proc/sys/kernel/cap_last_cap", "r");
if (fp == nullptr) {
err(EXIT_FAILURE, "opening cap_last_cap");
}
int cap_num = -1;
int n = fscanf(fp, "%d\n", &cap_num);
fclose(fp);
if (n != 1) {
fprintf(stderr, "Could not parse cap_last_cap file.\n");
exit(EXIT_FAILURE);
}
return cap_num;
}
void PrintCapabilities() {
fprintf(stdout, "CAP_NUM,EFFECTIVE,PERMITTED,INHERITABLE,BOUNDING,AMBIENT\n");
const int cap_last_cap = MaxCapabilitySupported();
for (int capability = 0; capability <= cap_last_cap; capability++) {
fprintf(stdout, "%d,%d,%d,%d,%d,%d\n", capability, b2d(HasCapabilityEffective(capability)),
b2d(HasCapabilityPermitted(capability)), b2d(HasCapabilityInheritable(capability)),
b2d(HasCapabilityBounding(capability)), b2d(HasCapabilityAmbient(capability)));
}
}
void PrintSecurebits() {
int res = prctl(PR_GET_SECUREBITS);
if (res == -1) {
err(EXIT_FAILURE, "prctl(PR_GET_SECUREBITS)");
}
fprintf(stdout, "%x\n", res);
}
} // namespace
int main(int argc, char** argv) {
if (argc == 0) {
exit(EXIT_FAILURE);
}
if (argc != 2) {
fprintf(stderr, "Usage: %s <command>\n", argv[0]);
fprintf(stderr, "commands:\n");
fprintf(stderr, "\tsecurebits: print the securebits flags\n");
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "securebits") == 0) {
PrintSecurebits();
} else if (strcmp(argv[1], "capabilities") == 0) {
PrintCapabilities();
} else {
fprintf(stderr, "Invalid command: %s\n", argv[1]);
exit(EXIT_FAILURE);
}
return 0;
}