mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-05 00:35:13 +00:00
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f9e9954f12 | ||
|
3ec3fc47a1 | ||
|
86d193e183 | ||
|
ca7f79174e | ||
|
515d93ab1a | ||
|
ad6833bb34 | ||
|
3c5d40e84a | ||
|
eac7202808 | ||
|
3b61d42f79 | ||
|
f34d60b1e8 | ||
|
29b21b09d4 | ||
|
96395d9b82 | ||
|
9980ae76d8 | ||
|
dd136f4dd9 | ||
|
e5a3c03357 | ||
|
6831a8f440 | ||
|
ea5b52d3b2 | ||
|
3cdeb140a1 | ||
|
8c49449e46 | ||
|
a3685436eb | ||
|
2610fe4e80 | ||
|
c7f761b710 | ||
|
f00f296201 | ||
|
83772acf00 | ||
|
1d35eedef8 | ||
|
a597a612a7 | ||
|
64463c8686 | ||
|
7bd1c4d8ef | ||
|
c7bd872071 | ||
|
3d33fd440b | ||
|
e37cbd43c9 | ||
|
f91f33f2c6 | ||
|
51751aa687 | ||
|
89f1a84dfe | ||
|
d984b3edb6 | ||
|
2a7ddbc773 | ||
|
54bb7dccf0 | ||
|
aff29ef0ee | ||
|
26e85c17bd | ||
|
bdcd76a8ea | ||
|
e69cb50479 | ||
|
5a25bc6240 | ||
|
06e15a7789 | ||
|
d0e086e93a | ||
|
0e6b48cc78 |
@@ -104,6 +104,7 @@ test-profiles:
|
||||
script:
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-extras
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
|
@@ -454,6 +454,7 @@ static int detailed_output(FILE *json) {
|
||||
const char *process_statuses[] = {"enforce", "complain", "unconfined", "mixed", "kill"};
|
||||
int ret;
|
||||
size_t i;
|
||||
int need_finish = 0;
|
||||
|
||||
ret = get_profiles(&profiles, &nprofiles);
|
||||
if (ret != 0) {
|
||||
@@ -534,18 +535,19 @@ static int detailed_output(FILE *json) {
|
||||
} else {
|
||||
fprintf(json, "%s\"%s\": [{\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
|
||||
// first element will be a unique executable
|
||||
j == 0 ? "" : "], ",
|
||||
j == 0 && !need_finish ? "" : "], ",
|
||||
filtered[j].exe, filtered[j].profile, filtered[j].pid, filtered[j].mode);
|
||||
}
|
||||
|
||||
}
|
||||
if (j > 0) {
|
||||
fprintf(json, "]");
|
||||
need_finish = 1;
|
||||
}
|
||||
}
|
||||
free_processes(filtered, nfiltered);
|
||||
}
|
||||
if (json) {
|
||||
if (need_finish > 0) {
|
||||
fprintf(json, "]");
|
||||
}
|
||||
fprintf(json, "}}\n");
|
||||
}
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
3.1.3
|
||||
3.1.6
|
||||
|
@@ -33,9 +33,9 @@ INCLUDES = $(all_includes)
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 13
|
||||
AA_LIB_REVISION = 2
|
||||
AA_LIB_REVISION = 3
|
||||
AA_LIB_AGE = 12
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.12.2
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.12.3
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
|
1
libraries/libapparmor/testsuite/test_multi/file_xm.in
Normal file
1
libraries/libapparmor/testsuite/test_multi/file_xm.in
Normal file
@@ -0,0 +1 @@
|
||||
type=AVC msg=audit(1676978994.840:1493): apparmor="DENIED" operation="link" profile="cargo" name="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib" pid=12412 comm="cargo" requested_mask="xm" denied_mask="xm" fsuid=250 ouid=250 target="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib"FSUID="portage" OUID="portage"
|
16
libraries/libapparmor/testsuite/test_multi/file_xm.out
Normal file
16
libraries/libapparmor/testsuite/test_multi/file_xm.out
Normal file
@@ -0,0 +1,16 @@
|
||||
START
|
||||
File: file_xm.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1676978994.840:1493
|
||||
Operation: link
|
||||
Mask: xm
|
||||
Denied Mask: xm
|
||||
fsuid: 250
|
||||
ouid: 250
|
||||
Profile: cargo
|
||||
Name: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib
|
||||
Command: cargo
|
||||
Name2: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib
|
||||
PID: 12412
|
||||
Epoch: 1676978994
|
||||
Audit subid: 1493
|
@@ -0,0 +1,4 @@
|
||||
profile cargo {
|
||||
owner /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib m,
|
||||
|
||||
}
|
@@ -172,7 +172,7 @@ B<MOUNT FLAGS EXPRESSION> = ( I<MOUNT FLAGS LIST> | I<MOUNT EXPRESSION> )
|
||||
|
||||
B<MOUNT FLAGS LIST> = Comma separated list of I<MOUNT FLAGS>.
|
||||
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nouser' | 'user' )
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nostrictatime' | 'lazytime' | 'nolazytime' | 'nouser' | 'user' | 'symfollow' | 'nosymfollow' )
|
||||
|
||||
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
|
||||
|
||||
|
733
parser/mount.cc
733
parser/mount.cc
@@ -98,6 +98,9 @@
|
||||
* nomand
|
||||
* #define MS_DIRSYNC 128 Directory modifications are synchronous
|
||||
* dirsync
|
||||
* #define MS_NOSYMFOLLOW 256 Do not follow symlinks
|
||||
* symfollow
|
||||
* nosymfollow
|
||||
* #define MS_NOATIME 1024 Do not update access times
|
||||
* noatime
|
||||
* atime
|
||||
@@ -139,6 +142,9 @@
|
||||
* #define MS_STRICTATIME (1<<24) Always perform atime updates
|
||||
* strictatime
|
||||
* nostrictatime
|
||||
* #define MS_LAZYTIME (1<<25) Update the on-disk [acm]times lazily
|
||||
* lazytime
|
||||
* nolazytime
|
||||
* #define MS_NOSEC (1<<28)
|
||||
* #define MS_BORN (1<<29)
|
||||
* #define MS_ACTIVE (1<<30)
|
||||
@@ -246,6 +252,8 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"mand", MS_MAND, 0},
|
||||
{"nomand", 0, MS_MAND},
|
||||
{"dirsync", MS_DIRSYNC, 0},
|
||||
{"symfollow", 0, MS_NOSYMFOLLOW},
|
||||
{"nosymfollow", MS_NOSYMFOLLOW, 0},
|
||||
{"atime", 0, MS_NOATIME},
|
||||
{"noatime", MS_NOATIME, 0},
|
||||
{"diratime", 0, MS_NODIRATIME},
|
||||
@@ -283,6 +291,9 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"iversion", MS_IVERSION, 0},
|
||||
{"noiversion", 0, MS_IVERSION},
|
||||
{"strictatime", MS_STRICTATIME, 0},
|
||||
{"nostrictatime", 0, MS_STRICTATIME},
|
||||
{"lazytime", MS_LAZYTIME, 0},
|
||||
{"nolazytime", 0, MS_LAZYTIME},
|
||||
{"user", 0, (unsigned int) MS_NOUSER},
|
||||
{"nouser", (unsigned int) MS_NOUSER, 0},
|
||||
|
||||
@@ -298,6 +309,22 @@ static struct mnt_keyword_table mnt_conds_table[] = {
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static ostream &dump_flags(ostream &os,
|
||||
pair <unsigned int, unsigned int> flags)
|
||||
{
|
||||
for (int i = 0; mnt_opts_table[i].keyword; i++) {
|
||||
if ((flags.first & mnt_opts_table[i].set) ||
|
||||
(flags.second & mnt_opts_table[i].clear))
|
||||
os << mnt_opts_table[i].keyword;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, pair<unsigned int, unsigned int> flags)
|
||||
{
|
||||
return dump_flags(os, flags);
|
||||
}
|
||||
|
||||
static int find_mnt_keyword(struct mnt_keyword_table *table, const char *name)
|
||||
{
|
||||
int i;
|
||||
@@ -320,7 +347,7 @@ int is_valid_mnt_cond(const char *name, int src)
|
||||
|
||||
static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
unsigned int flags = 0, invflags = 0;
|
||||
*inv = 0;
|
||||
|
||||
struct value_list *entry, *tmp, *prev = NULL;
|
||||
@@ -329,11 +356,11 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
i = find_mnt_keyword(mnt_opts_table, entry->value);
|
||||
if (i != -1) {
|
||||
flags |= mnt_opts_table[i].set;
|
||||
*inv |= mnt_opts_table[i].clear;
|
||||
invflags |= 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);
|
||||
mnt_opts_table[i].clear, flags, invflags);
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *list)
|
||||
@@ -344,9 +371,27 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
if (inv)
|
||||
*inv = invflags;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static bool conflicting_flags(unsigned int flags, unsigned int inv)
|
||||
{
|
||||
if (flags & inv) {
|
||||
for (int i = 0; i < 31; i++) {
|
||||
unsigned int mask = 1 << i;
|
||||
if ((flags & inv) & mask) {
|
||||
cerr << "conflicting flag values = "
|
||||
<< flags << ", " << inv << "\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
@@ -369,22 +414,19 @@ static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
static struct cond_entry *extract_options(struct cond_entry **conds, int eq)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
|
||||
struct cond_entry *entry, *tmp, *prev = NULL;
|
||||
struct cond_entry *list = NULL, *entry, *tmp, *prev = NULL;
|
||||
|
||||
list_for_each_safe(*conds, entry, tmp) {
|
||||
if ((strcmp(entry->name, "options") == 0 ||
|
||||
strcmp(entry->name, "option") == 0) &&
|
||||
entry->eq == eq) {
|
||||
list_remove_at(*conds, prev, entry);
|
||||
PDEBUG(" extracting option %s\n", entry->name);
|
||||
list_append(entry->vals, list);
|
||||
list = entry->vals;
|
||||
entry->vals = NULL;
|
||||
free_cond_entry(entry);
|
||||
PDEBUG(" extracting %s %s\n", entry->name, entry->eq ?
|
||||
"=" : "in");
|
||||
list_append(entry, list);
|
||||
list = entry;
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
@@ -392,60 +434,129 @@ static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
return list;
|
||||
}
|
||||
|
||||
static void perror_conds(const char *rule, struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
|
||||
list_for_each(conds, entry) {
|
||||
PERROR( "unsupported %s condition '%s%s(...)'\n", rule, entry->name, entry->eq ? "=" : " in ");
|
||||
}
|
||||
}
|
||||
|
||||
static void perror_vals(const char *rule, struct value_list *vals)
|
||||
{
|
||||
struct value_list *entry;
|
||||
|
||||
list_for_each(vals, entry) {
|
||||
PERROR( "unsupported %s value '%s'\n", rule, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
||||
unsigned int &inv_flags)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
struct value_list *vals;
|
||||
|
||||
entry = list_pop(opts);
|
||||
vals = entry->vals;
|
||||
entry->vals = NULL;
|
||||
/* fail if there are any unknown optional flags */
|
||||
if (opts) {
|
||||
PERROR(" unsupported multiple 'mount options %s(...)'\n", entry->eq ? "=" : " in ");
|
||||
exit(1);
|
||||
}
|
||||
free_cond_entry(entry);
|
||||
|
||||
flags = extract_flags(&vals, &inv_flags);
|
||||
if (vals) {
|
||||
perror_vals("mount option", vals);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
int allow_p):
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
flags(0), inv_flags(0), audit(0), deny(0)
|
||||
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
|
||||
if (src_conds) {
|
||||
struct value_list *list = extract_options(&src_conds, 0);
|
||||
/* move options in () to local list */
|
||||
struct cond_entry *opts_in = extract_options(&src_conds, 0);
|
||||
|
||||
opts = extract_options(&src_conds, 1);
|
||||
if (opts)
|
||||
flags = extract_flags(&opts, &inv_flags);
|
||||
if (opts_in) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
|
||||
if (list) {
|
||||
unsigned int tmpflags, tmpinv_flags = 0;
|
||||
|
||||
tmpflags = extract_flags(&list, &tmpinv_flags);
|
||||
/* these flags are optional so set both */
|
||||
tmpflags |= tmpinv_flags;
|
||||
tmpinv_flags |= tmpflags;
|
||||
|
||||
flags |= tmpflags;
|
||||
inv_flags |= tmpinv_flags;
|
||||
|
||||
if (opts)
|
||||
list_append(opts, list);
|
||||
else if (list)
|
||||
opts = list;
|
||||
while ((entry = list_pop(opts_in))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* optional flags if set/clear mean the same
|
||||
* thing and can be represented by a single
|
||||
* bitset, also there is no need to check for
|
||||
* conflicting flags when they are optional
|
||||
*/
|
||||
opt_flagsv.push_back(tmpflags | tmpinv_flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* move options=() to opts list */
|
||||
struct cond_entry *opts_eq = extract_options(&src_conds, 1);
|
||||
if (opts_eq) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
|
||||
while ((entry = list_pop(opts_eq))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* throw away tmpinv_flags, only needed in
|
||||
* consistancy check
|
||||
*/
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
tmpflags |= MS_REMOUNT;
|
||||
|
||||
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||
PERROR("conflicting flags in the rule\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
flagsv.push_back(tmpflags);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_conds) {
|
||||
perror_conds("mount", src_conds);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||
} else {
|
||||
flagsv.push_back(MS_ALL_FLAGS);
|
||||
opt_flagsv.push_back(MS_ALL_FLAGS);
|
||||
}
|
||||
} else if (!(flagsv.size())) {
|
||||
/* no flags but opts set */
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
else
|
||||
flagsv.push_back(0);
|
||||
} else if (!(opt_flagsv.size())) {
|
||||
opt_flagsv.push_back(0);
|
||||
}
|
||||
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
flags |= MS_REMOUNT;
|
||||
inv_flags = 0;
|
||||
} else if (!(flags | inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
flags = MS_ALL_FLAGS;
|
||||
inv_flags = MS_ALL_FLAGS;
|
||||
}
|
||||
|
||||
allow = allow_p;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
exit(1);
|
||||
}
|
||||
if (opts) {
|
||||
PERROR(" unsupported mount options\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
@@ -459,7 +570,11 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
else
|
||||
os << "error: unknown mount perm";
|
||||
|
||||
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
|
||||
for (unsigned int i = 0; i < flagsv.size(); i++)
|
||||
os << " flags=(0x" << hex << flagsv[i] << ")";
|
||||
for (unsigned int i = 0; i < opt_flagsv.size(); i++)
|
||||
os << " flags in (0x" << hex << opt_flagsv[i] << ")";
|
||||
|
||||
if (dev_type) {
|
||||
os << " type=";
|
||||
print_value_list(dev_type);
|
||||
@@ -515,7 +630,7 @@ int mnt_rule::expand_variables(void)
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
@@ -528,7 +643,7 @@ static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
if ((opt_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
@@ -583,7 +698,9 @@ void mnt_rule::warn_once(const char *name)
|
||||
rule_t::warn_once(name, "mount rules not enforce");
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
|
||||
int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
@@ -592,8 +709,320 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_REMOUNT_FLAGS,
|
||||
opt_flags & MS_REMOUNT_FLAGS))
|
||||
goto fail;
|
||||
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_BIND_FLAGS,
|
||||
opt_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
char *mountpoint = mnt_point;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* change type base rules can specify the mount point by using
|
||||
* the parser token position reserved to device. that's why if
|
||||
* the mount point is not specified, we use device in its
|
||||
* place. this is a deprecated behavior.
|
||||
*
|
||||
* change type base rules can not be conditional on device
|
||||
* (source), device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (flags && flags != MS_ALL_FLAGS && device && mnt_point) {
|
||||
PERROR("source and mount point cannot be used at the "
|
||||
"same time for propagation type flags");
|
||||
goto fail;
|
||||
} else if (device && !mnt_point) {
|
||||
mountpoint = device;
|
||||
}
|
||||
if (!convert_entry(mntbuf, mountpoint))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MAKE_FLAGS,
|
||||
opt_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MOVE_FLAGS,
|
||||
opt_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_NEW_FLAGS,
|
||||
opt_flags & MS_NEW_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
/*
|
||||
* XXX: added !flags to cover cases like:
|
||||
* mount options in (bind) /d -> /4,
|
||||
*/
|
||||
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
/* no mount flags specified, generate multiple rules */
|
||||
if (!device && !dev_type &&
|
||||
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if ((!device || !mnt_point) && !dev_type && !opts &&
|
||||
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_move_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
return gen_policy_remount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& (!device || !mnt_point) && !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_move_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
((flags | opt_flags) & ~MS_CMDS)) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} /* else must be RULE_OK for some rules */
|
||||
|
||||
return RULE_OK;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int count = 0;
|
||||
unsigned int tmpflags, tmpinv_flags;
|
||||
|
||||
if (!features_supports_mount) {
|
||||
warn_once(prof.name);
|
||||
@@ -605,202 +1034,10 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
int tmpallow;
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
for (size_t i = 0; i < flagsv.size(); i++) {
|
||||
for (size_t j = 0; j < opt_flagsv.size(); j++) {
|
||||
if (gen_flag_rules(prof, count, flagsv[i], opt_flagsv[j]) == RULE_ERROR)
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !device && !dev_type && !opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags | inv_flags) & ~MS_CMDS) {
|
||||
int tmpallow;
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= ~MS_CMDS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpinv_flags &= ~MS_CMDS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (allow & AA_MAY_UMOUNT) {
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#define __AA_MOUNT_H
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
@@ -39,6 +40,8 @@
|
||||
#define MS_MAND (1 << 6)
|
||||
#define MS_NOMAND 0
|
||||
#define MS_DIRSYNC (1 << 7)
|
||||
#define MS_SYMFOLLOW 0
|
||||
#define MS_NOSYMFOLLOW (1 << 8)
|
||||
#define MS_NODIRSYNC 0
|
||||
#define MS_NOATIME (1 << 10)
|
||||
#define MS_ATIME 0
|
||||
@@ -61,6 +64,7 @@
|
||||
#define MS_IVERSION (1 << 23)
|
||||
#define MS_NOIVERSION 0
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#define MS_LAZYTIME (1 << 25)
|
||||
#define MS_NOUSER (1 << 31)
|
||||
#define MS_USER 0
|
||||
|
||||
@@ -74,12 +78,14 @@
|
||||
|
||||
#define MS_ALL_FLAGS (MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC | \
|
||||
MS_SYNC | MS_REMOUNT | MS_MAND | MS_DIRSYNC | \
|
||||
MS_NOSYMFOLLOW | \
|
||||
MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_RBIND | \
|
||||
MS_MOVE | MS_VERBOSE | MS_ACL | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED | \
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | MS_USER)
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | \
|
||||
MS_LAZYTIME | MS_USER)
|
||||
|
||||
/* set of flags we don't use but define (but not with the kernel values)
|
||||
* for MNT_FLAGS
|
||||
@@ -94,16 +100,15 @@
|
||||
MS_KERNMOUNT | MS_STRICTATIME)
|
||||
|
||||
#define MS_BIND_FLAGS (MS_BIND | MS_RBIND)
|
||||
#define MS_MAKE_FLAGS ((MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
#define MS_MAKE_CMDS (MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED) | \
|
||||
(MS_ALL_FLAGS & ~(MNT_FLAGS)))
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_MAKE_FLAGS (MS_ALL_FLAGS & ~(MNT_FLAGS))
|
||||
#define MS_MOVE_FLAGS (MS_MOVE)
|
||||
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | MS_MAKE_CMDS)
|
||||
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT & ~MS_BIND & ~MS_RBIND))
|
||||
#define MS_NEW_FLAGS (MS_ALL_FLAGS & ~MS_CMDS)
|
||||
|
||||
#define MNT_SRC_OPT 1
|
||||
#define MNT_DST_OPT 2
|
||||
@@ -121,6 +126,19 @@
|
||||
|
||||
|
||||
class mnt_rule: public rule_t {
|
||||
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_move_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_new_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
public:
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
@@ -128,7 +146,7 @@ public:
|
||||
struct value_list *dev_type;
|
||||
struct value_list *opts;
|
||||
|
||||
unsigned int flags, inv_flags;
|
||||
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
|
@@ -232,6 +232,7 @@ do { \
|
||||
#endif
|
||||
|
||||
|
||||
#define list_first(LIST) (LIST)
|
||||
#define list_for_each(LIST, ENTRY) \
|
||||
for ((ENTRY) = (LIST); (ENTRY); (ENTRY) = (ENTRY)->next)
|
||||
#define list_for_each_safe(LIST, ENTRY, TMP) \
|
||||
@@ -265,6 +266,16 @@ do { \
|
||||
prev; \
|
||||
})
|
||||
|
||||
#define list_pop(LIST) \
|
||||
({ \
|
||||
typeof(LIST) _entry = (LIST); \
|
||||
if (LIST) { \
|
||||
(LIST) = (LIST)->next; \
|
||||
_entry->next = NULL; \
|
||||
} \
|
||||
_entry; \
|
||||
})
|
||||
|
||||
#define list_remove_at(LIST, PREV, ENTRY) \
|
||||
if (PREV) \
|
||||
(PREV)->next = (ENTRY)->next; \
|
||||
|
@@ -165,6 +165,7 @@ FILE *search_path(char *filename, char **fullpath, bool *skip)
|
||||
if (g_includecache->find(buf)) {
|
||||
/* hit do not want to re-include */
|
||||
*skip = true;
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -167,10 +167,10 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
include_file = search_path(filename, &fullpath, &cached);
|
||||
if (!include_file && cached) {
|
||||
goto skip;
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
} else if (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
}
|
||||
|
||||
} else if (g_includecache->find(filename)) {
|
||||
|
@@ -1146,7 +1146,7 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
retval = process_binary(option, kernel_interface,
|
||||
cachename);
|
||||
if (!retval || skip_bad_cache_rebuild)
|
||||
return retval;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1209,7 +1209,8 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
||||
/* cleanup */
|
||||
reset_parser(profilename);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1696,6 +1697,7 @@ int main(int argc, char *argv[])
|
||||
if (ofile)
|
||||
fclose(ofile);
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
@@ -486,13 +486,18 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
&prof->xmatch_len);
|
||||
if (ptype == ePatternBasic)
|
||||
prof->xmatch_len = strlen(name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternInvalid) {
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
return FALSE;
|
||||
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
}
|
||||
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
/* no regex so do not set xmatch */
|
||||
prof->xmatch = NULL;
|
||||
prof->xmatch_len = 0;
|
||||
|
@@ -1773,7 +1773,7 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
|
||||
{
|
||||
autofclose FILE *f = NULL;
|
||||
struct stat my_stat;
|
||||
char *fullpath = NULL;
|
||||
autofree char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
|
@@ -643,6 +643,16 @@ verify_binary_equality "attachment slash filtering" \
|
||||
@{FOO}=/foo
|
||||
/t @{BAR}/@{FOO} { }"
|
||||
|
||||
# This can potentially fail as ideally it requires a better dfa comparison
|
||||
# routine as it can generates hormomorphic dfas. The enumeration of the
|
||||
# dfas dumped will be different, even if the binary is the same
|
||||
# Note: this test in the future will require -O filter-deny and
|
||||
# -O minimize and -O remove-unreachable.
|
||||
verify_binary_equality "mount specific deny doesn't affect non-overlapping" \
|
||||
"/t { mount options=bind /e/ -> /**, }" \
|
||||
"/t { audit deny mount /s/** -> /**,
|
||||
mount options=bind /e/ -> /**, }"
|
||||
|
||||
if [ $fails -ne 0 ] || [ $errors -ne 0 ]
|
||||
then
|
||||
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
|
||||
|
7
parser/tst/simple_tests/mount/bad_1.sd
Normal file
7
parser/tst/simple_tests/mount/bad_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, ro) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_2.sd
Normal file
7
parser/tst/simple_tests/mount/bad_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_3.sd
Normal file
7
parser/tst/simple_tests/mount/bad_3.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=procfs -> /foo,
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=(procfs) none -> /foo,
|
7
parser/tst/simple_tests/mount/bad_opt_29.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_29.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(strictatime, nostrictatime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_opt_30.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_30.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(lazytime, nolazytime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_opt_31.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_31.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(symfollow, nosymfollow) -> /foo,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_32.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_32.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(slave) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_35.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_35.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rslave) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_36.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_36.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(unbindable) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_37.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_37.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(runbindable) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_38.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_38.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(private) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_39.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_39.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rprivate) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_40.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_40.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(shared) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_41.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_41.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rshared) /snap/bin/** -> /**,
|
||||
}
|
@@ -3,5 +3,5 @@
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, ro) -> /foo,
|
||||
mount options=(rw nosuid) -> /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,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_56.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_56.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nostrictatime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nostrictatime /a -> /1,
|
||||
mount options=(nostrictatime) /b -> /2,
|
||||
mount options in (nostrictatime) /d -> /4,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_57.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_57.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "lazytime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=lazytime /a -> /1,
|
||||
mount options=(lazytime) /b -> /2,
|
||||
mount options in (lazytime) /d -> /4,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_58.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_58.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nolazytime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nolazytime /a -> /1,
|
||||
mount options=(nolazytime) /b -> /2,
|
||||
mount options in (nolazytime) /d -> /4,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_59.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_59.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "strictatime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,strictatime) /c -> /3,
|
||||
mount options in (ro,strictatime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_60.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_60.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "nostrictatime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,nostrictatime) /c -> /3,
|
||||
mount options in (ro,nostrictatime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_61.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_61.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "lazytime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,lazytime) /c -> /3,
|
||||
mount options in (ro,lazytime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_62.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_62.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "nolazytime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,nolazytime) /c -> /3,
|
||||
mount options in (ro,nolazytime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_63.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_63.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (strictatime, nostrictatime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_64.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_64.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (lazytime, nolazytime) -> /foo,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_65.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_65.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nosymfollow" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nosymfollow /a -> /1,
|
||||
mount options=(nosymfollow) /b -> /2,
|
||||
mount options in (nosymfollow) /d -> /4,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_66.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_66.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "symfollow" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,symfollow) /c -> /3,
|
||||
mount options in (ro,symfollow) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_67.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_67.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (symfollow, nosymfollow) -> /foo,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_68.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_68.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "unbindable" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=unbindable /1,
|
||||
mount options=(unbindable) /2,
|
||||
mount options=(rw,unbindable) /3,
|
||||
mount options in (unbindable) /4,
|
||||
mount options in (ro,unbindable) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_69.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_69.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "runbindable" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=runbindable /1,
|
||||
mount options=(runbindable) /2,
|
||||
mount options=(rw,runbindable) /3,
|
||||
mount options in (runbindable) /4,
|
||||
mount options in (ro,runbindable) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_70.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_70.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "rprivate" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=rprivate /1,
|
||||
mount options=(rprivate) /2,
|
||||
mount options=(rw,rprivate) /3,
|
||||
mount options in (rprivate) /4,
|
||||
mount options in (ro,rprivate) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_71.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_71.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "private" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=private /1,
|
||||
mount options=(private) /2,
|
||||
mount options=(rw,private) /3,
|
||||
mount options in (private) /4,
|
||||
mount options in (ro,private) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_72.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_72.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "slave" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=slave /1,
|
||||
mount options=(slave) /2,
|
||||
mount options=(rw,slave) /3,
|
||||
mount options in (slave) /4,
|
||||
mount options in (ro,slave) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_73.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_73.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "rslave" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=rslave /1,
|
||||
mount options=(rslave) /2,
|
||||
mount options=(rw,rslave) /3,
|
||||
mount options in (rslave) /4,
|
||||
mount options in (ro,rslave) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_74.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_74.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "shared" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=shared /1,
|
||||
mount options=(shared) /2,
|
||||
mount options=(rw,shared) /3,
|
||||
mount options in (shared) /4,
|
||||
mount options in (ro,shared) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_75.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_75.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "rshared" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=rshared /1,
|
||||
mount options=(rshared) /2,
|
||||
mount options=(rw,rshared) /3,
|
||||
mount options in (rshared) /4,
|
||||
mount options in (ro,rshared) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_76.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_76.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-unbindable" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-unbindable /1,
|
||||
mount options=(make-unbindable) /2,
|
||||
mount options=(rw,make-unbindable) /3,
|
||||
mount options in (make-unbindable) /4,
|
||||
mount options in (ro,make-unbindable) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_77.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_77.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-runbindable" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-runbindable /1,
|
||||
mount options=(make-runbindable) /2,
|
||||
mount options=(rw,make-runbindable) /3,
|
||||
mount options in (make-runbindable) /4,
|
||||
mount options in (ro,make-runbindable) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_78.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_78.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-private" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-private /1,
|
||||
mount options=(make-private) /2,
|
||||
mount options=(rw,make-private) /3,
|
||||
mount options in (make-private) /4,
|
||||
mount options in (ro,make-private) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_79.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_79.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-rprivate" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-rprivate /1,
|
||||
mount options=(make-rprivate) /2,
|
||||
mount options=(rw,make-rprivate) /3,
|
||||
mount options in (make-rprivate) /4,
|
||||
mount options in (ro,make-rprivate) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_80.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_80.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-slave" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-slave /1,
|
||||
mount options=(make-slave) /2,
|
||||
mount options=(rw,make-slave) /3,
|
||||
mount options in (make-slave) /4,
|
||||
mount options in (ro,make-slave) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_81.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_81.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-shared" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-shared /1,
|
||||
mount options=(make-shared) /2,
|
||||
mount options=(rw,make-shared) /3,
|
||||
mount options in (make-shared) /4,
|
||||
mount options in (ro,make-shared) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_82.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_82.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-rslave" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-rslave /1,
|
||||
mount options=(make-rslave) /2,
|
||||
mount options=(rw,make-rslave) /3,
|
||||
mount options in (make-rslave) /4,
|
||||
mount options in (ro,make-rslave) /5,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_83.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_83.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "make-rshared" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=make-rshared /1,
|
||||
mount options=(make-rshared) /2,
|
||||
mount options=(rw,make-rshared) /3,
|
||||
mount options in (make-rshared) /4,
|
||||
mount options in (ro,make-rshared) /5,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_84.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_84.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description test we can parse rules associated with MR 1054
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(slave) /**,
|
||||
mount options=(slave) -> /**,
|
||||
mount /snap/bin/** -> /**,
|
||||
}
|
@@ -83,7 +83,7 @@ local:
|
||||
fn=$$(basename $$profile); \
|
||||
echo "# Site-specific additions and overrides for '$$fn'" > ${PROFILES_SOURCE}/local/$$fn; \
|
||||
grep "include[[:space:]]\\+if[[:space:]]\\+exists[[:space:]]\\+<local/$$fn>" "$$profile" >/dev/null || { echo "$$profile doesn't contain include if exists <local/$$fn>" ; exit 1; } ; \
|
||||
done; \
|
||||
done
|
||||
|
||||
.PHONY: install
|
||||
install: local
|
||||
@@ -119,7 +119,7 @@ CHECK_PROFILES=$(filter-out ${IGNORE_FILES} ${SUBDIRS}, $(wildcard ${PROFILES_SO
|
||||
CHECK_ABSTRACTIONS=$(shell find ${ABSTRACTIONS_SOURCE} -type f -print)
|
||||
|
||||
.PHONY: check
|
||||
check: check-parser check-logprof check-abstractions.d
|
||||
check: check-parser check-logprof check-abstractions.d check-extras
|
||||
|
||||
.PHONY: check-parser
|
||||
check-parser: test-dependencies local
|
||||
@@ -151,3 +151,11 @@ check-abstractions.d:
|
||||
test "$$file" = 'ubuntu-helpers' && continue ; \
|
||||
grep -q "^ include if exists <abstractions/$${file}.d>$$" $$file || { echo "$$file does not contain 'include if exists <abstractions/$${file}.d>'"; exit 1; } ; \
|
||||
done
|
||||
|
||||
.PHONY: check-extras
|
||||
check-extras:
|
||||
@echo "*** Checking if all extra profiles contain include if exists <local/*>"
|
||||
$(Q)cd ${EXTRAS_SOURCE} && for file in * ; do \
|
||||
test "$$file" = 'README' && continue ; \
|
||||
grep -q "^ include if exists <local/$${file}>$$" $$file || { echo "$$file does not contain 'include if exists <local/$${file}>'"; exit 1; } ; \
|
||||
done
|
||||
|
@@ -31,6 +31,11 @@
|
||||
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
|
||||
/{usr/,}lib/@{multiarch}/security/ r,
|
||||
|
||||
# gssapi
|
||||
@{etc_ro}/gss/mech r,
|
||||
@{etc_ro}/gss/mech.d/ r,
|
||||
@{etc_ro}/gss/mech.d/*.conf r,
|
||||
|
||||
# kerberos
|
||||
include <abstractions/kerberosclient>
|
||||
# SuSE's pwdutils are different:
|
||||
|
@@ -36,8 +36,8 @@
|
||||
/usr/share/locale-langpack/** r,
|
||||
/usr/share/locale/** r,
|
||||
/usr/share/**/locale/** r,
|
||||
/usr/share/zoneinfo/ r,
|
||||
/usr/share/zoneinfo/** r,
|
||||
/usr/share/zoneinfo{,-icu}/ r,
|
||||
/usr/share/zoneinfo{,-icu}/** r,
|
||||
/usr/share/X11/locale/** r,
|
||||
@{run}/systemd/journal/dev-log w,
|
||||
# systemd native journal API (see sd_journal_print(4))
|
||||
@@ -62,6 +62,7 @@
|
||||
@{etc_ro}/ld.so.conf r,
|
||||
@{etc_ro}/ld.so.conf.d/{,*.conf} r,
|
||||
@{etc_ro}/ld.so.preload r,
|
||||
@{etc_ro}/ld-musl-*.path r,
|
||||
/{usr/,}lib{,32,64}/ld{,32,64}-*.so mr,
|
||||
/{usr/,}lib/@{multiarch}/ld{,32,64}-*.so mr,
|
||||
/{usr/,}lib/tls/i686/{cmov,nosegneg}/ld-*.so mr,
|
||||
@@ -103,6 +104,9 @@
|
||||
@{sys}/devices/system/cpu/online r,
|
||||
@{sys}/devices/system/cpu/possible r,
|
||||
|
||||
# transparent hugepage support
|
||||
@{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size r,
|
||||
|
||||
# glibc's *printf protections read the maps file
|
||||
@{PROC}/@{pid}/{maps,auxv,status} r,
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
@{system_share_dirs}/mime/** r,
|
||||
|
||||
# per-user configurations
|
||||
owner @{HOME}/.icons/ r,
|
||||
owner @{HOME}/.icons/{,**} r,
|
||||
owner @{HOME}/.recently-used.xbel* rw,
|
||||
owner @{HOME}/.local/share/recently-used.xbel* rw,
|
||||
owner @{HOME}/.config/user-dirs.dirs r,
|
||||
|
@@ -22,6 +22,11 @@
|
||||
/usr/lib/@{multiarch}/krb5/plugins/preauth/ r,
|
||||
/usr/lib/@{multiarch}/krb5/plugins/preauth/* mr,
|
||||
|
||||
/usr/lib{,32,64}/krb5/plugins/authdata/ r,
|
||||
/usr/lib{,32,64}/krb5/plugins/authdata/* mr,
|
||||
/usr/lib/@{multiarch}/krb5/plugins/authdata/ r,
|
||||
/usr/lib/@{multiarch}/krb5/plugins/authdata/* mr,
|
||||
|
||||
/etc/krb5.keytab rk,
|
||||
/etc/krb5.conf r,
|
||||
/etc/krb5.conf.d/ r,
|
||||
|
@@ -23,7 +23,7 @@
|
||||
/var/lib/samba/** rwk,
|
||||
/var/log/samba/cores/ rw,
|
||||
/var/log/samba/cores/** rw,
|
||||
/var/log/samba/* w,
|
||||
/var/log/samba/* rw,
|
||||
@{run}/{,lock/}samba/ w,
|
||||
@{run}/{,lock/}samba/*.tdb rwk,
|
||||
@{run}/{,lock/}samba/msg.{lock,sock}/ rwk,
|
||||
|
@@ -38,5 +38,6 @@ profile snap_browsers {
|
||||
/snap/opera/[0-9]*/meta/{snap.yaml,hooks/} r,
|
||||
|
||||
/var/lib/snapd/sequence/{chromium,firefox,opera}.json r,
|
||||
/var/lib/snapd/inhibit/{chromium,firefox,opera}.lock rk,
|
||||
# add other browsers here
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ profile syslogd /{usr/,}{bin,sbin}/syslogd {
|
||||
|
||||
/dev/log wl,
|
||||
/var/lib/*/dev/log wl,
|
||||
/dev/kmsg r,
|
||||
/proc/kmsg r,
|
||||
|
||||
/dev/tty* w,
|
||||
|
@@ -13,11 +13,15 @@
|
||||
# with the goal of having only user-modified config files in /etc/, directories
|
||||
# like /usr/etc/ get introduced for storing the default config.
|
||||
|
||||
# @{etc_ro} contains read-only directories with configuration files.
|
||||
# @{etc_ro} contains directories with configuration files, including read-only directories.
|
||||
# Do not use @{etc_ro} in rules that allow write access.
|
||||
@{etc_ro}=/etc/ /usr/etc/
|
||||
|
||||
# @{etc_rw} contains directories where writing to configuration files is allowed.
|
||||
# @{etc_rw} should always be a subset of @{etc_ro}.
|
||||
#
|
||||
# Only use @{etc_rw} if the profile allows writing to a configuration file.
|
||||
# For rules that only allows read access, use @{etc_ro}.
|
||||
@{etc_rw}=/etc/
|
||||
|
||||
# Also, include files in tunables/etc.d/ for site-specific adjustments to
|
||||
|
@@ -45,6 +45,9 @@ profile nscd /usr/{bin,sbin}/nscd {
|
||||
/{etc,run,run/host,/usr/lib}/userdb/ r,
|
||||
/{etc,run,run/host,/usr/lib}/userdb/*.{user,user-privileged,group,group-privileged} r,
|
||||
|
||||
# needed by unscd
|
||||
@{run}/systemd/notify w,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.sbin.nscd>
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ profile winbindd /usr/{bin,sbin}/winbindd {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/samba>
|
||||
include <abstractions/kerberosclient>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
@@ -30,6 +31,7 @@ profile winbindd /usr/{bin,sbin}/winbindd {
|
||||
/usr/{bin,sbin}/winbindd mr,
|
||||
/var/cache/krb5rcache/* rwk,
|
||||
/var/cache/samba/*.tdb rwk,
|
||||
/var/lib/sss/pubconf/kdcinfo.* r,
|
||||
/var/log/samba/log.winbindd rw,
|
||||
@{run}/{samba/,}winbindd.pid rwk,
|
||||
@{run}/samba/winbindd/ rw,
|
||||
|
@@ -18,7 +18,7 @@ include <tunables/global>
|
||||
# /usr/lib/firefox-4.0b8/firefox
|
||||
# but not:
|
||||
# /usr/lib/firefox-4.0b8/firefox.sh
|
||||
/usr/lib/firefox{,-[0-9]*}/firefox{,*[^s][^h]} {
|
||||
profile firefox /usr/lib/firefox{,-[0-9]*}/firefox{,*[^s][^h]} {
|
||||
include <abstractions/audio>
|
||||
include <abstractions/cups-client>
|
||||
include <abstractions/dbus-session>
|
||||
@@ -128,7 +128,6 @@ include <tunables/global>
|
||||
@{HOME}/.mozilla/firefox/*/gmp-widevinecdm/*/lib*so m,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
# Local path is disabled, we only enable them for profiles we promote
|
||||
# out of extras.
|
||||
include if exists <local/usr.bin.firefox>
|
||||
include if exists <local/firefox>
|
||||
}
|
@@ -4,7 +4,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
/usr/lib/firefox/firefox.sh {
|
||||
profile firefox.sh /usr/lib/firefox/firefox.sh {
|
||||
include <abstractions/base>
|
||||
include <abstractions/bash>
|
||||
include <abstractions/consoles>
|
@@ -328,6 +328,9 @@ unix_fd_client: unix_fd_client.c unix_fd_common.o
|
||||
attach_disconnected: attach_disconnected.c unix_fd_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
mount: mount.c
|
||||
${CC} ${CFLAGS} -std=gnu99 ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
build-dep:
|
||||
@if [ `whoami` = "root" ] ;\
|
||||
then \
|
||||
|
@@ -16,7 +16,7 @@ fi
|
||||
out=$($1 -- cat /proc/self/attr/current 2>&1)
|
||||
rc=$?
|
||||
|
||||
if [ $rc -eq 0 ] && [ "$out" == "$2" ]; then
|
||||
if [ $rc -eq 0 ] && [ "$out" = "$2" ]; then
|
||||
echo PASS
|
||||
exit 0
|
||||
elif [ $rc -ne 0 ]; then
|
||||
|
@@ -55,7 +55,7 @@ fi
|
||||
# MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" = "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
|
@@ -97,7 +97,7 @@ for TEST in ${TESTS} ; do
|
||||
|
||||
# no capabilities allowed
|
||||
genprofile ${my_entries}
|
||||
if [ "${TEST}" == "syscall_ptrace" -a "$(kernel_features ptrace)" == "true" ] ; then
|
||||
if [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ] ; then
|
||||
# ptrace between profiles confining tasks of same pid is controlled by the ptrace rule
|
||||
# capability + ptrace rule needed between pids
|
||||
runchecktest "${TEST} -- no caps" pass ${my_arg}
|
||||
@@ -111,9 +111,9 @@ for TEST in ${TESTS} ; do
|
||||
|
||||
# iterate through each of the capabilities
|
||||
for cap in ${CAPABILITIES} ; do
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" == "XTRUE" ] ; then
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
expected_result=pass
|
||||
elif [ "${TEST}" == "syscall_ptrace" -a "$(kernel_features ptrace)" == "true" ]; then
|
||||
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
|
||||
expected_result=pass
|
||||
else
|
||||
expected_result=fail
|
||||
@@ -126,7 +126,7 @@ for TEST in ${TESTS} ; do
|
||||
# a subprofile.
|
||||
settest ${testwrapper}
|
||||
genprofile hat:$bin/${TEST} addimage:${bin}/${TEST} ${my_entries}
|
||||
if [ "${TEST}" == "syscall_ptrace" -a "$(kernel_features ptrace)" == "true" ] ; then
|
||||
if [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ] ; then
|
||||
# ptrace between profiles confining tasks of same pid is controlled by the ptrace rule
|
||||
# capability + ptrace rule needed between pids
|
||||
runchecktest "${TEST} changehat -- no caps" pass $bin/${TEST} ${my_arg}
|
||||
@@ -139,9 +139,9 @@ for TEST in ${TESTS} ; do
|
||||
runchecktest "${TEST} changehat -- all caps" pass $bin/${TEST} ${my_arg}
|
||||
|
||||
for cap in ${CAPABILITIES} ; do
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" == "XTRUE" ] ; then
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
expected_result=pass
|
||||
elif [ "${TEST}" == "syscall_ptrace" -a "$(kernel_features ptrace)" == "true" ]; then
|
||||
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
|
||||
expected_result=pass
|
||||
else
|
||||
expected_result=fail
|
||||
@@ -156,75 +156,75 @@ cap=sys_chroot
|
||||
settest syscall_chroot
|
||||
|
||||
# test deny keyword works
|
||||
genprofile cap:${cap}:deny ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, deny keyword" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow keyword works
|
||||
genprofile cap:${cap}:allow ${syscall_chroot_extra_entries}
|
||||
genprofile qual=allow:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow keyword" pass ${syscall_chroot_args}
|
||||
|
||||
### allow/deny overlap tests ###
|
||||
|
||||
# test allow & deny keyword behavior, allow first
|
||||
genprofile cap:${cap}:allow cap:${cap}:deny ${syscall_chroot_extra_entries}
|
||||
genprofile qual=allow:cap:${cap} qual=deny:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow & deny keyword behavior, allow first
|
||||
genprofile cap:${cap} cap:${cap}:deny ${syscall_chroot_extra_entries}
|
||||
genprofile cap:${cap} qual=deny:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow & deny keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow & deny keyword behavior, deny first
|
||||
genprofile cap:${cap}:deny cap:${cap}:allow ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:${cap} qual=allow:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow & deny keyword behavior, deny first
|
||||
genprofile cap:${cap}:deny cap:${cap} ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:${cap} cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow & deny keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow all & deny all capability keyword behavior, allow first
|
||||
genprofile cap:ALL:allow cap:ALL:deny ${syscall_chroot_extra_entries}
|
||||
genprofile qual=allow:cap:ALL qual=deny:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny all caps keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow all & deny all capability keyword behavior, allow first
|
||||
genprofile cap:ALL cap:ALL:deny ${syscall_chroot_extra_entries}
|
||||
genprofile cap:ALL qual=deny:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow all & deny all caps keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow all & deny all capability keyword behavior, deny first
|
||||
genprofile cap:ALL:deny cap:ALL:allow ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:ALL qual=allow:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny all caps keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow all & deny all capability keyword behavior, deny first
|
||||
genprofile cap:ALL:deny cap:ALL ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:ALL cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow & deny all caps keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow all & deny keywords behavior, allow first
|
||||
genprofile cap:ALL:allow cap:${cap}:deny ${syscall_chroot_extra_entries}
|
||||
genprofile qual=allow:cap:ALL qual=deny:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow all & deny keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow all & deny keywords behavior, allow first
|
||||
genprofile cap:ALL cap:${cap}:deny ${syscall_chroot_extra_entries}
|
||||
genprofile cap:ALL qual=deny:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow all & deny keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow all & deny keywords behavior, deny first
|
||||
genprofile cap:${cap}:deny cap:ALL:allow ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:${cap} qual=allow:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow all & deny keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow all & deny keywords behavior, deny first
|
||||
genprofile cap:${cap}:deny cap:ALL ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:${cap} cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow all & deny keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow & deny all keywords behavior, allow first
|
||||
genprofile cap:${cap}:allow cap:ALL:deny ${syscall_chroot_extra_entries}
|
||||
genprofile qual=allow:cap:${cap} qual=deny:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny all keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow & deny all keywords behavior, allow first
|
||||
genprofile cap:${cap} cap:ALL:deny ${syscall_chroot_extra_entries}
|
||||
genprofile cap:${cap} qual=deny:cap:ALL ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow & deny all keyword, allow first" fail ${syscall_chroot_args}
|
||||
|
||||
# test allow & deny all keywords behavior, deny first
|
||||
genprofile cap:ALL:deny cap:${cap}:allow ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:ALL qual=allow:cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, allow & deny all keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
||||
# test implicit allow & deny all keywords behavior, deny first
|
||||
genprofile cap:ALL:deny cap:${cap} ${syscall_chroot_extra_entries}
|
||||
genprofile qual=deny:cap:ALL cap:${cap} ${syscall_chroot_extra_entries}
|
||||
runchecktest "syscall_chroot -- capability ${cap}, implicit allow & deny all keyword, deny first" fail ${syscall_chroot_args}
|
||||
|
@@ -47,7 +47,7 @@ runchecktest "NO CHANGEPROFILE (access parent file)" pass nochange $file
|
||||
runchecktest "NO CHANGEPROFILE (access sub file)" fail nochange $subfile
|
||||
|
||||
errno=EACCES
|
||||
if [ "$(kernel_features domain/stack)" == "true" ]; then
|
||||
if [ "$(kernel_features domain/stack)" = "true" ]; then
|
||||
# The returned errno changed in the set of kernel patches that
|
||||
# introduced AppArmor profile stacking
|
||||
errno=ENOENT
|
||||
|
@@ -18,7 +18,7 @@ cleancorefile()
|
||||
checkcorefile()
|
||||
{
|
||||
# global _testdesc _pfmode _known outfile
|
||||
if [ ${1:0:1} == "x" ] ; then
|
||||
if [ ${1:0:1} = "x" ] ; then
|
||||
requirement=${1#x}
|
||||
_known=" (known problem)"
|
||||
else
|
||||
|
@@ -128,7 +128,8 @@ start_dbus_daemon()
|
||||
return 1
|
||||
fi
|
||||
|
||||
out=$(dbus-daemon --fork --print-pid --print-address --config-file=dbus.conf)
|
||||
bus_addr=$(mktemp --dry-run /tmp/dbus-XXXXXX)
|
||||
out=$(dbus-daemon --fork --print-pid --print-address --address="unix:abstract=$bus_addr" --config-file=dbus.conf)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "Failed to start DBus daemon"
|
||||
|
@@ -65,7 +65,9 @@ okperm=rwl
|
||||
badperm=wl
|
||||
af_unix=""
|
||||
|
||||
if [ "$(kernel_features network/af_unix)" == "true" -a "$(parser_supports 'unix,')" == "true" ]; then
|
||||
if [ "$(kernel_features network_v8)" = "true" -a "$(parser_supports 'unix,')" = "true" ]; then
|
||||
af_unix="unix:create"
|
||||
elif [ "$(kernel_features network/af_unix)" = "true" -a "$(parser_supports 'unix,')" = "true" ]; then
|
||||
af_unix="unix:create"
|
||||
fi
|
||||
|
||||
|
@@ -57,7 +57,7 @@ local_runchecktest()
|
||||
|
||||
checktestbg
|
||||
|
||||
if [ "$teststatus" == "pass" -a -n "$actual_confinement" -a "$actual_confinement" != "$expected_confinement" ]
|
||||
if [ "$teststatus" = "pass" -a -n "$actual_confinement" -a "$actual_confinement" != "$expected_confinement" ]
|
||||
then
|
||||
echo "Error: ${testname} failed. Test '${_testdesc}' actual confinement '$actual_confinement' differed from expected confinement '$expected_confinement'"
|
||||
testfailed
|
||||
|
@@ -51,7 +51,7 @@ touch $file $otherfile $sharedfile $thirdfile
|
||||
# meaning the below conditional check has the wrong results for those
|
||||
# kernels. Since this test is not about testing mmap just always add
|
||||
# the mmap perm
|
||||
#if [ "$(kernel_features domain/fix_binfmt_elf_mmap)" == "true" ]; then
|
||||
#if [ "$(kernel_features domain/fix_binfmt_elf_mmap)" = "true" ]; then
|
||||
# elfmmap="m"
|
||||
#else
|
||||
# elfmmap=""
|
||||
|
@@ -37,10 +37,17 @@ sub usage {
|
||||
print STDERR "Usage $0 [--nowarn|--escape] execname [rules]\n";
|
||||
print STDERR " $0 --help\n";
|
||||
print STDERR " $0 --stdin\n";
|
||||
print STDERR "Options:\n";
|
||||
print STDERR " nowarn: don't warn if execname does not exist\n";
|
||||
print STDERR " nodefault: don't include default rules/ldd output\n";
|
||||
print STDERR " escape: escape stuff that would be treated as regexs\n";
|
||||
print STDERR " help: print this message\n";
|
||||
print STDERR "Rule Qualifiers:\n";
|
||||
print STDERR " qualifiers can optionally be added to a rule with 'qual='\n";
|
||||
print STDERR " Examples:\n";
|
||||
print STDERR " /path/to/file:rw\n";
|
||||
print STDERR " qual=audit:/path/to/file:rw\n";
|
||||
print STDERR " qual=audit,deny:/path/to/file:rw\n";
|
||||
}
|
||||
|
||||
# genprofile passes in $bin:w as default rule atm
|
||||
@@ -146,185 +153,183 @@ sub gen_binary($) {
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_netdomain($) {
|
||||
my $rule = shift;
|
||||
sub gen_netdomain($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
# only split on single ':'s
|
||||
my @rules = split (/(?<!:):(?!:)/, $rule);
|
||||
# convert '::' to ':' -- for port designations
|
||||
foreach (@rules) { s/::/:/g; }
|
||||
push (@{$output_rules{$hat}}, " @rules,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}@rules,\n");
|
||||
}
|
||||
|
||||
sub gen_network($) {
|
||||
my $rule = shift;
|
||||
sub gen_network($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
push (@{$output_rules{$hat}}, " @rules,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}@rules,\n");
|
||||
}
|
||||
|
||||
sub gen_unix($) {
|
||||
my $rule = shift;
|
||||
sub gen_unix($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
if ($rule =~ /^unix:ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " unix,\n");
|
||||
} else {
|
||||
$rule =~ s/:/ /g;
|
||||
push(@{$output_rules{$hat}}, " " . $rule . ",\n");
|
||||
push(@{$output_rules{$hat}}, " " . $qualifier . $rule . ",\n");
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_cap($) {
|
||||
my $rule = shift;
|
||||
sub gen_cap($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " capability,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}capability,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " capability $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " $rules[2] capability,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " $rules[2] capability $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}capability $rules[1],\n");
|
||||
}
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid capability description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_ptrace($) {
|
||||
my $rule = shift;
|
||||
sub gen_ptrace($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " ptrace,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}ptrace,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " ptrace $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}ptrace $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " ptrace $rules[1] $rules[2],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}ptrace $rules[1] $rules[2],\n");
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid ptrace description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_signal($) {
|
||||
my $rule = shift;
|
||||
sub gen_signal($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " signal,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}signal,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " signal $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}signal $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " signal $rules[1] $rules[2],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}signal $rules[1] $rules[2],\n");
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid signal description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_mount($) {
|
||||
my $rule = shift;
|
||||
sub gen_mount($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " mount,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1] $rules[2],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1] $rules[2],\n");
|
||||
} elsif (@rules == 4) {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1] $rules[2] $rules[3],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1] $rules[2] $rules[3],\n");
|
||||
} elsif (@rules == 5) {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
} elsif (@rules == 6) {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
} elsif (@rules == 7) {
|
||||
push (@{$output_rules{$hat}}, " mount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}mount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid mount description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_remount($) {
|
||||
my $rule = shift;
|
||||
sub gen_remount($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " remount,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1] $rules[2],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1] $rules[2],\n");
|
||||
} elsif (@rules == 4) {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1] $rules[2] $rules[3],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1] $rules[2] $rules[3],\n");
|
||||
} elsif (@rules == 5) {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
} elsif (@rules == 6) {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
} elsif (@rules == 7) {
|
||||
push (@{$output_rules{$hat}}, " remount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}remount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid remount description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_umount($) {
|
||||
my $rule = shift;
|
||||
sub gen_umount($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " umount,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1],\n");
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1] $rules[2],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1] $rules[2],\n");
|
||||
} elsif (@rules == 4) {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1] $rules[2] $rules[3],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1] $rules[2] $rules[3],\n");
|
||||
} elsif (@rules == 5) {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1] $rules[2] $rules[3] $rules[4],\n");
|
||||
} elsif (@rules == 6) {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5],\n");
|
||||
} elsif (@rules == 7) {
|
||||
push (@{$output_rules{$hat}}, " umount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}umount $rules[1] $rules[2] $rules[3] $rules[4] $rules[5] $rules[6],\n");
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid umount description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_pivot_root($) {
|
||||
my $rule = shift;
|
||||
sub gen_pivot_root($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " pivot_root,\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}pivot_root,\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " pivot_root $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}pivot_root $rules[1],\n");
|
||||
}
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid pivot_root description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_file($) {
|
||||
my $rule = shift;
|
||||
sub gen_file($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
if (!$qualifier) {
|
||||
$qualifier = "";
|
||||
}
|
||||
|
||||
my @rules = split (/:/, $rule);
|
||||
# default: file rules
|
||||
if (@rules == 1) {
|
||||
# support raw rules
|
||||
push (@{$output_rules{$hat}}, " $rules[0],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}$rules[0],\n");
|
||||
} elsif (@rules == 2) {
|
||||
if ($escape) {
|
||||
$rules[0]=~ s/(["[\]{}\:])/\\$1/g;
|
||||
$rules[0]=~ s/(\#)/\\043/g;
|
||||
}
|
||||
if ($rules[0]=~ /[\s\!\"\^]/) {
|
||||
push (@{$output_rules{$hat}}, " \"$rules[0]\" $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}\"$rules[0]\" $rules[1],\n");
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " $rules[0] $rules[1],\n");
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}$rules[0] $rules[1],\n");
|
||||
}
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid file access '$rule', ignored\n";
|
||||
@@ -341,34 +346,34 @@ sub gen_flag($) {
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_change_profile($) {
|
||||
my $rule = shift;
|
||||
sub gen_change_profile($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules == 2) {
|
||||
if ($rules[1] =~ /^ALL$/) {
|
||||
push (@{$output_rules{$hat}}, " change_profile,\n",);
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}change_profile,\n",);
|
||||
} else {
|
||||
push (@{$output_rules{$hat}}, " change_profile -> $rules[1],\n",);
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}change_profile -> $rules[1],\n",);
|
||||
}
|
||||
} elsif (@rules == 3) {
|
||||
push (@{$output_rules{$hat}}, " change_profile $rules[1] -> $rules[2],\n",);
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}change_profile $rules[1] -> $rules[2],\n",);
|
||||
} elsif (@rules == 4) {
|
||||
push (@{$output_rules{$hat}}, " change_profile $rules[1] $rules[2] -> $rules[3],\n",);
|
||||
push (@{$output_rules{$hat}}, " ${qualifier}change_profile $rules[1] $rules[2] -> $rules[3],\n",);
|
||||
} else {
|
||||
(!$nowarn) && print STDERR "Warning: invalid change_profile description '$rule', ignored\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_hat($) {
|
||||
my $rule = shift;
|
||||
sub gen_hat($@) {
|
||||
my ($rule, $qualifier) = @_;
|
||||
my @rules = split (/:/, $rule);
|
||||
if (@rules != 2) {
|
||||
(!$nowarn) && print STDERR "Warning: invalid hat description '$rule', ignored\n";
|
||||
} else {
|
||||
$hat = $rules[1];
|
||||
# give every profile/hat access to change_hat
|
||||
@{$output_rules{$hat}} = ( " /proc/*/attr/current w,\n",);
|
||||
push(@{$output_rules{$hat}}, " /proc/*/attr/apparmor/current w,\n");
|
||||
@{$output_rules{$hat}} = ( " ${qualifier}/proc/*/attr/current w,\n",);
|
||||
push(@{$output_rules{$hat}}, " ${qualifier}/proc/*/attr/apparmor/current w,\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,34 +433,42 @@ sub gen_from_args() {
|
||||
}
|
||||
|
||||
for my $rule (@ARGV) {
|
||||
my $qualifier = "";
|
||||
if ($rule =~ /^qual=([^:]*):(.*)/) {
|
||||
# Strip qualifiers from rule to pass as separate argument
|
||||
$qualifier = "$1 ";
|
||||
$rule = $2;
|
||||
$qualifier =~ s/,/ /g;
|
||||
}
|
||||
|
||||
#($fn, @rules) = split (/:/, $rule);
|
||||
if ($rule =~ /^(tcp|udp)/) {
|
||||
# netdomain rules
|
||||
gen_netdomain($rule);
|
||||
gen_netdomain($rule, $qualifier);
|
||||
} elsif ($rule =~ /^network:/) {
|
||||
gen_network($rule);
|
||||
gen_network($rule, $qualifier);
|
||||
} elsif ($rule =~ /^unix:/) {
|
||||
gen_unix($rule);
|
||||
gen_unix($rule, $qualifier);
|
||||
} elsif ($rule =~ /^cap:/) {
|
||||
gen_cap($rule);
|
||||
gen_cap($rule, $qualifier);
|
||||
} elsif ($rule =~ /^ptrace:/) {
|
||||
gen_ptrace($rule);
|
||||
gen_ptrace($rule, $qualifier);
|
||||
} elsif ($rule =~ /^signal:/) {
|
||||
gen_signal($rule);
|
||||
gen_signal($rule, $qualifier);
|
||||
} elsif ($rule =~ /^mount:/) {
|
||||
gen_mount($rule);
|
||||
gen_mount($rule, $qualifier);
|
||||
} elsif ($rule =~ /^remount:/) {
|
||||
gen_remount($rule);
|
||||
gen_remount($rule, $qualifier);
|
||||
} elsif ($rule =~ /^umount:/) {
|
||||
gen_umount($rule);
|
||||
gen_umount($rule, $qualifier);
|
||||
} elsif ($rule =~ /^pivot_root:/) {
|
||||
gen_pivot_root($rule);
|
||||
gen_pivot_root($rule, $qualifier);
|
||||
} elsif ($rule =~ /^flag:/) {
|
||||
gen_flag($rule);
|
||||
} elsif ($rule =~ /^hat:/) {
|
||||
gen_hat($rule);
|
||||
gen_hat($rule, $qualifier);
|
||||
} elsif ($rule =~ /^change_profile:/) {
|
||||
gen_change_profile($rule);
|
||||
gen_change_profile($rule, $qualifier);
|
||||
} elsif ($rule =~ /^addimage:/) {
|
||||
gen_addimage($rule);
|
||||
$addimage = 1;
|
||||
@@ -464,7 +477,7 @@ sub gen_from_args() {
|
||||
} elsif ($rule =~ /^path:/) {
|
||||
gen_path($rule);
|
||||
} else {
|
||||
gen_file($rule);
|
||||
gen_file($rule, $qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,27 +14,163 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct mnt_keyword_table {
|
||||
const char *keyword;
|
||||
unsigned long set;
|
||||
unsigned long clear;
|
||||
};
|
||||
|
||||
static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{ "rw", 0, MS_RDONLY }, /* read-write */
|
||||
{ "ro", MS_RDONLY, 0 }, /* read-only */
|
||||
|
||||
{ "exec", 0, MS_NOEXEC }, /* permit execution of binaries */
|
||||
{ "noexec", MS_NOEXEC, 0 }, /* don't execute binaries */
|
||||
|
||||
{ "suid", 0, MS_NOSUID }, /* honor suid executables */
|
||||
{ "nosuid", MS_NOSUID, 0 }, /* don't honor suid executables */
|
||||
|
||||
{ "dev", 0, MS_NODEV }, /* interpret device files */
|
||||
{ "nodev", MS_NODEV, 0 }, /* don't interpret devices */
|
||||
|
||||
{ "async", 0, MS_SYNCHRONOUS }, /* asynchronous I/O */
|
||||
{ "sync", MS_SYNCHRONOUS, 0 }, /* synchronous I/O */
|
||||
|
||||
{ "loud", 0, MS_SILENT }, /* print out messages. */
|
||||
{ "silent", MS_SILENT, 0 }, /* be quiet */
|
||||
|
||||
{ "nomand", 0, MS_MANDLOCK }, /* forbid mandatory locks on this FS */
|
||||
{ "mand", MS_MANDLOCK, 0 }, /* allow mandatory locks on this FS */
|
||||
|
||||
{ "atime", 0, MS_NOATIME }, /* update access time */
|
||||
{ "noatime", MS_NOATIME, 0 }, /* do not update access time */
|
||||
|
||||
{ "noiversion", 0, MS_I_VERSION }, /* don't update inode I_version time */
|
||||
{ "iversion", MS_I_VERSION, 0 }, /* update inode I_version time */
|
||||
|
||||
{ "diratime", 0, MS_NODIRATIME }, /* update dir access times */
|
||||
{ "nodiratime", MS_NODIRATIME, 0 }, /* do not update dir access times */
|
||||
|
||||
{ "nostrictatime", 0, MS_STRICTATIME }, /* kernel default atime */
|
||||
{ "strictatime", MS_STRICTATIME, 0 }, /* strict atime semantics */
|
||||
|
||||
/* MS_LAZYTIME added in 4.0 kernel */
|
||||
#ifdef MS_LAZYTIME
|
||||
{ "nolazytime", 0, MS_LAZYTIME },
|
||||
{ "lazytime", MS_LAZYTIME, 0 }, /* update {a,m,c}time on the in-memory inode only */
|
||||
#endif
|
||||
|
||||
{ "acl", MS_POSIXACL, 0 },
|
||||
{ "noacl", 0, MS_POSIXACL },
|
||||
|
||||
{ "norelatime", 0, MS_RELATIME },
|
||||
{ "relatime", MS_RELATIME, 0 },
|
||||
|
||||
{ "dirsync", MS_DIRSYNC, 0 }, /* synchronous directory modifications */
|
||||
{ "nodirsync", 0, MS_DIRSYNC },
|
||||
|
||||
/* MS_NOSYMFOLLOW added in 5.10 kernel */
|
||||
#ifdef MS_NOSYMFOLLOW
|
||||
{ "nosymfollow", MS_NOSYMFOLLOW, 0 },
|
||||
{ "symfollow", 0, MS_NOSYMFOLLOW },
|
||||
#endif
|
||||
|
||||
{ "bind", MS_BIND, 0 }, /* remount part of the tree elsewhere */
|
||||
{ "rbind", MS_BIND | MS_REC, 0 }, /* idem, plus mounted subtrees */
|
||||
{ "unbindable", MS_UNBINDABLE, 0 }, /* unbindable */
|
||||
{ "runbindable", MS_UNBINDABLE | MS_REC, 0 },
|
||||
{ "private", MS_PRIVATE, 0 }, /* private */
|
||||
{ "rprivate", MS_PRIVATE | MS_REC, 0 },
|
||||
{ "slave", MS_SLAVE, 0 }, /* slave */
|
||||
{ "rslave", MS_SLAVE | MS_REC, 0 },
|
||||
{ "shared", MS_SHARED, 0 }, /* shared */
|
||||
{ "rshared", MS_SHARED | MS_REC, 0 },
|
||||
|
||||
{ "move", MS_MOVE, 0 },
|
||||
|
||||
{ "remount", MS_REMOUNT, 0 },
|
||||
};
|
||||
|
||||
const unsigned int mnt_opts_table_size =
|
||||
sizeof(mnt_opts_table) / sizeof(struct mnt_keyword_table);
|
||||
|
||||
|
||||
unsigned long get_mnt_opt_bit(char *key)
|
||||
{
|
||||
for (unsigned int i = 0; i < mnt_opts_table_size; i++) {
|
||||
if (strcmp(mnt_opts_table[i].keyword, key) == 0) {
|
||||
return mnt_opts_table[i].set;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "FAIL: invalid option\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void usage(char *prog_name)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s mount|umount <source> <target> [options]\n", prog_name);
|
||||
fprintf(stderr, "Options are:\n");
|
||||
fprintf(stderr, "-o flags sent to the mount syscall\n");
|
||||
fprintf(stderr, "-d data sent to the mount syscall\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "usage: %s [mount|umount] loopdev mountpoint\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
char *options = NULL;
|
||||
char *data = NULL;
|
||||
int index;
|
||||
int c;
|
||||
char *op, *source, *target, *token;
|
||||
unsigned long flags = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "o:d:h")) != -1) {
|
||||
switch (c)
|
||||
{
|
||||
case 'o':
|
||||
options = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
data = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "mount") == 0) {
|
||||
if (mount(argv[2], argv[3], "ext2", 0xc0ed0000 | MS_NODEV, NULL ) == -1) {
|
||||
index = optind;
|
||||
if (argc - optind < 3) {
|
||||
fprintf(stderr, "FAIL: missing positional arguments\n");
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
op = argv[index++];
|
||||
source = argv[index++];
|
||||
target = argv[index++];
|
||||
|
||||
if (options) {
|
||||
token = strtok(options, ",");
|
||||
while (token) {
|
||||
flags |= get_mnt_opt_bit(token);
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(op, "mount") == 0) {
|
||||
if (mount(source, target, "ext2", flags, data) == -1) {
|
||||
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
|
||||
argv[2], argv[3],
|
||||
strerror(errno));
|
||||
source, target, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
} else if (strcmp(argv[1], "umount") == 0) {
|
||||
if (umount(argv[3]) == -1) {
|
||||
} else if (strcmp(op, "umount") == 0) {
|
||||
if (umount(target) == -1) {
|
||||
fprintf(stderr, "FAIL: umount %s failed - %s\n",
|
||||
argv[3],
|
||||
strerror(errno));
|
||||
target, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
|
@@ -28,9 +28,11 @@ bin=$pwd
|
||||
|
||||
mount_file=$tmpdir/mountfile
|
||||
mount_point=$tmpdir/mountpoint
|
||||
mount_point2=$tmpdir/mountpoint2
|
||||
mount_bad=$tmpdir/mountbad
|
||||
loop_device="unset"
|
||||
fstype="ext2"
|
||||
root_was_shared="no"
|
||||
|
||||
setup_mnt() {
|
||||
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
|
||||
@@ -41,6 +43,10 @@ remove_mnt() {
|
||||
if [ $? -eq 0 ] ; then
|
||||
/bin/umount -t${fstype} ${mount_point}
|
||||
fi
|
||||
mountpoint -q "${mount_point2}"
|
||||
if [ $? -eq 0 ] ; then
|
||||
/bin/umount -t${fstype} ${mount_point2}
|
||||
fi
|
||||
mountpoint -q "${mount_bad}"
|
||||
if [ $? -eq 0 ] ; then
|
||||
/bin/umount -t${fstype} ${mount_bad}
|
||||
@@ -53,12 +59,16 @@ mount_cleanup() {
|
||||
then
|
||||
/sbin/losetup -d ${loop_device} &> /dev/null
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
mount --make-shared /
|
||||
fi
|
||||
}
|
||||
do_onexit="mount_cleanup"
|
||||
|
||||
dd if=/dev/zero of=${mount_file} bs=1024 count=512 2> /dev/null
|
||||
/sbin/mkfs -t${fstype} -F ${mount_file} > /dev/null 2> /dev/null
|
||||
/bin/mkdir ${mount_point}
|
||||
/bin/mkdir ${mount_point2}
|
||||
/bin/mkdir ${mount_bad}
|
||||
|
||||
# in a modular udev world, the devices won't exist until the loopback
|
||||
@@ -71,6 +81,199 @@ fi
|
||||
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
|
||||
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED which does
|
||||
# not work with "move", so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily. snippet from pivot_root.sh
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
# no findmnt or findmnt doesn't know the PROPAGATION column,
|
||||
# but init is systemd so assume rootfs is shared
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
mount --make-private /
|
||||
fi
|
||||
|
||||
options=(
|
||||
# default and non-default options
|
||||
"rw,ro"
|
||||
"exec,noexec"
|
||||
"suid,nosuid"
|
||||
"dev,nodev"
|
||||
"async,sync"
|
||||
"loud,silent"
|
||||
"nomand,mand"
|
||||
"atime,noatime"
|
||||
"noiversion,iversion"
|
||||
"diratime,nodiratime"
|
||||
"nostrictatime,strictatime"
|
||||
"norelatime,relatime"
|
||||
"nodirsync,dirsync"
|
||||
"noacl,acl"
|
||||
)
|
||||
|
||||
# Options added in newer kernels
|
||||
new_options=(
|
||||
"nolazytime,lazytime"
|
||||
"symfollow,nosymfollow"
|
||||
)
|
||||
|
||||
prop_options=(
|
||||
"unbindable"
|
||||
"runbindable"
|
||||
"private"
|
||||
"rprivate"
|
||||
"slave"
|
||||
"rslave"
|
||||
"shared"
|
||||
"rshared"
|
||||
)
|
||||
|
||||
combinations=()
|
||||
|
||||
setup_all_combinations() {
|
||||
n=${#options[@]}
|
||||
for (( i = 1; i < (1 << n); i++ )); do
|
||||
list=()
|
||||
for (( j = 0; j < n; j++ )); do
|
||||
if (( (1 << j) & i )); then
|
||||
current_options="${options[j]}"
|
||||
nondefault=${current_options#*,}
|
||||
list+=("$nondefault")
|
||||
fi
|
||||
done
|
||||
combination=$(IFS=,; printf "%s" "${list[*]}")
|
||||
combinations+=($combination)
|
||||
done
|
||||
}
|
||||
|
||||
run_all_combinations_test() {
|
||||
for combination in "${combinations[@]}"; do
|
||||
if [ "$(parser_supports "mount options=($combination),")" = "true" ] ; then
|
||||
genprofile cap:sys_admin "mount:options=($combination)"
|
||||
runchecktest "MOUNT (confined cap mount combination pass test $combination)" pass mount ${loop_device} ${mount_point} -o $combination
|
||||
remove_mnt
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL" "qual=deny:mount:options=($combination)"
|
||||
runchecktest "MOUNT (confined cap mount combination deny test $combination)" fail mount ${loop_device} ${mount_point} -o $combination
|
||||
remove_mnt
|
||||
else
|
||||
echo " not supported by parser - skipping mount option=($combination),"
|
||||
fi
|
||||
|
||||
genprofile cap:sys_admin "mount:options=(rw)"
|
||||
runchecktest "MOUNT (confined cap mount combination fail test $combination)" fail mount ${loop_device} ${mount_point} -o $combination
|
||||
remove_mnt
|
||||
done
|
||||
}
|
||||
|
||||
test_nonfs_options() {
|
||||
if [ "$(parser_supports "mount options=($1),")" != "true" ] ; then
|
||||
echo " not supported by parser - skipping mount options=($1),"
|
||||
return
|
||||
fi
|
||||
|
||||
genprofile cap:sys_admin "mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount $1)" pass mount ${loop_device} ${mount_point} -o $1
|
||||
remove_mnt
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL" "qual=deny:mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount deny $1)" fail mount ${loop_device} ${mount_point} -o $1
|
||||
remove_mnt
|
||||
|
||||
genprofile cap:sys_admin "mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount bad option $2)" fail mount ${loop_device} ${mount_point} -o $2
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
test_dir_options() {
|
||||
if [ "$(parser_supports "mount options=($1),")" != "true" ] ; then
|
||||
echo " not supported by parser - skipping mount option=($1),"
|
||||
return
|
||||
fi
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL"
|
||||
runchecktest "MOUNT (confined cap mount dir setup $1)" pass mount ${loop_device} ${mount_point}
|
||||
genprofile cap:sys_admin "mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount dir $1)" pass mount ${mount_point} ${mount_point2} -o $1
|
||||
remove_mnt
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL" "qual=deny:mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount dir setup 2 $1)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (confined cap mount dir deny $1)" fail mount ${mount_point} ${mount_point2} -o $1
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
test_propagation_options() {
|
||||
if [ "$(parser_supports "mount options=($1),")" != "true" ] ; then
|
||||
echo " not supported by parser - skipping mount option=($1),"
|
||||
return
|
||||
fi
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL"
|
||||
runchecktest "MOUNT (confined cap mount propagation setup $1)" pass mount ${loop_device} ${mount_point}
|
||||
genprofile cap:sys_admin "mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount propagation $1)" pass mount none ${mount_point} -o $1
|
||||
genprofile cap:sys_admin "mount:options=($1):-> ${mount_point}/"
|
||||
runchecktest "MOUNT (confined cap mount propagation $1 mountpoint)" pass mount none ${mount_point} -o $1
|
||||
genprofile cap:sys_admin "mount:options=($1):${mount_point}/"
|
||||
runchecktest "MOUNT (confined cap mount propagation $1 source as mountpoint - deprecated)" pass mount none ${mount_point} -o $1
|
||||
remove_mnt
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL" "qual=deny:mount:options=($1)"
|
||||
runchecktest "MOUNT (confined cap mount propagation deny setup 2 $1)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (confined cap mount propagation deny $1)" fail mount none ${mount_point} -o $1
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
test_remount() {
|
||||
# setup by mounting first
|
||||
genprofile cap:sys_admin "mount:ALL"
|
||||
runchecktest "MOUNT (confined cap mount remount setup)" pass mount ${loop_device} ${mount_point}
|
||||
|
||||
genprofile cap:sys_admin "mount:options=(remount)"
|
||||
runchecktest "MOUNT (confined cap mount remount option)" pass mount ${loop_device} ${mount_point} -o remount
|
||||
|
||||
genprofile cap:sys_admin "remount:ALL"
|
||||
runchecktest "MOUNT (confined cap mount remount)" pass mount ${loop_device} ${mount_point} -o remount
|
||||
|
||||
genprofile cap:sys_admin "mount:ALL" "qual=deny:mount:options=(remount)"
|
||||
runchecktest "MOUNT (confined cap mount remount deny option)" fail mount ${loop_device} ${mount_point} -o remount
|
||||
|
||||
genprofile cap:sys_admin "qual=deny:remount:ALL"
|
||||
runchecktest "MOUNT (confined cap mount remount deny)" fail mount ${loop_device} ${mount_point} -o remount
|
||||
|
||||
# TODO: add test for remount options
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
test_options() {
|
||||
for i in "${options[@]}"; do
|
||||
default="${i%,*}"
|
||||
nondefault="${i#*,}"
|
||||
|
||||
test_nonfs_options $default $nondefault
|
||||
test_nonfs_options $nondefault $default
|
||||
done
|
||||
|
||||
for i in "bind" "rbind" "move"; do
|
||||
test_dir_options $i
|
||||
done
|
||||
|
||||
for i in "${prop_options[@]}"; do
|
||||
test_propagation_options $i
|
||||
done
|
||||
|
||||
test_remount
|
||||
|
||||
# the following combinations tests take a long time to complete
|
||||
# setup_all_combinations
|
||||
# run_all_combinations_test
|
||||
}
|
||||
|
||||
# TEST 1. Make sure can mount and umount unconfined
|
||||
runchecktest "MOUNT (unconfined)" pass mount ${loop_device} ${mount_point}
|
||||
@@ -80,6 +283,43 @@ setup_mnt
|
||||
runchecktest "UMOUNT (unconfined)" pass umount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
|
||||
# Check mount options that may not be available on this kernel
|
||||
for i in "${new_options[@]}"; do
|
||||
default="${i%,*}"
|
||||
if "$bin/mount" mount ${loop_device} ${mount_point} -o $default > /dev/null 2>&1; then
|
||||
remove_mnt
|
||||
options+=($i)
|
||||
else
|
||||
echo " not supported by kernel - skipping mount options=($i),"
|
||||
fi
|
||||
done
|
||||
|
||||
for i in "${options[@]}"; do
|
||||
default="${i%,*}"
|
||||
nondefault="${i#*,}"
|
||||
|
||||
runchecktest "MOUNT (unconfined mount $default)" pass mount ${loop_device} ${mount_point} -o $default
|
||||
remove_mnt
|
||||
runchecktest "MOUNT (unconfined mount $nondefault)" pass mount ${loop_device} ${mount_point} -o $nondefault
|
||||
remove_mnt
|
||||
done
|
||||
|
||||
for i in "bind" "rbind" "move"; do
|
||||
runchecktest "MOUNT (unconfined mount setup $i)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (unconfined mount $i)" pass mount ${mount_point} ${mount_point2} -o $i
|
||||
remove_mnt
|
||||
done
|
||||
|
||||
for i in "${prop_options[@]}"; do
|
||||
runchecktest "MOUNT (unconfined mount dir setup $i)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (unconfined mount dir $i)" pass mount none ${mount_point} -o $i
|
||||
remove_mnt
|
||||
done
|
||||
|
||||
runchecktest "MOUNT (unconfined mount remount setup)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (unconfined mount remount)" pass mount ${loop_device} ${mount_point} -o remount
|
||||
remove_mnt
|
||||
|
||||
# TEST A2. confine MOUNT no perms
|
||||
genprofile
|
||||
runchecktest "MOUNT (confined no perm)" fail mount ${loop_device} ${mount_point}
|
||||
@@ -91,6 +331,7 @@ remove_mnt
|
||||
|
||||
|
||||
if [ "$(kernel_features mount)" != "true" -o "$(parser_supports 'mount,')" != "true" ] ; then
|
||||
echo " mount rules not supported, using capability check ..."
|
||||
genprofile capability:sys_admin
|
||||
runchecktest "MOUNT (confined cap)" pass mount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
@@ -157,6 +398,17 @@ else
|
||||
runchecktest "UMOUNT (confined cap umount:ALL)" pass umount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
|
||||
# MR:https://gitlab.com/apparmor/apparmor/-/merge_requests/1054
|
||||
# https://bugs.launchpad.net/apparmor/+bug/2023814
|
||||
# https://bugzilla.opensuse.org/show_bug.cgi?id=1211989
|
||||
# based on rules from profile in bug that triggered issue
|
||||
genprofile cap:sys_admin "qual=deny:mount:/snap/bin/:-> /**" \
|
||||
"mount:options=(rw,bind):-> ${mount_point}/"
|
||||
|
||||
runchecktest "MOUNT (confined cap bind mount with deny mount that doesn't overlap)" pass mount ${mount_point2} ${mount_point} -o bind
|
||||
remove_mnt
|
||||
|
||||
test_options
|
||||
fi
|
||||
|
||||
#need tests for move mount, remount, bind mount, chroot
|
||||
#need tests for chroot
|
||||
|
@@ -38,7 +38,7 @@ badchild=r
|
||||
# Add genprofile params that are common to all hats here
|
||||
common=""
|
||||
|
||||
if [ "$(kernel_features signal)" == "true" -a "$(parser_supports 'signal,')" == "true" ] ; then
|
||||
if [ "$(kernel_features signal)" = "true" -a "$(parser_supports 'signal,')" = "true" ] ; then
|
||||
# Allow send/receive of all signals
|
||||
common="${common} signal:ALL"
|
||||
fi
|
||||
|
@@ -44,7 +44,7 @@ do_test()
|
||||
shift 4
|
||||
|
||||
desc="ONEXEC $desc ($prof -> $target_prof)"
|
||||
if [ "$target_prof" == "nochange" ] ; then
|
||||
if [ "$target_prof" = "nochange" ] ; then
|
||||
runchecktest "$desc" $res -l "$prof" -- "$@"
|
||||
else
|
||||
runchecktest "$desc" $res -O "$target_prof" -l "$prof" -L "$target_prof" -- "$@"
|
||||
|
@@ -55,7 +55,7 @@ fi
|
||||
# MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" = "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
|
@@ -86,6 +86,19 @@ requires_kernel_features()
|
||||
fi
|
||||
}
|
||||
|
||||
requires_any_of_kernel_features()
|
||||
{
|
||||
while [ $# -gt 0 ]; do
|
||||
local res=$(kernel_features "$1")
|
||||
if [ "$res" = "true" ] ; then
|
||||
return 0;
|
||||
fi
|
||||
shift
|
||||
done
|
||||
echo "$res. Skipping tests ..."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# requires_namespace_interface() - exit if namespace interface is not available
|
||||
requires_namespace_interface()
|
||||
{
|
||||
|
@@ -55,7 +55,7 @@ runchecktest "test 2 -h prog" pass -h -n 100 $helper ${bin_true}
|
||||
runchecktest "test 2 -hc prog" pass -h -c -n 100 $helper ${bin_true}
|
||||
|
||||
|
||||
if [ "$(kernel_features ptrace)" == "true" -a "$(parser_supports 'ptrace,')" == "true" ] ; then
|
||||
if [ "$(kernel_features ptrace)" = "true" -a "$(parser_supports 'ptrace,')" = "true" ] ; then
|
||||
. $bin/ptrace_v6.inc
|
||||
else
|
||||
. $bin/ptrace_v5.inc
|
||||
|
@@ -93,7 +93,7 @@ querytest()
|
||||
runchecktest "$desc" "$pf" "$expect" "$label" "$perms" $*
|
||||
}
|
||||
|
||||
if [ "$(kernel_features dbus)" == "true" ]; then
|
||||
if [ "$(kernel_features dbus)" = "true" ]; then
|
||||
# Check querying of a label that the kernel doesn't know about
|
||||
# aa_query_label() should return an error
|
||||
expect anything
|
||||
@@ -227,7 +227,7 @@ fi
|
||||
genqueryprofile "file,"
|
||||
expect allow
|
||||
perms file exec,write,read,append,create,delete,setattr,getattr,chmod,chown,link,linksubset,lock,exec_mmap
|
||||
if [ "$(kernel_features query/label/multi_transaction)" == "true" ] ; then
|
||||
if [ "$(kernel_features query/label/multi_transaction)" = "true" ] ; then
|
||||
querytest "QUERY file (all base perms #1)" pass /anything
|
||||
querytest "QUERY file (all base perms #2)" pass /everything
|
||||
else
|
||||
|
@@ -37,7 +37,7 @@ af_unix_create_label=""
|
||||
af_unix_inherit=""
|
||||
aa_enabled="/sys/module/apparmor/parameters/enabled:r"
|
||||
|
||||
if [ "$(kernel_features network/af_unix)" == "true" -a "$(parser_supports 'unix,')" == "true" ]; then
|
||||
if [ "$(kernel_features network/af_unix)" = "true" -a "$(parser_supports 'unix,')" = "true" ]; then
|
||||
# AppArmor requires that the process inheriting the sock file
|
||||
# descriptors have send,receive perms in its profile
|
||||
af_unix_create="unix:(create,getopt)"
|
||||
|
@@ -29,7 +29,7 @@ bin=$pwd
|
||||
|
||||
# check if we can run the test at all
|
||||
fstype=$(stat -f --format '%T' "${tmpdir}")
|
||||
if [ "${fstype}" == "tmpfs" ] ; then
|
||||
if [ "${fstype}" = "tmpfs" ] ; then
|
||||
echo "ERROR: tmpdir '${tmpdir}' is of type tmpfs; can't mount a swapfile on it" 1>&2
|
||||
echo "ERROR: skipping swap tests" 1>&2
|
||||
num_testfailures=1
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user