mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 01:57:43 +00:00
Make capabilities tracker into a class
Signed-off-by: Ryan Lee <ryan.lee@canonical.com>
This commit is contained in:
parent
f6f3279c10
commit
d7cf845437
@ -63,7 +63,6 @@ typedef enum capability_flags {
|
|||||||
} capability_flags;
|
} capability_flags;
|
||||||
|
|
||||||
int name_to_capability(const char *keyword);
|
int name_to_capability(const char *keyword);
|
||||||
void capabilities_init(void);
|
|
||||||
void __debug_capabilities(uint64_t capset, const char *name);
|
void __debug_capabilities(uint64_t capset, const char *name);
|
||||||
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags);
|
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags);
|
||||||
void clear_cap_flag(capability_flags flags);
|
void clear_cap_flag(capability_flags flags);
|
||||||
|
@ -1620,7 +1620,6 @@ int main(int argc, char *argv[])
|
|||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
init_base_dir();
|
init_base_dir();
|
||||||
capabilities_init();
|
|
||||||
|
|
||||||
process_early_args(argc, argv);
|
process_early_args(argc, argv);
|
||||||
process_config_file(config_file);
|
process_config_file(config_file);
|
||||||
|
@ -168,7 +168,7 @@ static int get_table_token(const char *name unused, const unordered_map<string,
|
|||||||
{
|
{
|
||||||
auto token_entry = table.find(keyword);
|
auto token_entry = table.find(keyword);
|
||||||
if (token_entry == table.end()) {
|
if (token_entry == table.end()) {
|
||||||
PDEBUG("Unable to find %s %s\n", name, keyword);
|
PDEBUG("Unable to find %s %s\n", name, keyword.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
PDEBUG("Found %s %s\n", name, keyword.c_str());
|
PDEBUG("Found %s %s\n", name, keyword.c_str());
|
||||||
@ -202,55 +202,163 @@ struct capability_table {
|
|||||||
capability_flags flags;
|
capability_flags flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enum for the results of adding a capability, with values assigned to match
|
||||||
|
* the int values returned by the old capable_add_cap function:
|
||||||
|
*
|
||||||
|
* -1: error
|
||||||
|
* 0: no change - capability already in table
|
||||||
|
* 1: added flag to capability in table
|
||||||
|
* 2: added new capability
|
||||||
|
*/
|
||||||
|
enum add_cap_result {
|
||||||
|
ERROR = -1, // Was only used for OOM conditions
|
||||||
|
ALREADY_EXISTS = 0,
|
||||||
|
FLAG_ADDED = 1,
|
||||||
|
CAP_ADDED = 2
|
||||||
|
};
|
||||||
|
|
||||||
static struct capability_table base_capability_table[] = {
|
static struct capability_table base_capability_table[] = {
|
||||||
/* capabilities */
|
/* capabilities */
|
||||||
#include "cap_names.h"
|
#include "cap_names.h"
|
||||||
|
};
|
||||||
|
static const size_t BASE_CAP_TABLE_SIZE = sizeof(base_capability_table)/sizeof(struct capability_table);
|
||||||
|
|
||||||
/* terminate */
|
class capability_lookup {
|
||||||
{NULL, 0, 0, CAPFLAGS_CLEAR}
|
vector<capability_table> cap_table;
|
||||||
|
// Use unordered_map to avoid pulling in two map implementations
|
||||||
|
// We may want to switch to boost::multiindex to avoid duplication
|
||||||
|
unordered_map<string, capability_table&> name_cap_map;
|
||||||
|
unordered_map<unsigned int, capability_table&> int_cap_map;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add_capability_table_entry_raw(capability_table entry) {
|
||||||
|
cap_table.push_back(entry);
|
||||||
|
capability_table &entry_ref = cap_table.back();
|
||||||
|
name_cap_map.emplace(string(entry_ref.name), entry_ref);
|
||||||
|
int_cap_map.emplace(entry_ref.cap, entry_ref);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
capability_lookup() :
|
||||||
|
cap_table(vector<capability_table>()),
|
||||||
|
name_cap_map(unordered_map<string, capability_table&>(BASE_CAP_TABLE_SIZE)),
|
||||||
|
int_cap_map(unordered_map<unsigned int, capability_table&>(BASE_CAP_TABLE_SIZE)) {
|
||||||
|
cap_table.reserve(BASE_CAP_TABLE_SIZE);
|
||||||
|
for (size_t i=0; i<BASE_CAP_TABLE_SIZE; i++) {
|
||||||
|
add_capability_table_entry_raw(base_capability_table[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
capability_table* find_cap_entry_by_name(string const & name) const {
|
||||||
|
auto map_entry = this->name_cap_map.find(name);
|
||||||
|
if (map_entry == this->name_cap_map.end()) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
PDEBUG("Found %s %s\n", name.c_str(), map_entry->second.name);
|
||||||
|
return &map_entry->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
capability_table* find_cap_entry_by_num(unsigned int cap) const {
|
||||||
|
auto map_entry = this->int_cap_map.find(cap);
|
||||||
|
if (map_entry == this->int_cap_map.end()) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
PDEBUG("Found %d %d\n", cap, map_entry->second.cap);
|
||||||
|
return &map_entry->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int name_to_capability(string const &cap) const {
|
||||||
|
auto map_entry = this->name_cap_map.find(cap);
|
||||||
|
if (map_entry == this->name_cap_map.end()) {
|
||||||
|
PDEBUG("Unable to find %s %s\n", "capability", cap.c_str());
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return map_entry->second.cap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *capability_to_name(unsigned int cap) const {
|
||||||
|
auto map_entry = this->int_cap_map.find(cap);
|
||||||
|
if (map_entry == this->int_cap_map.end()) {
|
||||||
|
return "invalid-capability";
|
||||||
|
} else {
|
||||||
|
return map_entry->second.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int capability_backmap(unsigned int cap) const {
|
||||||
|
auto map_entry = this->int_cap_map.find(cap);
|
||||||
|
if (map_entry == this->int_cap_map.end()) {
|
||||||
|
return NO_BACKMAP_CAP;
|
||||||
|
} else {
|
||||||
|
return map_entry->second.backmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool capability_in_kernel(unsigned int cap) const {
|
||||||
|
auto map_entry = this->int_cap_map.find(cap);
|
||||||
|
if (map_entry == this->int_cap_map.end()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return map_entry->second.flags & CAPFLAG_KERNEL_FEATURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __debug_capabilities(uint64_t capset, const char *name) const {
|
||||||
|
printf("%s:", name);
|
||||||
|
|
||||||
|
for (auto it = this->cap_table.cbegin(); it != this->cap_table.cend(); it++) {
|
||||||
|
if ((1ull << it->cap) & capset)
|
||||||
|
printf (" %s", it->name);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_cap_result capable_add_cap(string const & str, unsigned int cap,
|
||||||
|
capability_flags flag) {
|
||||||
|
struct capability_table *ent = this->find_cap_entry_by_name(str);
|
||||||
|
if (ent) {
|
||||||
|
if (ent->cap != cap) {
|
||||||
|
pwarn(WARN_UNEXPECTED, "feature capability '%s:%d' does not equal expected %d. Ignoring ...\n", str.c_str(), cap, ent->cap);
|
||||||
|
/* TODO: make warn to error config */
|
||||||
|
return add_cap_result::ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
if (ent->flags & flag)
|
||||||
|
return add_cap_result::ALREADY_EXISTS;
|
||||||
|
ent->flags = (capability_flags) (ent->flags | flag);
|
||||||
|
return add_cap_result::FLAG_ADDED;
|
||||||
|
} else {
|
||||||
|
struct capability_table new_entry;
|
||||||
|
new_entry.name = strdup(str.c_str());
|
||||||
|
if (!new_entry.name) {
|
||||||
|
yyerror(_("Out of memory"));
|
||||||
|
return add_cap_result::ERROR;
|
||||||
|
}
|
||||||
|
new_entry.cap = cap;
|
||||||
|
new_entry.flags = flag;
|
||||||
|
try {
|
||||||
|
this->add_capability_table_entry_raw(new_entry);
|
||||||
|
} catch (const std::bad_alloc &_e) {
|
||||||
|
yyerror(_("Out of memory"));
|
||||||
|
return add_cap_result::ERROR;
|
||||||
|
}
|
||||||
|
// TODO: exception catching for causes other than OOM
|
||||||
|
return add_cap_result::CAP_ADDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_cap_flag(capability_flags flags)
|
||||||
|
{
|
||||||
|
for (auto it = this->cap_table.begin(); it != this->cap_table.end(); it++) {
|
||||||
|
PDEBUG("Clearing capability flag for capability \"%s\"\n", it->name);
|
||||||
|
it->flags = (capability_flags) (it->flags & ~flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct capability_table *cap_table;
|
static capability_lookup cap_table;
|
||||||
static int cap_table_size;
|
|
||||||
|
|
||||||
void capabilities_init(void)
|
|
||||||
{
|
|
||||||
cap_table = (struct capability_table *) malloc(sizeof(base_capability_table));
|
|
||||||
if (!cap_table)
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
memcpy(cap_table, base_capability_table, sizeof(base_capability_table));
|
|
||||||
cap_table_size = sizeof(base_capability_table)/sizeof(struct capability_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct capability_table *find_cap_entry_by_name(const char *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; cap_table[i].name; i++) {
|
|
||||||
PDEBUG("Checking %s %s\n", name, cap_table[i].name);
|
|
||||||
if (strcmp(name, cap_table[i].name) == 0) {
|
|
||||||
PDEBUG("Found %s %s\n", name, cap_table[i].name);
|
|
||||||
return &cap_table[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct capability_table *find_cap_entry_by_num(unsigned int cap)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; cap_table[i].name; i++) {
|
|
||||||
PDEBUG("Checking %d %d\n", cap, cap_table[i].cap);
|
|
||||||
if (cap == cap_table[i].cap) {
|
|
||||||
PDEBUG("Found %d %d\n", cap, cap_table[i].cap);
|
|
||||||
return &cap_table[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* don't mark up str with \0 */
|
/* don't mark up str with \0 */
|
||||||
static const char *strn_token(const char *str, size_t &len)
|
static const char *strn_token(const char *str, size_t &len)
|
||||||
@ -288,59 +396,6 @@ bool strcomp (const char *lhs, const char *rhs)
|
|||||||
return null_strcmp(lhs, rhs) < 0;
|
return null_strcmp(lhs, rhs) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns: -1: error
|
|
||||||
* 0: no change - capability already in table
|
|
||||||
* 1: added flag to capability in table
|
|
||||||
* 2: added new capability
|
|
||||||
*/
|
|
||||||
static int capable_add_cap(const char *str, int len, unsigned int cap,
|
|
||||||
capability_flags flag)
|
|
||||||
{
|
|
||||||
/* extract name from str so we can treat as a string */
|
|
||||||
autofree char *name = strndup(str, len);
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
yyerror(_("Out of memory"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
struct capability_table *ent = find_cap_entry_by_name(name);
|
|
||||||
if (ent) {
|
|
||||||
if (ent->cap != cap) {
|
|
||||||
pwarn(WARN_UNEXPECTED, "feature capability '%s:%d' does not equal expected %d. Ignoring ...\n", name, cap, ent->cap);
|
|
||||||
/* TODO: make warn to error config */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ent->flags & flag)
|
|
||||||
return 0; /* no change */
|
|
||||||
ent->flags = (capability_flags) (ent->flags | flag);
|
|
||||||
return 1; /* modified */
|
|
||||||
} else {
|
|
||||||
struct capability_table *tmp;
|
|
||||||
|
|
||||||
tmp = (struct capability_table *) reallocarray(cap_table, sizeof(struct capability_table), cap_table_size+1);
|
|
||||||
if (!tmp) {
|
|
||||||
yyerror(_("Out of memory"));
|
|
||||||
/* TODO: change away from yyerror */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cap_table = tmp;
|
|
||||||
ent = &cap_table[cap_table_size - 1]; /* overwrite null */
|
|
||||||
ent->name = strndup(name, len);
|
|
||||||
if (!ent->name) {
|
|
||||||
/* TODO: change away from yyerror */
|
|
||||||
yyerror(_("Out of memory"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ent->cap = cap;
|
|
||||||
ent->flags = flag;
|
|
||||||
cap_table[cap_table_size].name = NULL; /* new null */
|
|
||||||
cap_table_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2; /* added */
|
|
||||||
}
|
|
||||||
|
|
||||||
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||||
{
|
{
|
||||||
autofree char *value = NULL;
|
autofree char *value = NULL;
|
||||||
@ -357,7 +412,8 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
|||||||
for (capstr = strn_token(value, len);
|
for (capstr = strn_token(value, len);
|
||||||
capstr;
|
capstr;
|
||||||
capstr = strn_token(capstr + len, len)) {
|
capstr = strn_token(capstr + len, len)) {
|
||||||
if (capable_add_cap(capstr, len, n, flags) < 0)
|
string capstr_as_str = string(capstr, len);
|
||||||
|
if (cap_table.capable_add_cap(capstr_as_str, n, flags) < 0)
|
||||||
return false;
|
return false;
|
||||||
n++;
|
n++;
|
||||||
if (len > valuelen) {
|
if (len > valuelen) {
|
||||||
@ -373,70 +429,32 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
|||||||
|
|
||||||
void clear_cap_flag(capability_flags flags)
|
void clear_cap_flag(capability_flags flags)
|
||||||
{
|
{
|
||||||
int i;
|
cap_table.clear_cap_flag(flags);
|
||||||
|
|
||||||
for (i = 0; cap_table[i].name; i++) {
|
|
||||||
PDEBUG("Clearing capability flag for capability \"%s\"\n", cap_table[i].name);
|
|
||||||
cap_table[i].flags = (capability_flags) (cap_table[i].flags & ~flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int name_to_capability(const char *cap)
|
int name_to_capability(const char *cap)
|
||||||
{
|
{
|
||||||
struct capability_table *ent;
|
return cap_table.name_to_capability(string(cap));
|
||||||
|
|
||||||
ent = find_cap_entry_by_name(cap);
|
|
||||||
if (ent)
|
|
||||||
return ent->cap;
|
|
||||||
|
|
||||||
PDEBUG("Unable to find %s %s\n", "capability", cap);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *capability_to_name(unsigned int cap)
|
const char *capability_to_name(unsigned int cap)
|
||||||
{
|
{
|
||||||
struct capability_table *ent;
|
return cap_table.capability_to_name(cap);
|
||||||
|
|
||||||
ent = find_cap_entry_by_num(cap);
|
|
||||||
if (ent)
|
|
||||||
return ent->name;
|
|
||||||
|
|
||||||
return "invalid-capability";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int capability_backmap(unsigned int cap)
|
int capability_backmap(unsigned int cap)
|
||||||
{
|
{
|
||||||
struct capability_table *ent;
|
return cap_table.capability_backmap(cap);
|
||||||
|
|
||||||
ent = find_cap_entry_by_num(cap);
|
|
||||||
if (ent)
|
|
||||||
return ent->backmap;
|
|
||||||
|
|
||||||
return NO_BACKMAP_CAP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool capability_in_kernel(unsigned int cap)
|
bool capability_in_kernel(unsigned int cap)
|
||||||
{
|
{
|
||||||
struct capability_table *ent;
|
return cap_table.capability_in_kernel(cap);
|
||||||
|
|
||||||
ent = find_cap_entry_by_num(cap);
|
|
||||||
if (ent)
|
|
||||||
return ent->flags & CAPFLAG_KERNEL_FEATURE;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __debug_capabilities(uint64_t capset, const char *name)
|
void __debug_capabilities(uint64_t capset, const char *name)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
cap_table.__debug_capabilities(capset, name);
|
||||||
|
|
||||||
printf("%s:", name);
|
|
||||||
|
|
||||||
for (i = 0; cap_table[i].name; i++) {
|
|
||||||
if ((1ull << cap_table[i].cap) & capset)
|
|
||||||
printf (" %s", cap_table[i].name);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *processunquoted(const char *string, int len)
|
char *processunquoted(const char *string, int len)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user