mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Compare commits
34 Commits
v2.8-beta2
...
v2.7.1
Author | SHA1 | Date | |
---|---|---|---|
|
022a988e4e | ||
|
95f9b1d07c | ||
|
4258749515 | ||
|
62b2a00331 | ||
|
463415347d | ||
|
a52313485f | ||
|
67b440a019 | ||
|
da1bb2f219 | ||
|
0badfb7816 | ||
|
87bf30b6d0 | ||
|
51369a0c3e | ||
|
6ae5a71ea2 | ||
|
850a565dce | ||
|
a0cf904972 | ||
|
8760451216 | ||
|
d096f8f7a5 | ||
|
beb695f7b0 | ||
|
ac80b7ca03 | ||
|
a729e8fd75 | ||
|
f4c661e070 | ||
|
15e636a329 | ||
|
49b9a83d9e | ||
|
069d98d007 | ||
|
8c82eec301 | ||
|
455d8a5140 | ||
|
efd20f879c | ||
|
977929f558 | ||
|
cb60e9b3df | ||
|
f57d90d935 | ||
|
f66a2e2e66 | ||
|
d1281c4988 | ||
|
c93fc7c758 | ||
|
e2c5ecafce | ||
|
888ef7b0e2 |
@@ -1 +1 @@
|
||||
2.7.99
|
||||
2.7.1
|
||||
|
@@ -16,5 +16,4 @@ BUILT_SOURCES = $(man_MANS)
|
||||
--section=2 \
|
||||
--release="AppArmor $(VERSION)" \
|
||||
--center="AppArmor" \
|
||||
--stderr \
|
||||
$< > $@
|
||||
|
@@ -85,9 +85,14 @@ Insufficient kernel memory was available.
|
||||
|
||||
The calling application is not confined by apparmor.
|
||||
|
||||
=item B<ECHILD>
|
||||
|
||||
The application's profile has no hats defined for it.
|
||||
|
||||
=item B<EACCES>
|
||||
|
||||
The task does not have sufficient permissions to change its domain.
|
||||
The specified I<profile> does not exist in this profile or the
|
||||
process tried to change another process's domain.
|
||||
|
||||
=back
|
||||
|
||||
@@ -170,7 +175,6 @@ The output when run:
|
||||
|
||||
If /tmp/change_p is to be confined as well, then the following profile can be
|
||||
used (in addition to the one for 'i_cant_be_trusted_anymore', above):
|
||||
|
||||
# Confine change_p to be able to read /etc/passwd and aa_change_profile()
|
||||
# to the 'i_cant_be_trusted_anymore' profile.
|
||||
/tmp/change_p {
|
||||
|
@@ -38,9 +38,8 @@ Link with B<-lapparmor> when compiling.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The aa_is_enabled function returns true (1) if apparmor is enabled.
|
||||
If it isn't it sets the errno(3) to reflect the reason it is not
|
||||
enabled and returns 0.
|
||||
The aa_is_enabled function returns true (1) if apparmor is enabled. If it
|
||||
isn't it sets the errno to reflect the reason it is not enabled and returns 0.
|
||||
|
||||
The aa_find_mountpoint function finds where the apparmor filesystem is mounted
|
||||
on the system, and returns a string containing the mount path. It is the
|
||||
@@ -58,10 +57,10 @@ appropriately.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
B<aa_is_enabled>
|
||||
|
||||
=over 4
|
||||
|
||||
B<aa_is_enabled>
|
||||
|
||||
=item B<ENOSYS>
|
||||
|
||||
AppArmor extensions to the system are not available.
|
||||
@@ -85,21 +84,18 @@ Did not have sufficient permissions to determine if AppArmor is enabled.
|
||||
|
||||
=item B<EACCES>
|
||||
|
||||
Did not have sufficient permissions to determine if AppArmor is enabled.
|
||||
+Did not have sufficient permissions to determine if AppArmor is enabled.
|
||||
|
||||
=back
|
||||
|
||||
B<aa_find_mountpoint>
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<ENOMEM>
|
||||
|
||||
Insufficient memory was available.
|
||||
|
||||
=item B<EACCES>
|
||||
|
||||
Access to the required paths was denied.
|
||||
Access to the the required paths was denied.
|
||||
|
||||
=item B<ENOENT>
|
||||
|
||||
|
@@ -50,7 +50,7 @@ Link with B<-lapparmor> when compiling.
|
||||
The aa_getcon function gets the current AppArmor confinement context for the
|
||||
current task. The confinement context is usually just the name of the AppArmor
|
||||
profile restricting the task, but it may include the profile namespace or in
|
||||
some cases a set of profile names (known as a stack of profiles). The returned string *con should be freed using free().
|
||||
some cases a set of profile names (known as a stack of profiles). The returned string *con should be freed using <free()>.
|
||||
|
||||
The aa_gettaskcon function is like the aa_getcon function except it will work
|
||||
for any arbitrary task in the system.
|
||||
|
@@ -76,8 +76,8 @@ EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\"
|
||||
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_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||
parser_alias.c mount.c
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h
|
||||
parser_alias.c
|
||||
HDRS = parser.h parser_include.h immunix.h
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(SRCS:.c=.o)
|
||||
@@ -200,9 +200,6 @@ parser_alias.o: parser_alias.c parser.h
|
||||
parser_common.o: parser_common.c parser.h
|
||||
$(CC) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.c mount.h parser.h immunix.h
|
||||
$(CC) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||
@mv -f .ver $@
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# 2008, 2009
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# Copyright (c) 2010 - 2012
|
||||
# Copyright (c) 2010
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# 2008, 2009
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# Copyright (c) 2010 - 2012
|
||||
# Copyright (c) 2010
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# 2008, 2009
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# Copyright (c) 2010 - 2012
|
||||
# Copyright (c) 2010
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
@@ -127,21 +127,16 @@ Perform no caching at all: disables -W, implies -T.
|
||||
|
||||
=item -T, --skip-read-cache
|
||||
|
||||
By default, if a profile's cache is found in the location specified by
|
||||
--cache-loc and the timestamp is newer than the profile, it will be loaded
|
||||
from the cache. This option disables this cache loading behavior.
|
||||
By default, if a profile's cache is found in /etc/apparmor.d/cache/ and
|
||||
the timestamp is newer than the profile, it will be loaded from the cache.
|
||||
This option disables this cache loading behavior.
|
||||
|
||||
=item -W, --write-cache
|
||||
|
||||
Write out cached profiles to the location specified in --cache-loc. Off
|
||||
by default. In cases where abstractions have been changed, and the parser
|
||||
is running with "--replace", it may make sense to also use
|
||||
"--skip-read-cache" with the "--write-cache" option.
|
||||
|
||||
=item -L, --cache-loc
|
||||
|
||||
Set the location of the cache directory. If not specified the cache location
|
||||
defaults to /etc/apparmor.d/cache
|
||||
Write out cached profiles to /etc/apparmor.d/cache/. Off by default.
|
||||
In cases where abstractions have been changed, and the parser is running
|
||||
with "--replace", it may make sense to also use "--skip-read-cache" with
|
||||
the "--write-cache" option.
|
||||
|
||||
=item -Q, --skip-kernel-load
|
||||
|
||||
|
@@ -96,9 +96,6 @@
|
||||
|
||||
#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
|
||||
|
||||
#define ALL_USER_EXEC (AA_USER_EXEC | AA_USER_EXEC_TYPE)
|
||||
#define ALL_OTHER_EXEC (AA_OTHER_EXEC | AA_OTHER_EXEC_TYPE)
|
||||
|
||||
#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
|
||||
(AA_MAY_LINK << AA_OTHER_SHIFT))
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
TARGET=libapparmor_re.a
|
||||
|
||||
CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS}
|
||||
CXXFLAGS := ${CFLAGS} -std=c++0x
|
||||
CXXFLAGS := ${CFLAGS}
|
||||
|
||||
ARFLAGS=-rcs
|
||||
|
||||
@@ -12,16 +12,16 @@ BISON := bison
|
||||
|
||||
all : ${TARGET}
|
||||
|
||||
libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o
|
||||
libapparmor_re.a: parse.o expr-tree.o hfa.o compressed_hfa.o aare_rules.o
|
||||
ar ${ARFLAGS} $@ $^
|
||||
|
||||
expr-tree.o: expr-tree.cc expr-tree.h
|
||||
|
||||
hfa.o: hfa.cc apparmor_re.h hfa.h ../immunix.h
|
||||
|
||||
aare_rules.o: aare_rules.cc aare_rules.h apparmor_re.h expr-tree.h hfa.h chfa.h parse.h ../immunix.h
|
||||
aare_rules.o: aare_rules.cc aare_rules.h apparmor_re.h expr-tree.h hfa.h compressed_hfa.h parse.h ../immunix.h
|
||||
|
||||
chfa.o: chfa.cc chfa.h ../immunix.h
|
||||
compressed_hfa.o: compressed_hfa.cc compressed_hfa.h ../immunix.h
|
||||
|
||||
parse.o : parse.cc apparmor_re.h expr-tree.h
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "expr-tree.h"
|
||||
#include "parse.h"
|
||||
#include "hfa.h"
|
||||
#include "chfa.h"
|
||||
#include "compressed_hfa.h"
|
||||
#include "../immunix.h"
|
||||
|
||||
struct aare_ruleset {
|
||||
@@ -98,7 +98,6 @@ extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
|
||||
{
|
||||
Node *tree = NULL, *accept;
|
||||
int exact_match;
|
||||
uint32_t allow = perms;
|
||||
|
||||
assert(perms != 0);
|
||||
|
||||
@@ -221,11 +220,7 @@ extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
|
||||
}
|
||||
cerr << " -> ";
|
||||
tree->dump(cerr);
|
||||
if (deny)
|
||||
cerr << " deny";
|
||||
cerr << " (0x" << hex << allow <<"/" << audit << dec << ")";
|
||||
accept->dump(cerr);
|
||||
cerr << "\n\n";
|
||||
cerr << "\n\n";
|
||||
}
|
||||
|
||||
if (rules->root)
|
||||
@@ -275,23 +270,6 @@ extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
|
||||
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("minimized dfa");
|
||||
}
|
||||
|
||||
if (flags & DFA_CONTROL_FILTER_DENY &&
|
||||
flags & DFA_CONTROL_MINIMIZE &&
|
||||
dfa.apply_and_clear_deny()) {
|
||||
/* Do a second minimization pass as removal of deny
|
||||
* information has moved some states from accepting
|
||||
* to none accepting partitions
|
||||
*
|
||||
* TODO: add this as a tail pass to minimization
|
||||
* so we don't need to do a full second pass
|
||||
*/
|
||||
dfa.minimize(flags);
|
||||
|
||||
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("minimized dfa");
|
||||
}
|
||||
|
||||
if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
|
||||
dfa.remove_unreachable(flags);
|
||||
|
||||
@@ -313,10 +291,10 @@ extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
|
||||
} else if (flags & DFA_DUMP_EQUIV)
|
||||
cerr << "\nDFA did not generate an equivalence class\n";
|
||||
|
||||
CHFA chfa(dfa, eq, flags);
|
||||
TransitionTable transition_table(dfa, eq, flags);
|
||||
if (flags & DFA_DUMP_TRANS_TABLE)
|
||||
chfa.dump(cerr);
|
||||
chfa.flex_table(stream, "");
|
||||
transition_table.dump(cerr);
|
||||
transition_table.flex_table(stream, "");
|
||||
}
|
||||
catch(int error) {
|
||||
*size = 0;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -26,7 +26,7 @@ typedef enum dfaflags {
|
||||
DFA_CONTROL_TREE_LEFT = 1 << 3,
|
||||
DFA_CONTROL_MINIMIZE = 1 << 4,
|
||||
DFA_CONTROL_MINIMIZE_HASH_TRANS = 1 << 5,
|
||||
DFA_CONTROL_FILTER_DENY = 1 << 6,
|
||||
DFA_CONTROL_MINIMIZE_HASH_PERMS = 1 << 6,
|
||||
DFA_CONTROL_REMOVE_UNREACHABLE = 1 << 7,
|
||||
DFA_CONTROL_TRANS_HIGH = 1 << 8,
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -30,10 +30,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hfa.h"
|
||||
#include "chfa.h"
|
||||
#include "../immunix.h"
|
||||
#include "compressed_hfa.h"
|
||||
|
||||
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
void TransitionTable::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
size_t prev, size_t start)
|
||||
{
|
||||
for (size_t i = start; i < free_list.size(); i++) {
|
||||
@@ -48,10 +47,11 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
/**
|
||||
* new Construct the transition table.
|
||||
*/
|
||||
CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
TransitionTable::TransitionTable(DFA &dfa, map<uchar, uchar> &eq,
|
||||
dfaflags_t flags): eq(eq)
|
||||
{
|
||||
if (flags & DFA_DUMP_TRANS_PROGRESS)
|
||||
fprintf(stderr, "Compressing HFA:\r");
|
||||
fprintf(stderr, "Compressing trans table:\r");
|
||||
|
||||
if (eq.empty())
|
||||
max_eq = 255;
|
||||
@@ -74,14 +74,14 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
if (*i == dfa.start || *i == dfa.nonmatching)
|
||||
continue;
|
||||
optimal += (*i)->trans.size();
|
||||
optimal += (*i)->cases.cases.size();
|
||||
if (flags & DFA_CONTROL_TRANS_HIGH) {
|
||||
size_t range = 0;
|
||||
if ((*i)->trans.size())
|
||||
if ((*i)->cases.cases.size())
|
||||
range =
|
||||
(*i)->trans.rbegin()->first -
|
||||
(*i)->trans.begin()->first;
|
||||
size_t ord = ((256 - (*i)->trans.size()) << 8) | (256 - range);
|
||||
(*i)->cases.cases.rbegin()->first -
|
||||
(*i)->cases.begin()->first;
|
||||
size_t ord = ((256 - (*i)->cases.cases.size()) << 8) | (256 - range);
|
||||
/* reverse sort by entry count, most entries first */
|
||||
order.insert(make_pair(ord, *i));
|
||||
}
|
||||
@@ -113,8 +113,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||
insert_state(free_list, *i, dfa);
|
||||
accept[num.size()] = (*i)->perms.allow;
|
||||
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
|
||||
accept[num.size()] = (*i)->accept;
|
||||
accept2[num.size()] = (*i)->audit;
|
||||
num.insert(make_pair(*i, num.size()));
|
||||
}
|
||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||
@@ -130,8 +130,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
if (i->second != dfa.nonmatching &&
|
||||
i->second != dfa.start) {
|
||||
insert_state(free_list, i->second, dfa);
|
||||
accept[num.size()] = i->second->perms.allow;
|
||||
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
|
||||
accept[num.size()] = i->second->accept;
|
||||
accept2[num.size()] = i->second->audit;
|
||||
num.insert(make_pair(i->second, num.size()));
|
||||
}
|
||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||
@@ -154,14 +154,14 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does <trans> fit into position <base> of the transition table?
|
||||
* Does <cases> fit into position <base> of the transition table?
|
||||
*/
|
||||
bool CHFA::fits_in(vector<pair<size_t, size_t> > &free_list
|
||||
bool TransitionTable::fits_in(vector<pair<size_t, size_t> > &free_list
|
||||
__attribute__ ((unused)), size_t pos,
|
||||
StateTrans &trans)
|
||||
Cases &cases)
|
||||
{
|
||||
size_t c, base = pos - trans.begin()->first;
|
||||
for (StateTrans::iterator i = trans.begin(); i != trans.end(); i++) {
|
||||
size_t c, base = pos - cases.begin()->first;
|
||||
for (Cases::iterator i = cases.begin(); i != cases.end(); i++) {
|
||||
c = base + i->first;
|
||||
/* if it overflows the next_check array it fits in as we will
|
||||
* resize */
|
||||
@@ -177,21 +177,21 @@ bool CHFA::fits_in(vector<pair<size_t, size_t> > &free_list
|
||||
/**
|
||||
* Insert <state> of <dfa> into the transition table.
|
||||
*/
|
||||
void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
void TransitionTable::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
State *from, DFA &dfa)
|
||||
{
|
||||
State *default_state = dfa.nonmatching;
|
||||
size_t base = 0;
|
||||
int resize;
|
||||
|
||||
StateTrans &trans = from->trans;
|
||||
size_t c = trans.begin()->first;
|
||||
Cases &cases = from->cases;
|
||||
size_t c = cases.begin()->first;
|
||||
size_t prev = 0;
|
||||
size_t x = first_free;
|
||||
|
||||
if (from->otherwise)
|
||||
default_state = from->otherwise;
|
||||
if (trans.empty())
|
||||
if (cases.otherwise)
|
||||
default_state = cases.otherwise;
|
||||
if (cases.cases.empty())
|
||||
goto do_insert;
|
||||
|
||||
repeat:
|
||||
@@ -203,16 +203,16 @@ repeat:
|
||||
}
|
||||
|
||||
/* try inserting until we succeed. */
|
||||
while (x && !fits_in(free_list, x, trans)) {
|
||||
while (x && !fits_in(free_list, x, cases)) {
|
||||
prev = x;
|
||||
x = free_list[x].second;
|
||||
}
|
||||
if (!x) {
|
||||
resize = 256 - trans.begin()->first;
|
||||
resize = 256 - cases.begin()->first;
|
||||
x = free_list.size();
|
||||
/* set prev to last free */
|
||||
} else if (x + 255 - trans.begin()->first >= next_check.size()) {
|
||||
resize = (255 - trans.begin()->first - (next_check.size() - 1 - x));
|
||||
} else if (x + 255 - cases.begin()->first >= next_check.size()) {
|
||||
resize = (255 - cases.begin()->first - (next_check.size() - 1 - x));
|
||||
for (size_t y = x; y; y = free_list[y].second)
|
||||
prev = y;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ repeat:
|
||||
}
|
||||
|
||||
base = x - c;
|
||||
for (StateTrans::iterator j = trans.begin(); j != trans.end(); j++) {
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
next_check[base + j->first] = make_pair(j->second, from);
|
||||
size_t prev = free_list[base + j->first].first;
|
||||
size_t next = free_list[base + j->first].second;
|
||||
@@ -248,7 +248,7 @@ do_insert:
|
||||
/**
|
||||
* Text-dump the transition table (for debugging).
|
||||
*/
|
||||
void CHFA::dump(ostream &os)
|
||||
void TransitionTable::dump(ostream &os)
|
||||
{
|
||||
map<size_t, const State *> st;
|
||||
for (map<const State *, size_t>::iterator i = num.begin(); i != num.end(); i++) {
|
||||
@@ -342,7 +342,7 @@ template<class Iter>
|
||||
os << fill64(sizeof(td) + sizeof(*pos) * size);
|
||||
}
|
||||
|
||||
void CHFA::flex_table(ostream &os, const char *name)
|
||||
void TransitionTable::flex_table(ostream &os, const char *name)
|
||||
{
|
||||
const char th_version[] = "notflex";
|
||||
struct table_set_header th = { 0, 0, 0, 0 };
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -16,10 +16,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Create a compressed hfa (chfa) from and hfa
|
||||
* Create a compressed hfa from and hfa
|
||||
*/
|
||||
#ifndef __LIBAA_RE_CHFA_H
|
||||
#define __LIBAA_RE_CHFA_H
|
||||
#ifndef __LIBAA_RE_COMPRESSED_HFA_H
|
||||
#define __LIBAA_RE_COMPRESSED_HFA_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -28,17 +28,17 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CHFA {
|
||||
class TransitionTable {
|
||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||
public:
|
||||
CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags);
|
||||
TransitionTable(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags);
|
||||
void dump(ostream & os);
|
||||
void flex_table(ostream &os, const char *name);
|
||||
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
size_t prev, size_t start);
|
||||
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
||||
StateTrans &cases);
|
||||
Cases &cases);
|
||||
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
State *state, DFA &dfa);
|
||||
|
||||
@@ -53,4 +53,4 @@ class CHFA {
|
||||
size_t first_free;
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_CHFA_H */
|
||||
#endif /* __LIBAA_RE_COMPRESSED_HFA_H */
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -187,22 +187,14 @@ void normalize_tree(Node *t, int dir)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
if (dynamic_cast<TwoChildNode *>(t) &&
|
||||
(&epsnode == t->child[dir]) &&
|
||||
(&epsnode != t->child[!dir])) {
|
||||
if ((&epsnode == t->child[dir]) &&
|
||||
(&epsnode != t->child[!dir]) &&
|
||||
dynamic_cast<TwoChildNode *>(t)) {
|
||||
// (E | a) -> (a | E)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = t->child[!dir];
|
||||
if (dynamic_cast<TwoChildNode *>(c) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
t->child[dir] = c;
|
||||
t->child[!dir] = &epsnode;
|
||||
Node *c = t->child[dir];
|
||||
t->child[dir] = t->child[!dir];
|
||||
t->child[!dir] = c;
|
||||
// Don't break here as 'a' may be a tree that
|
||||
// can be pulled up.
|
||||
} else if ((dynamic_cast<AltNode *>(t) &&
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -81,15 +81,17 @@ ostream &operator<<(ostream &os, const NodeSet &state);
|
||||
* (i.e., following an AnyCharNode or NotCharSetNode). This avoids
|
||||
* enumerating all the explicit tranitions for default matches.
|
||||
*/
|
||||
typedef struct Cases {
|
||||
typedef struct NodeCases {
|
||||
typedef map<uchar, NodeSet *>::iterator iterator;
|
||||
iterator begin() { return cases.begin(); }
|
||||
iterator end() { return cases.end(); }
|
||||
|
||||
Cases(): otherwise(0) { }
|
||||
NodeCases(): otherwise(0) { }
|
||||
map<uchar, NodeSet *> cases;
|
||||
NodeSet *otherwise;
|
||||
} Cases;
|
||||
}
|
||||
|
||||
NodeCases;
|
||||
|
||||
ostream &operator<<(ostream &os, Node &node);
|
||||
|
||||
@@ -203,8 +205,7 @@ public:
|
||||
ImportantNode(): LeafNode() { }
|
||||
void compute_firstpos() { firstpos.insert(this); }
|
||||
void compute_lastpos() { lastpos.insert(this); }
|
||||
virtual void follow(Cases &cases) = 0;
|
||||
virtual int is_accept(void) = 0;
|
||||
virtual void follow(NodeCases &cases) = 0;
|
||||
};
|
||||
|
||||
/* common base class for all the different classes that contain
|
||||
@@ -213,14 +214,13 @@ public:
|
||||
class CNode: public ImportantNode {
|
||||
public:
|
||||
CNode(): ImportantNode() { }
|
||||
int is_accept(void) { return false; }
|
||||
};
|
||||
|
||||
/* Match one specific character (/c/). */
|
||||
class CharNode: public CNode {
|
||||
public:
|
||||
CharNode(uchar c): c(c) { }
|
||||
void follow(Cases &cases)
|
||||
void follow(NodeCases &cases)
|
||||
{
|
||||
NodeSet **x = &cases.cases[c];
|
||||
if (!*x) {
|
||||
@@ -251,7 +251,7 @@ public:
|
||||
class CharSetNode: public CNode {
|
||||
public:
|
||||
CharSetNode(Chars &chars): chars(chars) { }
|
||||
void follow(Cases &cases)
|
||||
void follow(NodeCases &cases)
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
NodeSet **x = &cases.cases[*i];
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
class NotCharSetNode: public CNode {
|
||||
public:
|
||||
NotCharSetNode(Chars &chars): chars(chars) { }
|
||||
void follow(Cases &cases)
|
||||
void follow(NodeCases & cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
cases.otherwise = new NodeSet;
|
||||
@@ -305,7 +305,7 @@ public:
|
||||
* the old otherwise state for the matching characters.
|
||||
*/
|
||||
cases.otherwise->insert(followpos.begin(), followpos.end());
|
||||
for (Cases::iterator i = cases.begin(); i != cases.end();
|
||||
for (NodeCases::iterator i = cases.begin(); i != cases.end();
|
||||
i++) {
|
||||
if (chars.find(i->first) == chars.end())
|
||||
i->second->insert(followpos.begin(),
|
||||
@@ -340,12 +340,12 @@ public:
|
||||
class AnyCharNode: public CNode {
|
||||
public:
|
||||
AnyCharNode() { }
|
||||
void follow(Cases &cases)
|
||||
void follow(NodeCases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
cases.otherwise = new NodeSet;
|
||||
cases.otherwise->insert(followpos.begin(), followpos.end());
|
||||
for (Cases::iterator i = cases.begin(); i != cases.end();
|
||||
for (NodeCases::iterator i = cases.begin(); i != cases.end();
|
||||
i++)
|
||||
i->second->insert(followpos.begin(), followpos.end());
|
||||
}
|
||||
@@ -365,7 +365,6 @@ public:
|
||||
class AcceptNode: public ImportantNode {
|
||||
public:
|
||||
AcceptNode() { }
|
||||
int is_accept(void) { return true; }
|
||||
void release(void)
|
||||
{
|
||||
/* don't delete AcceptNode via release as they are shared, and
|
||||
@@ -373,7 +372,7 @@ public:
|
||||
*/
|
||||
}
|
||||
|
||||
void follow(Cases &cases __attribute__ ((unused)))
|
||||
void follow(NodeCases &cases __attribute__ ((unused)))
|
||||
{
|
||||
/* Nothing to follow. */
|
||||
}
|
||||
@@ -574,6 +573,22 @@ void label_nodes(Node *root);
|
||||
unsigned long hash_NodeSet(NodeSet *ns);
|
||||
void flip_tree(Node *node);
|
||||
|
||||
/* Comparison operator for sets of <NodeSet *>.
|
||||
* Compare set hashes, and if the sets have the same hash
|
||||
* do compare pointer comparison on set of <Node *>, the pointer comparison
|
||||
* allows us to determine which Sets of <Node *> we have seen already from
|
||||
* new ones when constructing the DFA.
|
||||
*/
|
||||
struct deref_less_than {
|
||||
bool operator()(pair<unsigned long, NodeSet *>const &lhs,
|
||||
pair<unsigned long, NodeSet *>const &rhs)const
|
||||
{
|
||||
if (lhs.first == rhs.first)
|
||||
return *(lhs.second) < *(rhs.second);
|
||||
else
|
||||
return lhs.first < rhs.first;
|
||||
}
|
||||
};
|
||||
|
||||
class MatchFlag: public AcceptNode {
|
||||
public:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -30,40 +30,11 @@
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
|
||||
#include "expr-tree.h"
|
||||
#include "hfa.h"
|
||||
#include "../immunix.h"
|
||||
|
||||
|
||||
ostream &operator<<(ostream &os, const CacheStats &cache)
|
||||
{
|
||||
/* dump the state label */
|
||||
os << "cache: size=";
|
||||
os << cache.size();
|
||||
os << " dups=";
|
||||
os << cache.dup;
|
||||
os << " longest=";
|
||||
os << cache.max;
|
||||
if (cache.size()) {
|
||||
os << " avg=";
|
||||
os << cache.sum / cache.size();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, const ProtoState &proto)
|
||||
{
|
||||
/* dump the state label */
|
||||
os << '{';
|
||||
os << proto.nnodes;
|
||||
os << ',';
|
||||
os << proto.anodes;
|
||||
os << '}';
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, const State &state)
|
||||
{
|
||||
/* dump the state label */
|
||||
@@ -73,48 +44,46 @@ ostream &operator<<(ostream &os, const State &state)
|
||||
return os;
|
||||
}
|
||||
|
||||
static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
|
||||
)
|
||||
State *DFA::add_new_state(NodeMap &nodemap,
|
||||
pair<unsigned long, NodeSet *> index,
|
||||
NodeSet *nodes, dfa_stats_t &stats)
|
||||
{
|
||||
*anodes = *nnodes = NULL;
|
||||
for (NodeSet::iterator i = nodes->begin(); i != nodes->end(); ) {
|
||||
if ((*i)->is_accept()) {
|
||||
if (!*anodes)
|
||||
*anodes = new NodeSet;
|
||||
(*anodes)->insert(*i);
|
||||
NodeSet::iterator k = i++;
|
||||
nodes->erase(k);
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
*nnodes = nodes;
|
||||
State *state = new State(nodemap.size(), nodes);
|
||||
states.push_back(state);
|
||||
nodemap.insert(make_pair(index, state));
|
||||
stats.proto_sum += nodes->size();
|
||||
if (nodes->size() > stats.proto_max)
|
||||
stats.proto_max = nodes->size();
|
||||
return state;
|
||||
}
|
||||
|
||||
State *DFA::add_new_state(NodeSet *nodes, State *other)
|
||||
State *DFA::find_target_state(NodeMap &nodemap, list<State *> &work_queue,
|
||||
NodeSet *nodes, dfa_stats_t &stats)
|
||||
{
|
||||
/* The splitting of nodes should probably get pushed down into
|
||||
* follow(), ie. put in separate lists from the start
|
||||
*/
|
||||
NodeSet *anodes, *nnodes;
|
||||
hashedNodeVec *nnodev;
|
||||
split_node_types(nodes, &anodes, &nnodes);
|
||||
nnodev = nnodes_cache.insert(nnodes);
|
||||
anodes = anodes_cache.insert(anodes);
|
||||
State *target;
|
||||
|
||||
ProtoState proto(nnodev, anodes);
|
||||
State *state = new State(node_map.size(), proto, other);
|
||||
pair<NodeMap::iterator,bool> x = node_map.insert(proto, state);
|
||||
if (x.second == false) {
|
||||
delete state;
|
||||
pair<unsigned long, NodeSet *> index = make_pair(hash_NodeSet(nodes), nodes);
|
||||
|
||||
map<pair<unsigned long, NodeSet *>, State *, deref_less_than>::iterator x = nodemap.find(index);
|
||||
|
||||
if (x == nodemap.end()) {
|
||||
/* set of nodes isn't known so create new state, and nodes to
|
||||
* state mapping
|
||||
*/
|
||||
target = add_new_state(nodemap, index, nodes, stats);
|
||||
work_queue.push_back(target);
|
||||
} else {
|
||||
states.push_back(state);
|
||||
work_queue.push_back(state);
|
||||
/* set of nodes already has a mapping so free this one */
|
||||
stats.duplicates++;
|
||||
delete(nodes);
|
||||
target = x->second;
|
||||
}
|
||||
|
||||
return x.first->second;
|
||||
return target;
|
||||
}
|
||||
|
||||
void DFA::update_state_transitions(State *state)
|
||||
void DFA::update_state_transitions(NodeMap &nodemap, list<State *> &work_queue,
|
||||
State *state, dfa_stats_t &stats)
|
||||
{
|
||||
/* Compute possible transitions for state->nodes. This is done by
|
||||
* iterating over all the nodes in state->nodes and combining the
|
||||
@@ -122,12 +91,9 @@ void DFA::update_state_transitions(State *state)
|
||||
*
|
||||
* The resultant transition set is a mapping of characters to
|
||||
* sets of nodes.
|
||||
*
|
||||
* Note: the follow set for accept nodes is always empty so we don't
|
||||
* need to compute follow for the accept nodes in a protostate
|
||||
*/
|
||||
Cases cases;
|
||||
for (hashedNodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
|
||||
NodeCases cases;
|
||||
for (NodeSet::iterator i = state->nodes->begin(); i != state->nodes->end(); i++)
|
||||
(*i)->follow(cases);
|
||||
|
||||
/* Now for each set of nodes in the computed transitions, make
|
||||
@@ -137,22 +103,22 @@ void DFA::update_state_transitions(State *state)
|
||||
|
||||
/* check the default transition first */
|
||||
if (cases.otherwise)
|
||||
state->otherwise = add_new_state(cases.otherwise, nonmatching);
|
||||
else
|
||||
state->otherwise = nonmatching;
|
||||
state->cases.otherwise = find_target_state(nodemap, work_queue,
|
||||
cases.otherwise,
|
||||
stats);;
|
||||
|
||||
/* For each transition from *from, check if the set of nodes it
|
||||
* transitions to already has been mapped to a state
|
||||
*/
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
for (NodeCases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
State *target;
|
||||
target = add_new_state(j->second, nonmatching);
|
||||
target = find_target_state(nodemap, work_queue, j->second, stats);
|
||||
|
||||
/* Don't insert transition that the otherwise transition
|
||||
/* Don't insert transition that the default transition
|
||||
* already covers
|
||||
*/
|
||||
if (target != state->otherwise)
|
||||
state->trans[j->first] = target;
|
||||
if (target != state->cases.otherwise)
|
||||
state->cases.cases[j->first] = target;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +131,7 @@ void DFA::dump_node_to_dfa(void)
|
||||
" State <= Nodes\n"
|
||||
"-------------------\n";
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
cerr << " " << (*i)->label << " <= " << (*i)->proto << "\n";
|
||||
cerr << " " << (*i)->label << " <= " << *(*i)->nodes << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,6 +139,7 @@ void DFA::dump_node_to_dfa(void)
|
||||
*/
|
||||
DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
{
|
||||
dfa_stats_t stats = { 0, 0, 0 };
|
||||
int i = 0;
|
||||
|
||||
if (flags & DFA_DUMP_PROGRESS)
|
||||
@@ -190,8 +157,15 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
(*i)->compute_followpos();
|
||||
}
|
||||
|
||||
nonmatching = add_new_state(new NodeSet, NULL);
|
||||
start = add_new_state(new NodeSet(root->firstpos), nonmatching);
|
||||
NodeMap nodemap;
|
||||
NodeSet *emptynode = new NodeSet;
|
||||
nonmatching = add_new_state(nodemap,
|
||||
make_pair(hash_NodeSet(emptynode), emptynode),
|
||||
emptynode, stats);
|
||||
|
||||
NodeSet *first = new NodeSet(root->firstpos);
|
||||
start = add_new_state(nodemap, make_pair(hash_NodeSet(first), first),
|
||||
first, stats);
|
||||
|
||||
/* the work_queue contains the states that need to have their
|
||||
* transitions computed. This could be done with a recursive
|
||||
@@ -203,18 +177,14 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
* manner, this may help reduce the number of entries on the
|
||||
* work_queue at any given time, thus reducing peak memory use.
|
||||
*/
|
||||
list<State *> work_queue;
|
||||
work_queue.push_back(start);
|
||||
|
||||
while (!work_queue.empty()) {
|
||||
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
|
||||
cerr << "\033[2KCreating dfa: queue "
|
||||
<< work_queue.size()
|
||||
<< "\tstates "
|
||||
<< states.size()
|
||||
<< "\teliminated duplicates "
|
||||
<< node_map.dup
|
||||
<< "\r";
|
||||
}
|
||||
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS))
|
||||
fprintf(stderr, "\033[2KCreating dfa: queue %zd\tstates %zd\teliminated duplicates %d\r",
|
||||
work_queue.size(), states.size(),
|
||||
stats.duplicates);
|
||||
i++;
|
||||
|
||||
State *from = work_queue.front();
|
||||
@@ -223,7 +193,7 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
/* Update 'from's transitions, and if it transitions to any
|
||||
* unknown State create it and add it to the work_queue
|
||||
*/
|
||||
update_state_transitions(from);
|
||||
update_state_transitions(nodemap, work_queue, from, stats);
|
||||
|
||||
} /* while (!work_queue.empty()) */
|
||||
|
||||
@@ -239,68 +209,34 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
if (flags & DFA_DUMP_NODE_TO_DFA)
|
||||
dump_node_to_dfa();
|
||||
|
||||
if (flags & (DFA_DUMP_STATS)) {
|
||||
cerr << "\033[2KCreated dfa: states "
|
||||
<< states.size()
|
||||
<< " proto { "
|
||||
<< node_map
|
||||
<< " }, nnodes { "
|
||||
<< nnodes_cache
|
||||
<< " }, anodes { "
|
||||
<< anodes_cache
|
||||
<< " }\n";
|
||||
}
|
||||
for (NodeMap::iterator i = nodemap.begin(); i != nodemap.end(); i++)
|
||||
delete i->first.second;
|
||||
nodemap.clear();
|
||||
|
||||
if (flags & (DFA_DUMP_STATS))
|
||||
fprintf(stderr, "\033[2KCreated dfa: states %zd,\teliminated duplicates %d,\tprotostate sets: longest %u, avg %u\n",
|
||||
states.size(), stats.duplicates, stats.proto_max,
|
||||
(unsigned int)(stats.proto_sum / states.size()));
|
||||
|
||||
/* Clear out uniq_nnodes as they are no longer needed.
|
||||
* Do not clear out uniq_anodes, as we need them for minimizations
|
||||
* diffs, unions, ...
|
||||
*/
|
||||
nnodes_cache.clear();
|
||||
node_map.clear();
|
||||
}
|
||||
|
||||
DFA::~DFA()
|
||||
{
|
||||
anodes_cache.clear();
|
||||
nnodes_cache.clear();
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
State *DFA::match_len(State *state, const char *str, size_t len)
|
||||
{
|
||||
for (; len > 0; ++str, --len)
|
||||
state = state->next(*str);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
State *DFA::match_until(State *state, const char *str, const char term)
|
||||
{
|
||||
while (*str != term)
|
||||
state = state->next(*str++);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
State *DFA::match(const char *str)
|
||||
{
|
||||
return match_until(start, str, 0);
|
||||
}
|
||||
|
||||
void DFA::dump_uniq_perms(const char *s)
|
||||
{
|
||||
set<perms_t> uniq;
|
||||
set<pair<uint32_t, uint32_t> > uniq;
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
uniq.insert((*i)->perms);
|
||||
uniq.insert(make_pair((*i)->accept, (*i)->audit));
|
||||
|
||||
cerr << "Unique Permission sets: " << s << " (" << uniq.size() << ")\n";
|
||||
cerr << "----------------------\n";
|
||||
for (set<perms_t >::iterator i = uniq.begin(); i != uniq.end(); i++) {
|
||||
cerr << " allow:" << hex << i->allow << " deny:"
|
||||
<< i->deny << " audit:" << i->audit
|
||||
<< " quiet:" << i->quiet << dec << "\n";
|
||||
for (set<pair<uint32_t, uint32_t> >::iterator i = uniq.begin();
|
||||
i != uniq.end(); i++) {
|
||||
cerr << " " << hex << i->first << " " << i->second << dec << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +244,7 @@ void DFA::dump_uniq_perms(const char *s)
|
||||
void DFA::remove_unreachable(dfaflags_t flags)
|
||||
{
|
||||
set<State *> reachable;
|
||||
list<State *> work_queue;
|
||||
|
||||
/* find the set of reachable states */
|
||||
reachable.insert(nonmatching);
|
||||
@@ -317,11 +254,11 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
||||
work_queue.pop_front();
|
||||
reachable.insert(from);
|
||||
|
||||
if (from->otherwise != nonmatching &&
|
||||
reachable.find(from->otherwise) == reachable.end())
|
||||
work_queue.push_back(from->otherwise);
|
||||
if (from->cases.otherwise &&
|
||||
(reachable.find(from->cases.otherwise) == reachable.end()))
|
||||
work_queue.push_back(from->cases.otherwise);
|
||||
|
||||
for (StateTrans::iterator j = from->trans.begin(); j != from->trans.end(); j++) {
|
||||
for (Cases::iterator j = from->cases.begin(); j != from->cases.end(); j++) {
|
||||
if (reachable.find(j->second) == reachable.end())
|
||||
work_queue.push_back(j->second);
|
||||
}
|
||||
@@ -340,12 +277,10 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
||||
cerr << "unreachable: " << **i;
|
||||
if (*i == start)
|
||||
cerr << " <==";
|
||||
if (!(*i)->perms.is_null()) {
|
||||
if ((*i)->accept) {
|
||||
cerr << " (0x" << hex
|
||||
<< (*i)->perms.allow << " "
|
||||
<< (*i)->perms.deny << " "
|
||||
<< (*i)->perms.audit << " "
|
||||
<< (*i)->perms.quiet << dec
|
||||
<< (*i)->accept << " "
|
||||
<< (*i)->audit << dec
|
||||
<< ')';
|
||||
}
|
||||
cerr << "\n";
|
||||
@@ -366,22 +301,22 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
||||
/* test if two states have the same transitions under partition_map */
|
||||
bool DFA::same_mappings(State *s1, State *s2)
|
||||
{
|
||||
if (s1->otherwise != nonmatching) {
|
||||
if (s2->otherwise == nonmatching)
|
||||
if (s1->cases.otherwise && s1->cases.otherwise != nonmatching) {
|
||||
if (!s2->cases.otherwise || s2->cases.otherwise == nonmatching)
|
||||
return false;
|
||||
Partition *p1 = s1->otherwise->partition;
|
||||
Partition *p2 = s2->otherwise->partition;
|
||||
Partition *p1 = s1->cases.otherwise->partition;
|
||||
Partition *p2 = s2->cases.otherwise->partition;
|
||||
if (p1 != p2)
|
||||
return false;
|
||||
} else if (s2->otherwise != nonmatching) {
|
||||
} else if (s2->cases.otherwise && s2->cases.otherwise != nonmatching) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s1->trans.size() != s2->trans.size())
|
||||
if (s1->cases.cases.size() != s2->cases.cases.size())
|
||||
return false;
|
||||
for (StateTrans::iterator j1 = s1->trans.begin(); j1 != s1->trans.end(); j1++) {
|
||||
StateTrans::iterator j2 = s2->trans.find(j1->first);
|
||||
if (j2 == s2->trans.end())
|
||||
for (Cases::iterator j1 = s1->cases.begin(); j1 != s1->cases.end(); j1++) {
|
||||
Cases::iterator j2 = s2->cases.cases.find(j1->first);
|
||||
if (j2 == s2->cases.end())
|
||||
return false;
|
||||
Partition *p1 = j1->second->partition;
|
||||
Partition *p2 = j2->second->partition;
|
||||
@@ -395,7 +330,7 @@ bool DFA::same_mappings(State *s1, State *s2)
|
||||
/* Do simple djb2 hashing against a States transition cases
|
||||
* this provides a rough initial guess at state equivalence as if a state
|
||||
* has a different number of transitions or has transitions on different
|
||||
* trans they will never be equivalent.
|
||||
* cases they will never be equivalent.
|
||||
* Note: this only hashes based off of the alphabet (not destination)
|
||||
* as different destinations could end up being equiv
|
||||
*/
|
||||
@@ -403,31 +338,22 @@ size_t DFA::hash_trans(State *s)
|
||||
{
|
||||
unsigned long hash = 5381;
|
||||
|
||||
for (StateTrans::iterator j = s->trans.begin(); j != s->trans.end(); j++) {
|
||||
for (Cases::iterator j = s->cases.begin(); j != s->cases.end(); j++) {
|
||||
hash = ((hash << 5) + hash) + j->first;
|
||||
State *k = j->second;
|
||||
hash = ((hash << 5) + hash) + k->trans.size();
|
||||
hash = ((hash << 5) + hash) + k->cases.cases.size();
|
||||
}
|
||||
|
||||
if (s->otherwise != nonmatching) {
|
||||
if (s->cases.otherwise && s->cases.otherwise != nonmatching) {
|
||||
hash = ((hash << 5) + hash) + 5381;
|
||||
State *k = s->otherwise;
|
||||
hash = ((hash << 5) + hash) + k->trans.size();
|
||||
State *k = s->cases.otherwise;
|
||||
hash = ((hash << 5) + hash) + k->cases.cases.size();
|
||||
}
|
||||
|
||||
hash = (hash << 8) | s->trans.size();
|
||||
hash = (hash << 8) | s->cases.cases.size();
|
||||
return hash;
|
||||
}
|
||||
|
||||
int DFA::apply_and_clear_deny(void)
|
||||
{
|
||||
int c = 0;
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
c += (*i)->apply_and_clear_deny();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* minimize the number of dfa states */
|
||||
void DFA::minimize(dfaflags_t flags)
|
||||
{
|
||||
@@ -447,11 +373,19 @@ void DFA::minimize(dfaflags_t flags)
|
||||
int accept_count = 0;
|
||||
int final_accept = 0;
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
size_t hash = 0;
|
||||
uint64_t permtype = ((uint64_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint64_t) (*i)->perms.allow;
|
||||
uint64_t perm_hash = 0;
|
||||
if (flags & DFA_CONTROL_MINIMIZE_HASH_PERMS) {
|
||||
/* make every unique perm create a new partition */
|
||||
perm_hash = ((uint64_t) (*i)->audit) << 32 |
|
||||
(uint64_t) (*i)->accept;
|
||||
} else if ((*i)->audit || (*i)->accept) {
|
||||
/* combine all perms together into a single parition */
|
||||
perm_hash = 1;
|
||||
} /* else not an accept state so 0 for perm_hash */
|
||||
size_t trans_hash = 0;
|
||||
if (flags & DFA_CONTROL_MINIMIZE_HASH_TRANS)
|
||||
hash |= hash_trans(*i);
|
||||
pair<uint64_t, size_t> group = make_pair(permtype, hash);
|
||||
trans_hash = hash_trans(*i);
|
||||
pair<uint64_t, size_t> group = make_pair(perm_hash, trans_hash);
|
||||
map<pair<uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group);
|
||||
if (p == perm_map.end()) {
|
||||
Partition *part = new Partition();
|
||||
@@ -459,7 +393,7 @@ void DFA::minimize(dfaflags_t flags)
|
||||
perm_map.insert(make_pair(group, part));
|
||||
partitions.push_back(part);
|
||||
(*i)->partition = part;
|
||||
if (permtype)
|
||||
if (perm_hash)
|
||||
accept_count++;
|
||||
} else {
|
||||
(*i)->partition = p->second;
|
||||
@@ -553,11 +487,11 @@ void DFA::minimize(dfaflags_t flags)
|
||||
cerr << *rep << " : ";
|
||||
|
||||
/* update representative state's transitions */
|
||||
if (rep->otherwise != nonmatching) {
|
||||
Partition *partition = rep->otherwise->partition;
|
||||
rep->otherwise = *partition->begin();
|
||||
if (rep->cases.otherwise) {
|
||||
Partition *partition = rep->cases.otherwise->partition;
|
||||
rep->cases.otherwise = *partition->begin();
|
||||
}
|
||||
for (StateTrans::iterator c = rep->trans.begin(); c != rep->trans.end(); c++) {
|
||||
for (Cases::iterator c = rep->cases.begin(); c != rep->cases.end(); c++) {
|
||||
Partition *partition = c->second->partition;
|
||||
c->second = *partition->begin();
|
||||
}
|
||||
@@ -571,9 +505,10 @@ void DFA::minimize(dfaflags_t flags)
|
||||
if (flags & DFA_DUMP_MIN_PARTS)
|
||||
cerr << **i << ", ";
|
||||
(*i)->label = -1;
|
||||
rep->perms.add((*i)->perms);
|
||||
rep->accept |= (*i)->accept;
|
||||
rep->audit |= (*i)->audit;
|
||||
}
|
||||
if (!rep->perms.is_null())
|
||||
if (rep->accept || rep->audit)
|
||||
final_accept++;
|
||||
//if ((*p)->size() > 1)
|
||||
//cerr << "\n";
|
||||
@@ -628,15 +563,13 @@ out:
|
||||
void DFA::dump(ostream & os)
|
||||
{
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if (*i == start || !(*i)->perms.is_null()) {
|
||||
if (*i == start || (*i)->accept) {
|
||||
os << **i;
|
||||
if (*i == start)
|
||||
os << " <== (allow/deny/audit/quiet)";
|
||||
if (!(*i)->perms.is_null()) {
|
||||
os << " (0x " << hex << (*i)->perms.allow << "/"
|
||||
<< (*i)->perms.deny << "/"
|
||||
<< (*i)->perms.audit << "/"
|
||||
<< (*i)->perms.quiet << ')';
|
||||
os << " <==";
|
||||
if ((*i)->accept) {
|
||||
os << " (0x" << hex << (*i)->accept << " "
|
||||
<< (*i)->audit << dec << ')';
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
@@ -644,34 +577,12 @@ void DFA::dump(ostream & os)
|
||||
os << "\n";
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
Chars excluded;
|
||||
|
||||
for (StateTrans::iterator j = (*i)->trans.begin();
|
||||
j != (*i)->trans.end(); j++) {
|
||||
if (j->second == nonmatching) {
|
||||
excluded.insert(j->first);
|
||||
} else {
|
||||
os << **i << " -> " << *(j)->second << ": 0x"
|
||||
<< hex << (int) j->first;
|
||||
if (isprint(j->first))
|
||||
os << " " << j->first;
|
||||
os << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ((*i)->otherwise != nonmatching) {
|
||||
os << **i << " -> " << *(*i)->otherwise << ": [";
|
||||
if (!excluded.empty()) {
|
||||
os << "^";
|
||||
for (Chars::iterator k = excluded.begin();
|
||||
k != excluded.end(); k++) {
|
||||
if (isprint(*k))
|
||||
os << *k;
|
||||
else
|
||||
os << "\\0x" << hex << (int) *k;
|
||||
}
|
||||
}
|
||||
os << "]\n";
|
||||
if ((*i)->cases.otherwise)
|
||||
os << **i << " -> " << (*i)->cases.otherwise << "\n";
|
||||
for (Cases::iterator j = (*i)->cases.begin();
|
||||
j != (*i)->cases.end(); j++) {
|
||||
os << **i << " -> " << j->second << ": "
|
||||
<< j->first << "\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
@@ -692,44 +603,35 @@ void DFA::dump_dot_graph(ostream & os)
|
||||
if (*i == start) {
|
||||
os << "\t\tstyle=bold" << "\n";
|
||||
}
|
||||
if (!(*i)->perms.is_null()) {
|
||||
os << "\t\tlabel=\"" << **i << "\\n(0x " << hex
|
||||
<< (*i)->perms.allow << "/"
|
||||
<< (*i)->perms.deny << "/"
|
||||
<< (*i)->perms.audit << "/"
|
||||
<< (*i)->perms.quiet << ")\"\n";
|
||||
uint32_t perms = (*i)->accept;
|
||||
if (perms) {
|
||||
os << "\t\tlabel=\"" << **i << "\\n("
|
||||
<< perms << ")\"" << "\n";
|
||||
}
|
||||
os << "\t]" << "\n";
|
||||
}
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
Cases &cases = (*i)->cases;
|
||||
Chars excluded;
|
||||
|
||||
for (StateTrans::iterator j = (*i)->trans.begin(); j != (*i)->trans.end(); j++) {
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
if (j->second == nonmatching)
|
||||
excluded.insert(j->first);
|
||||
else {
|
||||
os << "\t\"" << **i << "\" -> \"" << *j->second
|
||||
<< "\" [" << "\n";
|
||||
os << "\t\tlabel=\"";
|
||||
if (isprint(j->first))
|
||||
os << j->first;
|
||||
else
|
||||
os << "\\0xhex" << (int) j->first;
|
||||
|
||||
os << "\"\n\t]" << "\n";
|
||||
os << "\t\tlabel=\"" << j->first << "\"\n";
|
||||
os << "\t]" << "\n";
|
||||
}
|
||||
}
|
||||
if ((*i)->otherwise != nonmatching) {
|
||||
os << "\t\"" << **i << "\" -> \"" << *(*i)->otherwise
|
||||
if (cases.otherwise && cases.otherwise != nonmatching) {
|
||||
os << "\t\"" << **i << "\" -> \"" << *cases.otherwise
|
||||
<< "\" [" << "\n";
|
||||
if (!excluded.empty()) {
|
||||
os << "\t\tlabel=\"[^";
|
||||
for (Chars::iterator i = excluded.begin();
|
||||
i != excluded.end(); i++) {
|
||||
if (isprint(*i))
|
||||
os << *i;
|
||||
else
|
||||
os << "\\0x" << hex << (int) *i;
|
||||
os << *i;
|
||||
}
|
||||
os << "]\"" << "\n";
|
||||
}
|
||||
@@ -749,9 +651,11 @@ map<uchar, uchar> DFA::equivalence_classes(dfaflags_t flags)
|
||||
uchar next_class = 1;
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
Cases & cases = (*i)->cases;
|
||||
|
||||
/* Group edges to the same next state together */
|
||||
map<const State *, Chars> node_sets;
|
||||
for (StateTrans::iterator j = (*i)->trans.begin(); j != (*i)->trans.end(); j++)
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++)
|
||||
node_sets[j->second].insert(j->first);
|
||||
|
||||
for (map<const State *, Chars>::iterator j = node_sets.begin();
|
||||
@@ -838,9 +742,10 @@ void DFA::apply_equivalence_classes(map<uchar, uchar> &eq)
|
||||
*/
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
map<uchar, State *> tmp;
|
||||
tmp.swap((*i)->trans);
|
||||
for (StateTrans::iterator j = tmp.begin(); j != tmp.end(); j++)
|
||||
(*i)->trans.insert(make_pair(eq[j->first], j->second));
|
||||
tmp.swap((*i)->cases.cases);
|
||||
for (Cases::iterator j = tmp.begin(); j != tmp.end(); j++)
|
||||
(*i)->cases.cases.
|
||||
insert(make_pair(eq[j->first], j->second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,66 +789,81 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
|
||||
* have any exact matches, then they override the execute and safe
|
||||
* execute flags.
|
||||
*/
|
||||
int accept_perms(NodeSet *state, perms_t &perms)
|
||||
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
|
||||
{
|
||||
int error = 0;
|
||||
uint32_t exact_match_allow = 0;
|
||||
uint32_t exact_audit = 0;
|
||||
|
||||
perms.clear();
|
||||
|
||||
if (!state)
|
||||
return error;
|
||||
uint32_t perms = 0, exact_match_perms = 0;
|
||||
uint32_t audit = 0, exact_audit = 0, quiet = 0, deny = 0;
|
||||
|
||||
if (error)
|
||||
*error = 0;
|
||||
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
||||
MatchFlag *match;
|
||||
if (!(match = dynamic_cast<MatchFlag *>(*i)))
|
||||
continue;
|
||||
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
||||
/* exact match only ever happens with x */
|
||||
if (!is_merged_x_consistent(exact_match_allow,
|
||||
match->flag))
|
||||
error = 1;;
|
||||
exact_match_allow |= match->flag;
|
||||
if (!is_merged_x_consistent(exact_match_perms,
|
||||
match->flag) && error)
|
||||
*error = 1;;
|
||||
exact_match_perms |= match->flag;
|
||||
exact_audit |= match->audit;
|
||||
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
|
||||
perms.deny |= match->flag;
|
||||
perms.quiet |= match->audit;
|
||||
deny |= match->flag;
|
||||
quiet |= match->audit;
|
||||
} else {
|
||||
if (!is_merged_x_consistent(perms.allow, match->flag))
|
||||
error = 1;
|
||||
perms.allow |= match->flag;
|
||||
perms.audit |= match->audit;
|
||||
if (!is_merged_x_consistent(perms, match->flag)
|
||||
&& error)
|
||||
*error = 1;
|
||||
perms |= match->flag;
|
||||
audit |= match->audit;
|
||||
}
|
||||
}
|
||||
|
||||
perms.allow |= exact_match_allow & ~(ALL_AA_EXEC_TYPE);
|
||||
//if (audit || quiet)
|
||||
//fprintf(stderr, "perms: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", perms, audit, exact_match_perms, exact_audit, deny, quiet);
|
||||
|
||||
if (exact_match_allow & AA_USER_EXEC_TYPE) {
|
||||
perms.allow = (exact_match_allow & AA_USER_EXEC_TYPE) |
|
||||
(perms.allow & ~AA_USER_EXEC_TYPE);
|
||||
perms.audit = (exact_audit & AA_USER_EXEC_TYPE) |
|
||||
(perms.audit & ~AA_USER_EXEC_TYPE);
|
||||
perms.exact = AA_USER_EXEC_TYPE;
|
||||
perms |= exact_match_perms & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
|
||||
|
||||
if (exact_match_perms & AA_USER_EXEC_TYPE) {
|
||||
perms = (exact_match_perms & AA_USER_EXEC_TYPE) |
|
||||
(perms & ~AA_USER_EXEC_TYPE);
|
||||
audit = (exact_audit & AA_USER_EXEC_TYPE) |
|
||||
(audit & ~AA_USER_EXEC_TYPE);
|
||||
}
|
||||
if (exact_match_allow & AA_OTHER_EXEC_TYPE) {
|
||||
perms.allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) |
|
||||
(perms.allow & ~AA_OTHER_EXEC_TYPE);
|
||||
perms.audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
|
||||
(perms.audit & ~AA_OTHER_EXEC_TYPE);
|
||||
perms.exact |= AA_OTHER_EXEC_TYPE;
|
||||
if (exact_match_perms & AA_OTHER_EXEC_TYPE) {
|
||||
perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) |
|
||||
(perms & ~AA_OTHER_EXEC_TYPE);
|
||||
audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
|
||||
(audit & ~AA_OTHER_EXEC_TYPE);
|
||||
}
|
||||
if (AA_USER_EXEC & perms.deny)
|
||||
perms.deny |= AA_USER_EXEC_TYPE;
|
||||
if (perms & AA_USER_EXEC & deny)
|
||||
perms &= ~AA_USER_EXEC_TYPE;
|
||||
|
||||
if (AA_OTHER_EXEC & perms.deny)
|
||||
perms.deny |= AA_OTHER_EXEC_TYPE;
|
||||
if (perms & AA_OTHER_EXEC & deny)
|
||||
perms &= ~AA_OTHER_EXEC_TYPE;
|
||||
|
||||
perms.allow &= ~perms.deny;
|
||||
perms.quiet &= perms.deny;
|
||||
perms &= ~deny;
|
||||
|
||||
if (error)
|
||||
if (audit_ctl)
|
||||
*audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny);
|
||||
|
||||
// if (perms & AA_ERROR_BIT) {
|
||||
// fprintf(stderr, "error bit 0x%x\n", perms);
|
||||
// exit(255);
|
||||
//}
|
||||
|
||||
//if (perms & AA_EXEC_BITS)
|
||||
//fprintf(stderr, "accept perm: 0x%x\n", perms);
|
||||
/*
|
||||
if (perms & ~AA_VALID_PERMS)
|
||||
yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), perms);
|
||||
*/
|
||||
|
||||
//if (perms & AA_CHANGE_HAT)
|
||||
// fprintf(stderr, "change_hat 0x%x\n", perms);
|
||||
|
||||
if (*error)
|
||||
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
|
||||
|
||||
return error;
|
||||
return perms;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2010 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -33,291 +33,28 @@
|
||||
#include "expr-tree.h"
|
||||
|
||||
class State;
|
||||
/**
|
||||
* State cases are identical to NodesCases except they map to State *
|
||||
* instead of NodeSet.
|
||||
* Out-edges from a state to another: we store the follow State
|
||||
* for each input character that is not a default match in cases and
|
||||
* default matches in otherwise as well as in all matching explicit cases
|
||||
* This avoids enumerating all the explicit tranitions for default matches.
|
||||
*/
|
||||
typedef struct Cases {
|
||||
typedef map<uchar, State *>::iterator iterator;
|
||||
iterator begin() { return cases.begin(); }
|
||||
iterator end() { return cases.end(); }
|
||||
|
||||
Cases(): otherwise(0) { }
|
||||
|
||||
map<uchar, State *> cases;
|
||||
State *otherwise;
|
||||
} Cases;
|
||||
|
||||
typedef map<uchar, State *> StateTrans;
|
||||
typedef list<State *> Partition;
|
||||
|
||||
#include "../immunix.h"
|
||||
|
||||
class perms_t {
|
||||
public:
|
||||
perms_t(void) throw(int): allow(0), deny(0), audit(0), quiet(0), exact(0) { };
|
||||
|
||||
bool is_null(void) { return !(allow | deny | audit | quiet); }
|
||||
|
||||
void clear(void) { allow = deny = audit = quiet = 0; }
|
||||
void add(perms_t &rhs)
|
||||
{
|
||||
deny |= rhs.deny;
|
||||
|
||||
if (!is_merged_x_consistent(allow & ALL_USER_EXEC,
|
||||
rhs.allow & ALL_USER_EXEC)) {
|
||||
if ((exact & AA_USER_EXEC_TYPE) &&
|
||||
!(rhs.exact & AA_USER_EXEC_TYPE)) {
|
||||
/* do nothing */
|
||||
} else if ((rhs.exact & AA_USER_EXEC_TYPE) &&
|
||||
!(exact & AA_USER_EXEC_TYPE)) {
|
||||
allow = (allow & ~AA_USER_EXEC_TYPE) |
|
||||
(rhs.allow & AA_USER_EXEC_TYPE);
|
||||
} else
|
||||
throw 1;
|
||||
} else
|
||||
allow |= rhs.allow & AA_USER_EXEC_TYPE;
|
||||
|
||||
if (!is_merged_x_consistent(allow & ALL_OTHER_EXEC,
|
||||
rhs.allow & ALL_OTHER_EXEC)) {
|
||||
if ((exact & AA_OTHER_EXEC_TYPE) &&
|
||||
!(rhs.exact & AA_OTHER_EXEC_TYPE)) {
|
||||
/* do nothing */
|
||||
} else if ((rhs.exact & AA_OTHER_EXEC_TYPE) &&
|
||||
!(exact & AA_OTHER_EXEC_TYPE)) {
|
||||
allow = (allow & ~AA_OTHER_EXEC_TYPE) |
|
||||
(rhs.allow & AA_OTHER_EXEC_TYPE);
|
||||
} else
|
||||
throw 1;
|
||||
} else
|
||||
allow |= rhs.allow & AA_OTHER_EXEC_TYPE;
|
||||
|
||||
|
||||
allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE));
|
||||
audit |= rhs.audit;
|
||||
quiet = (quiet | rhs.quiet);
|
||||
|
||||
/*
|
||||
if (exec & AA_USER_EXEC_TYPE &&
|
||||
(exec & AA_USER_EXEC_TYPE) != (allow & AA_USER_EXEC_TYPE))
|
||||
throw 1;
|
||||
if (exec & AA_OTHER_EXEC_TYPE &&
|
||||
(exec & AA_OTHER_EXEC_TYPE) != (allow & AA_OTHER_EXEC_TYPE))
|
||||
throw 1;
|
||||
*/
|
||||
}
|
||||
|
||||
int apply_and_clear_deny(void)
|
||||
{
|
||||
if (deny) {
|
||||
allow &= ~deny;
|
||||
quiet &= deny;
|
||||
deny = 0;
|
||||
return is_null();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator<(perms_t const &rhs)const
|
||||
{
|
||||
if (allow < rhs.allow)
|
||||
return allow < rhs.allow;
|
||||
if (deny < rhs.deny)
|
||||
return deny < rhs.deny;
|
||||
if (audit < rhs.audit)
|
||||
return audit < rhs.audit;
|
||||
return quiet < rhs.quiet;
|
||||
}
|
||||
|
||||
uint32_t allow, deny, audit, quiet, exact;
|
||||
};
|
||||
|
||||
int accept_perms(NodeSet *state, perms_t &perms);
|
||||
|
||||
/*
|
||||
* hashedNodes - for efficient set comparison
|
||||
*/
|
||||
class hashedNodeSet {
|
||||
public:
|
||||
unsigned long hash;
|
||||
NodeSet *nodes;
|
||||
|
||||
hashedNodeSet(NodeSet *n): nodes(n)
|
||||
{
|
||||
hash = hash_NodeSet(n);
|
||||
}
|
||||
|
||||
bool operator<(hashedNodeSet const &rhs)const
|
||||
{
|
||||
if (hash == rhs.hash) {
|
||||
if (nodes->size() == rhs.nodes->size())
|
||||
return *nodes < *(rhs.nodes);
|
||||
else
|
||||
return nodes->size() < rhs.nodes->size();
|
||||
} else {
|
||||
return hash < rhs.hash;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class hashedNodeVec {
|
||||
public:
|
||||
typedef ImportantNode ** iterator;
|
||||
iterator begin() { return nodes; }
|
||||
iterator end() { iterator t = nodes ? &nodes[len] : NULL; return t; }
|
||||
|
||||
unsigned long hash;
|
||||
unsigned long len;
|
||||
ImportantNode **nodes;
|
||||
|
||||
hashedNodeVec(NodeSet *n)
|
||||
{
|
||||
hash = hash_NodeSet(n);
|
||||
len = n->size();
|
||||
nodes = new ImportantNode *[n->size()];
|
||||
|
||||
unsigned int j = 0;
|
||||
for (NodeSet::iterator i = n->begin(); i != n->end(); i++, j++) {
|
||||
nodes[j] = *i;
|
||||
}
|
||||
}
|
||||
|
||||
hashedNodeVec(NodeSet *n, unsigned long h): hash(h)
|
||||
{
|
||||
len = n->size();
|
||||
nodes = new ImportantNode *[n->size()];
|
||||
ImportantNode **j = nodes;
|
||||
for (NodeSet::iterator i = n->begin(); i != n->end(); i++) {
|
||||
*(j++) = *i;
|
||||
}
|
||||
}
|
||||
|
||||
~hashedNodeVec()
|
||||
{
|
||||
delete nodes;
|
||||
}
|
||||
|
||||
unsigned long size()const { return len; }
|
||||
|
||||
bool operator<(hashedNodeVec const &rhs)const
|
||||
{
|
||||
if (hash == rhs.hash) {
|
||||
if (len == rhs.size()) {
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
if (nodes[i] != rhs.nodes[i])
|
||||
return nodes[i] < rhs.nodes[i];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return len < rhs.size();
|
||||
}
|
||||
return hash < rhs.hash;
|
||||
}
|
||||
};
|
||||
|
||||
class CacheStats {
|
||||
public:
|
||||
unsigned long dup, sum, max;
|
||||
|
||||
CacheStats(void): dup(0), sum(0), max(0) { };
|
||||
|
||||
void clear(void) { dup = sum = max = 0; }
|
||||
virtual unsigned long size(void) const = 0;
|
||||
};
|
||||
|
||||
class NodeCache: public CacheStats {
|
||||
public:
|
||||
set<hashedNodeSet> cache;
|
||||
|
||||
NodeCache(void): cache() { };
|
||||
~NodeCache() { clear(); };
|
||||
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (set<hashedNodeSet>::iterator i = cache.begin();
|
||||
i != cache.end(); i++) {
|
||||
delete i->nodes;
|
||||
}
|
||||
cache.clear();
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
NodeSet *insert(NodeSet *nodes)
|
||||
{
|
||||
if (!nodes)
|
||||
return NULL;
|
||||
pair<set<hashedNodeSet>::iterator,bool> uniq;
|
||||
uniq = cache.insert(hashedNodeSet(nodes));
|
||||
if (uniq.second == false) {
|
||||
delete(nodes);
|
||||
dup++;
|
||||
} else {
|
||||
sum += nodes->size();
|
||||
if (nodes->size() > max)
|
||||
max = nodes->size();
|
||||
}
|
||||
return uniq.first->nodes;
|
||||
}
|
||||
};
|
||||
|
||||
struct deref_less_than {
|
||||
bool operator()(hashedNodeVec * const &lhs, hashedNodeVec * const &rhs)const
|
||||
{
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
|
||||
class NodeVecCache: public CacheStats {
|
||||
public:
|
||||
set<hashedNodeVec *, deref_less_than> cache;
|
||||
|
||||
NodeVecCache(void): cache() { };
|
||||
~NodeVecCache() { clear(); };
|
||||
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (set<hashedNodeVec *>::iterator i = cache.begin();
|
||||
i != cache.end(); i++) {
|
||||
delete *i;
|
||||
}
|
||||
cache.clear();
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
hashedNodeVec *insert(NodeSet *nodes)
|
||||
{
|
||||
if (!nodes)
|
||||
return NULL;
|
||||
pair<set<hashedNodeVec *>::iterator,bool> uniq;
|
||||
hashedNodeVec *nv = new hashedNodeVec(nodes);
|
||||
uniq = cache.insert(nv);
|
||||
if (uniq.second == false) {
|
||||
delete nv;
|
||||
dup++;
|
||||
} else {
|
||||
sum += nodes->size();
|
||||
if (nodes->size() > max)
|
||||
max = nodes->size();
|
||||
}
|
||||
delete(nodes);
|
||||
return (*uniq.first);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ProtoState - NodeSet and ancillery information used to create a state
|
||||
*/
|
||||
class ProtoState {
|
||||
public:
|
||||
hashedNodeVec *nnodes;
|
||||
NodeSet *anodes;
|
||||
|
||||
ProtoState(hashedNodeVec *n, NodeSet *a = NULL): nnodes(n), anodes(a) { };
|
||||
bool operator<(ProtoState const &rhs)const
|
||||
{
|
||||
if (nnodes == rhs.nnodes)
|
||||
return anodes < rhs.anodes;
|
||||
return nnodes < rhs.nnodes;
|
||||
}
|
||||
|
||||
unsigned long size(void)
|
||||
{
|
||||
if (anodes)
|
||||
return nnodes->size() + anodes->size();
|
||||
return nnodes->size();
|
||||
}
|
||||
};
|
||||
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
|
||||
|
||||
/*
|
||||
* State - DFA individual state information
|
||||
@@ -326,8 +63,7 @@ public:
|
||||
* the start state is setup to have label == 1
|
||||
* audit: the audit permission mask for the state
|
||||
* accept: the accept permissions for the state
|
||||
* trans: set of transitions from this state
|
||||
* otherwise: the default state for transitions not in @trans
|
||||
* cases: set of transitions from this state
|
||||
* parition: Is a temporary work variable used during dfa minimization.
|
||||
* it can be replaced with a map, but that is slower and uses more
|
||||
* memory.
|
||||
@@ -336,110 +72,62 @@ public:
|
||||
*/
|
||||
class State {
|
||||
public:
|
||||
State(int l, ProtoState &n, State *other) throw(int):
|
||||
label(l), perms(), trans()
|
||||
State(): label(0), audit(0), accept(0), cases(), nodes(NULL) { };
|
||||
State(int l): label(l), audit(0), accept(0), cases(), nodes(NULL) { };
|
||||
State(int l, NodeSet * n) throw(int):
|
||||
label(l), audit(0), accept(0), cases(), nodes(n)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (other)
|
||||
otherwise = other;
|
||||
else
|
||||
otherwise = this;
|
||||
|
||||
proto = n;
|
||||
|
||||
/* Compute permissions associated with the State. */
|
||||
error = accept_perms(n.anodes, perms);
|
||||
accept = accept_perms(nodes, &audit, &error);
|
||||
if (error) {
|
||||
//cerr << "Failing on accept perms " << error << "\n";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
State *next(uchar c) {
|
||||
StateTrans::iterator i = trans.find(c);
|
||||
if (i != trans.end())
|
||||
return i->second;
|
||||
return otherwise;
|
||||
};
|
||||
|
||||
int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
|
||||
|
||||
int label;
|
||||
perms_t perms;
|
||||
StateTrans trans;
|
||||
State *otherwise;
|
||||
|
||||
/* temp storage for State construction */
|
||||
uint32_t audit, accept;
|
||||
Cases cases;
|
||||
union {
|
||||
Partition *partition;
|
||||
ProtoState proto;
|
||||
NodeSet *nodes;
|
||||
};
|
||||
};
|
||||
|
||||
ostream &operator<<(ostream &os, const State &state);
|
||||
|
||||
class NodeMap: public CacheStats
|
||||
{
|
||||
public:
|
||||
typedef map<ProtoState, State *>::iterator iterator;
|
||||
iterator begin() { return cache.begin(); }
|
||||
iterator end() { return cache.end(); }
|
||||
|
||||
map<ProtoState, State *> cache;
|
||||
|
||||
NodeMap(void): cache() { };
|
||||
~NodeMap() { clear(); };
|
||||
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
cache.clear();
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
pair<iterator,bool> insert(ProtoState &proto, State *state)
|
||||
{
|
||||
pair<iterator,bool> uniq;
|
||||
uniq = cache.insert(make_pair(proto, state));
|
||||
if (uniq.second == false) {
|
||||
dup++;
|
||||
} else {
|
||||
sum += proto.size();
|
||||
if (proto.size() > max)
|
||||
max = proto.size();
|
||||
}
|
||||
return uniq;
|
||||
}
|
||||
};
|
||||
|
||||
typedef map<pair<unsigned long, NodeSet *>, State *, deref_less_than> NodeMap;
|
||||
/* Transitions in the DFA. */
|
||||
|
||||
/* dfa_stats - structure to group various stats about dfa creation
|
||||
* duplicates - how many duplicate NodeSets where encountered and discarded
|
||||
* proto_max - maximum length of a NodeSet encountered during dfa construction
|
||||
* proto_sum - sum of NodeSet length during dfa construction. Used to find
|
||||
* average length.
|
||||
*/
|
||||
typedef struct dfa_stats {
|
||||
unsigned int duplicates, proto_max, proto_sum;
|
||||
} dfa_stats_t;
|
||||
|
||||
class DFA {
|
||||
void dump_node_to_dfa(void);
|
||||
State *add_new_state(NodeSet *nodes, State *other);
|
||||
void update_state_transitions(State *state);
|
||||
|
||||
/* temporary values used during computations */
|
||||
NodeCache anodes_cache;
|
||||
NodeVecCache nnodes_cache;
|
||||
NodeMap node_map;
|
||||
list<State *> work_queue;
|
||||
|
||||
State *add_new_state(NodeMap &nodemap,
|
||||
pair<unsigned long, NodeSet *> index,
|
||||
NodeSet *nodes, dfa_stats_t &stats);
|
||||
void update_state_transitions(NodeMap &nodemap,
|
||||
list<State *> &work_queue,
|
||||
State *state, dfa_stats_t &stats);
|
||||
State *find_target_state(NodeMap &nodemap, list<State *> &work_queue,
|
||||
NodeSet *nodes, dfa_stats_t &stats);
|
||||
public:
|
||||
DFA(Node *root, dfaflags_t flags);
|
||||
virtual ~DFA();
|
||||
|
||||
State *match_len(State *state, const char *str, size_t len);
|
||||
State *match_until(State *state, const char *str, const char term);
|
||||
State *match(const char *str);
|
||||
|
||||
void remove_unreachable(dfaflags_t flags);
|
||||
bool same_mappings(State *s1, State *s2);
|
||||
size_t hash_trans(State *s);
|
||||
void minimize(dfaflags_t flags);
|
||||
int apply_and_clear_deny(void);
|
||||
void dump(ostream &os);
|
||||
void dump_dot_graph(ostream &os);
|
||||
void dump_uniq_perms(const char *s);
|
||||
|
@@ -169,7 +169,7 @@ int hexdigit(char c)
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return 10 + c - 'A';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return 10 + c - 'a';
|
||||
return 10 + c - 'A';
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
506
parser/mount.c
506
parser/mount.c
@@ -1,506 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The mount command, its mix of options and flags, its permissions and
|
||||
* mapping are a mess.
|
||||
* mount [-lhV]
|
||||
*
|
||||
* mount -a [-fFnrsvw] [-t vfstype] [-O optlist]
|
||||
*
|
||||
* mount [-fnrsvw] [-o option[,option]...] device|dir
|
||||
*
|
||||
* mount [-fnrsvw] [-t vfstype] [-o options] device dir
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* Mount flags of no interest for apparmor mediation
|
||||
* -a, --all
|
||||
* -F fork for simultaneous mount
|
||||
* -f fake, do everything except that actual system call
|
||||
* -h --help
|
||||
* -i, --internal-only
|
||||
* -n mount without writing in /etc/mtab
|
||||
* -O <optlist> limits what is auto mounted
|
||||
* -p, --pass-fd num
|
||||
* -s Tolerate sloppy mount options
|
||||
* -U uuid
|
||||
* -V --version
|
||||
* --no-canonicalize
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* what do we do with these
|
||||
* -l list?
|
||||
* -L <label> label
|
||||
* -v --verbose deprecated
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* Filesystem type
|
||||
* -t <vfstype>
|
||||
* vfstype=<vfstype>
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* Mount Flags/options (-o --options)
|
||||
* -o option[,option]
|
||||
*
|
||||
* The Linux kernel has 32 fs - independent mount flags, that mount command
|
||||
* is responsible for stripping out and mapping to a 32 bit flags field.
|
||||
* The mount commands mapping is documented below.
|
||||
*
|
||||
* Unfortunately we can not directly use this mapping as we need to be able
|
||||
* represent, whether none, 1 or both options of a flag can be present for
|
||||
* example
|
||||
* ro, and rw information is stored in a single bit. But we need 2 bits
|
||||
* of information.
|
||||
* ro - the mount can only be readonly
|
||||
* rw - the mount can only be rw
|
||||
* ro/rw - the mount can be either ro/rw
|
||||
* the fourth state of neither ro/rw does not exist, but still we need
|
||||
* >1 bit to represent the possible choices
|
||||
*
|
||||
* The fs specific mount options are passed into the kernel as a string
|
||||
* to be interpreted by the filesystem.
|
||||
*
|
||||
*
|
||||
* #define MS_RDONLY 1 Mount read-only
|
||||
* ro -r --read-only [source] dest
|
||||
* rw -w
|
||||
* #define MS_NOSUID 2 Ignore suid and sgid bits
|
||||
* nosuid
|
||||
* suid
|
||||
* #define MS_NODEV 4 Disallow access to device special files
|
||||
* nodev
|
||||
* dev
|
||||
* #define MS_NOEXEC 8 Disallow program execution
|
||||
* noexec
|
||||
* exec
|
||||
* #define MS_SYNCHRONOUS 16 Writes are synced at once
|
||||
* sync
|
||||
* async
|
||||
* #define MS_REMOUNT 32 Alter flags of a mounted FS
|
||||
* remount source dest
|
||||
* #define MS_MANDLOCK 64 Allow mandatory locks on an FS
|
||||
* mand
|
||||
* nomand
|
||||
* #define MS_DIRSYNC 128 Directory modifications are synchronous
|
||||
* dirsync
|
||||
* #define MS_NOATIME 1024 Do not update access times
|
||||
* noatime
|
||||
* atime
|
||||
* #define MS_NODIRATIME 2048 Do not update directory access times
|
||||
* nodiratime
|
||||
* diratime
|
||||
* #define MS_BIND 4096
|
||||
* --bind -B source dest
|
||||
* #define MS_MOVE 8192
|
||||
* --move -M source dest
|
||||
* #define MS_REC 16384
|
||||
* --rbind -R source dest
|
||||
* --make-rshared dest
|
||||
* --make-rslave dest
|
||||
* --make-rprivate dest
|
||||
* --make-runbindable dest
|
||||
* #define MS_VERBOSE 32768 MS_VERBOSE is deprecated
|
||||
* #define MS_SILENT 32768
|
||||
* silent
|
||||
* load
|
||||
* #define MS_POSIXACL (1<<16) VFS does not apply the umask
|
||||
* acl
|
||||
* noacl
|
||||
* #define MS_UNBINDABLE (1<<17) change to unbindable
|
||||
* --make-unbindable dest
|
||||
* #define MS_PRIVATE (1<<18) change to private
|
||||
* --make-private dest
|
||||
* #define MS_SLAVE (1<<19) change to slave
|
||||
* --make-slave dest
|
||||
* #define MS_SHARED (1<<20) change to shared
|
||||
* --make-shared dest
|
||||
* #define MS_RELATIME (1<<21) Update atime relative to mtime/ctime
|
||||
* relatime
|
||||
* norelatime
|
||||
* #define MS_KERNMOUNT (1<<22) this is a kern_mount call
|
||||
* #define MS_I_VERSION (1<<23) Update inode I_version field
|
||||
* iversion
|
||||
* noiversion
|
||||
* #define MS_STRICTATIME (1<<24) Always perform atime updates
|
||||
* strictatime
|
||||
* nostrictatime
|
||||
* #define MS_NOSEC (1<<28)
|
||||
* #define MS_BORN (1<<29)
|
||||
* #define MS_ACTIVE (1<<30)
|
||||
* #define MS_NOUSER (1<<31)
|
||||
* nouser
|
||||
* user
|
||||
*
|
||||
* other mount options of interest
|
||||
*
|
||||
* selinux
|
||||
* context=<context>
|
||||
* fscontext=<context>
|
||||
* defcontext=<context>,
|
||||
* rootcontext=<context>
|
||||
*
|
||||
* defaults -> rw, suid, dev, exec, auto, nouser, async
|
||||
* owner -> implies nosuid and nodev
|
||||
* users -> implies noexec, nosuid, and nodev
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* AppArmor mount rules
|
||||
*
|
||||
* AppArmor mount rules try to leverage mount syntax within apparmor syntax
|
||||
* this can not be done entirely but it is largely covered.
|
||||
*
|
||||
* The general mount syntax is
|
||||
* [audit] [deny] [owner] mount [conds]* [source] [ -> [conds] path],
|
||||
* [audit] [deny] remount [conds]* [path],
|
||||
* [audit] [deny] umount [conds]* [path],
|
||||
*
|
||||
* Note: leading owner option applies owner condition to both sours and dest
|
||||
* path.
|
||||
*
|
||||
* where [conds] can be
|
||||
* fstype=<expr>
|
||||
* options=<expr>
|
||||
* owner[=<expr>]
|
||||
*
|
||||
* <expr> := <re> | '(' (<re>[,])+ ')'
|
||||
*
|
||||
* If a condition is not specified then it is assumed to match all possible
|
||||
* entries for it. ie. a missing fstype means all fstypes are matched.
|
||||
* However if a condition is specified then the rule only grants permission
|
||||
* for mounts matching the specified pattern.
|
||||
*
|
||||
* Examples.
|
||||
* mount, # allow any mount
|
||||
* mount /dev/foo, # allow mounting of /dev/foo anywhere
|
||||
* mount options=ro /dev/foo, #allow mounting /dev/foo as read only
|
||||
* mount options=(ro,foo) /dev/foo,
|
||||
* mount options=ro options=foo /dev/foo,
|
||||
* mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) overlay -> /mnt/
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* pivotroot
|
||||
* pivotroot [oldroot=<value>] <path> -> <profile>
|
||||
* pivotroot <path> -> { }
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* chroot
|
||||
* chroot <path> -> <profile>
|
||||
* chroot <path> -> { }
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
* AppArmor mount rule encoding
|
||||
*
|
||||
* TODO:
|
||||
* add semantic checking of options against specified filesytem types
|
||||
* to catch mount options that can't be covered.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "mount.h"
|
||||
|
||||
struct mnt_keyword_table {
|
||||
char *keyword;
|
||||
unsigned int set;
|
||||
unsigned int clear;
|
||||
};
|
||||
|
||||
static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"ro", MS_RDONLY, 0},
|
||||
{"r", MS_RDONLY, 0},
|
||||
{"read-only", MS_RDONLY, 0},
|
||||
{"rw", 0, MS_RDONLY},
|
||||
{"w", 0, MS_RDONLY},
|
||||
{"suid", 0, MS_NOSUID},
|
||||
{"nosuid", MS_NOSUID, 0},
|
||||
{"dev", 0, MS_NODEV},
|
||||
{"nodev", MS_NODEV, 0},
|
||||
{"exec", 0, MS_NOEXEC},
|
||||
{"noexec", MS_NOEXEC, 0},
|
||||
{"sync", MS_SYNC, 0},
|
||||
{"async", 0, MS_SYNC},
|
||||
{"remount", MS_REMOUNT, 0},
|
||||
{"mand", MS_MAND, 0},
|
||||
{"nomand", 0, MS_MAND},
|
||||
{"dirsync", MS_DIRSYNC, 0},
|
||||
{"atime", 0, MS_NOATIME},
|
||||
{"noatime", MS_NOATIME, 0},
|
||||
{"diratime", 0, MS_NODIRATIME},
|
||||
{"nodiratime", MS_NODIRATIME, 0},
|
||||
{"bind", MS_BIND, 0},
|
||||
{"B", MS_BIND, 0},
|
||||
{"move", MS_MOVE, 0},
|
||||
{"M", MS_MOVE, 0},
|
||||
{"rbind", MS_RBIND, 0},
|
||||
{"R", MS_RBIND, 0},
|
||||
{"verbose", MS_VERBOSE, 0},
|
||||
{"silent", MS_SILENT, 0},
|
||||
{"load", 0, MS_SILENT},
|
||||
{"acl", MS_ACL, 0},
|
||||
{"noacl", 0, MS_ACL},
|
||||
{"make-unbindable", MS_UNBINDABLE, 0},
|
||||
{"make-runbindable", MS_RUNBINDABLE, 0},
|
||||
{"make-private", MS_PRIVATE, 0},
|
||||
{"make-rprivate", MS_RPRIVATE, 0},
|
||||
{"make-slave", MS_SLAVE, 0},
|
||||
{"make-rslave", MS_RSLAVE, 0},
|
||||
{"make-shared", MS_SHARED, 0},
|
||||
{"make-rshared", MS_RSHARED, 0},
|
||||
|
||||
{"relatime", MS_RELATIME, 0},
|
||||
{"norelatime", 0, MS_NORELATIME},
|
||||
{"iversion", MS_IVERSION, 0},
|
||||
{"noiversion", 0, MS_IVERSION},
|
||||
{"strictatime", MS_STRICTATIME, 0},
|
||||
{"user", 0, MS_NOUSER},
|
||||
{"nouser", MS_NOUSER, 0},
|
||||
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static struct mnt_keyword_table mnt_conds_table[] = {
|
||||
{"options", MNT_SRC_OPT, MNT_COND_OPTIONS},
|
||||
{"option", MNT_SRC_OPT, MNT_COND_OPTIONS},
|
||||
{"fstype", MNT_SRC_OPT | MNT_DST_OPT, MNT_COND_FSTYPE},
|
||||
{"vfstype", MNT_SRC_OPT | MNT_DST_OPT, MNT_COND_FSTYPE},
|
||||
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static int find_mnt_keyword(struct mnt_keyword_table *table, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; table[i].keyword; i++) {
|
||||
if (strcmp(name, table[i].keyword) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int is_valid_mnt_cond(const char *name, int src)
|
||||
{
|
||||
int i;
|
||||
i = find_mnt_keyword(mnt_conds_table, name);
|
||||
if (i != -1)
|
||||
return (mnt_conds_table[i].set & src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
*inv = 0;
|
||||
|
||||
struct value_list *entry, *tmp, *prev = NULL;
|
||||
list_for_each_safe(*list, entry, tmp) {
|
||||
int i;
|
||||
i = find_mnt_keyword(mnt_opts_table, entry->value);
|
||||
if (i != -1) {
|
||||
flags |= mnt_opts_table[i].set;
|
||||
*inv |= mnt_opts_table[i].clear;
|
||||
PDEBUG(" extracting mount flag %s req: 0x%x inv: 0x%x"
|
||||
" => req: 0x%x inv: 0x%x\n",
|
||||
entry->value, mnt_opts_table[i].set,
|
||||
mnt_opts_table[i].clear, flags, *inv);
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *list)
|
||||
*list = tmp;
|
||||
entry->next = NULL;
|
||||
free_value_list(entry);
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
|
||||
struct cond_entry *entry, *tmp, *prev = NULL;
|
||||
|
||||
list_for_each_safe(*conds, entry, tmp) {
|
||||
if (strcmp(entry->name, "fstype") == 0 ||
|
||||
strcmp(entry->name, "vfstype") == 0) {
|
||||
PDEBUG(" extracting fstype\n");
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *conds)
|
||||
*conds = tmp;
|
||||
entry->next = NULL;
|
||||
list_append(entry->vals, list);
|
||||
list = entry->vals;
|
||||
entry->vals = NULL;
|
||||
free_cond_entry(entry);
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct value_list *extract_options(struct cond_entry **conds)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
|
||||
struct cond_entry *entry, *tmp, *prev = NULL;
|
||||
|
||||
list_for_each_safe(*conds, entry, tmp) {
|
||||
if (strcmp(entry->name, "options") == 0 ||
|
||||
strcmp(entry->name, "option") == 0) {
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *conds)
|
||||
*conds = tmp;
|
||||
entry->next = NULL;
|
||||
PDEBUG(" extracting option %s\n", entry->name);
|
||||
list_append(entry->vals, list);
|
||||
list = entry->vals;
|
||||
entry->vals = NULL;
|
||||
free_cond_entry(entry);
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
struct mnt_entry *new_mnt_entry(struct cond_entry *src_conds, char *device,
|
||||
struct cond_entry *dst_conds __unused, char *mnt_point,
|
||||
int allow)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
|
||||
struct mnt_entry *ent;
|
||||
ent = (struct mnt_entry *) calloc(1, sizeof(struct mnt_entry));
|
||||
if (ent) {
|
||||
ent->mnt_point = mnt_point;
|
||||
ent->device = device;
|
||||
ent->dev_type = extract_fstype(&src_conds);
|
||||
|
||||
ent->flags = 0;
|
||||
|
||||
if (src_conds) {
|
||||
ent->opts = extract_options(&src_conds);
|
||||
if (ent->opts)
|
||||
ent->flags = extract_flags(&ent->opts,
|
||||
&ent->inv_flags);
|
||||
}
|
||||
|
||||
if (allow & AA_DUMMY_REMOUNT) {
|
||||
allow = AA_MAY_MOUNT;
|
||||
ent->flags |= MS_REMOUNT;
|
||||
ent->inv_flags = 0;
|
||||
} else if (!(ent->flags | ent->inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
ent->flags = 0xffffffff;
|
||||
ent->inv_flags = 0xffffffff;
|
||||
}
|
||||
|
||||
ent->allow = allow;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
void free_mnt_entry(struct mnt_entry *ent)
|
||||
{
|
||||
if (!ent)
|
||||
return;
|
||||
|
||||
free_mnt_entry(ent->next);
|
||||
free_value_list(ent->opts);
|
||||
free_value_list(ent->dev_type);
|
||||
free(ent->device);
|
||||
free(ent->mnt_point);
|
||||
free(ent->trans);
|
||||
|
||||
free(ent);
|
||||
}
|
||||
|
||||
|
||||
struct mnt_entry *dup_mnt_entry(struct mnt_entry *orig)
|
||||
{
|
||||
struct mnt_entry *entry = NULL;
|
||||
|
||||
entry = (struct mnt_entry *) calloc(1, sizeof(struct mnt_entry));
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->mnt_point = orig->mnt_point ? strdup(orig->mnt_point) : NULL;
|
||||
entry->device = orig->device ? strdup(orig->device) : NULL;
|
||||
entry->trans = orig->trans ? strdup(orig->trans) : NULL;
|
||||
|
||||
entry->dev_type = dup_value_list(orig->dev_type);
|
||||
entry->opts = dup_value_list(orig->opts);
|
||||
|
||||
entry->flags = orig->flags;
|
||||
entry->inv_flags = orig->inv_flags;
|
||||
|
||||
entry->allow = orig->allow;
|
||||
entry->audit = orig->audit;
|
||||
entry->deny = orig->deny;
|
||||
|
||||
entry->next = orig->next;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void print_mnt_entry(struct mnt_entry *entry)
|
||||
{
|
||||
if (entry->allow & AA_MAY_MOUNT)
|
||||
fprintf(stderr, "mount");
|
||||
else if (entry->allow & AA_MAY_UMOUNT)
|
||||
fprintf(stderr, "umount");
|
||||
else if (entry->allow & AA_MAY_PIVOTROOT)
|
||||
fprintf(stderr, "pivotroot");
|
||||
else
|
||||
fprintf(stderr, "error: unknonwn mount perm");
|
||||
|
||||
fprintf(stderr, " (0x%x - 0x%x) ", entry->flags, entry->inv_flags);
|
||||
if (entry->dev_type) {
|
||||
fprintf(stderr, " type=");
|
||||
print_value_list(entry->dev_type);
|
||||
}
|
||||
if (entry->opts) {
|
||||
fprintf(stderr, " options=");
|
||||
print_value_list(entry->opts);
|
||||
}
|
||||
if (entry->device)
|
||||
fprintf(stderr, " %s", entry->device);
|
||||
if (entry->mnt_point)
|
||||
fprintf(stderr, " -> %s", entry->mnt_point);
|
||||
if (entry->trans)
|
||||
fprintf(stderr, " -> %s", entry->trans);
|
||||
|
||||
fprintf(stderr, " %s (0x%x/0x%x)", entry->deny ? "deny" : "", entry->allow, entry->audit);
|
||||
fprintf(stderr, ",\n");
|
||||
}
|
134
parser/mount.h
134
parser/mount.h
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010
|
||||
* 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_MOUNT_H
|
||||
#define __AA_MOUNT_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
#define MS_RDONLY (1 << 0)
|
||||
#define MS_RW 0
|
||||
#define MS_NOSUID (1 << 1)
|
||||
#define MS_SUID 0
|
||||
#define MS_NODEV (1 << 2)
|
||||
#define MS_DEV 0
|
||||
#define MS_NOEXEC (1 << 3)
|
||||
#define MS_EXEC 0
|
||||
#define MS_SYNC (1 << 4)
|
||||
#define MS_ASYNC 0
|
||||
#define MS_REMOUNT (1 << 5)
|
||||
#define MS_MAND (1 << 6)
|
||||
#define MS_NOMAND 0
|
||||
#define MS_DIRSYNC (1 << 7)
|
||||
#define MS_NODIRSYNC 0
|
||||
#define MS_NOATIME (1 << 10)
|
||||
#define MS_ATIME 0
|
||||
#define MS_NODIRATIME (1 << 11)
|
||||
#define MS_DIRATIME 0
|
||||
#define MS_BIND (1 << 12)
|
||||
#define MS_MOVE (1 << 13)
|
||||
#define MS_REC (1 << 14)
|
||||
#define MS_VERBOSE (1 << 15)
|
||||
#define MS_SILENT (1 << 15)
|
||||
#define MS_LOAD 0
|
||||
#define MS_ACL (1 << 16)
|
||||
#define MS_NOACL 0
|
||||
#define MS_UNBINDABLE (1 << 17)
|
||||
#define MS_PRIVATE (1 << 18)
|
||||
#define MS_SLAVE (1 << 19)
|
||||
#define MS_SHARED (1 << 20)
|
||||
#define MS_RELATIME (1 << 21)
|
||||
#define MS_NORELATIME 0
|
||||
#define MS_IVERSION (1 << 23)
|
||||
#define MS_NOIVERSION 0
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#define MS_NOUSER (1 << 31)
|
||||
#define MS_USER 0
|
||||
|
||||
#define MS_ALL_FLAGS (MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC | \
|
||||
MS_SYNC | MS_REMOUNT | MS_MAND | MS_DIRSYNC | \
|
||||
MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_MOVE | \
|
||||
MS_REC | MS_VERBOSE | MS_ACL | MS_UNBINDABLE | \
|
||||
MS_PRIVATE | MS_SLAVE | MS_SHARED | MS_RELATIME | \
|
||||
MS_IVERSION | MS_STRICTATIME | MS_USER)
|
||||
|
||||
#define MS_RBIND (MS_BIND | MS_REC)
|
||||
#define MS_RUNBINDABLE (MS_UNBINDABLE | MS_REC)
|
||||
#define MS_RPRIVATE (MS_PRIVATE | MS_REC)
|
||||
#define MS_RSLAVE (MS_SLAVE | MS_REC)
|
||||
#define MS_RSHARED (MS_SHARED | MS_REC)
|
||||
|
||||
/* set of flags we don't use but define (but not with the kernel values)
|
||||
* for MNT_FLAGS
|
||||
*/
|
||||
#define MS_ACTIVE 0
|
||||
#define MS_BORN 0
|
||||
#define MS_KERNMOUNT 0
|
||||
|
||||
/* from kernel fs/namespace.c - set of flags masked off */
|
||||
#define MNT_FLAGS (MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | \
|
||||
MS_BORN | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| \
|
||||
MS_KERNMOUNT | MS_STRICTATIME)
|
||||
|
||||
#define MS_REMOUNT_FLAGS (MS_REMOUNT | MNT_FLAGS)
|
||||
#define MS_BIND_FLAGS (MS_BIND | MS_REC)
|
||||
#define MS_MAKE_FLAGS ((MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED | \
|
||||
MS_REC) | (MS_ALL_FLAGS & ~(MNT_FLAGS)))
|
||||
#define MS_MOVE_FLAGS (MS_MOVE)
|
||||
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_PRIVATE | MS_SLAVE | \
|
||||
MS_SHARED | MS_UNBINDABLE)
|
||||
|
||||
#define MNT_SRC_OPT 1
|
||||
#define MNT_DST_OPT 2
|
||||
|
||||
#define MNT_COND_FSTYPE 1
|
||||
#define MNT_COND_OPTIONS 2
|
||||
|
||||
#define AA_MAY_PIVOTROOT 1
|
||||
#define AA_MAY_MOUNT 2
|
||||
#define AA_MAY_UMOUNT 4
|
||||
#define AA_DUMMY_REMOUNT 32 /* dummy perm for remount rule - is remapped
|
||||
* to a mount option*/
|
||||
|
||||
|
||||
struct mnt_entry {
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
char *trans;
|
||||
struct value_list *dev_type;
|
||||
struct value_list *opts;
|
||||
|
||||
unsigned int flags, inv_flags;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
struct mnt_entry *next;
|
||||
};
|
||||
|
||||
void print_mnt_entry(struct mnt_entry *entry);
|
||||
|
||||
int is_valid_mnt_cond(const char *name, int src);
|
||||
struct mnt_entry *new_mnt_entry(struct cond_entry *sconds, char *device,
|
||||
struct cond_entry *dconds, char *mnt_point,
|
||||
int mode);
|
||||
struct mnt_entry *dup_mnt_entry(struct mnt_entry *orig);
|
||||
void free_mnt_entry(struct mnt_entry *ent);
|
||||
|
||||
|
||||
#endif /* __AA_MOUNT_H */
|
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
*
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd. (All rights reserved)
|
||||
* Copyright (c) 2010
|
||||
* 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
|
||||
@@ -19,22 +19,12 @@
|
||||
* Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_PARSER_H
|
||||
#define __AA_PARSER_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/resource.h>
|
||||
#include "immunix.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
|
||||
struct mnt_ent;
|
||||
|
||||
/* Global variable to pass token to lexer. Will be replaced by parameter
|
||||
* when lexer and parser are made reentrant
|
||||
*/
|
||||
extern int parser_token;
|
||||
|
||||
typedef enum pattern_t pattern_t;
|
||||
|
||||
struct flagval {
|
||||
@@ -54,19 +44,6 @@ struct cod_pattern {
|
||||
char *regex; // posix regex
|
||||
};
|
||||
|
||||
struct value_list {
|
||||
char *value;
|
||||
|
||||
struct value_list *next;
|
||||
};
|
||||
|
||||
struct cond_entry {
|
||||
char *name;
|
||||
struct value_list *vals;
|
||||
|
||||
struct cond_entry *next;
|
||||
};
|
||||
|
||||
struct cod_entry {
|
||||
char *namespace;
|
||||
char *name;
|
||||
@@ -130,6 +107,7 @@ struct codomain {
|
||||
uint64_t audit_caps;
|
||||
uint64_t deny_caps;
|
||||
uint64_t quiet_caps;
|
||||
uint64_t set_caps;
|
||||
|
||||
unsigned int *network_allowed; /* array of type masks
|
||||
* indexed by AF_FAMILY */
|
||||
@@ -141,8 +119,6 @@ struct codomain {
|
||||
|
||||
char *exec_table[AA_EXEC_COUNT];
|
||||
struct cod_entry *entries;
|
||||
struct mnt_entry *mnt_ents;
|
||||
|
||||
void *hat_table;
|
||||
//struct codomain *next;
|
||||
|
||||
@@ -150,11 +126,6 @@ struct codomain {
|
||||
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 {
|
||||
@@ -245,19 +216,12 @@ extern int preprocess_only;
|
||||
#define __unused __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
|
||||
#define list_for_each(LIST, ENTRY) \
|
||||
for ((ENTRY) = (LIST); (ENTRY); (ENTRY) = (ENTRY)->next)
|
||||
#define list_for_each_safe(LIST, ENTRY, TMP) \
|
||||
for ((ENTRY) = (LIST), (TMP) = (LIST) ? (LIST)->next : NULL; (ENTRY); (ENTRY) = (TMP), (TMP) = (TMP) ? (TMP)->next : NULL)
|
||||
#define list_last_entry(LIST, ENTRY) \
|
||||
for ((ENTRY) = (LIST); (ENTRY) && (ENTRY)->next; (ENTRY) = (ENTRY)->next)
|
||||
#define list_append(LISTA, LISTB) \
|
||||
do { \
|
||||
typeof(LISTA) ___tmp; \
|
||||
list_last_entry((LISTA), ___tmp);\
|
||||
___tmp->next = (LISTB); \
|
||||
} while (0)
|
||||
|
||||
/* from parser_common.c */
|
||||
extern int regex_type;
|
||||
@@ -265,7 +229,6 @@ extern int perms_create;
|
||||
extern int net_af_max_override;
|
||||
extern int kernel_load;
|
||||
extern int kernel_supports_network;
|
||||
extern int kernel_supports_mount;
|
||||
extern int flag_changehat_version;
|
||||
extern int conf_verbose;
|
||||
extern int conf_quiet;
|
||||
@@ -291,7 +254,7 @@ extern void update_mru_tstamp(FILE *file);
|
||||
extern FILE *yyin;
|
||||
extern void yyrestart(FILE *fp);
|
||||
extern int yyparse(void);
|
||||
extern void yyerror(const char *msg, ...);
|
||||
extern void yyerror(char *msg, ...);
|
||||
extern int yylex(void);
|
||||
|
||||
/* parser_include.c */
|
||||
@@ -302,24 +265,12 @@ extern int process_regex(struct codomain *cod);
|
||||
extern int post_process_entry(struct cod_entry *entry);
|
||||
extern void reset_regex(void);
|
||||
|
||||
extern int process_policydb(struct codomain *cod);
|
||||
|
||||
extern int process_policy_ents(struct codomain *cod);
|
||||
|
||||
/* parser_variable.c */
|
||||
extern int process_variables(struct codomain *cod);
|
||||
extern struct var_string *split_out_var(char *string);
|
||||
extern void free_var_string(struct var_string *var);
|
||||
|
||||
/* parser_misc.c */
|
||||
extern struct value_list *new_value_list(char *value);
|
||||
extern struct value_list *dup_value_list(struct value_list *list);
|
||||
extern void free_value_list(struct value_list *list);
|
||||
extern void print_value_list(struct value_list *list);
|
||||
extern struct cond_entry *new_cond_entry(char *name, struct value_list *list);
|
||||
extern void free_cond_entry(struct cond_entry *ent);
|
||||
extern void print_cond_entry(struct cond_entry *ent);
|
||||
extern char *processid(char *string, int len);
|
||||
extern char *processquoted(char *string, int len);
|
||||
extern char *processunquoted(char *string, int len);
|
||||
extern int get_keyword_token(const char *keyword);
|
||||
@@ -342,7 +293,6 @@ extern void debug_cod_list(struct codomain *list);
|
||||
extern int str_to_boolean(const char* str);
|
||||
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
||||
extern void free_cod_entries(struct cod_entry *list);
|
||||
extern void free_mnt_entries(struct mnt_entry *list);
|
||||
|
||||
/* parser_symtab.c */
|
||||
struct set_value {;
|
||||
@@ -381,11 +331,9 @@ extern void add_to_list(struct codomain *codomain);
|
||||
extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
|
||||
extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
|
||||
extern void post_process_nt_entries(struct codomain *cod);
|
||||
extern void post_process_mnt_entries(struct codomain *cod);
|
||||
extern int post_process_policy(int debug_only);
|
||||
extern int process_hat_regex(struct codomain *cod);
|
||||
extern int process_hat_variables(struct codomain *cod);
|
||||
extern int process_hat_policydb(struct codomain *cod);
|
||||
extern int post_merge_rules(void);
|
||||
extern int merge_hat_rules(struct codomain *cod);
|
||||
extern struct codomain *merge_policy(struct codomain *a, struct codomain *b);
|
||||
@@ -406,7 +354,7 @@ void free_policies(void);
|
||||
*/
|
||||
|
||||
/* parser_yacc.y */
|
||||
void yyerror(const char *msg, ...)
|
||||
void yyerror(char *msg, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[PATH_MAX];
|
||||
@@ -427,5 +375,3 @@ void yyerror(const char *msg, ...)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /** __AA_PARSER_H */
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd. (All rights reserved)
|
||||
* Copyright (c) 2010, 2011
|
||||
* 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
|
||||
@@ -27,7 +27,6 @@ int perms_create = 0; /* perms contain create flag */
|
||||
int net_af_max_override = -1; /* use kernel to determine af_max */
|
||||
int kernel_load = 1;
|
||||
int kernel_supports_network = 1; /* kernel supports network rules */
|
||||
int kernel_supports_mount = 0; /* kernel supports mount rules */
|
||||
int flag_changehat_version = FLAG_CHANGEHAT_1_5;
|
||||
int conf_verbose = 0;
|
||||
int conf_quiet = 0;
|
||||
@@ -35,7 +34,7 @@ int names_only = 0;
|
||||
int current_lineno = 1;
|
||||
int option = OPTION_ADD;
|
||||
|
||||
dfaflags_t dfaflags = DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_MINIMIZE_HASH_TRANS;
|
||||
dfaflags_t dfaflags = DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_MINIMIZE_HASH_TRANS | DFA_CONTROL_MINIMIZE_HASH_PERMS;
|
||||
|
||||
char *subdomainbase = NULL;
|
||||
char *progname = __FILE__;
|
||||
@@ -55,16 +54,18 @@ void pwarn(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char *newfmt;
|
||||
int rc;
|
||||
|
||||
if (conf_quiet || names_only || option == OPTION_REMOVE)
|
||||
return;
|
||||
|
||||
if (asprintf(&newfmt, _("Warning from %s (%s%sline %d): %s"),
|
||||
profilename ? profilename : "stdin",
|
||||
current_filename ? current_filename : "",
|
||||
current_filename ? " " : "",
|
||||
current_lineno,
|
||||
fmt) == -1)
|
||||
rc = asprintf(&newfmt, _("Warning from %s (%s%sline %d): %s"),
|
||||
profilename ? profilename : "stdin",
|
||||
current_filename ? current_filename : "",
|
||||
current_filename ? " " : "",
|
||||
current_lineno,
|
||||
fmt);
|
||||
if (!newfmt)
|
||||
return;
|
||||
|
||||
va_start(arg, fmt);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd.
|
||||
* Copyright (c) 2010
|
||||
* Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd.
|
||||
* Copyright (c) 2010
|
||||
* Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
|
@@ -59,7 +59,6 @@
|
||||
|
||||
#define SUBDOMAIN_INTERFACE_VERSION 2
|
||||
#define SUBDOMAIN_INTERFACE_DFA_VERSION 5
|
||||
#define SUBDOMAIN_INTERFACE_POLICY_DB 16
|
||||
|
||||
int sd_serialize_codomain(int option, struct codomain *cod);
|
||||
|
||||
@@ -610,14 +609,15 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||
|
||||
#define low_caps(X) ((u32) ((X) & 0xffffffff))
|
||||
#define high_caps(X) ((u32) (((X) >> 32) & 0xffffffff))
|
||||
allowed_caps = (profile->capabilities) & ~profile->deny_caps;
|
||||
allowed_caps = (profile->capabilities | profile->set_caps) &
|
||||
~profile->deny_caps;
|
||||
if (!sd_write32(p, low_caps(allowed_caps)))
|
||||
return 0;
|
||||
if (!sd_write32(p, low_caps(allowed_caps & profile->audit_caps)))
|
||||
return 0;
|
||||
if (!sd_write32(p, low_caps(profile->deny_caps & profile->quiet_caps)))
|
||||
return 0;
|
||||
if (!sd_write32(p, 0))
|
||||
if (!sd_write32(p, low_caps(profile->set_caps & ~profile->deny_caps)))
|
||||
return 0;
|
||||
|
||||
if (!sd_write_struct(p, "caps64"))
|
||||
@@ -628,7 +628,7 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||
return 0;
|
||||
if (!sd_write32(p, high_caps(profile->deny_caps & profile->quiet_caps)))
|
||||
return 0;
|
||||
if (!sd_write32(p, 0))
|
||||
if (!sd_write32(p, high_caps(profile->set_caps & ~profile->deny_caps)))
|
||||
return 0;
|
||||
if (!sd_write_structend(p))
|
||||
return 0;
|
||||
@@ -655,15 +655,6 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
||||
} else if (profile->network_allowed)
|
||||
pwarn(_("profile %s network rules not enforced\n"), profile->name);
|
||||
|
||||
if (profile->policy_dfa && regex_type == AARE_DFA) {
|
||||
if (!sd_write_struct(p, "policydb"))
|
||||
return 0;
|
||||
if (!sd_serialize_dfa(p, profile->policy_dfa, profile->policy_dfa_size))
|
||||
return 0;
|
||||
if (!sd_write_structend(p))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* either have a single dfa or lists of different entry types */
|
||||
if (regex_type == AARE_DFA) {
|
||||
if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size))
|
||||
@@ -695,13 +686,9 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
|
||||
{
|
||||
int version;
|
||||
|
||||
if (regex_type == AARE_DFA) {
|
||||
/* Not yet
|
||||
if (profile->policy_dfa)
|
||||
version = SUBDOMAIN_INTERFACE_POLICYDB;
|
||||
else */
|
||||
version = SUBDOMAIN_INTERFACE_DFA_VERSION;
|
||||
} else
|
||||
if (regex_type == AARE_DFA)
|
||||
version = SUBDOMAIN_INTERFACE_DFA_VERSION;
|
||||
else
|
||||
version = SUBDOMAIN_INTERFACE_VERSION;
|
||||
|
||||
|
||||
@@ -776,10 +763,10 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||
int len = 0;
|
||||
|
||||
if (profile_namespace) {
|
||||
len += strlen(profile_namespace) + 2;
|
||||
len += strlen(profile_namespace) + 1;
|
||||
ns = profile_namespace;
|
||||
} else if (cod->namespace) {
|
||||
len += strlen(cod->namespace) + 2;
|
||||
len += strlen(cod->namespace) + 1;
|
||||
ns = cod->namespace;
|
||||
}
|
||||
if (cod->parent) {
|
||||
@@ -791,7 +778,7 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||
goto exit;
|
||||
}
|
||||
if (ns)
|
||||
sprintf(name, ":%s:%s//%s", ns,
|
||||
sprintf(name, "%s:%s//%s", ns,
|
||||
cod->parent->name, cod->name);
|
||||
else
|
||||
sprintf(name, "%s//%s", cod->parent->name,
|
||||
@@ -803,7 +790,7 @@ int sd_serialize_codomain(int option, struct codomain *cod)
|
||||
error = -errno;
|
||||
goto exit;
|
||||
}
|
||||
sprintf(name, ":%s:%s", ns, cod->name);
|
||||
sprintf(name, "%s:%s", ns, cod->name);
|
||||
} else {
|
||||
name = cod->name;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd.
|
||||
* Copyright (c) 2010
|
||||
* Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -23,7 +23,6 @@
|
||||
/* eliminates need to link with libfl */
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
%option stack
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
@@ -45,7 +44,7 @@
|
||||
#endif
|
||||
/* #define DEBUG */
|
||||
#ifdef DEBUG
|
||||
#define PDEBUG(fmt, args...) printf("Lexer (state %d): " fmt, YY_START, ## args)
|
||||
#define PDEBUG(fmt, args...) printf("Lexer: " fmt, ## args)
|
||||
#else
|
||||
#define PDEBUG(fmt, args...) /* Do nothing */
|
||||
#endif
|
||||
@@ -168,35 +167,25 @@ void include_filename(char *filename, int search)
|
||||
|
||||
%}
|
||||
|
||||
CARET "^"
|
||||
UP "^"
|
||||
OPEN_BRACE \{
|
||||
CLOSE_BRACE \}
|
||||
SLASH \/
|
||||
COLON :
|
||||
END_OF_RULE [,]
|
||||
SEPARATOR {UP}
|
||||
RANGE -
|
||||
MODE_CHARS ([RrWwaLlMmkXx])|(([Pp]|[Cc])[Xx])|(([Pp]|[Cc])?([IiUu])[Xx])
|
||||
MODES {MODE_CHARS}+
|
||||
WS [[:blank:]]
|
||||
NUMBER [[:digit:]]+
|
||||
|
||||
ID_CHARS [^ \t\n"!,]
|
||||
ID {ID_CHARS}|(,{ID_CHARS})
|
||||
IDS {ID}+
|
||||
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
|
||||
POST_VAR_ID {POST_VAR_ID_CHARS}|(,{POST_VAR_ID_CHARS})
|
||||
LIST_VALUE_ID_CHARS [^ \t\n"!,]{-}[()]
|
||||
LIST_VALUE_ID {LIST_VALUE_ID_CHARS}+
|
||||
ID_CHARS_NOEQ [^ \t\n"!,]{-}[=]
|
||||
ID_NOEQ {ID_CHARS_NOEQ}|(,{ID_CHARS_NOEQ})
|
||||
IDS_NOEQ {ID_NOEQ}+
|
||||
ID [^ \t\n"!,]|(,[^ \t\n"!])
|
||||
POST_VAR_ID [^ =\+\t\n"!,]|(,[^ =\+\t\n"!])
|
||||
IP {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER}
|
||||
ALLOWED_QUOTED_ID [^\0"]|\\\"
|
||||
QUOTED_ID \"{ALLOWED_QUOTED_ID}*\"
|
||||
|
||||
IP {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER}
|
||||
|
||||
HAT hat{WS}*
|
||||
PROFILE profile{WS}*
|
||||
HAT hat[ \t]+
|
||||
KEYWORD [[:alpha:]_]+
|
||||
VARIABLE_NAME [[:alpha:]][[:alnum:]_]*
|
||||
SET_VAR_PREFIX @
|
||||
@@ -206,36 +195,25 @@ BOOL_VARIABLE $(\{{VARIABLE_NAME}\}|{VARIABLE_NAME})
|
||||
PATHNAME (\/|{SET_VARIABLE}{POST_VAR_ID}){ID}*
|
||||
QPATHNAME \"(\/|{SET_VAR_PREFIX})([^\0"]|\\\")*\"
|
||||
|
||||
OPEN_PAREN \(
|
||||
CLOSE_PAREN \)
|
||||
COMMA \,
|
||||
FLAGOPEN_PAREN \(
|
||||
FLAGCLOSE_PAREN \)
|
||||
FLAGSEP \,
|
||||
EQUALS =
|
||||
ADD_ASSIGN \+=
|
||||
ARROW ->
|
||||
LT_EQUAL <=
|
||||
|
||||
%x SUB_ID
|
||||
%x SUB_VALUE
|
||||
%x EXTCOND_MODE
|
||||
%x SUB_NAME
|
||||
%x SUB_NAME2
|
||||
%x NETWORK_MODE
|
||||
%x LIST_VAL_MODE
|
||||
%x FLAGS_MODE
|
||||
%x ASSIGN_MODE
|
||||
%x RLIMIT_MODE
|
||||
%x MOUNT_MODE
|
||||
%x CHANGE_PROFILE_MODE
|
||||
%x INCLUDE
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
/* Copied directly into yylex function */
|
||||
if (parser_token) {
|
||||
int t = parser_token;
|
||||
parser_token = 0;
|
||||
return t;
|
||||
}
|
||||
%}
|
||||
|
||||
<INCLUDE>{
|
||||
{WS}+ { /* Eat whitespace */ }
|
||||
\<([^\> \t\n]+)\> { /* <filename> */
|
||||
@@ -243,7 +221,7 @@ LT_EQUAL <=
|
||||
filename[strlen(filename) - 1] = '\0';
|
||||
include_filename(filename + 1, 1);
|
||||
free(filename);
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
\"([^\" \t\n]+)\" { /* "filename" */
|
||||
@@ -251,12 +229,12 @@ LT_EQUAL <=
|
||||
filename[strlen(filename) - 1] = '\0';
|
||||
include_filename(filename + 1, 0);
|
||||
free(filename);
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
[^\<\>\"{WS}]+ { /* filename */
|
||||
include_filename(yytext, 0);
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,34 +245,33 @@ LT_EQUAL <=
|
||||
if ( !YY_CURRENT_BUFFER ) yyterminate();
|
||||
}
|
||||
|
||||
<INITIAL,MOUNT_MODE>{
|
||||
{VARIABLE_NAME}/{WS}*= {
|
||||
/* we match to the = in the lexer so that
|
||||
* can switch scanner state. By the time
|
||||
* the parser see the = it may be to late
|
||||
* as bison may have requested the next
|
||||
* token from the scanner
|
||||
*/
|
||||
PDEBUG("conditional %s=\n", yytext);
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
yy_push_state(EXTCOND_MODE);
|
||||
return TOK_CONDID;
|
||||
}
|
||||
}
|
||||
|
||||
<SUB_ID>{
|
||||
({IDS}|{QUOTED_ID}) {
|
||||
<SUB_NAME>{
|
||||
{ID}+ {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {IDS} to match all TOK_IDs, but that would
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
yylval.id = processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found sub name: \"%s\"\n", yylval.id);
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
{QUOTED_ID} {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processquoted(yytext, yyleng);
|
||||
PDEBUG("Found sub name: \"%s\"\n", yylval.id);
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
@@ -305,22 +282,37 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
<SUB_VALUE>{
|
||||
({IDS}|{QUOTED_ID}) {
|
||||
<SUB_NAME2>{
|
||||
{ID}+ {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {IDS} to match all TOK_IDs, but that would
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
PDEBUG("Found sub value: \"%s\"\n", yylval.id);
|
||||
yy_pop_state();
|
||||
return TOK_VALUE;
|
||||
yylval.id = processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found sub name: \"%s\"\n", yylval.id);
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
{QUOTED_ID} {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processquoted(yytext, yyleng);
|
||||
PDEBUG("Found sub name: \"%s\"\n", yylval.id);
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
|
||||
[^\n] {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
@@ -328,27 +320,37 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
<LIST_VAL_MODE>{
|
||||
{CLOSE_PAREN} {
|
||||
<FLAGS_MODE>{
|
||||
{FLAGOPEN_PAREN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("listval: )\n");
|
||||
yy_pop_state();
|
||||
return TOK_CLOSEPAREN;
|
||||
PDEBUG("FLag (\n");
|
||||
return TOK_FLAG_OPENPAREN;
|
||||
}
|
||||
{FLAGCLOSE_PAREN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Flag )\n");
|
||||
BEGIN(INITIAL);
|
||||
return TOK_FLAG_CLOSEPAREN;
|
||||
}
|
||||
|
||||
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
|
||||
|
||||
{COMMA} {
|
||||
{FLAGSEP} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("listval: , \n");
|
||||
/* East comma, its an optional separator */
|
||||
PDEBUG("Flag , \n");
|
||||
return TOK_FLAG_SEP;
|
||||
}
|
||||
|
||||
({LIST_VALUE_ID}|{QUOTED_ID}) {
|
||||
{EQUALS} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
PDEBUG("listval: \"%s\"\n", yylval.id);
|
||||
return TOK_VALUE;
|
||||
PDEBUG("Flag = \n");
|
||||
return TOK_EQUALS;
|
||||
}
|
||||
{KEYWORD} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.flag_id = strdup(yytext);
|
||||
PDEBUG("Found flag: \"%s\"\n", yylval.flag_id);
|
||||
return TOK_FLAG_ID;
|
||||
}
|
||||
|
||||
[^\n] {
|
||||
@@ -358,46 +360,19 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
<EXTCOND_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
|
||||
|
||||
{EQUALS}{WS}*/[^(\n]{-}{WS} {
|
||||
DUMP_PREPROCESS;
|
||||
BEGIN(SUB_VALUE);
|
||||
return TOK_EQUALS;
|
||||
}
|
||||
|
||||
{EQUALS} {
|
||||
DUMP_PREPROCESS;
|
||||
return TOK_EQUALS;
|
||||
}
|
||||
|
||||
{OPEN_PAREN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("extcond listv\n");
|
||||
/* Don't push state here as this is a transition
|
||||
* start condition and we want to return to the start
|
||||
* condition that invoked <EXTCOND_MODE> when
|
||||
* LIST_VAL_ID is done
|
||||
*/
|
||||
BEGIN(LIST_VAL_MODE);
|
||||
return TOK_OPENPAREN;
|
||||
}
|
||||
|
||||
[^\n] {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
yyerror(_("Found unexpected character: '%s' %d"), yytext, *yytext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
<ASSIGN_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
|
||||
|
||||
({IDS}|{QUOTED_ID}) {
|
||||
{ID}+ {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.var_val = processid(yytext, yyleng);
|
||||
yylval.var_val = processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
|
||||
return TOK_VALUE;
|
||||
}
|
||||
|
||||
{QUOTED_ID} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.var_val = processquoted(yytext, yyleng);
|
||||
PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
|
||||
return TOK_VALUE;
|
||||
}
|
||||
@@ -413,7 +388,7 @@ LT_EQUAL <=
|
||||
\r?\n {
|
||||
DUMP_PREPROCESS;
|
||||
current_lineno++;
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
[^\n] {
|
||||
DUMP_PREPROCESS;
|
||||
@@ -425,14 +400,14 @@ LT_EQUAL <=
|
||||
<NETWORK_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
|
||||
|
||||
{IDS} {
|
||||
{ID}+ {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = strdup(yytext);
|
||||
return TOK_ID;
|
||||
}
|
||||
{END_OF_RULE} {
|
||||
DUMP_PREPROCESS;
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
return TOK_END_OF_RULE;
|
||||
}
|
||||
[^\n] {
|
||||
@@ -455,18 +430,32 @@ LT_EQUAL <=
|
||||
return TOK_ARROW;
|
||||
}
|
||||
|
||||
({IDS}|{QUOTED_ID}) {
|
||||
{ID}+ {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {IDS} to match all TOK_IDs, but that would
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
yylval.id = processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found change profile name: \"%s\"\n", yylval.id);
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
{QUOTED_ID} {
|
||||
/* Ugh, this is a gross hack. I used to use
|
||||
* {ID}+ to match all TOK_IDs, but that would
|
||||
* also match TOK_MODE + TOK_END_OF_RULE
|
||||
* without any spaces in between (because it's
|
||||
* a longer match). So now, when I want to
|
||||
* match any random string, I go into a
|
||||
* separate state. */
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processquoted(yytext, yyleng);
|
||||
PDEBUG("Found change profile quoted name: \"%s\"\n", yylval.id);
|
||||
BEGIN(INITIAL);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
@@ -478,6 +467,43 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
#include/.*\r?\n { /* include */
|
||||
PDEBUG("Matched #include\n");
|
||||
BEGIN(INCLUDE);
|
||||
}
|
||||
|
||||
#.*\r?\n { /* normal comment */
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||
current_lineno++;
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
{END_OF_RULE} { DUMP_PREPROCESS; return TOK_END_OF_RULE; }
|
||||
|
||||
{SEPARATOR} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched a separator\n");
|
||||
BEGIN(SUB_NAME);
|
||||
return TOK_SEP;
|
||||
}
|
||||
{ARROW} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched a arrow\n");
|
||||
return TOK_ARROW;
|
||||
}
|
||||
{EQUALS} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched equals for assignment\n");
|
||||
BEGIN(ASSIGN_MODE);
|
||||
return TOK_EQUALS;
|
||||
}
|
||||
{ADD_ASSIGN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched additive value assignment\n");
|
||||
BEGIN(ASSIGN_MODE);
|
||||
return TOK_ADD_ASSIGN;
|
||||
}
|
||||
<RLIMIT_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
|
||||
|
||||
@@ -500,94 +526,23 @@ LT_EQUAL <=
|
||||
|
||||
{END_OF_RULE} {
|
||||
DUMP_PREPROCESS;
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
return TOK_END_OF_RULE;
|
||||
}
|
||||
|
||||
\\\n {
|
||||
DUMP_PREPROCESS;
|
||||
current_lineno++;
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
\r?\n {
|
||||
DUMP_PREPROCESS;
|
||||
current_lineno++;
|
||||
yy_pop_state();
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
}
|
||||
|
||||
<MOUNT_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
|
||||
|
||||
{ARROW} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched arrow\n");
|
||||
return TOK_ARROW;
|
||||
}
|
||||
|
||||
({IDS_NOEQ}|{PATHNAME}|{QUOTED_ID}) {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
PDEBUG("Found ID: \"%s\"\n", yylval.id);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
{END_OF_RULE} {
|
||||
DUMP_PREPROCESS;
|
||||
yy_pop_state();
|
||||
return TOK_END_OF_RULE;
|
||||
}
|
||||
|
||||
[^\n] {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
yyerror(_("Found unexpected character: '%s'"), yytext);
|
||||
}
|
||||
|
||||
\r?\n {
|
||||
DUMP_PREPROCESS;
|
||||
current_lineno++;
|
||||
yy_pop_state();
|
||||
}
|
||||
}
|
||||
|
||||
#include/.*\r?\n { /* include */
|
||||
PDEBUG("Matched #include\n");
|
||||
yy_push_state(INCLUDE);
|
||||
}
|
||||
|
||||
#.*\r?\n { /* normal comment */
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||
current_lineno++;
|
||||
}
|
||||
|
||||
{END_OF_RULE} { DUMP_PREPROCESS; return TOK_END_OF_RULE; }
|
||||
|
||||
{CARET} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched hat ^\n");
|
||||
yy_push_state(SUB_ID);
|
||||
return TOK_CARET;
|
||||
}
|
||||
{ARROW} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched a arrow\n");
|
||||
return TOK_ARROW;
|
||||
}
|
||||
{EQUALS} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched equals for assignment\n");
|
||||
yy_push_state(ASSIGN_MODE);
|
||||
return TOK_EQUALS;
|
||||
}
|
||||
{ADD_ASSIGN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Matched additive value assignment\n");
|
||||
yy_push_state(ASSIGN_MODE);
|
||||
return TOK_ADD_ASSIGN;
|
||||
}
|
||||
{SET_VARIABLE} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.set_var = strdup(yytext);
|
||||
@@ -613,14 +568,21 @@ LT_EQUAL <=
|
||||
return TOK_CLOSE;
|
||||
}
|
||||
|
||||
({PATHNAME}|{QPATHNAME}) {
|
||||
{PATHNAME} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
yylval.id = processunquoted(yytext, yyleng);
|
||||
PDEBUG("Found id: \"%s\"\n", yylval.id);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
({MODES})/([[:space:],]) {
|
||||
{QPATHNAME} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.id = processquoted(yytext, yyleng);
|
||||
PDEBUG("Found id: \"%s\"\n", yylval.id);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
{MODES} {
|
||||
DUMP_PREPROCESS;
|
||||
yylval.mode = strdup(yytext);
|
||||
PDEBUG("Found modes: %s\n", yylval.mode);
|
||||
@@ -629,27 +591,21 @@ LT_EQUAL <=
|
||||
|
||||
{HAT} {
|
||||
DUMP_PREPROCESS;
|
||||
yy_push_state(SUB_ID);
|
||||
BEGIN(SUB_NAME2);
|
||||
return TOK_HAT;
|
||||
}
|
||||
|
||||
{PROFILE} {
|
||||
DUMP_PREPROCESS;
|
||||
yy_push_state(SUB_ID);
|
||||
return TOK_PROFILE;
|
||||
}
|
||||
|
||||
{COLON} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Found a colon\n");
|
||||
return TOK_COLON;
|
||||
}
|
||||
|
||||
{OPEN_PAREN} {
|
||||
{FLAGOPEN_PAREN} {
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("listval (\n");
|
||||
yy_push_state(LIST_VAL_MODE);
|
||||
return TOK_OPENPAREN;
|
||||
PDEBUG("FLag (\n");
|
||||
BEGIN(FLAGS_MODE);
|
||||
return TOK_FLAG_OPENPAREN;
|
||||
}
|
||||
|
||||
{VARIABLE_NAME} {
|
||||
@@ -664,21 +620,20 @@ LT_EQUAL <=
|
||||
PDEBUG("Found (var) id: \"%s\"\n", yylval.id);
|
||||
return TOK_ID;
|
||||
break;
|
||||
case TOK_PROFILE:
|
||||
BEGIN(SUB_NAME2);
|
||||
break;
|
||||
case TOK_FLAGS:
|
||||
BEGIN(FLAGS_MODE);
|
||||
break;
|
||||
case TOK_RLIMIT:
|
||||
yy_push_state(RLIMIT_MODE);
|
||||
BEGIN(RLIMIT_MODE);
|
||||
break;
|
||||
case TOK_NETWORK:
|
||||
yy_push_state(NETWORK_MODE);
|
||||
BEGIN(NETWORK_MODE);
|
||||
break;
|
||||
case TOK_CHANGE_PROFILE:
|
||||
yy_push_state(CHANGE_PROFILE_MODE);
|
||||
break;
|
||||
case TOK_MOUNT:
|
||||
case TOK_REMOUNT:
|
||||
case TOK_UMOUNT:
|
||||
DUMP_PREPROCESS;
|
||||
PDEBUG("Entering mount\n");
|
||||
yy_push_state(MOUNT_MODE);
|
||||
BEGIN(CHANGE_PROFILE_MODE);
|
||||
break;
|
||||
default: /* nothing */
|
||||
break;
|
||||
|
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
*
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd. (All rights reserved)
|
||||
* Copyright (c) 2010, 2011
|
||||
* 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
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <mntent.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <dirent.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* enable the following line to get voluminous debug info */
|
||||
@@ -60,7 +59,7 @@
|
||||
#define UNPRIVILEGED_OPS (!(PRIVILEGED_OPS))
|
||||
|
||||
const char *parser_title = "AppArmor parser";
|
||||
const char *parser_copyright = "Copyright (C) 1999-2008 Novell Inc.\nCopyright 2009-2012 Canonical Ltd.";
|
||||
const char *parser_copyright = "Copyright (C) 1999-2008 Novell Inc.\nCopyright 2009-2011 Canonical Ltd.";
|
||||
|
||||
char *progname;
|
||||
int opt_force_complain = 0;
|
||||
@@ -75,10 +74,8 @@ int preprocess_only = 0;
|
||||
int skip_mode_force = 0;
|
||||
struct timespec mru_tstamp;
|
||||
|
||||
#define FLAGS_STRING_SIZE 1024
|
||||
char *match_string = NULL;
|
||||
char *flags_string = NULL;
|
||||
char *cacheloc = NULL;
|
||||
|
||||
/* per-profile settings */
|
||||
int force_complain = 0;
|
||||
@@ -109,7 +106,6 @@ struct option long_options[] = {
|
||||
{"skip-read-cache", 0, 0, 'T'},
|
||||
{"write-cache", 0, 0, 'W'},
|
||||
{"show-cache", 0, 0, 'k'},
|
||||
{"cache-loc", 1, 0, 'L'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"dump", 1, 0, 'D'},
|
||||
{"Dump", 1, 0, 'D'},
|
||||
@@ -151,7 +147,6 @@ static void display_usage(char *command)
|
||||
"-K, --skip-cache Do not attempt to load or save cached profiles\n"
|
||||
"-T, --skip-read-cache Do not attempt to load cached profiles\n"
|
||||
"-W, --write-cache Save cached profile (force with -T)\n"
|
||||
"-L, --cache-loc n Set the location of the profile cache\n"
|
||||
"-q, --quiet Don't emit warnings\n"
|
||||
"-v, --verbose Show profile names as they load\n"
|
||||
"-Q, --skip-kernel-load Do everything except loading into kernel\n"
|
||||
@@ -230,10 +225,10 @@ optflag_table_t optflag_table[] = {
|
||||
{ 2, "expr-right-simplify", "right simplification first",
|
||||
DFA_CONTROL_TREE_LEFT },
|
||||
{ 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
|
||||
{ 1, "hash-perms", "minimization - hash permissions during setup",
|
||||
DFA_CONTROL_MINIMIZE_HASH_PERMS },
|
||||
{ 1, "hash-trans", "minimization - hash transitions during setup",
|
||||
DFA_CONTROL_MINIMIZE_HASH_TRANS },
|
||||
{ 1, "filter-deny", "filter out deny information from final dfa",
|
||||
DFA_CONTROL_FILTER_DENY },
|
||||
{ 1, "remove-unreachable", "dfa unreachable state removal",
|
||||
DFA_CONTROL_REMOVE_UNREACHABLE },
|
||||
{ 0, "compress-small",
|
||||
@@ -527,9 +522,6 @@ static int process_arg(int c, char *optarg)
|
||||
case 'T':
|
||||
skip_read_cache = 1;
|
||||
break;
|
||||
case 'L':
|
||||
cacheloc = strdup(optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
kernel_load = 0;
|
||||
break;
|
||||
@@ -675,137 +667,17 @@ int have_enough_privilege(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *snprintf_buffer(char *buf, char *pos, ssize_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i, remaining = size - (pos - buf);
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vsnprintf(pos, remaining, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (i >= size) {
|
||||
PERROR(_("Feature buffer full."));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return pos + i;
|
||||
}
|
||||
|
||||
static char *handle_features_dir(const char *filename, char **buffer, int size,
|
||||
char *pos)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
char *dirent_path = NULL;
|
||||
struct dirent *dirent;
|
||||
struct stat my_stat;
|
||||
int len;
|
||||
|
||||
PDEBUG("Opened features directory \"%s\"\n", filename);
|
||||
if (!(dir = opendir(filename))) {
|
||||
PDEBUG("opendir failed '%s'", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
int name_len;
|
||||
/* skip dotfiles silently. */
|
||||
if (dirent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (dirent_path)
|
||||
free(dirent_path);
|
||||
if (asprintf(&dirent_path, "%s/%s", filename, dirent->d_name) < 0)
|
||||
{
|
||||
PERROR(_("Memory allocation error."));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
name_len = strlen(dirent->d_name);
|
||||
if (!name_len)
|
||||
continue;
|
||||
|
||||
if (stat(dirent_path, &my_stat)) {
|
||||
PERROR(_("stat failed for '%s'"), dirent_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pos = snprintf_buffer(*buffer, pos, size, "%s {", dirent->d_name);
|
||||
if (S_ISREG(my_stat.st_mode)) {
|
||||
int file;
|
||||
int remaining = size - (pos - *buffer);
|
||||
if (!(file = open(dirent_path, O_RDONLY))) {
|
||||
PDEBUG("Could not open '%s' in '%s'", dirent_path, filename);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
PDEBUG("Opened features \"%s\" in \"%s\"\n", dirent_path, filename);
|
||||
if (my_stat.st_size > remaining) {
|
||||
PERROR(_("Feature buffer full."));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
do {
|
||||
len = read(file, pos, remaining);
|
||||
if (len > 0) {
|
||||
remaining -= len;
|
||||
pos += len;
|
||||
*pos = 0;
|
||||
}
|
||||
} while (len > 0);
|
||||
if (len < 0) {
|
||||
PDEBUG("Error reading feature file '%s'\n",
|
||||
dirent_path);
|
||||
exit(1);
|
||||
}
|
||||
close(file);
|
||||
|
||||
} else if (S_ISDIR(my_stat.st_mode)) {
|
||||
pos = handle_features_dir(dirent_path, buffer, size,
|
||||
pos);
|
||||
if (!pos)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
pos = snprintf_buffer(*buffer, pos, size, "}\n");
|
||||
}
|
||||
if (dirent_path)
|
||||
free(dirent_path);
|
||||
closedir(dir);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* match_string == NULL --> no match_string available
|
||||
match_string != NULL --> either a matching string specified on the
|
||||
command line, or the kernel supplied a match string */
|
||||
static void get_match_string(void) {
|
||||
|
||||
FILE *ms = NULL;
|
||||
struct stat stat_file;
|
||||
|
||||
/* has process_args() already assigned a match string? */
|
||||
if (match_string)
|
||||
goto out;
|
||||
|
||||
if (stat(FLAGS_FILE, &stat_file) == -1)
|
||||
goto out;
|
||||
|
||||
if (S_ISDIR(stat_file.st_mode)) {
|
||||
/* if we have a features directory default to */
|
||||
regex_type = AARE_DFA;
|
||||
perms_create = 1;
|
||||
|
||||
flags_string = malloc(FLAGS_STRING_SIZE);
|
||||
handle_features_dir(FLAGS_FILE, &flags_string, FLAGS_STRING_SIZE, flags_string);
|
||||
if (strstr(flags_string, "network"))
|
||||
kernel_supports_network = 1;
|
||||
if (strstr(flags_string, "mount"))
|
||||
kernel_supports_mount = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
ms = fopen(MATCH_STRING, "r");
|
||||
if (!ms)
|
||||
goto out;
|
||||
@@ -844,24 +716,20 @@ out:
|
||||
static void get_flags_string(char **flags, char *flags_file) {
|
||||
char *pos;
|
||||
FILE *f = NULL;
|
||||
size_t size;
|
||||
|
||||
/* abort if missing or already set */
|
||||
if (!flags || *flags)
|
||||
return;
|
||||
if (!flags || *flags) return;
|
||||
|
||||
f = fopen(flags_file, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
*flags = malloc(FLAGS_STRING_SIZE);
|
||||
*flags = malloc(1024);
|
||||
if (!*flags)
|
||||
goto fail;
|
||||
|
||||
size = fread(*flags, 1, FLAGS_STRING_SIZE - 1, f);
|
||||
if (!size || ferror(f))
|
||||
if (!fgets(*flags, 1024, f))
|
||||
goto fail;
|
||||
(*flags)[size] = 0;
|
||||
|
||||
fclose(f);
|
||||
pos = strstr(*flags, "change_hat=");
|
||||
@@ -1052,15 +920,6 @@ int process_profile(int option, char *profilename)
|
||||
if (retval != 0)
|
||||
goto out;
|
||||
|
||||
/* Test to see if profile is for another namespace, if so disable
|
||||
* caching for now
|
||||
* TODO: Add support for caching profiles in an alternate namespace
|
||||
* TODO: Add support for embedded namespace defines if they aren't
|
||||
* removed from the language.
|
||||
*/
|
||||
if (profile_namespace)
|
||||
skip_cache = 1;
|
||||
|
||||
/* Do secondary test to see if cached binary profile is good,
|
||||
* instead of checking against a presupplied list of files
|
||||
* use the timestamps from the files that were parsed.
|
||||
@@ -1069,14 +928,8 @@ int process_profile(int option, char *profilename)
|
||||
*/
|
||||
if ((profilename && option != OPTION_REMOVE) && !force_complain &&
|
||||
!skip_cache) {
|
||||
if (cacheloc) {
|
||||
cachename = strdup(cacheloc);
|
||||
if (!cachename) {
|
||||
PERROR(_("Memory allocation error."));
|
||||
exit(1);
|
||||
}
|
||||
} else if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
|
||||
PERROR(_("Memory allocation error."));
|
||||
if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
|
||||
perror("asprintf");
|
||||
exit(1);
|
||||
}
|
||||
/* Load a binary cache if it exists and is newest */
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
/* assistance routines */
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -37,7 +36,6 @@
|
||||
|
||||
#include "parser.h"
|
||||
#include "parser_yacc.h"
|
||||
#include "mount.h"
|
||||
|
||||
/* #define DEBUG */
|
||||
#ifdef DEBUG
|
||||
@@ -55,6 +53,8 @@ struct keyword_table {
|
||||
};
|
||||
|
||||
static struct keyword_table keyword_table[] = {
|
||||
/* flags */
|
||||
{"flags", TOK_FLAGS},
|
||||
/* network */
|
||||
{"network", TOK_NETWORK},
|
||||
/* misc keywords */
|
||||
@@ -73,17 +73,12 @@ static struct keyword_table keyword_table[] = {
|
||||
{"subset", TOK_SUBSET},
|
||||
{"audit", TOK_AUDIT},
|
||||
{"deny", TOK_DENY},
|
||||
{"profile", TOK_PROFILE},
|
||||
{"set", TOK_SET},
|
||||
{"rlimit", TOK_RLIMIT},
|
||||
{"alias", TOK_ALIAS},
|
||||
{"rewrite", TOK_ALIAS},
|
||||
{"ptrace", TOK_PTRACE},
|
||||
{"file", TOK_FILE},
|
||||
{"mount", TOK_MOUNT},
|
||||
{"remount", TOK_REMOUNT},
|
||||
{"umount", TOK_UMOUNT},
|
||||
{"unmount", TOK_UMOUNT},
|
||||
{"pivotroot", TOK_PIVOTROOT},
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
};
|
||||
@@ -402,16 +397,6 @@ char *processunquoted(char *string, int len)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char *processid(char *string, int len)
|
||||
{
|
||||
/* lexer should never call this fn if len <= 0 */
|
||||
assert(len > 0);
|
||||
|
||||
if (*string == '"')
|
||||
return processquoted(string, len);
|
||||
return processunquoted(string, len);
|
||||
}
|
||||
|
||||
/* rewrite a quoted string substituting escaped characters for the
|
||||
* real thing. Strip the quotes around the string */
|
||||
|
||||
@@ -782,20 +767,6 @@ void free_cod_entries(struct cod_entry *list)
|
||||
free(list);
|
||||
}
|
||||
|
||||
void free_mnt_entries(struct mnt_entry *list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
if (list->next)
|
||||
free_mnt_entries(list->next);
|
||||
free(list->mnt_point);
|
||||
free(list->device);
|
||||
free_value_list(list->dev_type);
|
||||
free_value_list(list->opts);
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
static void debug_base_perm_mask(int mask)
|
||||
{
|
||||
if (HAS_MAY_READ(mask))
|
||||
@@ -933,6 +904,8 @@ void debug_capabilities(struct codomain *cod)
|
||||
__debug_capabilities(cod->deny_caps, "Deny Caps");
|
||||
if (cod->quiet_caps != 0ull)
|
||||
__debug_capabilities(cod->quiet_caps, "Quiet Caps");
|
||||
if (cod->set_caps != 0ull)
|
||||
__debug_capabilities(cod->set_caps, "Set Capabilities");
|
||||
}
|
||||
|
||||
void debug_cod_list(struct codomain *cod)
|
||||
@@ -959,101 +932,6 @@ void debug_cod_list(struct codomain *cod)
|
||||
dump_policy_hats(cod);
|
||||
}
|
||||
|
||||
struct value_list *new_value_list(char *value)
|
||||
{
|
||||
struct value_list *val = calloc(1, sizeof(struct value_list));
|
||||
if (val)
|
||||
val->value = value;
|
||||
return val;
|
||||
}
|
||||
|
||||
void free_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *next;
|
||||
|
||||
while (list) {
|
||||
next = list->next;
|
||||
if (list->value)
|
||||
free(list->value);
|
||||
free(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
struct value_list *dup_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *entry, *dup, *head = NULL;
|
||||
char *value;
|
||||
|
||||
list_for_each(list, entry) {
|
||||
value = NULL;
|
||||
if (list->value) {
|
||||
value = strdup(list->value);
|
||||
if (!value)
|
||||
goto fail2;
|
||||
}
|
||||
dup = new_value_list(value);
|
||||
if (!dup)
|
||||
goto fail;
|
||||
if (head)
|
||||
list_append(head, dup);
|
||||
else
|
||||
head = dup;
|
||||
}
|
||||
|
||||
return head;
|
||||
|
||||
fail:
|
||||
free(value);
|
||||
fail2:
|
||||
free_value_list(head);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *entry;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
fprintf(stderr, "%s", list->value);
|
||||
list = list->next;
|
||||
list_for_each(list, entry) {
|
||||
fprintf(stderr, ", %s", entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
struct cond_entry *new_cond_entry(char *name, struct value_list *list)
|
||||
{
|
||||
struct cond_entry *ent = calloc(1, sizeof(struct cond_entry));
|
||||
if (ent) {
|
||||
ent->name = name;
|
||||
ent->vals = list;
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
void free_cond_entry(struct cond_entry *ent)
|
||||
{
|
||||
if (ent) {
|
||||
free(ent->name);
|
||||
free_value_list(ent->vals);
|
||||
free(ent);
|
||||
}
|
||||
}
|
||||
|
||||
void print_cond_entry(struct cond_entry *ent)
|
||||
{
|
||||
if (ent) {
|
||||
fprintf(stderr, "%s=(", ent->name);
|
||||
print_value_list(ent->vals);
|
||||
fprintf(stderr, ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
int test_str_to_boolean(void)
|
||||
{
|
||||
|
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
*
|
||||
* Copyright (c) 2010 - 2012
|
||||
* Canonical Ltd. (All rights reserved)
|
||||
* Copyright (c) 2010
|
||||
* 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
|
||||
@@ -29,7 +29,6 @@
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include "parser.h"
|
||||
#include "mount.h"
|
||||
#include "parser_yacc.h"
|
||||
|
||||
/* #define DEBUG */
|
||||
@@ -96,26 +95,10 @@ void add_hat_to_policy(struct codomain *cod, struct codomain *hat)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_entry_to_x_table(struct codomain *cod, char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||
if (!cod->exec_table[i]) {
|
||||
cod->exec_table[i] = name;
|
||||
return i;
|
||||
} else if (strcmp(cod->exec_table[i], name) == 0) {
|
||||
/* name already in table */
|
||||
free(name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
||||
{
|
||||
char *name = NULL;
|
||||
int i;
|
||||
|
||||
/* check to see if it is a local transition */
|
||||
if (!entry->namespace) {
|
||||
@@ -163,7 +146,18 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
|
||||
name = entry->nt_name;
|
||||
}
|
||||
|
||||
return add_entry_to_x_table(cod, name);
|
||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||
if (!cod->exec_table[i]) {
|
||||
cod->exec_table[i] = name;
|
||||
return i;
|
||||
} else if (strcmp(cod->exec_table[i], name) == 0) {
|
||||
/* name already in table */
|
||||
free(name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry)
|
||||
@@ -181,7 +175,7 @@ void post_process_nt_entries(struct codomain *cod)
|
||||
int mode = 0;
|
||||
int n = add_named_transition(cod, entry);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
|
||||
PERROR("Profile %s has to many specified profile transitions.\n", cod->name);
|
||||
exit(1);
|
||||
}
|
||||
if (entry->mode & AA_USER_EXEC)
|
||||
@@ -196,32 +190,6 @@ void post_process_nt_entries(struct codomain *cod)
|
||||
}
|
||||
}
|
||||
|
||||
void post_process_mnt_entries(struct codomain *cod)
|
||||
{
|
||||
struct mnt_entry *entry;
|
||||
|
||||
list_for_each(cod->mnt_ents, entry) {
|
||||
if (entry->trans) {
|
||||
unsigned int mode = 0;
|
||||
int n = add_entry_to_x_table(cod, entry->trans);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (entry->allow & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (entry->allow & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
entry->allow = ((entry->allow & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
|
||||
entry->trans = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void __merge_rules(const void *nodep, const VISIT value,
|
||||
const int __unused depth)
|
||||
{
|
||||
@@ -326,33 +294,6 @@ int process_hat_regex(struct codomain *cod)
|
||||
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)
|
||||
{
|
||||
@@ -704,6 +645,7 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b)
|
||||
a->audit_caps |= b->audit_caps;
|
||||
a->deny_caps |= b->deny_caps;
|
||||
a->quiet_caps |= b->quiet_caps;
|
||||
a->set_caps |= b->set_caps;
|
||||
|
||||
if (a->network_allowed) {
|
||||
size_t i;
|
||||
@@ -765,15 +707,6 @@ int post_process_policy(int debug_only)
|
||||
}
|
||||
}
|
||||
|
||||
if (!debug_only) {
|
||||
retval = post_process_policydb();
|
||||
if (retval != 0) {
|
||||
PERROR(_("%s: Errors found during policydb postprocess. Aborting.\n"),
|
||||
progname);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -795,15 +728,10 @@ void free_policy(struct codomain *cod)
|
||||
return;
|
||||
free_hat_table(cod->hat_table);
|
||||
free_cod_entries(cod->entries);
|
||||
free_mnt_entries(cod->mnt_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)
|
||||
|
@@ -28,8 +28,6 @@
|
||||
#include "parser.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
#include "mount.h"
|
||||
#include "policydb.h"
|
||||
|
||||
enum error_type {
|
||||
e_no_error,
|
||||
@@ -613,411 +611,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int build_list_val_expr(char *buffer, int size, struct value_list *list)
|
||||
{
|
||||
struct value_list *ent;
|
||||
char tmp[PATH_MAX + 3];
|
||||
char *p;
|
||||
int len;
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!list) {
|
||||
strncpy(buffer, "[^\\000]*", size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
p = buffer;
|
||||
strncpy(p, "(", size - (p - buffer));
|
||||
p++;
|
||||
if (p > buffer + size)
|
||||
goto fail;
|
||||
|
||||
ptype = convert_aaregex_to_pcre(list->value, 0, tmp, PATH_MAX+3, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
|
||||
len = strlen(tmp);
|
||||
if (len > size - (p - buffer))
|
||||
goto fail;
|
||||
strcpy(p, tmp);
|
||||
p += len;
|
||||
|
||||
list_for_each(list->next, ent) {
|
||||
ptype = convert_aaregex_to_pcre(ent->value, 0, tmp,
|
||||
PATH_MAX+3, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
|
||||
strncpy(p, "|", size - (p - buffer));
|
||||
p++;
|
||||
len = strlen(tmp);
|
||||
if (len > size - (p - buffer))
|
||||
goto fail;
|
||||
strcpy(p, tmp);
|
||||
p += len;
|
||||
}
|
||||
strncpy(p, ")", size - (p - buffer));
|
||||
p++;
|
||||
if (p > buffer + size)
|
||||
goto fail;
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int convert_entry(char *buffer, int size, char *entry)
|
||||
{
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (entry) {
|
||||
ptype = convert_aaregex_to_pcre(entry, 0, buffer, size, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
if (size < 8)
|
||||
return FALSE;
|
||||
|
||||
strcpy(buffer, "[^\\000]*");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
|
||||
if (flags == 0xffffffff) {
|
||||
/* all flags are optional */
|
||||
len = snprintf(p, size, "[^\\000]*");
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
/* else no entry = not set */
|
||||
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
p += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
if (buffer == p) {
|
||||
/* match nothing - use impossible 254 as regex parser doesn't
|
||||
* like the empty string
|
||||
*/
|
||||
if (size < 9)
|
||||
return FALSE;
|
||||
|
||||
strcpy(p, "(\\0xfe|)");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int build_mnt_opts(char *buffer, int size, struct value_list *opts)
|
||||
{
|
||||
struct value_list *ent;
|
||||
char tmp[PATH_MAX + 3];
|
||||
char *p;
|
||||
int len;
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!opts) {
|
||||
if (size < 8)
|
||||
return FALSE;
|
||||
strncpy(buffer, "[^\\000]*", size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
p = buffer;
|
||||
list_for_each(opts, ent) {
|
||||
ptype = convert_aaregex_to_pcre(ent->value, 0, tmp,
|
||||
PATH_MAX+3, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
|
||||
len = strlen(tmp);
|
||||
if (len > size - (p - buffer))
|
||||
goto fail;
|
||||
strcpy(p, tmp);
|
||||
p += len;
|
||||
if (ent->next && size - (p - buffer) > 1) {
|
||||
*p++ = ',';
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
{
|
||||
char mntbuf[PATH_MAX + 3];
|
||||
char devbuf[PATH_MAX + 3];
|
||||
char typebuf[PATH_MAX + 3];
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
char optsbuf[PATH_MAX + 3];
|
||||
char *p, *vec[5];
|
||||
int count = 0;
|
||||
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_REMOUNT)
|
||||
&& !entry->device && !entry->dev_type) {
|
||||
/* remount can't be conditional on device and type */
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (entry->mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
} else {
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
}
|
||||
/* skip device */
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, NULL))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
/* skip type */
|
||||
vec[2] = devbuf;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX,
|
||||
entry->flags & MS_REMOUNT_FLAGS,
|
||||
entry->inv_flags & MS_REMOUNT_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!build_mnt_opts(optsbuf, PATH_MAX, entry->opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_BIND)
|
||||
&& !entry->dev_type && !entry->opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
if (!convert_entry(typebuf, PATH_MAX +3, NULL))
|
||||
goto fail;
|
||||
vec[2] = typebuf;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX,
|
||||
entry->flags & MS_BIND_FLAGS,
|
||||
entry->inv_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) &&
|
||||
(entry->flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !entry->device && !entry->dev_type && !entry->opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
/* skip device and type */
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, NULL))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
vec[2] = devbuf;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX,
|
||||
entry->flags & MS_MAKE_FLAGS,
|
||||
entry->inv_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_MOVE)
|
||||
&& !entry->dev_type && !entry->opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
/* skip type */
|
||||
if (!convert_entry(typebuf, PATH_MAX +3, NULL))
|
||||
goto fail;
|
||||
vec[2] = typebuf;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX,
|
||||
entry->flags & MS_MOVE_FLAGS,
|
||||
entry->inv_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) &&
|
||||
(entry->flags | entry->inv_flags) & ~MS_CMDS) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
if (!build_list_val_expr(typebuf, PATH_MAX+2, entry->dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX,
|
||||
entry->flags & ~MS_CMDS,
|
||||
entry->inv_flags & ~MS_CMDS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!build_mnt_opts(optsbuf, PATH_MAX, entry->opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (entry->allow & AA_MAY_UMOUNT) {
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 1, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (entry->allow & AA_MAY_PIVOTROOT) {
|
||||
p = mntbuf;
|
||||
/* rule class single byte header */
|
||||
p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
|
||||
if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf;
|
||||
if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 2, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
/* didn't actually encode anything */
|
||||
goto fail;
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
PERROR("Enocoding of mount rule failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int post_process_policydb_ents(struct codomain *cod)
|
||||
{
|
||||
int ret = TRUE;
|
||||
int count = 0;
|
||||
|
||||
/* Add fns for rules that should be added to policydb here */
|
||||
if (cod->mnt_ents && kernel_supports_mount) {
|
||||
struct mnt_entry *entry;
|
||||
list_for_each(cod->mnt_ents, entry) {
|
||||
if (regex_type == AARE_DFA &&
|
||||
!process_mnt_entry(cod->policy_rules, entry))
|
||||
ret = FALSE;
|
||||
count++;
|
||||
}
|
||||
} else if (cod->mnt_ents && !kernel_supports_mount)
|
||||
pwarn("profile %s mount rules not enforced\n", cod->name);
|
||||
|
||||
cod->policy_rule_count = count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int process_policydb(struct codomain *cod)
|
||||
{
|
||||
int error = -1;
|
||||
|
||||
if (regex_type == AARE_DFA) {
|
||||
cod->policy_rules = aare_new_ruleset(0);
|
||||
if (!cod->policy_rules)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!post_process_policydb_ents(cod))
|
||||
goto out;
|
||||
|
||||
if (regex_type == AARE_DFA && cod->policy_rule_count > 0) {
|
||||
cod->policy_dfa = aare_create_dfa(cod->policy_rules,
|
||||
&cod->policy_dfa_size,
|
||||
dfaflags);
|
||||
aare_delete_ruleset(cod->policy_rules);
|
||||
cod->policy_rules = NULL;
|
||||
if (!cod->policy_dfa)
|
||||
goto out;
|
||||
}
|
||||
|
||||
aare_reset_matchflags();
|
||||
if (process_hat_policydb(cod) != 0)
|
||||
goto out;
|
||||
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
void reset_regex(void)
|
||||
{
|
||||
aare_reset_matchflags();
|
||||
|
@@ -28,7 +28,6 @@
|
||||
/* #define DEBUG */
|
||||
|
||||
#include "parser.h"
|
||||
#include "mount.h"
|
||||
|
||||
static inline char *get_var_end(char *var)
|
||||
{
|
||||
@@ -131,19 +130,17 @@ void free_var_string(struct var_string *var)
|
||||
free(var);
|
||||
}
|
||||
|
||||
/* doesn't handle variables in options atm */
|
||||
static int expand_entry_variables(char **name, void *entry,
|
||||
int (dup_and_chain)(void *))
|
||||
static int expand_entry_variables(struct cod_entry *entry)
|
||||
{
|
||||
struct set_value *valuelist;
|
||||
int ret = TRUE;
|
||||
char *value;
|
||||
struct var_string *split_var;
|
||||
|
||||
if (!entry) /* can happen when entry is optional */
|
||||
if (!entry) /* shouldn't happen */
|
||||
return ret;
|
||||
|
||||
while ((split_var = split_out_var(*name))) {
|
||||
while ((split_var = split_out_var(entry->name))) {
|
||||
valuelist = get_set_var(split_var->var);
|
||||
if (!valuelist) {
|
||||
int boolean = get_boolean_var(split_var->var);
|
||||
@@ -162,22 +159,24 @@ static int expand_entry_variables(char **name, void *entry,
|
||||
split_var->var);
|
||||
exit(1);
|
||||
}
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
free(entry->name);
|
||||
if (asprintf(&(entry->name), "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
value,
|
||||
split_var->suffix ? split_var->suffix : "") == -1)
|
||||
return FALSE;
|
||||
|
||||
while ((value = get_next_set_value(&valuelist))) {
|
||||
if (!dup_and_chain(entry)) {
|
||||
PERROR("Memory allocation error while handling set variable %s\n",
|
||||
struct cod_entry *dupe = copy_cod_entry(entry);
|
||||
if (!dupe) {
|
||||
PERROR("Memory allocaton error while handling set variable %s\n",
|
||||
split_var->var);
|
||||
exit(1);
|
||||
}
|
||||
entry->next = dupe;
|
||||
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
free(entry->name);
|
||||
if (asprintf(&(entry->name), "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "", value,
|
||||
split_var->suffix ? split_var->suffix : "") == -1)
|
||||
return FALSE;
|
||||
@@ -188,66 +187,15 @@ static int expand_entry_variables(char **name, void *entry,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int clone_and_chain_cod(void *v)
|
||||
{
|
||||
struct cod_entry *entry = v;
|
||||
struct cod_entry *dup = copy_cod_entry(entry);
|
||||
if (!dup)
|
||||
return 0;
|
||||
|
||||
entry->next = dup;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int clone_and_chain_mnt(void *v)
|
||||
{
|
||||
struct mnt_entry *entry = v;
|
||||
|
||||
struct mnt_entry *dup = dup_mnt_entry(entry);
|
||||
if (!dup)
|
||||
return 0;
|
||||
|
||||
entry->next = dup;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||
{
|
||||
int ret = TRUE, rc;
|
||||
struct cod_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
rc = expand_entry_variables(&entry->name, entry,
|
||||
clone_and_chain_cod);
|
||||
rc = expand_entry_variables(entry);
|
||||
if (!rc)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* does not currently support expansion of vars in options */
|
||||
static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
|
||||
{
|
||||
int ret = TRUE, rc;
|
||||
struct mnt_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
rc = expand_entry_variables(&entry->mnt_point, entry,
|
||||
clone_and_chain_mnt);
|
||||
if (!rc)
|
||||
return FALSE;
|
||||
rc = expand_entry_variables(&entry->device, entry,
|
||||
clone_and_chain_mnt);
|
||||
if (!rc)
|
||||
return FALSE;
|
||||
rc = expand_entry_variables(&entry->trans, entry,
|
||||
clone_and_chain_mnt);
|
||||
if (!rc)
|
||||
return FALSE;
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -261,10 +209,6 @@ int process_variables(struct codomain *cod)
|
||||
error = -1;
|
||||
}
|
||||
|
||||
if (!process_variables_in_mnt_entries(cod->mnt_ents)) {
|
||||
error = -1;
|
||||
}
|
||||
|
||||
if (process_hat_variables(cod) != 0) {
|
||||
error = -1;
|
||||
}
|
||||
|
@@ -2,8 +2,8 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
* NOVELL (All rights reserved)
|
||||
* Copyright (c) 2010-2012
|
||||
* Canonical Ltd.
|
||||
* Copyright (c) 2010
|
||||
* Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -32,7 +32,6 @@
|
||||
/* #define DEBUG */
|
||||
|
||||
#include "parser.h"
|
||||
#include "mount.h"
|
||||
#include "parser_include.h"
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -65,23 +64,21 @@
|
||||
|
||||
#define CAP_TO_MASK(x) (1ull << (x))
|
||||
|
||||
int parser_token = 0;
|
||||
struct value_list {
|
||||
char *value;
|
||||
struct value_list *next;
|
||||
};
|
||||
|
||||
void free_value_list(struct value_list *list);
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
char *link_id, char *nt);
|
||||
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode);
|
||||
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition);
|
||||
|
||||
void add_local_entry(struct codomain *cod);
|
||||
|
||||
%}
|
||||
|
||||
%token TOK_ID
|
||||
%token TOK_CONDID
|
||||
%token TOK_CARET
|
||||
%token TOK_SEP
|
||||
%token TOK_OPEN
|
||||
%token TOK_CLOSE
|
||||
%token TOK_MODE
|
||||
@@ -113,14 +110,6 @@ void add_local_entry(struct codomain *cod);
|
||||
%token TOK_SET
|
||||
%token TOK_ALIAS
|
||||
%token TOK_PTRACE
|
||||
%token TOK_OPENPAREN
|
||||
%token TOK_CLOSEPAREN
|
||||
%token TOK_COMMA
|
||||
%token TOK_FILE
|
||||
%token TOK_MOUNT
|
||||
%token TOK_REMOUNT
|
||||
%token TOK_UMOUNT
|
||||
%token TOK_PIVOTROOT
|
||||
|
||||
/* rlimits */
|
||||
%token TOK_RLIMIT
|
||||
@@ -147,6 +136,10 @@ void add_local_entry(struct codomain *cod);
|
||||
|
||||
/* debug flag values */
|
||||
%token TOK_FLAGS
|
||||
%token TOK_FLAG_OPENPAREN
|
||||
%token TOK_FLAG_CLOSEPAREN
|
||||
%token TOK_FLAG_SEP
|
||||
%token TOK_FLAG_ID
|
||||
|
||||
%union {
|
||||
char *id;
|
||||
@@ -156,8 +149,6 @@ void add_local_entry(struct codomain *cod);
|
||||
struct codomain *cod;
|
||||
struct cod_net_entry *net_entry;
|
||||
struct cod_entry *user_entry;
|
||||
struct mnt_entry *mnt_entry;
|
||||
|
||||
struct flagval flags;
|
||||
int fmode;
|
||||
uint64_t cap;
|
||||
@@ -166,13 +157,11 @@ void add_local_entry(struct codomain *cod);
|
||||
char *bool_var;
|
||||
char *var_val;
|
||||
struct value_list *val_list;
|
||||
struct cond_entry *cond_entry;
|
||||
int boolean;
|
||||
struct named_transition transition;
|
||||
}
|
||||
|
||||
%type <id> TOK_ID
|
||||
%type <id> TOK_CONDID
|
||||
%type <mode> TOK_MODE
|
||||
%type <fmode> file_mode
|
||||
%type <cod> profile_base
|
||||
@@ -183,19 +172,14 @@ void add_local_entry(struct codomain *cod);
|
||||
%type <cod> cond_rule
|
||||
%type <network_entry> network_rule
|
||||
%type <user_entry> rule
|
||||
%type <user_entry> file_rule
|
||||
%type <user_entry> file_rule_tail
|
||||
%type <user_entry> link_rule
|
||||
%type <user_entry> ptrace_rule
|
||||
%type <user_entry> frule
|
||||
%type <mnt_entry> mnt_rule
|
||||
%type <cond_entry> opt_conds
|
||||
%type <cond_entry> cond
|
||||
%type <flags> flags
|
||||
%type <flags> flagvals
|
||||
%type <flags> flagval
|
||||
%type <flag_id> TOK_FLAG_ID
|
||||
%type <cap> caps
|
||||
%type <cap> capability
|
||||
%type <cap> set_caps
|
||||
%type <user_entry> change_profile
|
||||
%type <set_var> TOK_SET_VAR
|
||||
%type <bool_var> TOK_BOOL_VAR
|
||||
@@ -207,12 +191,10 @@ void add_local_entry(struct codomain *cod);
|
||||
%type <boolean> opt_audit_flag
|
||||
%type <boolean> opt_owner_flag
|
||||
%type <boolean> opt_profile_flag
|
||||
%type <boolean> opt_flags
|
||||
%type <id> opt_namespace
|
||||
%type <id> opt_id
|
||||
%type <transition> opt_named_transition
|
||||
%type <boolean> opt_unsafe
|
||||
%type <boolean> opt_file
|
||||
%%
|
||||
|
||||
|
||||
@@ -257,7 +239,6 @@ profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
||||
cod->flags.complain = 1;
|
||||
|
||||
post_process_nt_entries(cod);
|
||||
post_process_mnt_entries(cod);
|
||||
PDEBUG("%s: flags='%s%s'\n",
|
||||
$2,
|
||||
cod->flags.complain ? "complain, " : "",
|
||||
@@ -388,23 +369,26 @@ varassign: TOK_BOOL_VAR TOK_EQUALS TOK_VALUE
|
||||
|
||||
valuelist: TOK_VALUE
|
||||
{
|
||||
struct value_list *val = new_value_list($1);
|
||||
if (!val)
|
||||
struct value_list *new = calloc(1, sizeof(struct value_list));
|
||||
if (!new)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("Matched: value (%s)\n", $1);
|
||||
|
||||
$$ = val;
|
||||
new->value = $1;
|
||||
new->next = NULL;
|
||||
$$ = new;
|
||||
}
|
||||
|
||||
valuelist: valuelist TOK_VALUE
|
||||
{
|
||||
struct value_list *val = new_value_list($2);
|
||||
if (!val)
|
||||
struct value_list *new = calloc(1, sizeof(struct value_list));
|
||||
if (!new)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("Matched: value list\n");
|
||||
|
||||
list_append($1, val);
|
||||
$$ = $1;
|
||||
new->value = $2;
|
||||
new->next = $1;
|
||||
$$ = new;
|
||||
}
|
||||
|
||||
flags: { /* nothing */
|
||||
@@ -413,32 +397,25 @@ flags: { /* nothing */
|
||||
$$ = fv;
|
||||
};
|
||||
|
||||
opt_flags: { /* nothing */ $$ = 0; }
|
||||
| TOK_CONDID TOK_EQUALS
|
||||
flags: TOK_FLAGS TOK_EQUALS TOK_FLAG_OPENPAREN flagvals TOK_FLAG_CLOSEPAREN
|
||||
{
|
||||
if (strcmp($1, "flags") != 0)
|
||||
yyerror("expected flags= got %s=", $1);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
flags: opt_flags TOK_OPENPAREN flagvals TOK_CLOSEPAREN
|
||||
{
|
||||
$$ = $3;
|
||||
$$ = $4;
|
||||
};
|
||||
|
||||
flagvals: flagvals flagval
|
||||
flags: TOK_FLAG_OPENPAREN flagvals TOK_FLAG_CLOSEPAREN
|
||||
{
|
||||
$1.complain = $1.complain || $2.complain;
|
||||
$1.audit = $1.audit || $2.audit;
|
||||
$1.path = $1.path | $2.path;
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
flagvals: flagvals TOK_FLAG_SEP flagval
|
||||
{
|
||||
$1.complain = $1.complain || $3.complain;
|
||||
$1.audit = $1.audit || $3.audit;
|
||||
$1.path = $1.path | $3.path;
|
||||
if (($1.path & (PATH_CHROOT_REL | PATH_NS_REL)) ==
|
||||
(PATH_CHROOT_REL | PATH_NS_REL))
|
||||
yyerror(_("Profile flag chroot_relative conflicts with namespace_relative"));
|
||||
|
||||
if (!($1.path & PATH_NS_REL))
|
||||
/* default to chroot relative profiles */
|
||||
$1.path |= PATH_CHROOT_REL;
|
||||
|
||||
if (($1.path & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED)) ==
|
||||
(PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))
|
||||
yyerror(_("Profile flag mediate_deleted conflicts with delegate_deleted"));
|
||||
@@ -457,7 +434,7 @@ flagvals: flagval
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
flagval: TOK_VALUE
|
||||
flagval: TOK_FLAG_ID
|
||||
{
|
||||
struct flagval fv = { 0, 0, 0, 0 };
|
||||
if (strcmp($1, "debug") == 0) {
|
||||
@@ -664,25 +641,6 @@ rules: rules opt_audit_flag network_rule
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
rules: rules opt_audit_flag TOK_DENY mnt_rule
|
||||
{
|
||||
$4->deny = $4->allow;
|
||||
if ($2)
|
||||
$4->audit = $4->allow;
|
||||
$4->next = $1->mnt_ents;
|
||||
$1->mnt_ents = $4;
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
rules: rules opt_audit_flag mnt_rule
|
||||
{
|
||||
if ($2)
|
||||
$3->audit = $3->allow;
|
||||
$3->next = $1->mnt_ents;
|
||||
$1->mnt_ents = $3;
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
rules: rules change_profile
|
||||
{
|
||||
PDEBUG("matched: rules change_profile\n");
|
||||
@@ -709,6 +667,12 @@ rules: rules opt_audit_flag capability
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules set_caps
|
||||
{
|
||||
$1->set_caps |= $2;
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules hat
|
||||
{
|
||||
PDEBUG("Matched: hat rule\n");
|
||||
@@ -928,16 +892,24 @@ opt_named_transition:
|
||||
$$.name = $5;
|
||||
};
|
||||
|
||||
rule: file_rule { $$ = $1; }
|
||||
| link_rule { $$ = $1; }
|
||||
| ptrace_rule {$$ = $1; }
|
||||
|
||||
opt_unsafe: { /* nothing */ $$ = 0; }
|
||||
| TOK_UNSAFE { $$ = 1; };
|
||||
| TOK_SAFE { $$ = 2; };
|
||||
|
||||
opt_file: { /* nothing */ $$ = 0; }
|
||||
| TOK_FILE { $$ = 1; }
|
||||
rule: opt_unsafe frule
|
||||
{
|
||||
if ($1) {
|
||||
if (!($2->mode & AA_EXEC_BITS))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
if ($1 == 1) {
|
||||
$2->mode |= (($2->mode & AA_EXEC_BITS) << 8) &
|
||||
ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
else if ($1 == 2)
|
||||
$2->mode &= ~ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
frule: id_or_var file_mode opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
@@ -961,45 +933,16 @@ frule: file_mode opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
|
||||
}
|
||||
};
|
||||
|
||||
file_rule: TOK_FILE TOK_END_OF_RULE
|
||||
{
|
||||
char *path = strdup("/**");
|
||||
int perms = ((AA_BASE_PERMS & ~AA_EXEC_TYPE) |
|
||||
(AA_EXEC_INHERIT | AA_MAY_EXEC));
|
||||
/* duplicate to other permission set */
|
||||
perms |= perms << AA_OTHER_SHIFT;
|
||||
if (!path)
|
||||
yyerror(_("Memory allocation error."));
|
||||
$$ = do_file_rule(NULL, path, perms, NULL, NULL);
|
||||
}
|
||||
| opt_file file_rule_tail { $$ = $2; }
|
||||
|
||||
|
||||
file_rule_tail: opt_unsafe frule
|
||||
{
|
||||
if ($1) {
|
||||
if (!($2->mode & AA_EXEC_BITS))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
if ($1 == 1) {
|
||||
$2->mode |= (($2->mode & AA_EXEC_BITS) << 8) &
|
||||
ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
else if ($1 == 2)
|
||||
$2->mode &= ~ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
file_rule_tail: opt_unsafe id_or_var file_mode id_or_var
|
||||
rule: opt_unsafe id_or_var file_mode id_or_var
|
||||
{
|
||||
/* Oopsie, we appear to be missing an EOL marker. If we
|
||||
* were *smart*, we could work around it. Since we're
|
||||
* obviously not smart, we'll just punt with a more
|
||||
* sensible error. */
|
||||
yyerror(_("missing an end of line character? (entry: %s)"), $2);
|
||||
yyerror(_("missing an end of line character? (entry: %s)"), $1);
|
||||
};
|
||||
|
||||
link_rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: link tok_id (%s) -> (%s)\n", $3, $5);
|
||||
@@ -1009,7 +952,7 @@ link_rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
ptrace_rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
|
||||
rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
entry = new_entry(NULL, $2, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
|
||||
@@ -1018,7 +961,7 @@ ptrace_rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
|
||||
$$ = entry;
|
||||
};
|
||||
|
||||
ptrace_rule: TOK_PTRACE TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
||||
rule: TOK_PTRACE TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
entry = new_entry($3, $5, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
|
||||
@@ -1066,67 +1009,7 @@ network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
|
||||
$$ = entry;
|
||||
}
|
||||
|
||||
cond: TOK_CONDID TOK_EQUALS TOK_VALUE
|
||||
{
|
||||
struct cond_entry *ent;
|
||||
struct value_list *value = new_value_list($3);
|
||||
if (!value)
|
||||
yyerror(_("Memory allocation error."));
|
||||
ent = new_cond_entry($1, value);
|
||||
if (!ent) {
|
||||
free_value_list(value);
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
$$ = ent;
|
||||
}
|
||||
|
||||
cond: TOK_CONDID TOK_EQUALS TOK_OPENPAREN valuelist TOK_CLOSEPAREN
|
||||
{
|
||||
struct cond_entry *ent = new_cond_entry($1, $4);
|
||||
|
||||
if (!ent)
|
||||
yyerror(_("Memory allocation error."));
|
||||
$$ = ent;
|
||||
}
|
||||
|
||||
opt_conds: { /* nothing */ $$ = NULL; }
|
||||
| opt_conds cond
|
||||
{
|
||||
$2->next = $1;
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_mnt_rule($2, $3, NULL, NULL, AA_MAY_MOUNT);
|
||||
}
|
||||
|
||||
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_ARROW opt_conds TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_mnt_rule($2, $3, $5, $6, AA_MAY_MOUNT);
|
||||
}
|
||||
|
||||
mnt_rule: TOK_REMOUNT opt_conds opt_id TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_mnt_rule($2, NULL, NULL, $3, AA_DUMMY_REMOUNT);
|
||||
}
|
||||
|
||||
mnt_rule: TOK_UMOUNT opt_conds opt_id TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_mnt_rule($2, NULL, NULL, $3, AA_MAY_UMOUNT);
|
||||
}
|
||||
|
||||
mnt_rule: TOK_PIVOTROOT opt_conds opt_id TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_pivot_rule($2, $3, NULL);
|
||||
}
|
||||
|
||||
mnt_rule: TOK_PIVOTROOT opt_conds opt_id TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_pivot_rule($2, $3, $5);
|
||||
}
|
||||
|
||||
hat_start: TOK_CARET {}
|
||||
hat_start: TOK_SEP {}
|
||||
| TOK_HAT {}
|
||||
|
||||
file_mode: TOK_MODE
|
||||
@@ -1160,17 +1043,17 @@ change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_COLON TOK_ID TOK_COLON TOK_ID T
|
||||
};
|
||||
|
||||
|
||||
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
|
||||
set_caps: TOK_SET TOK_CAPABILITY caps TOK_END_OF_RULE
|
||||
{
|
||||
if ($2 == 0) {
|
||||
/* bare capability keyword - set all caps */
|
||||
$$ = 0xffffffffffffffff;
|
||||
} else
|
||||
$$ = $2;
|
||||
$$ = $3;
|
||||
};
|
||||
|
||||
caps: { /* nothing */ $$ = 0; }
|
||||
| caps TOK_ID
|
||||
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
|
||||
{
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
caps: caps TOK_ID
|
||||
{
|
||||
int cap = name_to_capability($2);
|
||||
if (cap == -1)
|
||||
@@ -1179,14 +1062,26 @@ caps: { /* nothing */ $$ = 0; }
|
||||
$$ = $1 | CAP_TO_MASK(cap);
|
||||
}
|
||||
|
||||
caps: TOK_ID
|
||||
{
|
||||
int cap = name_to_capability($1);
|
||||
if (cap == -1)
|
||||
yyerror(_("Invalid capability %s."), $1);
|
||||
free($1);
|
||||
$$ = CAP_TO_MASK(cap);
|
||||
};
|
||||
|
||||
%%
|
||||
#define MAXBUFSIZE 4096
|
||||
|
||||
void vprintyyerror(const char *msg, va_list argptr)
|
||||
void yyerror(char *msg, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[MAXBUFSIZE];
|
||||
|
||||
vsnprintf(buf, sizeof(buf), msg, argptr);
|
||||
va_start(arg, msg);
|
||||
vsnprintf(buf, sizeof(buf), msg, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (profilename) {
|
||||
PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
|
||||
@@ -1200,28 +1095,23 @@ void vprintyyerror(const char *msg, va_list argptr)
|
||||
current_filename ? current_filename : "",
|
||||
current_lineno, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void printyyerror(const char *msg, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, msg);
|
||||
vprintyyerror(msg, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
void yyerror(const char *msg, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, msg);
|
||||
vprintyyerror(msg, arg);
|
||||
va_end(arg);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void free_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *next;
|
||||
|
||||
while (list) {
|
||||
next = list->next;
|
||||
if (list->value)
|
||||
free(list->value);
|
||||
free(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
||||
char *link_id, char *nt)
|
||||
{
|
||||
@@ -1259,74 +1149,3 @@ void add_local_entry(struct codomain *cod)
|
||||
add_entry_to_policy(cod, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static char *mnt_cond_msg[] = {"",
|
||||
" not allowed as source conditional",
|
||||
" not allowed as target conditional",
|
||||
"",
|
||||
NULL};
|
||||
|
||||
int verify_mnt_conds(struct cond_entry *conds, int src)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
int error = 0;
|
||||
|
||||
if (!conds)
|
||||
return 0;
|
||||
|
||||
list_for_each(conds, entry) {
|
||||
int res = is_valid_mnt_cond(entry->name, src);
|
||||
if (res <= 0) {
|
||||
printyyerror(_("invalid mount conditional %s%s"),
|
||||
entry->name,
|
||||
res == -1 ? "" : mnt_cond_msg[src]);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode)
|
||||
{
|
||||
struct mnt_entry *ent;
|
||||
|
||||
if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0)
|
||||
yyerror(_("bad mount rule"));
|
||||
|
||||
/* FIXME: atm conditions are not supported on dst
|
||||
if (verify_conds(dst_conds, DST_OPT) != 0)
|
||||
yyerror(_("bad mount rule"));
|
||||
*/
|
||||
if (dst_conds)
|
||||
yyerror(_("mount point conditions not currently supported"));
|
||||
|
||||
ent = new_mnt_entry(src_conds, src, dst_conds, dst, mode);
|
||||
if (!ent) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition)
|
||||
{
|
||||
struct mnt_entry *ent = NULL;
|
||||
|
||||
if (old) {
|
||||
if (strcmp(old->name, "oldroot") != 0)
|
||||
yyerror(_("invalid pivotroot conditional '%s'"), old->name);
|
||||
}
|
||||
|
||||
ent = new_mnt_entry(NULL, old->vals->value, NULL, root,
|
||||
AA_MAY_PIVOTROOT);
|
||||
ent->trans = transition;
|
||||
|
||||
old->vals->value = NULL;
|
||||
free_cond_entry(old);
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* 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_POLICYDB_H
|
||||
#define __AA_POLICYDB_H
|
||||
|
||||
/*
|
||||
* Class of mediation types in the AppArmor policy db
|
||||
*/
|
||||
#define AA_CLASS_COND 0
|
||||
#define AA_CLASS_UNKNOWN 1
|
||||
#define AA_CLASS_FILE 2
|
||||
#define AA_CLASS_CAP 3
|
||||
#define AA_CLASS_NET 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
#define AA_CLASS_MOUNT 7
|
||||
#define AA_CLASS_NS_DOMAIN 8
|
||||
#define AA_CLASS_PTRACE 9
|
||||
|
||||
#define AA_CLASS_ENV 16
|
||||
|
||||
#define AA_CLASS_DBUS 32
|
||||
#define AA_CLASS_X 33
|
||||
|
||||
#endif /* __AA_POLICYDB_H */
|
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999-2008 NOVELL (All rights reserved)
|
||||
# Copyright (c) 2009-2012 Canonical Ltd. (All rights reserved)
|
||||
# Copyright (c) 2009-2011 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
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# 2008, 2009
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# Copyright (c) 2010 - 2012
|
||||
# Copyright (c) 2010
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
@@ -12,8 +12,8 @@ endif
|
||||
|
||||
all: tests
|
||||
|
||||
.PHONY: tests error_output gen_xtrans parser_sanity caching minimize
|
||||
tests: error_output gen_xtrans parser_sanity caching minimize
|
||||
.PHONY: tests error_output gen_xtrans parser_sanity caching
|
||||
tests: error_output gen_xtrans parser_sanity caching
|
||||
|
||||
GEN_TRANS_DIRS=simple_tests/generated_x/ simple_tests/generated_perms_leading/ simple_tests/generated_perms_safe/
|
||||
|
||||
@@ -41,9 +41,6 @@ parser_sanity: $(PARSER)
|
||||
caching: $(PARSER)
|
||||
LANG=C ./caching.sh
|
||||
|
||||
minimize: $(PARSER)
|
||||
LANG=C ./minimize.sh
|
||||
|
||||
$(PARSER):
|
||||
make -C $(PARSER_DIR) $(PARSER_BIN)
|
||||
|
||||
|
@@ -49,34 +49,11 @@ echo -n "Profiles are cached when requested: "
|
||||
[ ! -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
read_features_dir()
|
||||
{
|
||||
directory="$1"
|
||||
if [ ! -d "$directory" ] ; then
|
||||
return
|
||||
fi
|
||||
for f in `ls -AU "$directory"` ; do
|
||||
if [ -f "$directory/$f" ] ; then
|
||||
read -r -d "" KF < "$directory/$f" || true
|
||||
echo -e "$f {$KF\n}"
|
||||
elif [ -d "$directory/$f" ] ; then
|
||||
echo -n "$f {"
|
||||
KF=`read_features_dir "$directory/$f" "$KF"` || true
|
||||
echo "$KF"
|
||||
echo -e "}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo -n "Kernel features are written to cache: "
|
||||
[ ! -f $basedir/cache/.features ] && echo "FAIL ($basedir/cache/.features missing)" && exit 1
|
||||
read -r -d "" CF < $basedir/cache/.features || true
|
||||
if [ -d /sys/kernel/security/apparmor/features ] ; then
|
||||
KF=`read_features_dir /sys/kernel/security/apparmor/features`
|
||||
else
|
||||
read -r -d "" KF < /sys/kernel/security/apparmor/features || true
|
||||
fi
|
||||
[ "$CF" != "$KF" ] && echo -e "FAIL (feature text mismatch:\n cache '$CF'\nvs\n kernel '$KF')" && exit 1
|
||||
read CF < $basedir/cache/.features || true
|
||||
read KF < /sys/kernel/security/apparmor/features || true
|
||||
[ "$CF" != "$KF" ] && echo "FAIL (feature text mismatch: cache '$CF' vs kernel '$KF')" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is loaded when it exists and features match: "
|
||||
|
@@ -1,199 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Format of -D dfa-states
|
||||
# dfa-states output is split into 2 parts:
|
||||
# the accept state infomation
|
||||
# {state} (allow deny audit XXX) ignore XXX for now
|
||||
# followed by the transition table information
|
||||
# {Y} -> {Z}: 0xXX Char #0xXX is the hex dump of Char
|
||||
# where the start state is always shown as
|
||||
# {1} <==
|
||||
#
|
||||
# Eg. echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ./apparmor_parser -QT -O minimize -D dfa-states --quiet
|
||||
#
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 0/2800a/0/2800a)
|
||||
# {4} (0x 10004/2800a/0/2800a)
|
||||
# {7} (0x 40010/2800a/0/2800a)
|
||||
# {8} (0x 80020/2800a/0/2800a)
|
||||
# {9} (0x 100040/2800a/0/2800a)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
#
|
||||
# {1} -> {2}: 0x2f /
|
||||
# {2} -> {4}: 0x61 a
|
||||
# {2} -> {3}: 0x62 b
|
||||
# {2} -> {3}: 0x63 c
|
||||
# {2} -> {7}: 0x64 d
|
||||
# {2} -> {8}: 0x65 e
|
||||
# {2} -> {9}: 0x66 f
|
||||
# {2} -> {3}: [^\0x0/]
|
||||
# {3} -> {3}: [^\0x0]
|
||||
# {4} -> {3}: [^\0x0]
|
||||
# {7} -> {a}: 0x0
|
||||
# {7} -> {3}: []
|
||||
# {8} -> {3}: [^\0x0]
|
||||
# {9} -> {3}: [^\0x0]
|
||||
# {a} -> {b}: 0x2f /
|
||||
# {b} -> {c}: [^/]
|
||||
# {c} -> {c}: []
|
||||
#
|
||||
# These tests currently only look at the accept state permissions
|
||||
#
|
||||
# To view any of these DFAs as graphs replace --D dfa-states with -D dfa-graph
|
||||
# strip of the test stuff around the parser command and use the the dot
|
||||
# command to convert
|
||||
# Eg.
|
||||
# echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ./apparmor_parser -QT -O minimize -D dfa-graph --quiet 2>min.graph
|
||||
# dot -T png -o min.png min.graph
|
||||
# and then view min.png in your favorite viewer
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
# test to see if minimization is eliminating non-redundant accept state
|
||||
# Test xtrans and regular perms separately. The are the same basic failure
|
||||
# but can xtrans has an extra code path.
|
||||
#
|
||||
# The permission test is setup to have all the none xtrans permissions show
|
||||
# up once on unique paths and have a global write permission that adds to
|
||||
# it.
|
||||
# This should result in a un-minimized dump looking like. Notice it has 6
|
||||
# states with accept information, 1 for each rule except for the 'w'
|
||||
# permission which is combined into a single state for /b and /**
|
||||
#
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 2800a/0/0/0)
|
||||
# {4} (0x 3800e/0/0/0)
|
||||
# {5} (0x 6801a/0/0/0)
|
||||
# {6} (0x a802a/0/0/0)
|
||||
# {7} (0x 12804a/0/0/0)
|
||||
# {a} (0x 40030/0/0/0)
|
||||
# A dump of minimization that is not respecting the uniqueness of the
|
||||
# permissions on the states looks like below. Notice it has only 3 states
|
||||
# with accept information
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 1b806e/0/0/0)
|
||||
# {5} (0x 6801a/0/0/0)
|
||||
# {a} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles basic perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# same test as above except with audit perms added
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 2800a/0/2800a/0)
|
||||
# {4} (0x 3800e/0/2800a/0)
|
||||
# {7} (0x 6801a/0/2800a/0)
|
||||
# {8} (0x a802a/0/2800a/0)
|
||||
# {9} (0x 12804a/0/2800a/0)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
echo -n "Minimize profiles audit perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# same test as above except with deny 'w' perm added to /**, this does not
|
||||
# elimnates the states with 'w' and 'a' because the quiet information is
|
||||
# being carried
|
||||
#
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 0/2800a/0/2800a)
|
||||
# {4} (0x 10004/2800a/0/2800a)
|
||||
# {7} (0x 40010/2800a/0/2800a)
|
||||
# {8} (0x 80020/2800a/0/2800a)
|
||||
# {9} (0x 100040/2800a/0/2800a)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles deny perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# same test as above except with audit deny 'w' perm added to /**, with the
|
||||
# parameter this elimnates the states with 'w' and 'a' because
|
||||
# the quiet information is NOT being carried
|
||||
#
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {4} (0x 10004/0/0/0)
|
||||
# {7} (0x 40010/0/0/0)
|
||||
# {8} (0x 80020/0/0/0)
|
||||
# {9} (0x 100040/0/0/0)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
|
||||
# The x transition test profile is setup so that there are 3 conflicting x
|
||||
# permissions, two are on paths that won't collide during dfa creation. The
|
||||
# 3rd is a generic permission that should be overriden during dfa creation.
|
||||
#
|
||||
# This should result in a dfa that specifies transitions on 'a' and 'b' to
|
||||
# unique states that store the alternate accept information. However
|
||||
# minimization can remove the unique accept permission states if x permissions
|
||||
# are treated as a single accept state.
|
||||
#
|
||||
# The minimized dump should retain the 'a' and 'b' transitions accept states.
|
||||
# notice the below dump has 3 states with accept information {3}, {4}, {5}
|
||||
#
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 2914a45/0/0/0)
|
||||
# {4} (0x 4115045/0/0/0)
|
||||
# {5} (0x 2514945/0/0/0)
|
||||
#
|
||||
# A dump of minimization that is not respecting the uniqueness of the
|
||||
# permissions on the states transitioned to by 'a' and 'b' looks like
|
||||
# below. Notice that only state {3} has accept information
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 2514945/0/0/0)
|
||||
#
|
||||
|
||||
echo -n "Minimize profiles xtrans "
|
||||
if [ `echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# same test as above + audit
|
||||
echo -n "Minimize profiles audit xtrans "
|
||||
if [ `echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
|
||||
# now try denying x and make sure perms are cleared
|
||||
# notice that only deny and quiet information is being carried
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 0/fe17f85/0/14005)
|
||||
|
||||
echo -n "Minimize profiles deny xtrans "
|
||||
if [ `echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 1 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# now try audit + denying x and make sure perms are cleared
|
||||
# notice that the deny info is being carried, by an artifical trap state
|
||||
# {1} <== (allow/deny/audit/quiet)
|
||||
# {3} (0x 0/fe17f85/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny xtrans "
|
||||
if [ `echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '(.*)$' | wc -l` -ne 1 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
echo "ok"
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION fail CAP_XXX syntax.
|
||||
#=EXRESULT FAIL
|
||||
# vim:syntax=subdomain
|
||||
# Last Modified: Sun Apr 17 19:44:44 2005
|
||||
#
|
||||
/does/not/exist {
|
||||
capability chown CAP_CHOWN,
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION fail unknown keyword
|
||||
#=EXRESULT FAIL
|
||||
# vim:syntax=subdomain
|
||||
# Last Modified: Sun Apr 17 19:44:44 2005
|
||||
#
|
||||
/does/not/exist {
|
||||
capability chown foobar,
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION validate some uses of capabilties.
|
||||
#=EXRESULT PASS
|
||||
# vim:syntax=subdomain
|
||||
# Last Modified: Sun Apr 17 19:44:44 2005
|
||||
#
|
||||
/does/not/exist {
|
||||
capability,
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#=DESCRIPTION validate some uses of capabilties.
|
||||
#=EXRESULT FAIL
|
||||
#=EXRESULT PASS
|
||||
# vim:syntax=subdomain
|
||||
# Last Modified: Sun Apr 17 19:44:44 2005
|
||||
#
|
||||
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic file rule
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file rw,
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION w and a conflict
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /a wa,
|
||||
}
|
||||
|
@@ -1,7 +0,0 @@
|
||||
k#
|
||||
#=DESCRIPTION comma in pathname
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foobar, r,
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
#=DESCRIPTION Simple test case for embedded spaces
|
||||
#=EXRESULT FAIL
|
||||
|
||||
/bin/foo {
|
||||
file /abc\ def r,
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION k to be lower case
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /bin/ls K,
|
||||
}
|
||||
|
@@ -1,41 +0,0 @@
|
||||
# vim:syntax=subdomain
|
||||
# Last Modified: Wed Aug 31 11:14:09 2005
|
||||
#=DESCRIPTION dos line endings
|
||||
#=EXRESULT PASS
|
||||
/usr/lib/RealPlayer10/realplay {
|
||||
#include <includes/base>
|
||||
#include <includes/fonts>
|
||||
|
||||
file /bin/bash ix,
|
||||
file /bin/sed ixr,
|
||||
file /bin/true ixr,
|
||||
file /etc/opt/gnome/pango/pango.modules r,
|
||||
file /opt/gnome/lib/gtk-2.0/2.4.0/loaders/* r,
|
||||
file /opt/gnome/lib/lib*so* r,
|
||||
file /opt/gnome/lib/pango/1.4.0/modules/* r,
|
||||
file /opt/gnome/share/icons r,
|
||||
file /opt/gnome/share/icons/** r,
|
||||
file /opt/gnome/bin/nautilus rux,
|
||||
file /root r,
|
||||
file /root/.Xauthority r,
|
||||
file /root/.fonts.cache-1 r,
|
||||
file /root/.realplayerrc rw,
|
||||
file /home/*/ r,
|
||||
file /home/*/.Xauthority r,
|
||||
file /home/*/.fonts.cache-1 r,
|
||||
file /home/*/.realplayerrc rw,
|
||||
file /usr/X11R6/lib/Acrobat7/Resource/Font/* r,
|
||||
file /usr/X11R6/lib/Acrobat7/Resource/Font/PFM/* r,
|
||||
file /usr/lib/RealPlayer10/** r,
|
||||
file /usr/lib/RealPlayer10/realplay.bin ixr,
|
||||
file /usr/lib/jvm/java-1.4.2-sun-1.4.2.06/jre/lib/fonts/** r,
|
||||
file /usr/lib/ooo-2.0/share/fonts/** r,
|
||||
file /opt/MozillaFirefox/bin/firefox.sh pxr,
|
||||
file /opt/MozillaFirefox/lib/firefox-bin pxr,
|
||||
file /opt/MozillaFirefox/lib/init.d r,
|
||||
file /usr/bin/opera pxr,
|
||||
file /usr/share/icons r,
|
||||
file /usr/share/icons/** r,
|
||||
file /opt/gnome/share/pixmaps r,
|
||||
file /opt/gnome/share/pixmaps/** r,
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION perms before pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
|
||||
file r /foo1,
|
||||
file w /foo1,
|
||||
file a /foo1,
|
||||
file k /foo1,
|
||||
file m /foo1,
|
||||
file l /foo1,
|
||||
file px /foo1,
|
||||
file Px /foo2,
|
||||
file ux /foo3,
|
||||
file Ux /foo4,
|
||||
file ix /foo5,
|
||||
file unsafe px /foo6,
|
||||
file unsafe Px /foo7,
|
||||
file unsafe ux /foo8,
|
||||
file unsafe Ux /foo9,
|
||||
file unsafe ix /foo10,
|
||||
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic file rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /usr/bin/foo r,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic file rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file,
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION A simple successful profile
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /usr/bin/foo r,
|
||||
file /usr/bin/blah rix,
|
||||
}
|
||||
|
@@ -1,13 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION test append
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /bin/cat a,
|
||||
file /bin/true ra,
|
||||
file /bin/false ma,
|
||||
file /lib/libc.so la,
|
||||
file /bin/less ixa,
|
||||
file /bin/more pxa,
|
||||
file /a uxa,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION carat in pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo^bar r,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION trailing carat in pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo/bar^ r,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION comma in pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo,bar r,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION comma at end of pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file "/foobar," r,
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
#=DESCRIPTION Simple test case for embedded spaces
|
||||
#=EXRESULT PASS
|
||||
|
||||
/bin/foo {
|
||||
file "/abc\ def" r,
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
#=DESCRIPTION Simple test case for embedded spaces
|
||||
#=EXRESULT PASS
|
||||
|
||||
/bin/foo {
|
||||
file "/abc def" r,
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
#=DESCRIPTION Simple test case for embedded spaces
|
||||
#=EXRESULT PASS
|
||||
|
||||
"/bin/fo o" {
|
||||
file "/abc def" r,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION carat in pathname
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo[^me]bar r,
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION k and other perms do not conflict
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /bin/a k,
|
||||
file /bin/b rk,
|
||||
file /bin/c wk,
|
||||
file /bin/d ak,
|
||||
file /bin/e lk,
|
||||
file /bin/e mk,
|
||||
file /bin/f pxk,
|
||||
file /bin/g Pxk,
|
||||
file /bin/h ixk,
|
||||
file /bin/i uxk,
|
||||
file /bin/j Uxk,
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION m and [uUpPi]x do not conflict
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /bin/cat mix,
|
||||
file /bin/true mpx,
|
||||
file /bin/false mux,
|
||||
file /lib/libc.so rwlm,
|
||||
file /bin/less mUx,
|
||||
file /bin/more mPx,
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION m and [upi]x do not conflict, seperate rules
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /bin/cat rm,
|
||||
file /bin/cat ix,
|
||||
file /bin/true px,
|
||||
file /bin/true m,
|
||||
file /bin/false m,
|
||||
file /bin/false ux,
|
||||
file /lib/libc.so rwl,
|
||||
file /lib/libc.so m,
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner can not follow path name
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo owner rw,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner cannot follow permission
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /foo rw owner,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner rules must have comma termination
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
owner file /foo rw
|
||||
file /bar rw,
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner not allowed after forward perm
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file rw owner /foo,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner not allowed after pathname in forward rule
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file rw /foo owner,
|
||||
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION owner block needs } termination
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
owner {
|
||||
file rw foo,
|
||||
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION test owner flag for file rules
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
|
||||
owner file /foo rw,
|
||||
owner file /foo/** rw,
|
||||
|
||||
owner file rw /bar,
|
||||
owner file rw /bar/**,
|
||||
|
||||
owner {
|
||||
file /one rw,
|
||||
file /one/** rw,
|
||||
|
||||
file rw /two,
|
||||
file rw /two/**,
|
||||
}
|
||||
|
||||
owner {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount fstype=(procfs) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount fstype=(procfs, sysfs) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount fstype={procfs,sysfs} -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount fstype=(procfs sysfs) none -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, ro) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=procfs -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=(procfs) none -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(bind) /bar -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /bar -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
remount /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
umount /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /**,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /{foo,bar},
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
|
||||
@{mntpnt}=/foo/bar
|
||||
|
||||
/usr/bin/foo {
|
||||
mount @{mntpnt},
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
@{dev}=/one /two /three /four
|
||||
|
||||
/usr/bin/foo {
|
||||
mount @{dev} -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount none -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount fstype=(procfs sysfs) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /dev/bar -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount /dev/** -> /foo,
|
||||
}
|
@@ -1,13 +1,11 @@
|
||||
#
|
||||
#=DESCRIPTION test for conflict resolution in minimization phase of dfa gen
|
||||
#=EXRESULT PASS
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
#
|
||||
/usr/bin/foo {
|
||||
|
||||
/b px,
|
||||
/* Pixr,
|
||||
/a Cx -> foo,
|
||||
# need to build minimal test for this yet
|
||||
|
||||
}
|
||||
|
||||
|
@@ -1,11 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION test for conflict resolution in minimization phase of dfa gen
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
#
|
||||
/usr/bin/foo {
|
||||
/b* px,
|
||||
/* Pixr,
|
||||
/a* Cx -> foo,
|
||||
}
|
||||
|
@@ -36,8 +36,6 @@
|
||||
/usr/lib{,32,64}/dri/** mr,
|
||||
/usr/lib/@{multiarch}/dri/** mr,
|
||||
/dev/dri/** rw,
|
||||
/etc/drirc r,
|
||||
owner @{HOME}/.drirc r,
|
||||
|
||||
# mouse themes
|
||||
/etc/X11/cursors/ r,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user