mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-04 00:05:14 +00:00
parser: support multiple mount conditionals in a single rule
Now that flag processing for mount rules with single option conditionals are fixed e-enable multiple mount conditionals on a single mount rule. The mount conditionals are equivalent to specifying multiple rules. mount options=(a,b,c) options=(c,d), is the same as mount options=(a,b,c), mount options=(c,d), and mount options in (a,b,c) options in (c,d), is the same as mount options in (a,b,c), mount options in (c,d), when multiple options= and options in are combined in a single rule it is the same as the cross product of the options. where mount options=(a,b,c) options in (d,e), is a single rule. mount options=(a,b,c) options=(d,e) options in (f), is equivalent to mount options=(a,b,c) options in (f), mount options=(d,e) options in (f), and while it is not recommended that multiple options= and options in conditions be used in a single rule. mount options=(a,b,c) options=(d,e) options in (f) options in (g), is equivalent to mount options=(a,b,c) options in (f), mount options=(a,b,c) options in (g), mount options=(d,e) options in (f), mount options=(d,e) options in (g), Bug Link: https://bugs.launchpad.net/apparmor/+bug/1597017 Signed-off-by: John Johansen <john.johansen@canonical.com> - rebased tobba1a023bf
- fixed infinite loop in mnt_rule::gen_policy_re Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> Acked-by: John Johansen <john.johansen@canonical.com> (cherry picked from commit1ec39fd437
) Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
This commit is contained in:
committed by
Jon Tourville
parent
0e35af4663
commit
bd315a7039
188
parser/mount.cc
188
parser/mount.cc
@@ -448,8 +448,7 @@ static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
|||||||
struct cond_entry *entry;
|
struct cond_entry *entry;
|
||||||
struct value_list *vals;
|
struct value_list *vals;
|
||||||
|
|
||||||
entry = list_first(opts);
|
entry = list_pop(opts);
|
||||||
list_remove(opts, entry);
|
|
||||||
vals = entry->vals;
|
vals = entry->vals;
|
||||||
entry->vals = NULL;
|
entry->vals = NULL;
|
||||||
/* fail if there are any unknown optional flags */
|
/* fail if there are any unknown optional flags */
|
||||||
@@ -470,7 +469,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
|||||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||||
int allow_p):
|
int allow_p):
|
||||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||||
flags(0), opt_flags(0), audit(0), deny(0)
|
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||||
{
|
{
|
||||||
/* FIXME: dst_conds are ignored atm */
|
/* FIXME: dst_conds are ignored atm */
|
||||||
dev_type = extract_fstype(&src_conds);
|
dev_type = extract_fstype(&src_conds);
|
||||||
@@ -481,30 +480,42 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
|||||||
|
|
||||||
if (opts_in) {
|
if (opts_in) {
|
||||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||||
|
struct cond_entry *entry;
|
||||||
|
|
||||||
process_one_option(opts_in, tmpflags, tmpinv_flags);
|
while ((entry = list_pop(opts_in))) {
|
||||||
/* optional flags if set/clear mean the same thing and can be
|
process_one_option(entry, tmpflags,
|
||||||
* represented by a single bitset
|
tmpinv_flags);
|
||||||
*/
|
/* optional flags if set/clear mean the same
|
||||||
opt_flags |= tmpflags;
|
* thing and can be represented by a single
|
||||||
opt_flags |= tmpinv_flags;
|
* 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 */
|
/* move options=() to opts list */
|
||||||
struct cond_entry *opts_eq = extract_options(&src_conds, 1);
|
struct cond_entry *opts_eq = extract_options(&src_conds, 1);
|
||||||
if (opts_eq) {
|
if (opts_eq) {
|
||||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||||
|
struct cond_entry *entry;
|
||||||
|
|
||||||
process_one_option(opts_eq, tmpflags, tmpinv_flags);
|
while ((entry = list_pop(opts_eq))) {
|
||||||
if (allow_p & AA_DUMMY_REMOUNT)
|
process_one_option(entry, tmpflags,
|
||||||
tmpflags |= MS_REMOUNT;
|
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)) {
|
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||||
PERROR("conflicting flags in the rule\n");
|
PERROR("conflicting flags in the rule\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
flagsv.push_back(tmpflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = tmpflags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_conds) {
|
if (src_conds) {
|
||||||
@@ -513,25 +524,28 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags | opt_flags)) {
|
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||||
/* no flag options, and not remount, allow everything */
|
/* no flag options, and not remount, allow everything */
|
||||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||||
flags = MS_REMOUNT;
|
flagsv.push_back(MS_REMOUNT);
|
||||||
opt_flags = MS_REMOUNT_FLAGS & (~MS_REMOUNT);
|
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||||
} else {
|
} else {
|
||||||
flags = MS_ALL_FLAGS;
|
flagsv.push_back(MS_ALL_FLAGS);
|
||||||
opt_flags = MS_ALL_FLAGS;
|
opt_flagsv.push_back(MS_ALL_FLAGS);
|
||||||
}
|
}
|
||||||
} else if (!flags) {
|
} else if (!(flagsv.size())) {
|
||||||
/* no flags but opts set */
|
/* no flags but opts set */
|
||||||
if (allow_p & AA_DUMMY_REMOUNT)
|
if (allow_p & AA_DUMMY_REMOUNT)
|
||||||
flags = MS_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) {
|
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||||
allow_p = AA_MAY_MOUNT;
|
allow_p = AA_MAY_MOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
allow = allow_p;
|
allow = allow_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +560,11 @@ ostream &mnt_rule::dump(ostream &os)
|
|||||||
else
|
else
|
||||||
os << "error: unknonwn mount perm";
|
os << "error: unknonwn mount perm";
|
||||||
|
|
||||||
os << " (0x" << hex << flags << " - 0x" << opt_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) {
|
if (dev_type) {
|
||||||
os << " type=";
|
os << " type=";
|
||||||
print_value_list(dev_type);
|
print_value_list(dev_type);
|
||||||
@@ -682,7 +700,8 @@ static void warn_once(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int mnt_rule::gen_policy_remount(Profile &prof, int &count)
|
int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||||
|
unsigned int flags, unsigned int opt_flags)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
std::string devbuf;
|
std::string devbuf;
|
||||||
@@ -750,7 +769,8 @@ fail:
|
|||||||
return RULE_ERROR;
|
return RULE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count)
|
int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||||
|
unsigned int flags, unsigned int opt_flags)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
std::string devbuf;
|
std::string devbuf;
|
||||||
@@ -789,7 +809,9 @@ fail:
|
|||||||
return RULE_ERROR;
|
return RULE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count)
|
int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||||
|
unsigned int flags,
|
||||||
|
unsigned int opt_flags)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
std::string devbuf;
|
std::string devbuf;
|
||||||
@@ -828,7 +850,8 @@ fail:
|
|||||||
return RULE_ERROR;
|
return RULE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mnt_rule::gen_policy_move_mount(Profile &prof, int &count)
|
int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||||
|
unsigned int flags, unsigned int opt_flags)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
std::string devbuf;
|
std::string devbuf;
|
||||||
@@ -869,7 +892,8 @@ fail:
|
|||||||
return RULE_ERROR;
|
return RULE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mnt_rule::gen_policy_new_mount(Profile &prof, int &count)
|
int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||||
|
unsigned int flags, unsigned int opt_flags)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
std::string devbuf;
|
std::string devbuf;
|
||||||
@@ -931,6 +955,53 @@ fail:
|
|||||||
return RULE_ERROR;
|
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 && !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 && !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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int mnt_rule::gen_policy_re(Profile &prof)
|
int mnt_rule::gen_policy_re(Profile &prof)
|
||||||
{
|
{
|
||||||
std::string mntbuf;
|
std::string mntbuf;
|
||||||
@@ -941,61 +1012,16 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
|||||||
const char *vec[5];
|
const char *vec[5];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (!kernel_supports_mount) {
|
|
||||||
warn_once(prof.name);
|
|
||||||
return RULE_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||||
|
|
||||||
/* a single mount rule may result in multiple matching rules being
|
/* a single mount rule may result in multiple matching rules being
|
||||||
* created in the backend to cover all the possible choices
|
* created in the backend to cover all the possible choices
|
||||||
*/
|
*/
|
||||||
|
for (size_t i = 0; i < flagsv.size(); i++) {
|
||||||
/*
|
for (size_t j = 0; j < opt_flagsv.size(); j++) {
|
||||||
* XXX: added !flags to cover cases like:
|
if (gen_flag_rules(prof, count, flagsv[i], opt_flagsv[j]) == RULE_ERROR)
|
||||||
* mount options in (bind) /d -> /4,
|
goto fail;
|
||||||
*/
|
}
|
||||||
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) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
if (!dev_type && !opts &&
|
|
||||||
gen_policy_bind_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
if (!device && !dev_type && !opts &&
|
|
||||||
gen_policy_change_mount_type(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
if (!dev_type && !opts &&
|
|
||||||
gen_policy_move_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
if (gen_policy_new_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
|
||||||
&& !device && !dev_type) {
|
|
||||||
if (gen_policy_remount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
|
||||||
&& !dev_type && !opts) {
|
|
||||||
if (gen_policy_bind_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
} else if ((allow & AA_MAY_MOUNT) &&
|
|
||||||
(flags & (MS_MAKE_CMDS))
|
|
||||||
&& !device && !dev_type && !opts) {
|
|
||||||
if (gen_policy_change_mount_type(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
|
||||||
&& !dev_type && !opts) {
|
|
||||||
if (gen_policy_move_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
} else if ((allow & AA_MAY_MOUNT) &&
|
|
||||||
(flags | opt_flags) & ~MS_CMDS) {
|
|
||||||
/* generic mount if flags are set that are not covered by
|
|
||||||
* above commands
|
|
||||||
*/
|
|
||||||
if (gen_policy_new_mount(prof, count) == RULE_ERROR)
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
if (allow & AA_MAY_UMOUNT) {
|
if (allow & AA_MAY_UMOUNT) {
|
||||||
/* rule class single byte header */
|
/* rule class single byte header */
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#define __AA_MOUNT_H
|
#define __AA_MOUNT_H
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
@@ -120,11 +121,19 @@
|
|||||||
|
|
||||||
|
|
||||||
class mnt_rule: public rule_t {
|
class mnt_rule: public rule_t {
|
||||||
int gen_policy_remount(Profile &prof, int &count);
|
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||||
int gen_policy_bind_mount(Profile &prof, int &count);
|
unsigned int opt_flags);
|
||||||
int gen_policy_change_mount_type(Profile &prof, int &count);
|
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||||
int gen_policy_move_mount(Profile &prof, int &count);
|
unsigned int opt_flags);
|
||||||
int gen_policy_new_mount(Profile &prof, int &count);
|
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:
|
public:
|
||||||
char *mnt_point;
|
char *mnt_point;
|
||||||
char *device;
|
char *device;
|
||||||
@@ -132,7 +141,7 @@ public:
|
|||||||
struct value_list *dev_type;
|
struct value_list *dev_type;
|
||||||
struct value_list *opts;
|
struct value_list *opts;
|
||||||
|
|
||||||
unsigned int flags, opt_flags;
|
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||||
|
|
||||||
int allow, audit;
|
int allow, audit;
|
||||||
int deny;
|
int deny;
|
||||||
|
@@ -238,6 +238,16 @@ do { \
|
|||||||
prev; \
|
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) \
|
#define list_remove_at(LIST, PREV, ENTRY) \
|
||||||
if (PREV) \
|
if (PREV) \
|
||||||
(PREV)->next = (ENTRY)->next; \
|
(PREV)->next = (ENTRY)->next; \
|
||||||
|
Reference in New Issue
Block a user