mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +00:00
parser: Use the kernel and policy abis to detect new capabilities
The kernel and policy abis can be used to detect and support new capabilities without having to update base_cap_names.h and and rebuilding the compiler. This is not perfect however in that the does not provide any backwards compatibility mappings, so we still need to keep the internal capability table. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
c3b0e835b5
commit
3880ef5b54
47
parser/capability.h
Normal file
47
parser/capability.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020
|
||||||
|
* Canonical Ltd. (All rights reserved)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of version 2 of the GNU General Public
|
||||||
|
* License published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, contact Novell, Inc. or Canonical
|
||||||
|
* Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AA_CAPABILITY_H
|
||||||
|
#define __AA_CAPABILITY_H
|
||||||
|
|
||||||
|
#define NO_BACKMAP_CAP 0xff
|
||||||
|
|
||||||
|
#ifndef CAP_PERFMON
|
||||||
|
#define CAP_PERFMON 38
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CAP_BPF
|
||||||
|
#define CAP_BPF 39
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum capability_flags {
|
||||||
|
CAPFLAGS_CLEAR = 0,
|
||||||
|
CAPFLAG_BASE_FEATURE = 1,
|
||||||
|
CAPFLAG_KERNEL_FEATURE = 2,
|
||||||
|
CAPFLAG_POLICY_FEATURE = 4,
|
||||||
|
CAPFLAG_EXTERNAL_FEATURE = 8,
|
||||||
|
} capability_flags;
|
||||||
|
|
||||||
|
int name_to_capability(const char *keyword);
|
||||||
|
void capabilities_init(void);
|
||||||
|
void __debug_capabilities(uint64_t capset, const char *name);
|
||||||
|
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags);
|
||||||
|
void clear_cap_flag(capability_flags flags);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __AA_CAPABILITY_H */
|
@ -397,8 +397,6 @@ extern char *processid(const char *string, int len);
|
|||||||
extern char *processquoted(const char *string, int len);
|
extern char *processquoted(const char *string, int len);
|
||||||
extern char *processunquoted(const char *string, int len);
|
extern char *processunquoted(const char *string, int len);
|
||||||
extern int get_keyword_token(const char *keyword);
|
extern int get_keyword_token(const char *keyword);
|
||||||
extern int name_to_capability(const char *keyword);
|
|
||||||
extern void capabilities_init(void);
|
|
||||||
extern int get_rlimit(const char *name);
|
extern int get_rlimit(const char *name);
|
||||||
extern char *process_var(const char *var);
|
extern char *process_var(const char *var);
|
||||||
extern int parse_mode(const char *mode);
|
extern int parse_mode(const char *mode);
|
||||||
@ -412,7 +410,6 @@ extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
|
|||||||
extern int str_to_boolean(const char* str);
|
extern int str_to_boolean(const char* str);
|
||||||
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
||||||
extern void free_cod_entries(struct cod_entry *list);
|
extern void free_cod_entries(struct cod_entry *list);
|
||||||
extern void __debug_capabilities(uint64_t capset, const char *name);
|
|
||||||
void debug_cod_entries(struct cod_entry *list);
|
void debug_cod_entries(struct cod_entry *list);
|
||||||
|
|
||||||
#define SECONDS_P_MS (1000LL * 1000LL)
|
#define SECONDS_P_MS (1000LL * 1000LL)
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
#include <sys/apparmor.h>
|
#include <sys/apparmor.h>
|
||||||
|
|
||||||
|
#include "capability.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "features.h"
|
#include "features.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
@ -923,6 +923,7 @@ void reset_parser(const char *filename)
|
|||||||
if (!specified_policy_features) {
|
if (!specified_policy_features) {
|
||||||
aa_features_unref(policy_features);
|
aa_features_unref(policy_features);
|
||||||
policy_features = NULL;
|
policy_features = NULL;
|
||||||
|
clear_cap_flag(CAPFLAG_POLICY_FEATURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1356,6 +1357,10 @@ int main(int argc, char *argv[])
|
|||||||
PERROR(_("Kernel features abi not found"));
|
PERROR(_("Kernel features abi not found"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (!add_cap_feature_mask(kernel_features, CAPFLAG_KERNEL_FEATURE)) {
|
||||||
|
PERROR(_("Failed to add kernel capabilities to known capabilities set"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(UNPRIVILEGED_OPS) &&
|
if (!(UNPRIVILEGED_OPS) &&
|
||||||
aa_kernel_interface_new(&kernel_interface, kernel_features, apparmorfs) == -1) {
|
aa_kernel_interface_new(&kernel_interface, kernel_features, apparmorfs) == -1) {
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <sys/apparmor.h>
|
#include <sys/apparmor.h>
|
||||||
#include <sys/apparmor_private.h>
|
#include <sys/apparmor_private.h>
|
||||||
|
|
||||||
|
#include "capability.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
@ -177,27 +178,9 @@ int get_rlimit(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define NO_BACKMAP_CAP 0xff
|
|
||||||
|
|
||||||
#ifndef CAP_PERFMON
|
|
||||||
#define CAP_PERFMON 38
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CAP_BPF
|
|
||||||
#define CAP_BPF 39
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum capability_flags {
|
|
||||||
CAPFLAGS_CLEAR = 0,
|
|
||||||
CAPFLAG_BASE_FEATURE = 1,
|
|
||||||
CAPFLAG_KERNEL_FEATURE = 2,
|
|
||||||
CAPFLAG_POLICY_FEATURE = 4,
|
|
||||||
CAPFLAG_EXTERNAL_FEATURE = 8,
|
|
||||||
} capability_flags;
|
|
||||||
|
|
||||||
struct capability_table {
|
struct capability_table {
|
||||||
const char *cap;
|
const char *name;
|
||||||
unsigned int token;
|
unsigned int cap;
|
||||||
unsigned int backmap;
|
unsigned int backmap;
|
||||||
capability_flags flags;
|
capability_flags flags;
|
||||||
};
|
};
|
||||||
@ -222,35 +205,149 @@ void capabilities_init(void)
|
|||||||
cap_table_size = sizeof(base_capability_table)/sizeof(struct capability_table);
|
cap_table_size = sizeof(base_capability_table)/sizeof(struct capability_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_cap_token(const char *name unused, struct capability_table *table,
|
struct capability_table *find_cap_entry_by_name(const char *name)
|
||||||
const char *cap)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; table[i].cap; i++) {
|
for (i = 0; cap_table[i].name; i++) {
|
||||||
PDEBUG("Checking %s %s\n", name, table[i].cap);
|
PDEBUG("Checking %s %s\n", name, cap_table[i].name);
|
||||||
if (strcmp(cap, table[i].cap) == 0) {
|
if (strcmp(name, cap_table[i].name) == 0) {
|
||||||
PDEBUG("Found %s %s\n", name, table[i].cap);
|
PDEBUG("Found %s %s\n", name, cap_table[i].name);
|
||||||
return table[i].token;
|
return &cap_table[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDEBUG("Unable to find %s %s\n", name, cap);
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't mark up str with \0 */
|
||||||
|
static const char *strn_token(const char *str, size_t &len)
|
||||||
|
{
|
||||||
|
const char *start;
|
||||||
|
|
||||||
|
while (isspace(*str))
|
||||||
|
str++;
|
||||||
|
start = str;
|
||||||
|
while (*str && !isspace(*str))
|
||||||
|
str++;
|
||||||
|
if (start == str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = str - start;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
struct capability_table *ent = find_cap_entry_by_name(name);
|
||||||
|
if (ent) {
|
||||||
|
if (ent->cap != cap) {
|
||||||
|
pwarn("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;
|
||||||
|
|
||||||
int name_to_capability(const char *keyword)
|
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)
|
||||||
{
|
{
|
||||||
return get_cap_token("capability", cap_table, keyword);
|
autofree char *value = NULL;
|
||||||
|
const char *capstr;
|
||||||
|
size_t valuelen, len = 0;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
value = aa_features_value(features, "caps/mask", &valuelen);
|
||||||
|
if (!value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for (capstr = strn_token(value, len);
|
||||||
|
capstr;
|
||||||
|
capstr = strn_token(capstr + len, len)) {
|
||||||
|
if (capable_add_cap(capstr, len, n, flags) < 0)
|
||||||
|
return false;
|
||||||
|
n++;
|
||||||
|
if (len > valuelen) {
|
||||||
|
PDEBUG("caplen is > remaining feature string");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
valuelen -= len;
|
||||||
|
PDEBUG("Adding %d capabilities\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_cap_flag(capability_flags flags)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; cap_table[i].name; i++) {
|
||||||
|
PDEBUG("Checking %s %s\n", name, cap_table[i].name);
|
||||||
|
cap_table[i].flags = (capability_flags) (cap_table[i].flags & ~flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int name_to_capability(const char *cap)
|
||||||
|
{
|
||||||
|
struct capability_table *ent;
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; cap_table[i].cap; i++) {
|
for (i = 0; cap_table[i].name; i++) {
|
||||||
if (cap_table[i].token == cap)
|
if (cap_table[i].cap == cap)
|
||||||
return cap_table[i].cap;
|
return cap_table[i].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "invalid-capability";
|
return "invalid-capability";
|
||||||
@ -262,9 +359,9 @@ void __debug_capabilities(uint64_t capset, const char *name)
|
|||||||
|
|
||||||
printf("%s:", name);
|
printf("%s:", name);
|
||||||
|
|
||||||
for (i = 0; cap_table[i].cap; i++) {
|
for (i = 0; cap_table[i].name; i++) {
|
||||||
if ((1ull << cap_table[i].token) & capset)
|
if ((1ull << cap_table[i].cap) & capset)
|
||||||
printf (" %s", cap_table[i].cap);
|
printf (" %s", cap_table[i].name);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
|
|
||||||
|
#include "capability.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
@ -299,6 +300,9 @@ list: preamble
|
|||||||
}
|
}
|
||||||
pwarn(_("%s: File '%s' missing feature abi, falling back to default policy feature abi\n"), progname, current_filename);
|
pwarn(_("%s: File '%s' missing feature abi, falling back to default policy feature abi\n"), progname, current_filename);
|
||||||
}
|
}
|
||||||
|
if (!add_cap_feature_mask(policy_features,
|
||||||
|
CAPFLAG_POLICY_FEATURE))
|
||||||
|
yyerror(_("Failed to add policy capabilities to known capabilities set"));
|
||||||
set_supported_features();
|
set_supported_features();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "capability.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
#include "libapparmor_re/aare_rules.h"
|
#include "libapparmor_re/aare_rules.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user