mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Convert codomain to a class
Convert the codomain to a class, and the policy lists that store codomains to stl containers instead of glibc twalk. Signed-off-by: John Johansen <john.johansen@canonical.com> [tyhicks: Merge with dbus changes and process_file_entries() cleanup] Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Acked-by: Steve Beattie <steve@nxnw.org>
This commit is contained in:
parent
dc76404590
commit
a28e66c5fe
16 changed files with 883 additions and 949 deletions
|
@ -76,8 +76,8 @@ EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\"
|
||||||
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||||
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
||||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||||
parser_alias.c mount.c dbus.c lib.c
|
parser_alias.c mount.c dbus.c lib.c profile.cc
|
||||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h
|
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h
|
||||||
TOOLS = apparmor_parser
|
TOOLS = apparmor_parser
|
||||||
|
|
||||||
OBJECTS = $(SRCS:.c=.o)
|
OBJECTS = $(SRCS:.c=.o)
|
||||||
|
@ -156,16 +156,16 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS)
|
||||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS)
|
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS)
|
||||||
|
|
||||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h
|
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
||||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||||
|
|
||||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h
|
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h
|
||||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||||
|
|
||||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_misc.o: parser_misc.c parser.h parser_yacc.h af_names.h cap_names.h
|
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h af_names.h cap_names.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_yacc.o: parser_yacc.c parser_yacc.h
|
parser_yacc.o: parser_yacc.c parser_yacc.h
|
||||||
|
@ -174,28 +174,28 @@ parser_yacc.o: parser_yacc.c parser_yacc.h
|
||||||
parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h
|
parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_interface.o: parser_interface.c parser.h libapparmor_re/apparmor_re.h
|
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_include.o: parser_include.c parser.h parser_include.h
|
parser_include.o: parser_include.c parser.h parser_include.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_merge.o: parser_merge.c parser.h
|
parser_merge.o: parser_merge.c parser.h profile.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_regex.o: parser_regex.c parser.h libapparmor_re/apparmor_re.h
|
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_symtab.o: parser_symtab.c parser.h
|
parser_symtab.o: parser_symtab.c parser.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_variable.o: parser_variable.c parser.h
|
parser_variable.o: parser_variable.c parser.h profile.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_policy.o: parser_policy.c parser.h parser_yacc.h
|
parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_alias.o: parser_alias.c parser.h
|
parser_alias.o: parser_alias.c parser.h profile.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_common.o: parser_common.c parser.h
|
parser_common.o: parser_common.c parser.h
|
||||||
|
@ -210,6 +210,9 @@ lib.o: lib.c lib.h parser.h
|
||||||
dbus.o: dbus.c dbus.h parser.h immunix.h
|
dbus.o: dbus.c dbus.h parser.h immunix.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
profile.o: profile.cc profile.h parser.h
|
||||||
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_version.h: Makefile
|
parser_version.h: Makefile
|
||||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||||
@mv -f .ver $@
|
@mv -f .ver $@
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
|
142
parser/parser.h
142
parser/parser.h
|
@ -33,6 +33,7 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
class Profile;
|
||||||
|
|
||||||
struct mnt_ent;
|
struct mnt_ent;
|
||||||
|
|
||||||
|
@ -49,12 +50,6 @@ struct prefixes {
|
||||||
int owner;
|
int owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct flagval {
|
|
||||||
int hat;
|
|
||||||
int complain;
|
|
||||||
int audit;
|
|
||||||
int path;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct named_transition {
|
struct named_transition {
|
||||||
int present;
|
int present;
|
||||||
|
@ -85,7 +80,7 @@ struct cod_entry {
|
||||||
char *name;
|
char *name;
|
||||||
char *link_name;
|
char *link_name;
|
||||||
char *nt_name;
|
char *nt_name;
|
||||||
struct codomain *codomain; /* Special codomain defined
|
Profile *prof; /* Special profile defined
|
||||||
* just for this executable */
|
* just for this executable */
|
||||||
int mode; /* mode is 'or' of AA_* bits */
|
int mode; /* mode is 'or' of AA_* bits */
|
||||||
int audit; /* audit flags for mode */
|
int audit; /* audit flags for mode */
|
||||||
|
@ -120,57 +115,6 @@ struct alt_name {
|
||||||
struct alt_name *next;
|
struct alt_name *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct codomain {
|
|
||||||
char *ns;
|
|
||||||
char *name; /* codomain name */
|
|
||||||
char *attachment;
|
|
||||||
struct alt_name *altnames;
|
|
||||||
void *xmatch;
|
|
||||||
size_t xmatch_size;
|
|
||||||
int xmatch_len;
|
|
||||||
|
|
||||||
/* char *sub_name; */ /* subdomain name or NULL */
|
|
||||||
/* int default_deny; */ /* TRUE or FALSE */
|
|
||||||
int local;
|
|
||||||
int local_mode; /* true if local, not hat */
|
|
||||||
int local_audit;
|
|
||||||
|
|
||||||
struct codomain *parent;
|
|
||||||
|
|
||||||
struct flagval flags;
|
|
||||||
|
|
||||||
uint64_t capabilities;
|
|
||||||
uint64_t audit_caps;
|
|
||||||
uint64_t deny_caps;
|
|
||||||
uint64_t quiet_caps;
|
|
||||||
|
|
||||||
unsigned int *network_allowed; /* array of type masks
|
|
||||||
* indexed by AF_FAMILY */
|
|
||||||
unsigned int *audit_network;
|
|
||||||
unsigned int *deny_network;
|
|
||||||
unsigned int *quiet_network;
|
|
||||||
|
|
||||||
struct aa_rlimits rlimits;
|
|
||||||
|
|
||||||
char *exec_table[AA_EXEC_COUNT];
|
|
||||||
struct cod_entry *entries;
|
|
||||||
struct dbus_entry *dbus_ents;
|
|
||||||
struct mnt_entry *mnt_ents;
|
|
||||||
|
|
||||||
void *hat_table;
|
|
||||||
//struct codomain *next;
|
|
||||||
|
|
||||||
aare_ruleset_t *dfarules;
|
|
||||||
int dfarule_count;
|
|
||||||
void *dfa;
|
|
||||||
size_t dfa_size;
|
|
||||||
|
|
||||||
aare_ruleset_t *policy_rules;
|
|
||||||
int policy_rule_count;
|
|
||||||
void *policy_dfa;
|
|
||||||
size_t policy_dfa_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sd_hat {
|
struct sd_hat {
|
||||||
char *hat_name;
|
char *hat_name;
|
||||||
unsigned int hat_magic;
|
unsigned int hat_magic;
|
||||||
|
@ -311,18 +255,18 @@ extern int yylex(void);
|
||||||
extern char *basedir;
|
extern char *basedir;
|
||||||
|
|
||||||
/* parser_regex.c */
|
/* parser_regex.c */
|
||||||
extern int process_regex(struct codomain *cod);
|
extern int process_regex(Profile *prof);
|
||||||
extern int post_process_entry(struct cod_entry *entry);
|
extern int post_process_entry(struct cod_entry *entry);
|
||||||
extern int process_dbus(struct codomain *cod);
|
extern int process_dbus(Profile *prof);
|
||||||
|
|
||||||
extern void reset_regex(void);
|
extern void reset_regex(void);
|
||||||
|
|
||||||
extern int process_policydb(struct codomain *cod);
|
extern int process_policydb(Profile *prof);
|
||||||
|
|
||||||
extern int process_policy_ents(struct codomain *cod);
|
extern int process_policy_ents(Profile *prof);
|
||||||
|
|
||||||
/* parser_variable.c */
|
/* parser_variable.c */
|
||||||
extern int process_variables(struct codomain *cod);
|
extern int process_variables(Profile *prof);
|
||||||
extern struct var_string *split_out_var(char *string);
|
extern struct var_string *split_out_var(char *string);
|
||||||
extern void free_var_string(struct var_string *var);
|
extern void free_var_string(struct var_string *var);
|
||||||
|
|
||||||
|
@ -353,13 +297,16 @@ extern struct aa_network_entry *network_entry(const char *family,
|
||||||
const char *protocol);
|
const char *protocol);
|
||||||
extern size_t get_af_max(void);
|
extern size_t get_af_max(void);
|
||||||
|
|
||||||
extern void debug_cod_list(struct codomain *list);
|
|
||||||
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
|
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
|
||||||
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 free_mnt_entries(struct mnt_entry *list);
|
extern void free_mnt_entries(struct mnt_entry *list);
|
||||||
extern void free_dbus_entries(struct dbus_entry *list);
|
extern void free_dbus_entries(struct dbus_entry *list);
|
||||||
|
extern void __debug_capabilities(uint64_t capset, const char *name);
|
||||||
|
void __debug_network(unsigned int *array, const char *name);
|
||||||
|
void debug_cod_entries(struct cod_entry *list);
|
||||||
|
|
||||||
|
|
||||||
/* parser_symtab.c */
|
/* parser_symtab.c */
|
||||||
struct set_value {;
|
struct set_value {;
|
||||||
|
@ -378,72 +325,41 @@ void free_symtabs(void);
|
||||||
|
|
||||||
/* parser_alias.c */
|
/* parser_alias.c */
|
||||||
extern int new_alias(const char *from, const char *to);
|
extern int new_alias(const char *from, const char *to);
|
||||||
extern void replace_aliases(struct codomain *cod);
|
extern int replace_profile_aliases(Profile *prof);
|
||||||
extern void free_aliases(void);
|
extern void free_aliases(void);
|
||||||
|
|
||||||
/* parser_merge.c */
|
/* parser_merge.c */
|
||||||
extern int codomain_merge_rules(struct codomain *cod);
|
extern int profile_merge_rules(Profile *prof);
|
||||||
|
|
||||||
/* parser_interface.c */
|
/* parser_interface.c */
|
||||||
typedef struct __sdserialize sd_serialize;
|
typedef struct __sdserialize sd_serialize;
|
||||||
extern int load_codomain(int option, struct codomain *cod);
|
extern int load_profile(int option, Profile *prof);
|
||||||
extern int sd_serialize_profile(sd_serialize *p, struct codomain *cod,
|
extern int sd_serialize_profile(sd_serialize *p, Profile *prof,
|
||||||
int flatten);
|
int flatten);
|
||||||
extern int sd_load_buffer(int option, char *buffer, int size);
|
extern int sd_load_buffer(int option, char *buffer, int size);
|
||||||
extern int cache_fd;
|
extern int cache_fd;
|
||||||
|
|
||||||
|
|
||||||
/* parser_policy.c */
|
/* parser_policy.c */
|
||||||
extern void add_to_list(struct codomain *codomain);
|
extern void add_to_list(Profile *profile);
|
||||||
extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
|
extern void add_hat_to_policy(Profile *policy, Profile *hat);
|
||||||
extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
|
extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry);
|
||||||
extern void post_process_file_entries(struct codomain *cod);
|
extern void post_process_file_entries(Profile *prof);
|
||||||
extern void post_process_mnt_entries(struct codomain *cod);
|
extern void post_process_mnt_entries(Profile *prof);
|
||||||
extern int post_process_policy(int debug_only);
|
extern int post_process_policy(int debug_only);
|
||||||
extern int process_hat_regex(struct codomain *cod);
|
extern int process_profile_regex(Profile *prof);
|
||||||
extern int process_hat_dbus(struct codomain *cod);
|
extern int process_profile_variables(Profile *prof);
|
||||||
extern int process_hat_variables(struct codomain *cod);
|
extern int process_profile_policydb(Profile *prof);
|
||||||
extern int process_hat_policydb(struct codomain *cod);
|
|
||||||
extern int post_merge_rules(void);
|
extern int post_merge_rules(void);
|
||||||
extern int merge_hat_rules(struct codomain *cod);
|
extern int merge_hat_rules(Profile *prof);
|
||||||
extern struct codomain *merge_policy(struct codomain *a, struct codomain *b);
|
extern Profile *merge_policy(Profile *a, Profile *b);
|
||||||
extern int load_policy(int option);
|
extern int load_policy(int option);
|
||||||
extern int load_hats(sd_serialize *p, struct codomain *cod);
|
extern int load_hats(sd_serialize *p, Profile *prof);
|
||||||
extern int load_flattened_hats(struct codomain *cod);
|
extern int load_flattened_hats(Profile *prof, int option);
|
||||||
extern void free_policy(struct codomain *cod);
|
extern void dump_policy_hats(Profile *prof);
|
||||||
extern void dump_policy(void);
|
|
||||||
extern void dump_policy_hats(struct codomain *cod);
|
|
||||||
extern void dump_policy_names(void);
|
extern void dump_policy_names(void);
|
||||||
|
void dump_policy(void);
|
||||||
|
|
||||||
void free_policies(void);
|
void free_policies(void);
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
|
||||||
/* For the unit-test builds, we must include function stubs for stuff that
|
|
||||||
* only exists in the excluded object files; everything else should live
|
|
||||||
* in parser_common.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* parser_yacc.y */
|
|
||||||
void yyerror(const char *msg, ...)
|
|
||||||
{
|
|
||||||
va_list arg;
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
|
|
||||||
va_start(arg, msg);
|
|
||||||
vsnprintf(buf, sizeof(buf), msg, arg);
|
|
||||||
va_end(arg);
|
|
||||||
|
|
||||||
PERROR(_("AppArmor parser error: %s\n"), buf);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MY_TEST(statement, error) \
|
|
||||||
if (!(statement)) { \
|
|
||||||
PERROR("FAIL: %s\n", error); \
|
|
||||||
rc = 1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** __AA_PARSER_H */
|
#endif /** __AA_PARSER_H */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "immunix.h"
|
#include "immunix.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
|
|
||||||
struct alias_rule {
|
struct alias_rule {
|
||||||
char *from;
|
char *from;
|
||||||
|
@ -105,7 +106,7 @@ static char *do_alias(struct alias_rule *alias, const char *target)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct codomain *target_cod;
|
static Profile *target_prof;
|
||||||
static struct cod_entry *target_list;
|
static struct cod_entry *target_list;
|
||||||
static void process_entries(const void *nodep, VISIT value, int __unused level)
|
static void process_entries(const void *nodep, VISIT value, int __unused level)
|
||||||
{
|
{
|
||||||
|
@ -155,7 +156,7 @@ static void process_entries(const void *nodep, VISIT value, int __unused level)
|
||||||
static void process_name(const void *nodep, VISIT value, int __unused level)
|
static void process_name(const void *nodep, VISIT value, int __unused level)
|
||||||
{
|
{
|
||||||
struct alias_rule **t = (struct alias_rule **) nodep;
|
struct alias_rule **t = (struct alias_rule **) nodep;
|
||||||
struct codomain *cod = target_cod;
|
Profile *prof = target_prof;
|
||||||
char *name;
|
char *name;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -164,10 +165,10 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
|
||||||
|
|
||||||
len = strlen((*t)->from);
|
len = strlen((*t)->from);
|
||||||
|
|
||||||
if (cod->attachment)
|
if (prof->attachment)
|
||||||
name = cod->attachment;
|
name = prof->attachment;
|
||||||
else
|
else
|
||||||
name = cod->name;
|
name = prof->name;
|
||||||
|
|
||||||
if (name && strncmp((*t)->from, name, len) == 0) {
|
if (name && strncmp((*t)->from, name, len) == 0) {
|
||||||
struct alt_name *alt;
|
struct alt_name *alt;
|
||||||
|
@ -179,21 +180,23 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
|
||||||
if (!alt)
|
if (!alt)
|
||||||
return;
|
return;
|
||||||
alt->name = n;
|
alt->name = n;
|
||||||
alt->next = cod->altnames;
|
alt->next = prof->altnames;
|
||||||
cod->altnames = alt;
|
prof->altnames = alt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void replace_aliases(struct codomain *cod)
|
int replace_profile_aliases(Profile *prof)
|
||||||
{
|
{
|
||||||
target_cod = cod;
|
target_prof = prof;
|
||||||
twalk(alias_table, process_name);
|
twalk(alias_table, process_name);
|
||||||
|
|
||||||
if (cod->entries) {
|
if (prof->entries) {
|
||||||
target_list = cod->entries;
|
target_list = prof->entries;
|
||||||
target_cod = cod;
|
target_prof = prof;
|
||||||
twalk(alias_table, process_entries);
|
twalk(alias_table, process_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_alias(void *nodep)
|
static void free_alias(void *nodep)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#define _(s) gettext(s)
|
#define _(s) gettext(s)
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "libapparmor_re/apparmor_re.h"
|
#include "libapparmor_re/apparmor_re.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -59,7 +60,7 @@
|
||||||
|
|
||||||
#define SUBDOMAIN_INTERFACE_DFA_VERSION 5
|
#define SUBDOMAIN_INTERFACE_DFA_VERSION 5
|
||||||
|
|
||||||
int sd_serialize_codomain(int option, struct codomain *cod);
|
int __sd_serialize_profile(int option, Profile *prof);
|
||||||
|
|
||||||
static void print_error(int error)
|
static void print_error(int error)
|
||||||
{
|
{
|
||||||
|
@ -100,30 +101,30 @@ static void print_error(int error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_codomain(int option, struct codomain *cod)
|
int load_profile(int option, Profile *prof)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
PDEBUG("Serializing policy for %s.\n", cod->name);
|
PDEBUG("Serializing policy for %s.\n", prof->name);
|
||||||
retval = sd_serialize_codomain(option, cod);
|
retval = __sd_serialize_profile(option, prof);
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
error = retval; /* yeah, we'll just report the last error */
|
error = retval; /* yeah, we'll just report the last error */
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case OPTION_ADD:
|
case OPTION_ADD:
|
||||||
PERROR(_("%s: Unable to add \"%s\". "),
|
PERROR(_("%s: Unable to add \"%s\". "),
|
||||||
progname, cod->name);
|
progname, prof->name);
|
||||||
print_error(error);
|
print_error(error);
|
||||||
break;
|
break;
|
||||||
case OPTION_REPLACE:
|
case OPTION_REPLACE:
|
||||||
PERROR(_("%s: Unable to replace \"%s\". "),
|
PERROR(_("%s: Unable to replace \"%s\". "),
|
||||||
progname, cod->name);
|
progname, prof->name);
|
||||||
print_error(error);
|
print_error(error);
|
||||||
break;
|
break;
|
||||||
case OPTION_REMOVE:
|
case OPTION_REMOVE:
|
||||||
PERROR(_("%s: Unable to remove \"%s\". "),
|
PERROR(_("%s: Unable to remove \"%s\". "),
|
||||||
progname, cod->name);
|
progname, prof->name);
|
||||||
print_error(error);
|
print_error(error);
|
||||||
break;
|
break;
|
||||||
case OPTION_STDOUT:
|
case OPTION_STDOUT:
|
||||||
|
@ -144,15 +145,15 @@ int load_codomain(int option, struct codomain *cod)
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case OPTION_ADD:
|
case OPTION_ADD:
|
||||||
printf(_("Addition succeeded for \"%s\".\n"),
|
printf(_("Addition succeeded for \"%s\".\n"),
|
||||||
cod->name);
|
prof->name);
|
||||||
break;
|
break;
|
||||||
case OPTION_REPLACE:
|
case OPTION_REPLACE:
|
||||||
printf(_("Replacement succeeded for \"%s\".\n"),
|
printf(_("Replacement succeeded for \"%s\".\n"),
|
||||||
cod->name);
|
prof->name);
|
||||||
break;
|
break;
|
||||||
case OPTION_REMOVE:
|
case OPTION_REMOVE:
|
||||||
printf(_("Removal succeeded for \"%s\".\n"),
|
printf(_("Removal succeeded for \"%s\".\n"),
|
||||||
cod->name);
|
prof->name);
|
||||||
break;
|
break;
|
||||||
case OPTION_STDOUT:
|
case OPTION_STDOUT:
|
||||||
case OPTION_OFILE:
|
case OPTION_OFILE:
|
||||||
|
@ -544,7 +545,7 @@ int count_tailglob_ents(struct cod_entry *list)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
int sd_serialize_profile(sd_serialize *p, Profile *profile,
|
||||||
int flattened)
|
int flattened)
|
||||||
{
|
{
|
||||||
uint64_t allowed_caps;
|
uint64_t allowed_caps;
|
||||||
|
@ -608,12 +609,12 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||||
|
|
||||||
#define low_caps(X) ((u32) ((X) & 0xffffffff))
|
#define low_caps(X) ((u32) ((X) & 0xffffffff))
|
||||||
#define high_caps(X) ((u32) (((X) >> 32) & 0xffffffff))
|
#define high_caps(X) ((u32) (((X) >> 32) & 0xffffffff))
|
||||||
allowed_caps = (profile->capabilities) & ~profile->deny_caps;
|
allowed_caps = (profile->caps.allow) & ~profile->caps.deny;
|
||||||
if (!sd_write32(p, low_caps(allowed_caps)))
|
if (!sd_write32(p, low_caps(allowed_caps)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, low_caps(allowed_caps & profile->audit_caps)))
|
if (!sd_write32(p, low_caps(allowed_caps & profile->caps.audit)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, low_caps(profile->deny_caps & profile->quiet_caps)))
|
if (!sd_write32(p, low_caps(profile->caps.deny & profile->caps.quiet)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, 0))
|
if (!sd_write32(p, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -622,9 +623,9 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, high_caps(allowed_caps)))
|
if (!sd_write32(p, high_caps(allowed_caps)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, high_caps(allowed_caps & profile->audit_caps)))
|
if (!sd_write32(p, high_caps(allowed_caps & profile->caps.audit)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, high_caps(profile->deny_caps & profile->quiet_caps)))
|
if (!sd_write32(p, high_caps(profile->caps.deny & profile->caps.quiet)))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write32(p, 0))
|
if (!sd_write32(p, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -634,36 +635,36 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||||
if (!sd_serialize_rlimits(p, &profile->rlimits))
|
if (!sd_serialize_rlimits(p, &profile->rlimits))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (profile->network_allowed && kernel_supports_network) {
|
if (profile->net.allow && kernel_supports_network) {
|
||||||
size_t i;
|
size_t i;
|
||||||
if (!sd_write_array(p, "net_allowed_af", get_af_max()))
|
if (!sd_write_array(p, "net_allowed_af", get_af_max()))
|
||||||
return 0;
|
return 0;
|
||||||
for (i = 0; i < get_af_max(); i++) {
|
for (i = 0; i < get_af_max(); i++) {
|
||||||
u16 allowed = profile->network_allowed[i] &
|
u16 allowed = profile->net.allow[i] &
|
||||||
~profile->deny_network[i];
|
~profile->net.deny[i];
|
||||||
if (!sd_write16(p, allowed))
|
if (!sd_write16(p, allowed))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write16(p, allowed & profile->audit_network[i]))
|
if (!sd_write16(p, allowed & profile->net.audit[i]))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write16(p, profile->deny_network[i] & profile->quiet_network[i]))
|
if (!sd_write16(p, profile->net.deny[i] & profile->net.quiet[i]))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!sd_write_arrayend(p))
|
if (!sd_write_arrayend(p))
|
||||||
return 0;
|
return 0;
|
||||||
} else if (profile->network_allowed)
|
} else if (profile->net.allow)
|
||||||
pwarn(_("profile %s network rules not enforced\n"), profile->name);
|
pwarn(_("profile %s network rules not enforced\n"), profile->name);
|
||||||
|
|
||||||
if (profile->policy_dfa) {
|
if (profile->policy.dfa) {
|
||||||
if (!sd_write_struct(p, "policydb"))
|
if (!sd_write_struct(p, "policydb"))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_serialize_dfa(p, profile->policy_dfa, profile->policy_dfa_size))
|
if (!sd_serialize_dfa(p, profile->policy.dfa, profile->policy.size))
|
||||||
return 0;
|
return 0;
|
||||||
if (!sd_write_structend(p))
|
if (!sd_write_structend(p))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* either have a single dfa or lists of different entry types */
|
/* either have a single dfa or lists of different entry types */
|
||||||
if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size))
|
if (!sd_serialize_dfa(p, profile->dfa.dfa, profile->dfa.size))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sd_serialize_xtable(p, profile->exec_table))
|
if (!sd_serialize_xtable(p, profile->exec_table))
|
||||||
|
@ -675,7 +676,7 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
|
int sd_serialize_top_profile(sd_serialize *p, Profile *profile)
|
||||||
{
|
{
|
||||||
int version;
|
int version;
|
||||||
|
|
||||||
|
@ -699,7 +700,7 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
int cache_fd = -1;
|
int cache_fd = -1;
|
||||||
int sd_serialize_codomain(int option, struct codomain *cod)
|
int __sd_serialize_profile(int option, Profile *prof)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int error = -ENOMEM, size, wsize;
|
int error = -ENOMEM, size, wsize;
|
||||||
|
@ -754,34 +755,34 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||||
if (profile_ns) {
|
if (profile_ns) {
|
||||||
len += strlen(profile_ns) + 2;
|
len += strlen(profile_ns) + 2;
|
||||||
ns = profile_ns;
|
ns = profile_ns;
|
||||||
} else if (cod->ns) {
|
} else if (prof->ns) {
|
||||||
len += strlen(cod->ns) + 2;
|
len += strlen(prof->ns) + 2;
|
||||||
ns = cod->ns;
|
ns = prof->ns;
|
||||||
}
|
}
|
||||||
if (cod->parent) {
|
if (prof->parent) {
|
||||||
name = (char *) malloc(strlen(cod->name) + 3 +
|
name = (char *) malloc(strlen(prof->name) + 3 +
|
||||||
strlen(cod->parent->name) + len);
|
strlen(prof->parent->name) + len);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), cod->name);
|
PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), prof->name);
|
||||||
error = -errno;
|
error = -errno;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (ns)
|
if (ns)
|
||||||
sprintf(name, ":%s:%s//%s", ns,
|
sprintf(name, ":%s:%s//%s", ns,
|
||||||
cod->parent->name, cod->name);
|
prof->parent->name, prof->name);
|
||||||
else
|
else
|
||||||
sprintf(name, "%s//%s", cod->parent->name,
|
sprintf(name, "%s//%s", prof->parent->name,
|
||||||
cod->name);
|
prof->name);
|
||||||
} else if (ns) {
|
} else if (ns) {
|
||||||
name = (char *) malloc(len + strlen(cod->name) + 1);
|
name = (char *) malloc(len + strlen(prof->name) + 1);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, cod->name);
|
PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, prof->name);
|
||||||
error = -errno;
|
error = -errno;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
sprintf(name, ":%s:%s", ns, cod->name);
|
sprintf(name, ":%s:%s", ns, prof->name);
|
||||||
} else {
|
} else {
|
||||||
name = cod->name;
|
name = prof->name;
|
||||||
}
|
}
|
||||||
size = strlen(name) + 1;
|
size = strlen(name) + 1;
|
||||||
if (kernel_load) {
|
if (kernel_load) {
|
||||||
|
@ -789,7 +790,7 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||||
if (wsize < 0)
|
if (wsize < 0)
|
||||||
error = -errno;
|
error = -errno;
|
||||||
}
|
}
|
||||||
if (cod->parent || ns)
|
if (prof->parent || ns)
|
||||||
free(name);
|
free(name);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -801,11 +802,11 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sd_serialize_top_profile(work_area, cod)) {
|
if (!sd_serialize_top_profile(work_area, prof)) {
|
||||||
close(fd);
|
close(fd);
|
||||||
free_sd_serial(work_area);
|
free_sd_serial(work_area);
|
||||||
PERROR(_("unable to serialize profile %s\n"),
|
PERROR(_("unable to serialize profile %s\n"),
|
||||||
cod->name);
|
prof->name);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,8 +836,8 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (cod->hat_table && option != OPTION_REMOVE) {
|
if (!prof->hat_table.empty() && option != OPTION_REMOVE) {
|
||||||
if (load_flattened_hats(cod) != 0)
|
if (load_flattened_hats(prof, option) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#define _(s) gettext(s)
|
#define _(s) gettext(s)
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "parser_include.h"
|
#include "parser_include.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define _(s) gettext(s)
|
#define _(s) gettext(s)
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
|
|
||||||
static int file_comp(const void *c1, const void *c2)
|
static int file_comp(const void *c1, const void *c2)
|
||||||
{
|
{
|
||||||
|
@ -74,35 +74,35 @@ static int file_comp(const void *c1, const void *c2)
|
||||||
return strcmp((*e1)->name, (*e2)->name);
|
return strcmp((*e1)->name, (*e2)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_file_entries(struct codomain *cod)
|
static int process_file_entries(Profile *prof)
|
||||||
{
|
{
|
||||||
struct cod_entry *cur, *next;
|
struct cod_entry *cur, *next;
|
||||||
struct cod_entry **table;
|
struct cod_entry **table;
|
||||||
int n, count = 0;
|
int n, count = 0;
|
||||||
|
|
||||||
for (cur = cod->entries; cur; cur = cur->next)
|
for (cur = prof->entries; cur; cur = cur->next)
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (count < 2)
|
if (count < 2)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1));
|
table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1));
|
||||||
if (!table) {
|
if (!table) {
|
||||||
PERROR(_("Couldn't merge entries. Out of Memory\n"));
|
PERROR(_("Couldn't merge entries. Out of Memory\n"));
|
||||||
return 0;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cur = cod->entries, n = 0; cur; cur = cur->next, n++)
|
for (cur = prof->entries, n = 0; cur; cur = cur->next, n++)
|
||||||
table[n] = cur;
|
table[n] = cur;
|
||||||
qsort(table, count, sizeof(struct cod_entry *), file_comp);
|
qsort(table, count, sizeof(struct cod_entry *), file_comp);
|
||||||
table[count] = NULL;
|
table[count] = NULL;
|
||||||
for (n = 0; n < count; n++)
|
for (n = 0; n < count; n++)
|
||||||
table[n]->next = table[n + 1];
|
table[n]->next = table[n + 1];
|
||||||
cod->entries = table[0];
|
prof->entries = table[0];
|
||||||
free(table);
|
free(table);
|
||||||
|
|
||||||
/* walk the sorted table merging similar entries */
|
/* walk the sorted table merging similar entries */
|
||||||
for (cur = cod->entries, next = cur->next; next; next = cur->next) {
|
for (cur = prof->entries, next = cur->next; next; next = cur->next) {
|
||||||
if (file_comp(&cur, &next) != 0) {
|
if (file_comp(&cur, &next) != 0) {
|
||||||
cur = next;
|
cur = next;
|
||||||
continue;
|
continue;
|
||||||
|
@ -111,8 +111,8 @@ static int process_file_entries(struct codomain *cod)
|
||||||
/* check for merged x consistency */
|
/* check for merged x consistency */
|
||||||
if (!is_merged_x_consistent(cur->mode, next->mode)) {
|
if (!is_merged_x_consistent(cur->mode, next->mode)) {
|
||||||
PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"),
|
PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"),
|
||||||
cod->name, cur->name);
|
prof->name, cur->name);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
cur->mode |= next->mode;
|
cur->mode |= next->mode;
|
||||||
cur->audit |= next->audit;
|
cur->audit |= next->audit;
|
||||||
|
@ -122,18 +122,10 @@ static int process_file_entries(struct codomain *cod)
|
||||||
free_cod_entries(next);
|
free_cod_entries(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int codomain_merge_rules(struct codomain *cod)
|
|
||||||
{
|
|
||||||
if (!process_file_entries(cod))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* XXX return error from this */
|
|
||||||
merge_hat_rules(cod);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
fail:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int profile_merge_rules(Profile *prof)
|
||||||
|
{
|
||||||
|
return process_file_entries(prof);
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
@ -952,23 +953,6 @@ void debug_cod_entries(struct cod_entry *list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_flags(struct codomain *cod)
|
|
||||||
{
|
|
||||||
printf("Profile Mode:\t");
|
|
||||||
|
|
||||||
if (cod->flags.complain)
|
|
||||||
printf("Complain");
|
|
||||||
else
|
|
||||||
printf("Enforce");
|
|
||||||
|
|
||||||
if (cod->flags.audit)
|
|
||||||
printf(", Audit");
|
|
||||||
|
|
||||||
if (cod->flags.hat)
|
|
||||||
printf(", Hat");
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *capnames[] = {
|
static const char *capnames[] = {
|
||||||
"chown",
|
"chown",
|
||||||
|
@ -1029,17 +1013,6 @@ void __debug_capabilities(uint64_t capset, const char *name)
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
void debug_capabilities(struct codomain *cod)
|
|
||||||
{
|
|
||||||
if (cod->capabilities != 0ull)
|
|
||||||
__debug_capabilities(cod->capabilities, "Capabilities");
|
|
||||||
if (cod->audit_caps != 0ull)
|
|
||||||
__debug_capabilities(cod->audit_caps, "Audit Caps");
|
|
||||||
if (cod->deny_caps != 0ull)
|
|
||||||
__debug_capabilities(cod->deny_caps, "Deny Caps");
|
|
||||||
if (cod->quiet_caps != 0ull)
|
|
||||||
__debug_capabilities(cod->quiet_caps, "Quiet Caps");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
||||||
* have to make sure these are in order. This means we are more brittle
|
* have to make sure these are in order. This means we are more brittle
|
||||||
|
@ -1129,44 +1102,6 @@ void __debug_network(unsigned int *array, const char *name)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_network(struct codomain *cod)
|
|
||||||
{
|
|
||||||
if (cod->network_allowed)
|
|
||||||
__debug_network(cod->network_allowed, "Network");
|
|
||||||
if (cod->audit_network)
|
|
||||||
__debug_network(cod->audit_network, "Audit Net");
|
|
||||||
if (cod->deny_network)
|
|
||||||
__debug_network(cod->deny_network, "Deny Net");
|
|
||||||
if (cod->quiet_network)
|
|
||||||
__debug_network(cod->quiet_network, "Quiet Net");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_cod_list(struct codomain *cod)
|
|
||||||
{
|
|
||||||
if (cod->ns)
|
|
||||||
printf("Ns:\t\t%s\n", cod->ns);
|
|
||||||
|
|
||||||
if (cod->name)
|
|
||||||
printf("Name:\t\t%s\n", cod->name);
|
|
||||||
else
|
|
||||||
printf("Name:\t\tNULL\n");
|
|
||||||
|
|
||||||
if (cod->local)
|
|
||||||
printf("Local To:\t%s\n", cod->parent->name);
|
|
||||||
|
|
||||||
debug_flags(cod);
|
|
||||||
|
|
||||||
debug_capabilities(cod);
|
|
||||||
|
|
||||||
debug_network(cod);
|
|
||||||
|
|
||||||
if (cod->entries)
|
|
||||||
debug_cod_entries(cod->entries);
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
dump_policy_hats(cod);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct value_list *new_value_list(char *value)
|
struct value_list *new_value_list(char *value)
|
||||||
{
|
{
|
||||||
|
@ -1274,6 +1209,9 @@ void print_cond_entry(struct cond_entry *ent)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
|
|
||||||
|
#include "unit_test.h"
|
||||||
|
|
||||||
int test_str_to_boolean(void)
|
int test_str_to_boolean(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define _(s) gettext(s)
|
#define _(s) gettext(s)
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
|
@ -43,70 +44,40 @@
|
||||||
#endif
|
#endif
|
||||||
#define NPDEBUG(fmt, args...) /* Do nothing */
|
#define NPDEBUG(fmt, args...) /* Do nothing */
|
||||||
|
|
||||||
void *policy_list = NULL;
|
|
||||||
|
|
||||||
static int codomain_compare(const void *a, const void *b)
|
ProfileList policy_list;
|
||||||
|
|
||||||
|
|
||||||
|
void add_to_list(Profile *prof)
|
||||||
{
|
{
|
||||||
struct codomain *A = (struct codomain *) a;
|
pair<ProfileList::iterator, bool> res = policy_list.insert(prof);
|
||||||
struct codomain *B = (struct codomain *) b;
|
if (!res.second) {
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
if (A->ns) {
|
|
||||||
if (B->ns)
|
|
||||||
res = strcmp(A->ns, B->ns);
|
|
||||||
else
|
|
||||||
res = -1;
|
|
||||||
} else if (B->ns)
|
|
||||||
res = 1;
|
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
return strcmp(A->name, B->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_to_list(struct codomain *codomain)
|
|
||||||
{
|
|
||||||
struct codomain **result;
|
|
||||||
|
|
||||||
result = (struct codomain **) tsearch(codomain, &policy_list, codomain_compare);
|
|
||||||
if (!result) {
|
|
||||||
PERROR("Memory allocation error\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*result != codomain) {
|
|
||||||
PERROR("Multiple definitions for profile %s exist,"
|
PERROR("Multiple definitions for profile %s exist,"
|
||||||
"bailing out.\n", codomain->name);
|
"bailing out.\n", prof->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_hat_to_policy(struct codomain *cod, struct codomain *hat)
|
void add_hat_to_policy(Profile *prof, Profile *hat)
|
||||||
{
|
{
|
||||||
struct codomain **result;
|
hat->parent = prof;
|
||||||
|
|
||||||
hat->parent = cod;
|
pair<ProfileList::iterator, bool> res = prof->hat_table.insert(hat);
|
||||||
|
if (!res.second) {
|
||||||
result = (struct codomain **) tsearch(hat, &(cod->hat_table), codomain_compare);
|
|
||||||
if (!result) {
|
|
||||||
PERROR("Memory allocation error\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*result != hat) {
|
|
||||||
PERROR("Multiple definitions for hat %s in profile %s exist,"
|
PERROR("Multiple definitions for hat %s in profile %s exist,"
|
||||||
"bailing out.\n", hat->name, cod->name);
|
"bailing out.\n", hat->name, prof->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_entry_to_x_table(struct codomain *cod, char *name)
|
static int add_entry_to_x_table(Profile *prof, char *name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||||
if (!cod->exec_table[i]) {
|
if (!prof->exec_table[i]) {
|
||||||
cod->exec_table[i] = name;
|
prof->exec_table[i] = name;
|
||||||
return i;
|
return i;
|
||||||
} else if (strcmp(cod->exec_table[i], name) == 0) {
|
} else if (strcmp(prof->exec_table[i], name) == 0) {
|
||||||
/* name already in table */
|
/* name already in table */
|
||||||
free(name);
|
free(name);
|
||||||
return i;
|
return i;
|
||||||
|
@ -116,7 +87,7 @@ static int add_entry_to_x_table(struct codomain *cod, char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
static int add_named_transition(Profile *prof, struct cod_entry *entry)
|
||||||
{
|
{
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
|
|
||||||
|
@ -125,7 +96,7 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
||||||
char *sub = strstr(entry->nt_name, "//");
|
char *sub = strstr(entry->nt_name, "//");
|
||||||
/* does the subprofile name match the rule */
|
/* does the subprofile name match the rule */
|
||||||
|
|
||||||
if (sub && strncmp(cod->name, sub, sub - entry->nt_name) &&
|
if (sub && strncmp(prof->name, sub, sub - entry->nt_name) &&
|
||||||
strcmp(sub + 2, entry->name) == 0) {
|
strcmp(sub + 2, entry->name) == 0) {
|
||||||
free(entry->nt_name);
|
free(entry->nt_name);
|
||||||
entry->nt_name = NULL;
|
entry->nt_name = NULL;
|
||||||
|
@ -140,13 +111,13 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
||||||
return AA_EXEC_LOCAL >> 10;
|
return AA_EXEC_LOCAL >> 10;
|
||||||
}
|
}
|
||||||
/* specified as cix so profile name is implicit */
|
/* specified as cix so profile name is implicit */
|
||||||
name = (char *) malloc(strlen(cod->name) + strlen(entry->nt_name)
|
name = (char *) malloc(strlen(prof->name) + strlen(entry->nt_name)
|
||||||
+ 3);
|
+ 3);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
PERROR("Memory allocation error\n");
|
PERROR("Memory allocation error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
sprintf(name, "%s//%s", cod->name, entry->nt_name);
|
sprintf(name, "%s//%s", prof->name, entry->nt_name);
|
||||||
free(entry->nt_name);
|
free(entry->nt_name);
|
||||||
entry->nt_name = name;
|
entry->nt_name = name;
|
||||||
}
|
}
|
||||||
|
@ -166,26 +137,26 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
||||||
name = entry->nt_name;
|
name = entry->nt_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return add_entry_to_x_table(cod, name);
|
return add_entry_to_x_table(prof, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry)
|
void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
|
||||||
{
|
{
|
||||||
entry->next = cod->entries;
|
entry->next = prof->entries;
|
||||||
cod->entries = entry;
|
prof->entries = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_process_file_entries(struct codomain *cod)
|
void post_process_file_entries(Profile *prof)
|
||||||
{
|
{
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
int cp_mode = 0;
|
int cp_mode = 0;
|
||||||
|
|
||||||
list_for_each(cod->entries, entry) {
|
list_for_each(prof->entries, entry) {
|
||||||
if (entry->nt_name) {
|
if (entry->nt_name) {
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
int n = add_named_transition(cod, entry);
|
int n = add_named_transition(prof, entry);
|
||||||
if (!n) {
|
if (!n) {
|
||||||
PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
|
PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (entry->mode & AA_USER_EXEC)
|
if (entry->mode & AA_USER_EXEC)
|
||||||
|
@ -217,20 +188,20 @@ void post_process_file_entries(struct codomain *cod)
|
||||||
PERROR("Memory allocation error\n");
|
PERROR("Memory allocation error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
add_entry_to_policy(cod, new_ent);
|
add_entry_to_policy(prof, new_ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_process_mnt_entries(struct codomain *cod)
|
void post_process_mnt_entries(Profile *prof)
|
||||||
{
|
{
|
||||||
struct mnt_entry *entry;
|
struct mnt_entry *entry;
|
||||||
|
|
||||||
list_for_each(cod->mnt_ents, entry) {
|
list_for_each(prof->mnt_ents, entry) {
|
||||||
if (entry->trans) {
|
if (entry->trans) {
|
||||||
unsigned int mode = 0;
|
unsigned int mode = 0;
|
||||||
int n = add_entry_to_x_table(cod, entry->trans);
|
int n = add_entry_to_x_table(prof, entry->trans);
|
||||||
if (!n) {
|
if (!n) {
|
||||||
PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
|
PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,335 +218,90 @@ void post_process_mnt_entries(struct codomain *cod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __merge_rules(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!codomain_merge_rules(*t)) {
|
|
||||||
PERROR(_("ERROR merging rules for profile %s, failed to load\n"),
|
|
||||||
(*t)->name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int post_merge_rules(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __merge_rules);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int merge_hat_rules(struct codomain *cod)
|
|
||||||
{
|
|
||||||
twalk(cod->hat_table, __merge_rules);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __process_regex(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (process_regex(*t) != 0) {
|
|
||||||
PERROR(_("ERROR processing regexs for profile %s, failed to load\n"),
|
|
||||||
(*t)->name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int post_process_regex(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __process_regex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_hat_regex(struct codomain *cod)
|
|
||||||
{
|
|
||||||
twalk(cod->hat_table, __process_regex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __process_policydb(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (process_policydb(*t) != 0) {
|
|
||||||
PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"),
|
|
||||||
(*t)->name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int post_process_policydb(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __process_policydb);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_hat_policydb(struct codomain *cod)
|
|
||||||
{
|
|
||||||
twalk(cod->hat_table, __process_policydb);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __process_variables(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (process_variables(*t) != 0) {
|
|
||||||
PERROR(_("ERROR expanding variables for profile %s, failed to load\n"),
|
|
||||||
(*t)->name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int post_process_variables(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __process_variables);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_hat_variables(struct codomain *cod)
|
|
||||||
{
|
|
||||||
twalk(cod->hat_table, __process_variables);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void __process_alias(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
replace_aliases((*t));
|
|
||||||
|
|
||||||
if ((*t)->hat_table)
|
|
||||||
twalk((*t)->hat_table, __process_alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
int post_process_alias(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __process_alias);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHANGEHAT_PATH "/proc/[0-9]*/attr/current"
|
#define CHANGEHAT_PATH "/proc/[0-9]*/attr/current"
|
||||||
|
|
||||||
/* add file rules to access /proc files to call change_hat()
|
/* add file rules to access /proc files to call change_hat()
|
||||||
*/
|
*/
|
||||||
static void __add_hat_rules_parent(const void *nodep, const VISIT value,
|
static int profile_add_hat_rules(Profile *prof)
|
||||||
const int __unused depth)
|
|
||||||
{
|
{
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
/* TODO: ??? fix logic for when to add to hat/base vs. local */
|
||||||
return;
|
/* don't add hat rules for local_profiles or base profiles */
|
||||||
|
if (prof->local || prof->hat_table.empty())
|
||||||
/* don't add hat rules if a parent profile with no hats */
|
return 0;
|
||||||
if (!(*t)->hat_table && !(*t)->parent)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* don't add hat rules for local_profiles */
|
|
||||||
if ((*t)->local)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
/* add entry to hat */
|
||||||
entry = new_entry(NULL, strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
|
entry = new_entry(NULL, strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
|
||||||
if (!entry) {
|
if (!entry)
|
||||||
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
return ENOMEM;
|
||||||
(*t)->name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
add_entry_to_policy(*t, entry);
|
|
||||||
|
|
||||||
twalk((*t)->hat_table, __add_hat_rules_parent);
|
add_entry_to_policy(prof, entry);
|
||||||
}
|
|
||||||
|
|
||||||
static int add_hat_rules(void)
|
|
||||||
{
|
|
||||||
twalk(policy_list, __add_hat_rules_parent);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yuck, is their no other way to pass arguments to a twalk action */
|
int load_policy_list(ProfileList &list, int option)
|
||||||
static int __load_option;
|
|
||||||
static int __load_error;
|
|
||||||
|
|
||||||
static void __load_policy(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
{
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
int res = 0;
|
||||||
|
|
||||||
if (value == preorder || value == endorder || __load_error)
|
for (ProfileList::iterator i = list.begin(); i != list.end(); i++) {
|
||||||
return;
|
res = load_profile(option, *i);
|
||||||
|
if (res != 0)
|
||||||
if (load_codomain(__load_option, *t) != 0) {
|
break;
|
||||||
__load_error = -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_flattened_hats(Profile *prof, int option)
|
||||||
|
{
|
||||||
|
return load_policy_list(prof->hat_table, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_policy(int option)
|
int load_policy(int option)
|
||||||
{
|
{
|
||||||
__load_option = option;
|
return load_policy_list(policy_list, option);
|
||||||
__load_error = 0;
|
|
||||||
twalk(policy_list, __load_policy);
|
|
||||||
return __load_error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yuck, is their no other way to pass arguments to a twalk action */
|
int load_hats(sd_serialize *p, Profile *prof)
|
||||||
static sd_serialize *__p;
|
|
||||||
|
|
||||||
static int __load_hat_error;
|
|
||||||
static void __load_hat(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
{
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
for (ProfileList::iterator i = prof->hat_table.begin(); i != prof->hat_table.end(); i++) {
|
||||||
|
if (!sd_serialize_profile(p, *i, 0)) {
|
||||||
if (value == preorder || value == endorder || __load_hat_error)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!sd_serialize_profile(__p, *t, 0)) {
|
|
||||||
PERROR(_("ERROR in profile %s, failed to load\n"),
|
PERROR(_("ERROR in profile %s, failed to load\n"),
|
||||||
(*t)->name);
|
(*i)->name);
|
||||||
__load_hat_error = -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __load_flattened_hat_error;
|
return 0;
|
||||||
static void __load_flattened_hat(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder || __load_flattened_hat_error)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (load_codomain(__load_option, *t) != 0) {
|
|
||||||
__load_flattened_hat_error = -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_flattened_hats(struct codomain *cod)
|
|
||||||
{
|
|
||||||
__load_flattened_hat_error = 0;
|
|
||||||
twalk(cod->hat_table, __load_flattened_hat);
|
|
||||||
return __load_flattened_hat_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int load_hats(sd_serialize *p, struct codomain *cod)
|
|
||||||
{
|
|
||||||
__p = p;
|
|
||||||
__load_hat_error = 0;
|
|
||||||
twalk(cod->hat_table, __load_hat);
|
|
||||||
return __load_hat_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __dump_policy(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
debug_cod_list(*t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump_policy(void)
|
void dump_policy(void)
|
||||||
{
|
{
|
||||||
twalk(policy_list, __dump_policy);
|
policy_list.dump();
|
||||||
}
|
|
||||||
|
|
||||||
void dump_policy_hats(struct codomain *cod)
|
|
||||||
{
|
|
||||||
twalk(cod->hat_table, __dump_policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Gar */
|
|
||||||
static struct codomain *__dump_policy_name;
|
|
||||||
|
|
||||||
static void __dump_policy_hatnames(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
printf("%s//%s\n", __dump_policy_name->name, (*t)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump_policy_hatnames(struct codomain *cod)
|
|
||||||
{
|
|
||||||
__dump_policy_name = cod;
|
|
||||||
twalk(cod->hat_table, __dump_policy_hatnames);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __dump_policy_names(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
|
||||||
|
|
||||||
if (value == preorder || value == endorder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
printf("%s\n", (*t)->name);
|
|
||||||
dump_policy_hatnames(*t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_policy_names(void)
|
void dump_policy_names(void)
|
||||||
{
|
{
|
||||||
twalk(policy_list, __dump_policy_names);
|
policy_list.dump_profile_names(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gar, more global arguments */
|
/* merge_hats: merges hat_table into hat_table owned by prof */
|
||||||
struct codomain *__hat_merge_policy;
|
static void merge_hats(Profile *prof, ProfileList &hats)
|
||||||
|
|
||||||
static void __merge_hat(const void *nodep, const VISIT value,
|
|
||||||
const int __unused depth)
|
|
||||||
{
|
{
|
||||||
struct codomain **t = (struct codomain **) nodep;
|
for (ProfileList::iterator i = hats.begin(); i != hats.end(); ) {
|
||||||
|
ProfileList::iterator cur = i++;
|
||||||
if (value == preorder || value == endorder)
|
add_hat_to_policy(prof, *cur);
|
||||||
return;
|
hats.erase(cur);
|
||||||
add_hat_to_policy(__hat_merge_policy, (*t));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* merge_hats: merges hat_table into hat_table owned by cod */
|
|
||||||
static void merge_hats(struct codomain *cod, void *hats)
|
|
||||||
{
|
|
||||||
__hat_merge_policy = cod;
|
|
||||||
twalk(hats, __merge_hat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't want to free the hat entries in the table, as they were pushed
|
Profile *merge_policy(Profile *a, Profile *b)
|
||||||
* onto the other table. */
|
|
||||||
static void empty_destroy(void __unused *nodep)
|
|
||||||
{
|
{
|
||||||
return;
|
Profile *ret = a;
|
||||||
}
|
|
||||||
|
|
||||||
struct codomain *merge_policy(struct codomain *a, struct codomain *b)
|
|
||||||
{
|
|
||||||
struct codomain *ret = a;
|
|
||||||
struct cod_entry *last;
|
struct cod_entry *last;
|
||||||
|
|
||||||
if (!a) {
|
if (!a) {
|
||||||
|
@ -603,131 +329,109 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b)
|
||||||
a->flags.complain = a->flags.complain || b->flags.complain;
|
a->flags.complain = a->flags.complain || b->flags.complain;
|
||||||
a->flags.audit = a->flags.audit || b->flags.audit;
|
a->flags.audit = a->flags.audit || b->flags.audit;
|
||||||
|
|
||||||
a->capabilities |= b->capabilities;
|
a->caps.allow |= b->caps.allow;
|
||||||
a->audit_caps |= b->audit_caps;
|
a->caps.audit |= b->caps.audit;
|
||||||
a->deny_caps |= b->deny_caps;
|
a->caps.deny |= b->caps.deny;
|
||||||
a->quiet_caps |= b->quiet_caps;
|
a->caps.quiet |= b->caps.quiet;
|
||||||
|
|
||||||
if (a->network_allowed) {
|
if (a->net.allow) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < get_af_max(); i++) {
|
for (i = 0; i < get_af_max(); i++) {
|
||||||
a->network_allowed[i] |= b->network_allowed[i];
|
a->net.allow[i] |= b->net.allow[i];
|
||||||
a->audit_network[i] |= b->audit_network[i];
|
a->net.audit[i] |= b->net.audit[i];
|
||||||
a->deny_network[i] |= b->deny_network[i];
|
a->net.deny[i] |= b->net.deny[i];
|
||||||
a->quiet_network[i] |= b->quiet_network[i];
|
a->net.quiet[i] |= b->net.quiet[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
merge_hats(a, b->hat_table);
|
merge_hats(a, b->hat_table);
|
||||||
tdestroy(b->hat_table, &empty_destroy);
|
delete b;
|
||||||
b->hat_table = NULL;
|
|
||||||
|
|
||||||
free_policy(b);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int process_profile_rules(Profile *profile)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = process_profile_regex(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR processing regexs for profile %s, failed to load\n"), profile->name);
|
||||||
|
exit(1);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = process_profile_policydb(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"),
|
||||||
|
(profile)->name);
|
||||||
|
exit(1);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int post_process_policy_list(ProfileList &list, int debug_only);
|
||||||
|
int post_process_profile(Profile *profile, int debug_only)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
error = profile_add_hat_rules(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
||||||
|
profile->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = process_profile_variables(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR expanding variables for profile %s, failed to load\n"), profile->name);
|
||||||
|
exit(1);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = replace_profile_aliases(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR replacing aliases for profile %s, failed to load\n"), profile->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = profile_merge_rules(profile);
|
||||||
|
if (error) {
|
||||||
|
PERROR(_("ERROR merging rules for profile %s, failed to load\n"), profile->name);
|
||||||
|
exit(1);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!debug_only) {
|
||||||
|
error = process_profile_rules(profile);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = post_process_policy_list(profile->hat_table, debug_only);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int post_process_policy_list(ProfileList &list, int debug_only)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
for (ProfileList::iterator i = list.begin(); i != list.end(); i++) {
|
||||||
|
error = post_process_profile(*i, debug_only);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
int post_process_policy(int debug_only)
|
int post_process_policy(int debug_only)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
return post_process_policy_list(policy_list, debug_only);
|
||||||
|
|
||||||
retval = add_hat_rules();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found during postprocessing. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = post_process_variables();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = post_process_alias();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found during postprocess. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = post_merge_rules();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found in combining rules postprocessing. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!debug_only) {
|
|
||||||
retval = post_process_regex();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!debug_only) {
|
|
||||||
retval = post_process_policydb();
|
|
||||||
if (retval != 0) {
|
|
||||||
PERROR(_("%s: Errors found during policydb postprocess. Aborting.\n"),
|
|
||||||
progname);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_hat_entry(void *nodep)
|
|
||||||
{
|
|
||||||
struct codomain *t = (struct codomain *)nodep;
|
|
||||||
free_policy(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_hat_table(void *hat_table)
|
|
||||||
{
|
|
||||||
if (hat_table)
|
|
||||||
tdestroy(hat_table, &free_hat_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_policy(struct codomain *cod)
|
|
||||||
{
|
|
||||||
if (!cod)
|
|
||||||
return;
|
|
||||||
free_hat_table(cod->hat_table);
|
|
||||||
free_cod_entries(cod->entries);
|
|
||||||
free_mnt_entries(cod->mnt_ents);
|
|
||||||
free_dbus_entries(cod->dbus_ents);
|
|
||||||
if (cod->dfarules)
|
|
||||||
aare_delete_ruleset(cod->dfarules);
|
|
||||||
if (cod->dfa)
|
|
||||||
free(cod->dfa);
|
|
||||||
if (cod->policy_rules)
|
|
||||||
aare_delete_ruleset(cod->policy_rules);
|
|
||||||
if (cod->policy_dfa)
|
|
||||||
free(cod->policy_dfa);
|
|
||||||
if (cod->name)
|
|
||||||
free(cod->name);
|
|
||||||
if (cod->attachment)
|
|
||||||
free(cod->attachment);
|
|
||||||
if (cod->ns)
|
|
||||||
free(cod->ns);
|
|
||||||
if (cod->network_allowed)
|
|
||||||
free(cod->network_allowed);
|
|
||||||
if (cod->audit_network)
|
|
||||||
free(cod->audit_network);
|
|
||||||
if (cod->deny_network)
|
|
||||||
free(cod->deny_network);
|
|
||||||
if (cod->quiet_network)
|
|
||||||
free(cod->quiet_network);
|
|
||||||
free(cod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_policies(void)
|
void free_policies(void)
|
||||||
{
|
{
|
||||||
if (policy_list)
|
policy_list.clear();
|
||||||
tdestroy(policy_list, (__free_fn_t)&free_policy);
|
|
||||||
policy_list = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "libapparmor_re/apparmor_re.h"
|
#include "libapparmor_re/apparmor_re.h"
|
||||||
#include "libapparmor_re/aare_rules.h"
|
#include "libapparmor_re/aare_rules.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
|
@ -384,30 +385,30 @@ static const char *local_name(const char *name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_profile_name_xmatch(struct codomain *cod)
|
static int process_profile_name_xmatch(Profile *prof)
|
||||||
{
|
{
|
||||||
char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
|
char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
|
||||||
pattern_t ptype;
|
pattern_t ptype;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
/* don't filter_slashes for profile names */
|
/* don't filter_slashes for profile names */
|
||||||
if (cod->attachment)
|
if (prof->attachment)
|
||||||
name = cod->attachment;
|
name = prof->attachment;
|
||||||
else
|
else
|
||||||
name = local_name(cod->name);
|
name = local_name(prof->name);
|
||||||
ptype = convert_aaregex_to_pcre(name, 0, tbuf, PATH_MAX + 3,
|
ptype = convert_aaregex_to_pcre(name, 0, tbuf, PATH_MAX + 3,
|
||||||
&cod->xmatch_len);
|
&prof->xmatch_len);
|
||||||
if (ptype == ePatternBasic)
|
if (ptype == ePatternBasic)
|
||||||
cod->xmatch_len = strlen(name);
|
prof->xmatch_len = strlen(name);
|
||||||
|
|
||||||
if (ptype == ePatternInvalid) {
|
if (ptype == ePatternInvalid) {
|
||||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else if (ptype == ePatternBasic && !(cod->altnames || cod->attachment)) {
|
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment)) {
|
||||||
/* no regex so do not set xmatch */
|
/* no regex so do not set xmatch */
|
||||||
cod->xmatch = NULL;
|
prof->xmatch = NULL;
|
||||||
cod->xmatch_len = 0;
|
prof->xmatch_len = 0;
|
||||||
cod->xmatch_size = 0;
|
prof->xmatch_size = 0;
|
||||||
} else {
|
} else {
|
||||||
/* build a dfa */
|
/* build a dfa */
|
||||||
aare_ruleset_t *rule = aare_new_ruleset(0);
|
aare_ruleset_t *rule = aare_new_ruleset(0);
|
||||||
|
@ -417,9 +418,9 @@ static int process_profile_name_xmatch(struct codomain *cod)
|
||||||
aare_delete_ruleset(rule);
|
aare_delete_ruleset(rule);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (cod->altnames) {
|
if (prof->altnames) {
|
||||||
struct alt_name *alt;
|
struct alt_name *alt;
|
||||||
list_for_each(cod->altnames, alt) {
|
list_for_each(prof->altnames, alt) {
|
||||||
int len;
|
int len;
|
||||||
ptype = convert_aaregex_to_pcre(alt->name, 0,
|
ptype = convert_aaregex_to_pcre(alt->name, 0,
|
||||||
tbuf,
|
tbuf,
|
||||||
|
@ -427,18 +428,18 @@ static int process_profile_name_xmatch(struct codomain *cod)
|
||||||
&len);
|
&len);
|
||||||
if (ptype == ePatternBasic)
|
if (ptype == ePatternBasic)
|
||||||
len = strlen(alt->name);
|
len = strlen(alt->name);
|
||||||
if (len < cod->xmatch_len)
|
if (len < prof->xmatch_len)
|
||||||
cod->xmatch_len = len;
|
prof->xmatch_len = len;
|
||||||
if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
|
if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
|
||||||
aare_delete_ruleset(rule);
|
aare_delete_ruleset(rule);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size,
|
prof->xmatch = aare_create_dfa(rule, &prof->xmatch_size,
|
||||||
dfaflags);
|
dfaflags);
|
||||||
aare_delete_ruleset(rule);
|
aare_delete_ruleset(rule);
|
||||||
if (!cod->xmatch)
|
if (!prof->xmatch)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,70 +551,54 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int post_process_entries(struct codomain *cod)
|
int post_process_entries(Profile *prof)
|
||||||
{
|
{
|
||||||
int ret = TRUE;
|
int ret = TRUE;
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
list_for_each(cod->entries, entry) {
|
list_for_each(prof->entries, entry) {
|
||||||
if (!process_dfa_entry(cod->dfarules, entry))
|
if (!process_dfa_entry(prof->dfa.rules, entry))
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cod->dfarule_count = count;
|
prof->dfa.count = count;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_regex(struct codomain *cod)
|
int process_profile_regex(Profile *prof)
|
||||||
{
|
{
|
||||||
int error = -1;
|
int error = -1;
|
||||||
|
|
||||||
if (!process_profile_name_xmatch(cod))
|
if (!process_profile_name_xmatch(prof))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cod->dfarules = aare_new_ruleset(0);
|
prof->dfa.rules = aare_new_ruleset(0);
|
||||||
if (!cod->dfarules)
|
if (!prof->dfa.rules)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!post_process_entries(cod))
|
if (!post_process_entries(prof))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (cod->dfarule_count > 0) {
|
if (prof->dfa.count > 0) {
|
||||||
cod->dfa = aare_create_dfa(cod->dfarules, &cod->dfa_size,
|
prof->dfa.dfa = aare_create_dfa(prof->dfa.rules, &prof->dfa.size,
|
||||||
dfaflags);
|
dfaflags);
|
||||||
aare_delete_ruleset(cod->dfarules);
|
aare_delete_ruleset(prof->dfa.rules);
|
||||||
cod->dfarules = NULL;
|
prof->dfa.rules = NULL;
|
||||||
if (!cod->dfa)
|
if (!prof->dfa.dfa)
|
||||||
goto out;
|
goto out;
|
||||||
/*
|
/*
|
||||||
if (cod->dfa_size == 0) {
|
if (prof->dfa_size == 0) {
|
||||||
PERROR(_("profile %s: has merged rules (%s) with "
|
PERROR(_("profile %s: has merged rules (%s) with "
|
||||||
"multiple x modifiers\n"),
|
"multiple x modifiers\n"),
|
||||||
cod->name, (char *) cod->dfa);
|
prof->name, (char *) prof->dfa);
|
||||||
free(cod->dfa);
|
free(prof->dfa);
|
||||||
cod->dfa = NULL;
|
prof->dfa = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Post process subdomain(s):
|
|
||||||
*
|
|
||||||
* They are chained from the toplevel subdomain pointer
|
|
||||||
* thru each <codomain> next pointer.
|
|
||||||
|
|
||||||
* i.e first subdomain is list->subdomain
|
|
||||||
* second subdomain is list->subdomain->next
|
|
||||||
*
|
|
||||||
* N.B sub-subdomains are not valid so:
|
|
||||||
* if (list->subdomain) {
|
|
||||||
* assert(list->subdomain->subdomain == NULL)
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
if (process_hat_regex(cod) != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
|
@ -1140,76 +1125,75 @@ fail:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int post_process_mnt_ents(struct codomain *cod)
|
static int post_process_mnt_ents(Profile *prof)
|
||||||
{
|
{
|
||||||
int ret = TRUE;
|
int ret = TRUE;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
/* Add fns for rules that should be added to policydb here */
|
/* Add fns for rules that should be added to policydb here */
|
||||||
if (cod->mnt_ents && kernel_supports_mount) {
|
if (prof->mnt_ents && kernel_supports_mount) {
|
||||||
struct mnt_entry *entry;
|
struct mnt_entry *entry;
|
||||||
list_for_each(cod->mnt_ents, entry) {
|
list_for_each(prof->mnt_ents, entry) {
|
||||||
if (!process_mnt_entry(cod->policy_rules, entry))
|
if (!process_mnt_entry(prof->policy.rules, entry))
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
} else if (cod->mnt_ents && !kernel_supports_mount)
|
} else if (prof->mnt_ents && !kernel_supports_mount)
|
||||||
pwarn("profile %s mount rules not enforced\n", cod->name);
|
pwarn("profile %s mount rules not enforced\n", prof->name);
|
||||||
|
|
||||||
|
prof->policy.count += count;
|
||||||
|
|
||||||
cod->policy_rule_count += count;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int post_process_dbus_ents(struct codomain *cod)
|
static int post_process_dbus_ents(Profile *prof)
|
||||||
{
|
{
|
||||||
int ret = TRUE;
|
int ret = TRUE;
|
||||||
struct dbus_entry *entry;
|
struct dbus_entry *entry;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
list_for_each(cod->dbus_ents, entry) {
|
list_for_each(prof->dbus_ents, entry) {
|
||||||
if (!process_dbus_entry(cod->policy_rules, entry))
|
if (!process_dbus_entry(prof->policy.rules, entry))
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cod->policy_rule_count += count;
|
prof->policy.count += count;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int post_process_policydb_ents(struct codomain *cod)
|
int post_process_policydb_ents(Profile *prof)
|
||||||
{
|
{
|
||||||
if (!post_process_mnt_ents(cod))
|
if (!post_process_mnt_ents(prof))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!post_process_dbus_ents(cod))
|
if (!post_process_dbus_ents(prof))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_policydb(struct codomain *cod)
|
int process_profile_policydb(Profile *prof)
|
||||||
{
|
{
|
||||||
int error = -1;
|
int error = -1;
|
||||||
|
|
||||||
cod->policy_rules = aare_new_ruleset(0);
|
prof->policy.rules = aare_new_ruleset(0);
|
||||||
if (!cod->policy_rules)
|
if (!prof->policy.rules)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!post_process_policydb_ents(cod))
|
if (!post_process_policydb_ents(prof))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (cod->policy_rule_count > 0) {
|
if (prof->policy.count > 0) {
|
||||||
cod->policy_dfa = aare_create_dfa(cod->policy_rules,
|
prof->policy.dfa = aare_create_dfa(prof->policy.rules,
|
||||||
&cod->policy_dfa_size,
|
&prof->policy.size,
|
||||||
dfaflags);
|
dfaflags);
|
||||||
aare_delete_ruleset(cod->policy_rules);
|
aare_delete_ruleset(prof->policy.rules);
|
||||||
cod->policy_rules = NULL;
|
prof->policy.rules = NULL;
|
||||||
if (!cod->policy_dfa)
|
if (!prof->policy.dfa)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
aare_reset_matchflags();
|
aare_reset_matchflags();
|
||||||
if (process_hat_policydb(cod) != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
|
@ -1223,6 +1207,9 @@ void reset_regex(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
|
|
||||||
|
#include "unit_test.h"
|
||||||
|
|
||||||
static int test_filter_slashes(void)
|
static int test_filter_slashes(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
|
@ -542,6 +542,9 @@ void free_symtabs(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
|
|
||||||
|
#include "unit_test.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
@ -137,12 +138,11 @@ static int expand_entry_variables(char **name, void *entry,
|
||||||
int (dup_and_chain)(void *))
|
int (dup_and_chain)(void *))
|
||||||
{
|
{
|
||||||
struct set_value *valuelist;
|
struct set_value *valuelist;
|
||||||
int ret = TRUE;
|
|
||||||
char *value;
|
char *value;
|
||||||
struct var_string *split_var;
|
struct var_string *split_var;
|
||||||
|
|
||||||
if (!entry) /* can happen when entry is optional */
|
if (!entry) /* can happen when entry is optional */
|
||||||
return ret;
|
return 0;
|
||||||
|
|
||||||
while ((split_var = split_out_var(*name))) {
|
while ((split_var = split_out_var(*name))) {
|
||||||
valuelist = get_set_var(split_var->var);
|
valuelist = get_set_var(split_var->var);
|
||||||
|
@ -168,7 +168,7 @@ static int expand_entry_variables(char **name, void *entry,
|
||||||
split_var->prefix ? split_var->prefix : "",
|
split_var->prefix ? split_var->prefix : "",
|
||||||
value,
|
value,
|
||||||
split_var->suffix ? split_var->suffix : "") == -1)
|
split_var->suffix ? split_var->suffix : "") == -1)
|
||||||
return FALSE;
|
return -1;
|
||||||
|
|
||||||
while ((value = get_next_set_value(&valuelist))) {
|
while ((value = get_next_set_value(&valuelist))) {
|
||||||
if (!dup_and_chain(entry)) {
|
if (!dup_and_chain(entry)) {
|
||||||
|
@ -181,12 +181,12 @@ static int expand_entry_variables(char **name, void *entry,
|
||||||
if (asprintf(name, "%s%s%s",
|
if (asprintf(name, "%s%s%s",
|
||||||
split_var->prefix ? split_var->prefix : "", value,
|
split_var->prefix ? split_var->prefix : "", value,
|
||||||
split_var->suffix ? split_var->suffix : "") == -1)
|
split_var->suffix ? split_var->suffix : "") == -1)
|
||||||
return FALSE;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_var_string(split_var);
|
free_var_string(split_var);
|
||||||
}
|
}
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clone_and_chain_cod(void *v)
|
int clone_and_chain_cod(void *v)
|
||||||
|
@ -229,103 +229,99 @@ int clone_and_chain_dbus(void *v)
|
||||||
|
|
||||||
static int process_variables_in_entries(struct cod_entry *entry_list)
|
static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||||
{
|
{
|
||||||
int ret = TRUE, rc;
|
int error = 0;
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
|
|
||||||
list_for_each(entry_list, entry) {
|
list_for_each(entry_list, entry) {
|
||||||
rc = expand_entry_variables(&entry->name, entry,
|
error = expand_entry_variables(&entry->name, entry,
|
||||||
clone_and_chain_cod);
|
clone_and_chain_cod);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* does not currently support expansion of vars in options */
|
/* does not currently support expansion of vars in options */
|
||||||
static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
|
static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
|
||||||
{
|
{
|
||||||
int ret = TRUE, rc;
|
int error = 0;
|
||||||
struct mnt_entry *entry;
|
struct mnt_entry *entry;
|
||||||
|
|
||||||
list_for_each(entry_list, entry) {
|
list_for_each(entry_list, entry) {
|
||||||
rc = expand_entry_variables(&entry->mnt_point, entry,
|
error = expand_entry_variables(&entry->mnt_point, entry,
|
||||||
clone_and_chain_mnt);
|
clone_and_chain_mnt);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->device, entry,
|
error = expand_entry_variables(&entry->device, entry,
|
||||||
clone_and_chain_mnt);
|
clone_and_chain_mnt);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->trans, entry,
|
error = expand_entry_variables(&entry->trans, entry,
|
||||||
clone_and_chain_mnt);
|
clone_and_chain_mnt);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_dbus_variables(struct dbus_entry *entry_list)
|
static int process_dbus_variables(struct dbus_entry *entry_list)
|
||||||
{
|
{
|
||||||
int ret = TRUE, rc;
|
int error = 0;
|
||||||
struct dbus_entry *entry;
|
struct dbus_entry *entry;
|
||||||
|
|
||||||
list_for_each(entry_list, entry) {
|
list_for_each(entry_list, entry) {
|
||||||
rc = expand_entry_variables(&entry->bus, entry,
|
error = expand_entry_variables(&entry->bus, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->name, entry,
|
error = expand_entry_variables(&entry->name, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->peer_label, entry,
|
error = expand_entry_variables(&entry->peer_label, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->path, entry,
|
error = expand_entry_variables(&entry->path, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->interface, entry,
|
error = expand_entry_variables(&entry->interface, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
rc = expand_entry_variables(&entry->member, entry,
|
error = expand_entry_variables(&entry->member, entry,
|
||||||
clone_and_chain_dbus);
|
clone_and_chain_dbus);
|
||||||
if (!rc)
|
if (error)
|
||||||
return FALSE;
|
return error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_variables(struct codomain *cod)
|
int process_profile_variables(Profile *prof)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (!process_variables_in_entries(cod->entries)) {
|
error = process_variables_in_entries(prof->entries);
|
||||||
error = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process_variables_in_mnt_entries(cod->mnt_ents)) {
|
if (!error)
|
||||||
error = -1;
|
error = process_variables_in_mnt_entries(prof->mnt_ents);
|
||||||
}
|
|
||||||
|
|
||||||
if (!process_dbus_variables(cod->dbus_ents)) {
|
if (!error)
|
||||||
error = -1;
|
error = process_dbus_variables(prof->dbus_ents);
|
||||||
}
|
|
||||||
|
|
||||||
if (process_hat_variables(cod) != 0) {
|
|
||||||
error = -1;
|
|
||||||
}
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
|
|
||||||
|
#include "unit_test.h"
|
||||||
|
|
||||||
int test_get_var_end(void)
|
int test_get_var_end(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
#include "parser_include.h"
|
#include "parser_include.h"
|
||||||
|
@ -76,7 +77,7 @@ struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||||
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||||
char *transition);
|
char *transition);
|
||||||
|
|
||||||
void add_local_entry(struct codomain *cod);
|
void add_local_entry(Profile *prof);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -164,13 +165,13 @@ void add_local_entry(struct codomain *cod);
|
||||||
char *flag_id;
|
char *flag_id;
|
||||||
char *mode;
|
char *mode;
|
||||||
struct aa_network_entry *network_entry;
|
struct aa_network_entry *network_entry;
|
||||||
struct codomain *cod;
|
Profile *prof;
|
||||||
struct cod_net_entry *net_entry;
|
struct cod_net_entry *net_entry;
|
||||||
struct cod_entry *user_entry;
|
struct cod_entry *user_entry;
|
||||||
struct mnt_entry *mnt_entry;
|
struct mnt_entry *mnt_entry;
|
||||||
struct dbus_entry *dbus_entry;
|
struct dbus_entry *dbus_entry;
|
||||||
|
|
||||||
struct flagval flags;
|
flagvals flags;
|
||||||
int fmode;
|
int fmode;
|
||||||
uint64_t cap;
|
uint64_t cap;
|
||||||
unsigned int allowed_protocol;
|
unsigned int allowed_protocol;
|
||||||
|
@ -189,12 +190,12 @@ void add_local_entry(struct codomain *cod);
|
||||||
%type <id> TOK_CONDLISTID
|
%type <id> TOK_CONDLISTID
|
||||||
%type <mode> TOK_MODE
|
%type <mode> TOK_MODE
|
||||||
%type <fmode> file_mode
|
%type <fmode> file_mode
|
||||||
%type <cod> profile_base
|
%type <prof> profile_base
|
||||||
%type <cod> profile
|
%type <prof> profile
|
||||||
%type <cod> rules
|
%type <prof> rules
|
||||||
%type <cod> hat
|
%type <prof> hat
|
||||||
%type <cod> local_profile
|
%type <prof> local_profile
|
||||||
%type <cod> cond_rule
|
%type <prof> cond_rule
|
||||||
%type <network_entry> network_rule
|
%type <network_entry> network_rule
|
||||||
%type <user_entry> rule
|
%type <user_entry> rule
|
||||||
%type <user_entry> file_rule
|
%type <user_entry> file_rule
|
||||||
|
@ -261,37 +262,37 @@ opt_id: { /* nothing */ $$ = NULL; }
|
||||||
|
|
||||||
profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
||||||
{
|
{
|
||||||
struct codomain *cod = $5;
|
Profile *prof = $5;
|
||||||
|
|
||||||
if (!cod) {
|
if (!prof) {
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
}
|
}
|
||||||
|
|
||||||
cod->name = $1;
|
prof->name = $1;
|
||||||
cod->attachment = $2;
|
prof->attachment = $2;
|
||||||
if ($2 && $2[0] != '/')
|
if ($2 && $2[0] != '/')
|
||||||
/* we don't support variables as part of the profile
|
/* we don't support variables as part of the profile
|
||||||
* name or attachment atm
|
* name or attachment atm
|
||||||
*/
|
*/
|
||||||
yyerror(_("Profile attachment must begin with a '/'."));
|
yyerror(_("Profile attachment must begin with a '/'."));
|
||||||
cod->flags = $3;
|
prof->flags = $3;
|
||||||
if (force_complain)
|
if (force_complain)
|
||||||
cod->flags.complain = 1;
|
prof->flags.complain = 1;
|
||||||
|
|
||||||
post_process_file_entries(cod);
|
post_process_file_entries(prof);
|
||||||
post_process_mnt_entries(cod);
|
post_process_mnt_entries(prof);
|
||||||
PDEBUG("%s: flags='%s%s'\n",
|
PDEBUG("%s: flags='%s%s'\n",
|
||||||
$2,
|
$2,
|
||||||
cod->flags.complain ? "complain, " : "",
|
prof->flags.complain ? "complain, " : "",
|
||||||
cod->flags.audit ? "audit" : "");
|
prof->flags.audit ? "audit" : "");
|
||||||
|
|
||||||
$$ = cod;
|
$$ = prof;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
profile: opt_profile_flag opt_ns profile_base
|
profile: opt_profile_flag opt_ns profile_base
|
||||||
{
|
{
|
||||||
struct codomain *cod = $3;
|
Profile *prof = $3;
|
||||||
if ($2)
|
if ($2)
|
||||||
PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name);
|
PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name);
|
||||||
else
|
else
|
||||||
|
@ -300,31 +301,31 @@ profile: opt_profile_flag opt_ns profile_base
|
||||||
if ($3->name[0] != '/' && !($1 || $2))
|
if ($3->name[0] != '/' && !($1 || $2))
|
||||||
yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
|
yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
|
||||||
|
|
||||||
cod->ns = $2;
|
prof->ns = $2;
|
||||||
if ($1 == 2)
|
if ($1 == 2)
|
||||||
cod->flags.hat = 1;
|
prof->flags.hat = 1;
|
||||||
$$ = cod;
|
$$ = prof;
|
||||||
};
|
};
|
||||||
|
|
||||||
local_profile: TOK_PROFILE profile_base
|
local_profile: TOK_PROFILE profile_base
|
||||||
{
|
{
|
||||||
|
|
||||||
struct codomain *cod = $2;
|
Profile *prof = $2;
|
||||||
|
|
||||||
if ($2)
|
if ($2)
|
||||||
PDEBUG("Matched: local profile %s { ... }\n", cod->name);
|
PDEBUG("Matched: local profile %s { ... }\n", prof->name);
|
||||||
cod->local = 1;
|
prof->local = 1;
|
||||||
$$ = cod;
|
$$ = prof;
|
||||||
};
|
};
|
||||||
|
|
||||||
hat: hat_start profile_base
|
hat: hat_start profile_base
|
||||||
{
|
{
|
||||||
struct codomain *cod = $2;
|
Profile *prof = $2;
|
||||||
if ($2)
|
if ($2)
|
||||||
PDEBUG("Matched: hat %s { ... }\n", cod->name);
|
PDEBUG("Matched: hat %s { ... }\n", prof->name);
|
||||||
|
|
||||||
cod->flags.hat = 1;
|
prof->flags.hat = 1;
|
||||||
$$ = cod;
|
$$ = prof;
|
||||||
};
|
};
|
||||||
|
|
||||||
preamble: { /* nothing */ }
|
preamble: { /* nothing */ }
|
||||||
|
@ -430,7 +431,7 @@ valuelist: valuelist TOK_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
flags: { /* nothing */
|
flags: { /* nothing */
|
||||||
struct flagval fv = { 0, 0, 0, 0 };
|
flagvals fv = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
$$ = fv;
|
$$ = fv;
|
||||||
};
|
};
|
||||||
|
@ -478,7 +479,7 @@ flagvals: flagval
|
||||||
|
|
||||||
flagval: TOK_VALUE
|
flagval: TOK_VALUE
|
||||||
{
|
{
|
||||||
struct flagval fv = { 0, 0, 0, 0 };
|
flagvals fv = { 0, 0, 0, 0 };
|
||||||
if (strcmp($1, "debug") == 0) {
|
if (strcmp($1, "debug") == 0) {
|
||||||
yyerror(_("Profile flag 'debug' is no longer valid."));
|
yyerror(_("Profile flag 'debug' is no longer valid."));
|
||||||
} else if (strcmp($1, "complain") == 0) {
|
} else if (strcmp($1, "complain") == 0) {
|
||||||
|
@ -531,13 +532,12 @@ opt_prefix: opt_audit_flag opt_perm_mode opt_owner_flag
|
||||||
}
|
}
|
||||||
|
|
||||||
rules: { /* nothing */
|
rules: { /* nothing */
|
||||||
struct codomain *cod = NULL;
|
Profile *prof = new Profile();
|
||||||
cod = (struct codomain *) calloc(1, sizeof(struct codomain));
|
if (!prof) {
|
||||||
if (!cod) {
|
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
}
|
}
|
||||||
|
|
||||||
$$ = cod;
|
$$ = prof;
|
||||||
};
|
};
|
||||||
|
|
||||||
rules: rules opt_prefix rule
|
rules: rules opt_prefix rule
|
||||||
|
@ -598,8 +598,8 @@ rules: rules opt_prefix TOK_OPEN rules TOK_CLOSE
|
||||||
add_entry_to_policy($1, entry);
|
add_entry_to_policy($1, entry);
|
||||||
}
|
}
|
||||||
$4->entries = NULL;
|
$4->entries = NULL;
|
||||||
// fix me transfer rules and free sub codomain
|
// fix me transfer rules and free sub profile
|
||||||
free_policy($4);
|
delete $4;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -612,40 +612,40 @@ rules: rules opt_prefix network_rule
|
||||||
yyerror(_("owner prefix not allowed"));
|
yyerror(_("owner prefix not allowed"));
|
||||||
if (!$3)
|
if (!$3)
|
||||||
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
||||||
if (!$1->network_allowed) {
|
if (!$1->net.allow) {
|
||||||
$1->network_allowed = (unsigned int *) calloc(get_af_max(),
|
$1->net.allow = (unsigned int *) calloc(get_af_max(),
|
||||||
sizeof(unsigned int));
|
sizeof(unsigned int));
|
||||||
$1->audit_network = (unsigned int *)calloc(get_af_max(),
|
$1->net.audit = (unsigned int *)calloc(get_af_max(),
|
||||||
sizeof(unsigned int));
|
sizeof(unsigned int));
|
||||||
$1->deny_network = (unsigned int *)calloc(get_af_max(),
|
$1->net.deny = (unsigned int *)calloc(get_af_max(),
|
||||||
sizeof(unsigned int));
|
sizeof(unsigned int));
|
||||||
$1->quiet_network = (unsigned int *)calloc(get_af_max(),
|
$1->net.quiet = (unsigned int *)calloc(get_af_max(),
|
||||||
sizeof(unsigned int));
|
sizeof(unsigned int));
|
||||||
if (!$1->network_allowed || !$1->audit_network ||
|
if (!$1->net.allow || !$1->net.audit ||
|
||||||
!$1->deny_network || !$1->quiet_network)
|
!$1->net.deny || !$1->net.quiet)
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
}
|
}
|
||||||
list_for_each_safe($3, entry, tmp) {
|
list_for_each_safe($3, entry, tmp) {
|
||||||
if (entry->type > SOCK_PACKET) {
|
if (entry->type > SOCK_PACKET) {
|
||||||
/* setting mask instead of a bit */
|
/* setting mask instead of a bit */
|
||||||
if ($2.deny) {
|
if ($2.deny) {
|
||||||
$1->deny_network[entry->family] |= entry->type;
|
$1->net.deny[entry->family] |= entry->type;
|
||||||
if (!$2.audit)
|
if (!$2.audit)
|
||||||
$1->quiet_network[entry->family] |= entry->type;
|
$1->net.quiet[entry->family] |= entry->type;
|
||||||
} else {
|
} else {
|
||||||
$1->network_allowed[entry->family] |= entry->type;
|
$1->net.allow[entry->family] |= entry->type;
|
||||||
if ($2.audit)
|
if ($2.audit)
|
||||||
$1->audit_network[entry->family] |= entry->type;
|
$1->net.audit[entry->family] |= entry->type;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($2.deny) {
|
if ($2.deny) {
|
||||||
$1->deny_network[entry->family] |= 1 << entry->type;
|
$1->net.deny[entry->family] |= 1 << entry->type;
|
||||||
if (!$2.audit)
|
if (!$2.audit)
|
||||||
$1->quiet_network[entry->family] |= 1 << entry->type;
|
$1->net.quiet[entry->family] |= 1 << entry->type;
|
||||||
} else {
|
} else {
|
||||||
$1->network_allowed[entry->family] |= 1 << entry->type;
|
$1->net.allow[entry->family] |= 1 << entry->type;
|
||||||
if ($2.audit)
|
if ($2.audit)
|
||||||
$1->audit_network[entry->family] |= 1 << entry->type;
|
$1->net.audit[entry->family] |= 1 << entry->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(entry);
|
free(entry);
|
||||||
|
@ -696,12 +696,12 @@ rules: rules opt_prefix capability
|
||||||
yyerror(_("owner prefix not allow on capability rules"));
|
yyerror(_("owner prefix not allow on capability rules"));
|
||||||
|
|
||||||
if ($2.deny)
|
if ($2.deny)
|
||||||
$1->deny_caps |= $3;
|
$1->caps.deny |= $3;
|
||||||
else
|
else
|
||||||
$1->capabilities |= $3;
|
$1->caps.allow |= $3;
|
||||||
|
|
||||||
if (!$2.audit)
|
if (!$2.audit)
|
||||||
$1->quiet_caps |= $3;
|
$1->caps.quiet |= $3;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -824,40 +824,40 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
||||||
|
|
||||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
|
||||||
{
|
{
|
||||||
struct codomain *ret = NULL;
|
Profile *ret = NULL;
|
||||||
PDEBUG("Matched: found conditional rules\n");
|
PDEBUG("Matched: found conditional rules\n");
|
||||||
if ($2) {
|
if ($2) {
|
||||||
ret = $4;
|
ret = $4;
|
||||||
} else {
|
} else {
|
||||||
free_policy($4);
|
delete $4;
|
||||||
}
|
}
|
||||||
$$ = ret;
|
$$ = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
|
||||||
{
|
{
|
||||||
struct codomain *ret = NULL;
|
Profile *ret = NULL;
|
||||||
PDEBUG("Matched: found conditional else rules\n");
|
PDEBUG("Matched: found conditional else rules\n");
|
||||||
if ($2) {
|
if ($2) {
|
||||||
ret = $4;
|
ret = $4;
|
||||||
free_policy($8);
|
delete $8;
|
||||||
} else {
|
} else {
|
||||||
ret = $8;
|
ret = $8;
|
||||||
free_policy($4);
|
delete $4;
|
||||||
}
|
}
|
||||||
$$ = ret;
|
$$ = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
|
||||||
{
|
{
|
||||||
struct codomain *ret = NULL;
|
Profile *ret = NULL;
|
||||||
PDEBUG("Matched: found conditional else-if rules\n");
|
PDEBUG("Matched: found conditional else-if rules\n");
|
||||||
if ($2) {
|
if ($2) {
|
||||||
ret = $4;
|
ret = $4;
|
||||||
free_policy($7);
|
delete $7;
|
||||||
} else {
|
} else {
|
||||||
ret = $7;
|
ret = $7;
|
||||||
free_policy($4);
|
delete $4;
|
||||||
}
|
}
|
||||||
$$ = ret;
|
$$ = ret;
|
||||||
}
|
}
|
||||||
|
@ -1307,25 +1307,25 @@ struct cod_entry *do_file_rule(char *ns, char *id, int mode,
|
||||||
/* Note: NOT currently in use, used for
|
/* Note: NOT currently in use, used for
|
||||||
* /foo x -> { /bah, } style transitions
|
* /foo x -> { /bah, } style transitions
|
||||||
*/
|
*/
|
||||||
void add_local_entry(struct codomain *cod)
|
void add_local_entry(Profile *prof)
|
||||||
{
|
{
|
||||||
/* ugh this has to be called after the hat is attached to its parent */
|
/* ugh this has to be called after the hat is attached to its parent */
|
||||||
if (cod->local_mode) {
|
if (prof->local_mode) {
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
char *trans = (char *) malloc(strlen(cod->parent->name) +
|
char *trans = (char *) malloc(strlen(prof->parent->name) +
|
||||||
strlen(cod->name) + 3);
|
strlen(prof->name) + 3);
|
||||||
char *name = strdup(cod->name);
|
char *name = strdup(prof->name);
|
||||||
if (!trans)
|
if (!trans)
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
sprintf(name, "%s//%s", cod->parent->name, cod->name);
|
sprintf(name, "%s//%s", prof->parent->name, prof->name);
|
||||||
|
|
||||||
entry = new_entry(NULL, name, cod->local_mode, NULL);
|
entry = new_entry(NULL, name, prof->local_mode, NULL);
|
||||||
entry->audit = cod->local_audit;
|
entry->audit = prof->local_audit;
|
||||||
entry->nt_name = trans;
|
entry->nt_name = trans;
|
||||||
if (!entry)
|
if (!entry)
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
|
|
||||||
add_entry_to_policy(cod, entry);
|
add_entry_to_policy(prof, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
90
parser/profile.cc
Normal file
90
parser/profile.cc
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "profile.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bool deref_profileptr_lt::operator()(Profile * const &lhs, Profile * const &rhs) const
|
||||||
|
{
|
||||||
|
return *lhs < *rhs;
|
||||||
|
};
|
||||||
|
|
||||||
|
pair<ProfileList::iterator,bool> ProfileList::insert(Profile *p)
|
||||||
|
{
|
||||||
|
return list.insert(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileList::erase(ProfileList::iterator pos)
|
||||||
|
{
|
||||||
|
list.erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileList::clear(void)
|
||||||
|
{
|
||||||
|
for(ProfileList::iterator i = list.begin(); i != list.end(); ) {
|
||||||
|
ProfileList::iterator k = i++;
|
||||||
|
delete *k;
|
||||||
|
list.erase(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileList::dump(void)
|
||||||
|
{
|
||||||
|
for(ProfileList::iterator i = list.begin(); i != list.end(); i++) {
|
||||||
|
(*i)->dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileList::dump_profile_names(bool children)
|
||||||
|
{
|
||||||
|
for (ProfileList::iterator i = list.begin(); i != list.end();i++) {
|
||||||
|
(*i)->dump_name(true);
|
||||||
|
printf("\n");
|
||||||
|
if (children && !(*i)->hat_table.empty())
|
||||||
|
(*i)->hat_table.dump_profile_names(children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile::~Profile()
|
||||||
|
{
|
||||||
|
hat_table.clear();
|
||||||
|
free_cod_entries(entries);
|
||||||
|
free_mnt_entries(mnt_ents);
|
||||||
|
free_dbus_entries(dbus_ents);
|
||||||
|
if (dfa.rules)
|
||||||
|
aare_delete_ruleset(dfa.rules);
|
||||||
|
if (dfa.dfa)
|
||||||
|
free(dfa.dfa);
|
||||||
|
if (policy.rules)
|
||||||
|
aare_delete_ruleset(policy.rules);
|
||||||
|
if (policy.dfa)
|
||||||
|
free(policy.dfa);
|
||||||
|
if (name)
|
||||||
|
free(name);
|
||||||
|
if (attachment)
|
||||||
|
free(attachment);
|
||||||
|
if (ns)
|
||||||
|
free(ns);
|
||||||
|
if (net.allow)
|
||||||
|
free(net.allow);
|
||||||
|
if (net.audit)
|
||||||
|
free(net.audit);
|
||||||
|
if (net.deny)
|
||||||
|
free(net.deny);
|
||||||
|
if (net.quiet)
|
||||||
|
free(net.quiet);
|
||||||
|
}
|
||||||
|
|
242
parser/profile.h
Normal file
242
parser/profile.h
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef __AA_PROFILE_H
|
||||||
|
#define __AA_PROFILE_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
class Profile;
|
||||||
|
|
||||||
|
class block {
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct deref_profileptr_lt {
|
||||||
|
bool operator()(Profile * const &lhs, Profile * const &rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProfileList {
|
||||||
|
public:
|
||||||
|
set<Profile *, deref_profileptr_lt> list;
|
||||||
|
|
||||||
|
typedef set<Profile *, deref_profileptr_lt>::iterator iterator;
|
||||||
|
iterator begin() { return list.begin(); }
|
||||||
|
iterator end() { return list.end(); }
|
||||||
|
|
||||||
|
ProfileList() { };
|
||||||
|
virtual ~ProfileList() { clear(); }
|
||||||
|
virtual bool empty(void) { return list.empty(); }
|
||||||
|
virtual pair<ProfileList::iterator,bool> insert(Profile *);
|
||||||
|
virtual void erase(ProfileList::iterator pos);
|
||||||
|
void clear(void);
|
||||||
|
void dump(void);
|
||||||
|
void dump_profile_names(bool children);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class flagvals {
|
||||||
|
public:
|
||||||
|
int hat;
|
||||||
|
int complain;
|
||||||
|
int audit;
|
||||||
|
int path;
|
||||||
|
|
||||||
|
void dump(void)
|
||||||
|
{
|
||||||
|
printf("Profile Mode:\t");
|
||||||
|
|
||||||
|
if (complain)
|
||||||
|
printf("Complain");
|
||||||
|
else
|
||||||
|
printf("Enforce");
|
||||||
|
|
||||||
|
if (audit)
|
||||||
|
printf(", Audit");
|
||||||
|
|
||||||
|
if (hat)
|
||||||
|
printf(", Hat");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct capabilities {
|
||||||
|
uint64_t allow;
|
||||||
|
uint64_t audit;
|
||||||
|
uint64_t deny;
|
||||||
|
uint64_t quiet;
|
||||||
|
|
||||||
|
capabilities(void) { allow = audit = deny = quiet; }
|
||||||
|
|
||||||
|
void dump()
|
||||||
|
{
|
||||||
|
if (allow != 0ull)
|
||||||
|
__debug_capabilities(allow, "Capabilities");
|
||||||
|
if (audit != 0ull)
|
||||||
|
__debug_capabilities(audit, "Audit Caps");
|
||||||
|
if (deny != 0ull)
|
||||||
|
__debug_capabilities(deny, "Deny Caps");
|
||||||
|
if (quiet != 0ull)
|
||||||
|
__debug_capabilities(quiet, "Quiet Caps");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct network {
|
||||||
|
unsigned int *allow; /* array of type masks
|
||||||
|
* indexed by AF_FAMILY */
|
||||||
|
unsigned int *audit;
|
||||||
|
unsigned int *deny;
|
||||||
|
unsigned int *quiet;
|
||||||
|
|
||||||
|
network(void) { allow = audit = deny = quiet = NULL; }
|
||||||
|
|
||||||
|
void dump(void) {
|
||||||
|
if (allow)
|
||||||
|
__debug_network(allow, "Network");
|
||||||
|
if (audit)
|
||||||
|
__debug_network(audit, "Audit Net");
|
||||||
|
if (deny)
|
||||||
|
__debug_network(deny, "Deny Net");
|
||||||
|
if (quiet)
|
||||||
|
__debug_network(quiet, "Quiet Net");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dfa_stuff {
|
||||||
|
aare_ruleset_t *rules;
|
||||||
|
int count;
|
||||||
|
void *dfa;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
dfa_stuff(void): rules(NULL), count(0), dfa(NULL), size(0) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Profile {
|
||||||
|
public:
|
||||||
|
char *ns;
|
||||||
|
char *name;
|
||||||
|
char *attachment;
|
||||||
|
struct alt_name *altnames;
|
||||||
|
void *xmatch;
|
||||||
|
size_t xmatch_size;
|
||||||
|
int xmatch_len;
|
||||||
|
|
||||||
|
/* char *sub_name; */ /* subdomain name or NULL */
|
||||||
|
/* int default_deny; */ /* TRUE or FALSE */
|
||||||
|
int local;
|
||||||
|
int local_mode; /* true if local, not hat */
|
||||||
|
int local_audit;
|
||||||
|
|
||||||
|
Profile *parent;
|
||||||
|
|
||||||
|
struct flagvals flags;
|
||||||
|
struct capabilities caps;
|
||||||
|
struct network net;
|
||||||
|
|
||||||
|
struct aa_rlimits rlimits;
|
||||||
|
|
||||||
|
char *exec_table[AA_EXEC_COUNT];
|
||||||
|
struct cod_entry *entries;
|
||||||
|
struct mnt_entry *mnt_ents;
|
||||||
|
struct dbus_entry *dbus_ents;
|
||||||
|
|
||||||
|
ProfileList hat_table;
|
||||||
|
|
||||||
|
struct dfa_stuff dfa;
|
||||||
|
struct dfa_stuff policy;
|
||||||
|
|
||||||
|
Profile(void)
|
||||||
|
{
|
||||||
|
ns = name = attachment = NULL;
|
||||||
|
altnames = NULL;
|
||||||
|
xmatch = NULL;
|
||||||
|
xmatch_size = 0;
|
||||||
|
xmatch_len = 0;
|
||||||
|
|
||||||
|
local = local_mode = local_audit = 0;
|
||||||
|
|
||||||
|
parent = NULL;
|
||||||
|
|
||||||
|
flags = { 0, 0, 0, 0};
|
||||||
|
rlimits = { 0 };
|
||||||
|
|
||||||
|
std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
|
||||||
|
|
||||||
|
entries = NULL;
|
||||||
|
mnt_ents = NULL;
|
||||||
|
dbus_ents = NULL;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Profile();
|
||||||
|
|
||||||
|
bool operator<(Profile const &rhs)const
|
||||||
|
{
|
||||||
|
if (ns) {
|
||||||
|
if (rhs.ns) {
|
||||||
|
int res = strcmp(ns, rhs.ns);
|
||||||
|
if (res != 0)
|
||||||
|
return res < 0;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
} else if (rhs.ns)
|
||||||
|
return true;
|
||||||
|
return strcmp(name, rhs.name) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(void)
|
||||||
|
{
|
||||||
|
if (ns)
|
||||||
|
printf("Ns:\t\t%s\n", ns);
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
printf("Name:\t\t%s\n", name);
|
||||||
|
else
|
||||||
|
printf("Name:\t\t<NULL>\n");
|
||||||
|
|
||||||
|
if (local) {
|
||||||
|
if (parent)
|
||||||
|
printf("Local To:\t%s\n", parent->name);
|
||||||
|
else
|
||||||
|
printf("Local To:\t<NULL>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
flags.dump();
|
||||||
|
caps.dump();
|
||||||
|
net.dump();
|
||||||
|
|
||||||
|
if (entries)
|
||||||
|
debug_cod_entries(entries);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
hat_table.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_name(bool fqp)
|
||||||
|
{
|
||||||
|
if (fqp && parent) {
|
||||||
|
parent->dump_name(fqp);
|
||||||
|
printf("//%s", name);
|
||||||
|
} else
|
||||||
|
printf("%s", name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __AA_PROFILE_H */
|
57
parser/unit_test.h
Normal file
57
parser/unit_test.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013
|
||||||
|
* 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_UNIT_TEST_H
|
||||||
|
#define __AA_UNIT_TEST_H
|
||||||
|
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
/* For the unit-test builds, we must include function stubs for stuff that
|
||||||
|
* only exists in the excluded object files; everything else should live
|
||||||
|
* in parser_common.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
|
||||||
|
#undef _
|
||||||
|
#define _(s) (s)
|
||||||
|
|
||||||
|
/* parser_yacc.y */
|
||||||
|
void yyerror(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
va_start(arg, msg);
|
||||||
|
vsnprintf(buf, sizeof(buf), msg, arg);
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
PERROR(_("AppArmor parser error: %s\n"), buf);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MY_TEST(statement, error) \
|
||||||
|
if (!(statement)) { \
|
||||||
|
PERROR("FAIL: %s\n", error); \
|
||||||
|
rc = 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* UNIT_TEST */
|
||||||
|
|
||||||
|
#endif /* __AA_UNIT_TEST_H */
|
Loading…
Add table
Reference in a new issue