mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Compare commits
77 Commits
v5.0.0-alp
...
v4.0.3
Author | SHA1 | Date | |
---|---|---|---|
|
b4dfdf50f5 | ||
|
5dd04c3389 | ||
|
1e9e52f243 | ||
|
9f57cbcb15 | ||
|
8146d3a6a3 | ||
|
d3d1c02b4e | ||
|
eb523cf53b | ||
|
507be2a990 | ||
|
3c24bc68b6 | ||
|
0193009b8b | ||
|
84a6bc1b6d | ||
|
9f849247b9 | ||
|
3fe2d323fc | ||
|
f0f7420f6c | ||
|
efef7d1b28 | ||
|
d61109d47e | ||
|
113ce2cfcd | ||
|
af7a10b5d9 | ||
|
4bb134e4bb | ||
|
4569381ec3 | ||
|
73a29ade16 | ||
|
d8e17207e8 | ||
|
0f51513a11 | ||
|
a07a8e69e0 | ||
|
24a0ebb5ef | ||
|
0310a122d4 | ||
|
6cad7b889e | ||
|
e2aff72f53 | ||
|
046fe9c1bd | ||
|
e4e60f1a4f | ||
|
ae01582798 | ||
|
98a0a2fee9 | ||
|
aada708bc1 | ||
|
dca6ac3b73 | ||
|
9d1388fdb6 | ||
|
a8637a5aa1 | ||
|
a866d77e72 | ||
|
527205bda9 | ||
|
e3be2e52ea | ||
|
d1311cc93f | ||
|
2a3cf471ab | ||
|
c31da2ec55 | ||
|
e8b2597676 | ||
|
6dee9d0a6a | ||
|
aa74b9b12d | ||
|
9ec5134322 | ||
|
fcd02fb69b | ||
|
1f4bba0448 | ||
|
af88a13712 | ||
|
8e74855531 | ||
|
951ea5b2fb | ||
|
eee50538da | ||
|
86be5d35f3 | ||
|
b7f9b66cba | ||
|
6d1e5dbbe6 | ||
|
f1173379ff | ||
|
b0eb95457b | ||
|
5ad4efec50 | ||
|
a635a86e1d | ||
|
c8e25e4689 | ||
|
68dd052873 | ||
|
4cef932170 | ||
|
8108a217a3 | ||
|
2284e99613 | ||
|
f763c44cd0 | ||
|
1d36e1f196 | ||
|
22ee6c19bc | ||
|
6198edb3d0 | ||
|
4d2a171466 | ||
|
e88cf3cd02 | ||
|
6f856dfee3 | ||
|
a6d8171bd6 | ||
|
26e7249f44 | ||
|
117d0cc444 | ||
|
1c7127d30d | ||
|
d111ddcc21 | ||
|
fa26623e6d |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -266,8 +266,8 @@ tests/regression/apparmor/mmap
|
||||
tests/regression/apparmor/mount
|
||||
tests/regression/apparmor/move_mount
|
||||
tests/regression/apparmor/named_pipe
|
||||
tests/regression/apparmor/net_finegrained_rcv
|
||||
tests/regression/apparmor/net_finegrained_snd
|
||||
tests/regression/apparmor/net_inet_rcv
|
||||
tests/regression/apparmor/net_inet_snd
|
||||
tests/regression/apparmor/net_raw
|
||||
tests/regression/apparmor/open
|
||||
tests/regression/apparmor/openat
|
||||
|
@@ -112,7 +112,7 @@ shellcheck:
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
|
@@ -172,7 +172,8 @@ static int load_policy_dir(const char *dir_path)
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
/* Only check regular files for now */
|
||||
if (dir->d_type == DT_REG) {
|
||||
len = strnlen(dir->d_name, PATH_MAX);
|
||||
/* As per POSIX dir->d_name has at most NAME_MAX characters */
|
||||
len = strnlen(dir->d_name, NAME_MAX);
|
||||
/* Ignores .features */
|
||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||
continue;
|
||||
|
@@ -1 +1 @@
|
||||
4.0.0~beta3
|
||||
4.0.3
|
||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 18
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||
AA_LIB_CURRENT = 20
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 19
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.19.0
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
|
@@ -127,6 +127,7 @@ APPARMOR_3.0 {
|
||||
APPARMOR_3.1 {
|
||||
global:
|
||||
aa_features_check;
|
||||
aa_split_overlay_str;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_3.0;
|
||||
|
@@ -157,9 +157,13 @@ key_capname "capname"
|
||||
key_offset "offset"
|
||||
key_target "target"
|
||||
key_laddr "laddr"
|
||||
key_saddr "saddr"
|
||||
key_faddr "faddr"
|
||||
key_daddr "daddr"
|
||||
key_lport "lport"
|
||||
key_srcport "src"
|
||||
key_fport "fport"
|
||||
key_destport "dest"
|
||||
key_bus "bus"
|
||||
key_dest "dest"
|
||||
key_path "path"
|
||||
@@ -351,9 +355,13 @@ yy_flex_debug = 0;
|
||||
{key_offset} { return(TOK_KEY_OFFSET); }
|
||||
{key_target} { return(TOK_KEY_TARGET); }
|
||||
{key_laddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
||||
{key_saddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
||||
{key_faddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||
{key_daddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||
{key_lport} { return(TOK_KEY_LPORT); }
|
||||
{key_srcport} { return(TOK_KEY_LPORT); }
|
||||
{key_fport} { return(TOK_KEY_FPORT); }
|
||||
{key_destport} { return(TOK_KEY_FPORT); }
|
||||
{key_bus} { return(TOK_KEY_BUS); }
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
|
@@ -135,7 +135,7 @@ static int do_test_walk_one(const char **str, const struct component *component,
|
||||
|
||||
static int test_walk_one(void)
|
||||
{
|
||||
struct component c;
|
||||
struct component c = (struct component) { NULL, 0 };
|
||||
const char *str;
|
||||
int rc = 0;
|
||||
|
||||
|
@@ -55,7 +55,7 @@ extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
||||
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
|
||||
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
||||
extern int aa_getcon(char **label, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
|
||||
extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||
int *audit);
|
||||
|
@@ -14,7 +14,7 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(CFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/home/ubuntu/bzr/apparmor/tests/regression/apparmor/mount {
|
||||
mount fstype=ext2 options="rw, mand" /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
||||
mount fstype=(ext2) options=(mand, rw) /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
type=AVC msg=audit(1715045678.914:344186): apparmor="ALLOWED" operation="mount" info="failed flags match" error=-13 profile="steam" name="/newroot/dev/" pid=26487 comm="srt-bwrap" flags="rw, nosuid, nodev, remount, bind, silent, relatime"
|
@@ -0,0 +1,14 @@
|
||||
START
|
||||
File: testcase_mount_02.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1715045678.914:344186
|
||||
Operation: mount
|
||||
Profile: steam
|
||||
Name: /newroot/dev/
|
||||
Command: srt-bwrap
|
||||
Info: failed flags match
|
||||
ErrorCode: 13
|
||||
PID: 26487
|
||||
Flags: rw, nosuid, nodev, remount, bind, silent, relatime
|
||||
Epoch: 1715045678
|
||||
Audit subid: 344186
|
@@ -0,0 +1,4 @@
|
||||
profile steam {
|
||||
mount options=(bind, nodev, nosuid, relatime, remount, rw, silent) -> /newroot/dev/,
|
||||
|
||||
}
|
@@ -39,7 +39,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
prefix_rule_t *rule;
|
||||
const prefixes *prefix = this;
|
||||
|
||||
rule = new unix_rule(0, audit, rule_mode);
|
||||
rule = new unix_rule(0xffffffff, audit, rule_mode);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
@@ -67,7 +67,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, 0);
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_MOUNT);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
|
@@ -148,7 +148,14 @@ B<CAPABILITY LIST> = ( I<CAPABILITY> )+
|
||||
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
|
||||
capabilities(7))
|
||||
|
||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<NETWORK ACCESS EXPR> ] [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ] [ I<NETWORK LOCAL EXPR> ] [ I<NETWORK PEER EXPR> ]
|
||||
|
||||
B<NETWORK ACCESS EXPR> = ( I<NETWORK ACCESS> | I<NETWORK ACCESS LIST> )
|
||||
|
||||
B<NETWORK ACCESS> = ( 'create' | 'bind' | 'listen' | 'accept' | 'connect' | 'shutdown' | 'getattr' | 'setattr' | 'getopt' | 'setopt' | 'send' | 'receive' | 'r' | 'w' | 'rw' )
|
||||
Some access modes are incompatible with some rules.
|
||||
|
||||
B<NETWORK ACCESS LIST> = '(' I<NETWORK ACCESS> ( [','] I<NETWORK ACCESS> )* ')'
|
||||
|
||||
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | 'mctp' ) ','
|
||||
|
||||
@@ -156,6 +163,22 @@ B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
||||
|
||||
B<PROTOCOL> = ( 'tcp' | 'udp' | 'icmp' )
|
||||
|
||||
B<NETWORK LOCAL EXPR> = ( I<NETWORK IP COND> | I<NETWORK PORT COND> )*
|
||||
Each cond can appear at most once.
|
||||
|
||||
B<NETWORK PEER EXPR> = 'peer' '=' '(' ( I<NETWORK IP COND> | I<NETWORK PORT COND> )+ ')'
|
||||
Each cond can appear at most once.
|
||||
|
||||
B<NETWORK IP COND> = 'ip' '=' ( 'none' | I<NETWORK IPV4> | I<NETWORK IPV6> )
|
||||
|
||||
B<NETWORK PORT COND> = 'port' '=' ( I<NETWORK PORT> )
|
||||
|
||||
B<NETWORK IPV4> = IPv4, represented by four 8-bit decimal numbers separated by '.'
|
||||
|
||||
B<NETWORK IPV6> = IPv6, represented by eight groups of four hexadecimal numbers separated by ':'. Shortened representation of contiguous zeros is allowed by using '::'
|
||||
|
||||
B<NETWORK PORT> = 16-bit number ranging from 0 to 65535
|
||||
|
||||
B<MOUNT RULE> = ( I<MOUNT> | I<REMOUNT> | I<UMOUNT> )
|
||||
|
||||
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ '-E<gt>' [ I<MOUNTPOINT FILEGLOB> ]
|
||||
@@ -912,11 +935,10 @@ and other operations that are typically reserved for the root user.
|
||||
|
||||
=head2 Network Rules
|
||||
|
||||
AppArmor supports simple coarse grained network mediation. The network
|
||||
rule restrict all socket(2) based operations. The mediation done is
|
||||
a coarse-grained check on whether a socket of a given type and family
|
||||
can be created, read, or written. There is no mediation based of port
|
||||
number or protocol beyond tcp, udp, and raw. Network netlink(7) rules may
|
||||
AppArmor supports simple coarse grained network mediation. The
|
||||
network rule restrict all socket(2) based operations. The mediation
|
||||
done is a coarse-grained check on whether a socket of a given type and
|
||||
family can be created, read, or written. Network netlink(7) rules may
|
||||
only specify type 'dgram' and 'raw'.
|
||||
|
||||
AppArmor network rules are accumulated so that the granted network
|
||||
@@ -933,6 +955,48 @@ eg.
|
||||
network inet6 tcp, #allow access to tcp only for inet6 addresses
|
||||
network netlink raw, #allow access to AF_NETLINK SOCK_RAW
|
||||
|
||||
=head3 Network permissions
|
||||
|
||||
Network rule permissions are implied when a rule does not explicitly
|
||||
state an access list. By default if a rule does not have an access
|
||||
list all permissions that are compatible with the specified set of
|
||||
local and peer conditionals are implied.
|
||||
|
||||
The create, bind, listen, shutdown, getattr, setattr, getopt, and
|
||||
setopt permissions are local socket permissions. They are only applied
|
||||
to the local socket and can't be specified in rules that have a peer
|
||||
conditional. The accept permission applies to the combination of a
|
||||
local and peer socket. The connect, send, and receive permissions are
|
||||
peer socket permissions.
|
||||
|
||||
=head3 Mediation of inet/inet6 family
|
||||
|
||||
AppArmor supports fine grained mediation of the inet and inet6
|
||||
families by using the ip and port conditionals. The ip conditional
|
||||
accepts both IPv4 and IPv6 using the regular representation of four
|
||||
octets separated by '.' for IPv4 and eight groups of four hexadecimal
|
||||
numbers separated by ':' for IPv6. Contiguous leading zeros can be
|
||||
replaced by '::' once. On a connected socket, the sender and receiver
|
||||
don't need to be specified in the recvfrom and sendto system calls. In
|
||||
that case, and with unbounded sockets, the IP address is none, or
|
||||
unknown. Unknown or Unbound IP addresses are represented in policy by the
|
||||
'none' keyword. When the ip conditional is omitted, then all IP
|
||||
addresses will be allowed: IPv4, IPv6 and none. If INADDR_ANY or
|
||||
in6addr_any is used, then the ip conditional can be omitted or they
|
||||
can be represented by:
|
||||
|
||||
network ip=::, #allow in6addr_any
|
||||
network ip=0.0.0.0; #allow INADDR_ANY
|
||||
|
||||
The network rules support the specification of local and remote IP
|
||||
addresses and ports.
|
||||
|
||||
network ip=127.0.0.1 port=8080,
|
||||
network peer=(ip=10.139.15.23 port=8081),
|
||||
network ip=fd74:1820:b03a:b361::cf32 peer=(ip=fd74:1820:b03a:b361::a0f9),
|
||||
network port=8080 peer=(port=8081),
|
||||
network ip=127.0.0.1 port=8080 peer=(ip=10.139.15.23 port=8081),
|
||||
|
||||
=head2 Mount Rules
|
||||
|
||||
AppArmor supports mount mediation and allows specifying filesystem types and
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_action()
|
||||
{
|
||||
echo "$1"
|
||||
@@ -25,36 +27,50 @@ aa_action()
|
||||
return $?
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_warning_msg()
|
||||
{
|
||||
echo "Warning: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_failure_msg()
|
||||
{
|
||||
echo "Error: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_start()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_end()
|
||||
{
|
||||
printf ""
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_daemon_msg()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_skipped_msg()
|
||||
{
|
||||
echo "Skipped: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_end_msg()
|
||||
{
|
||||
printf ""
|
||||
|
@@ -189,6 +189,19 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
* a b c T
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static Node *simplify_eps_pair(Node *t)
|
||||
{
|
||||
if (t->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
t->child[0] == &epsnode &&
|
||||
t->child[1] == &epsnode) {
|
||||
t->release();
|
||||
return &epsnode;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static void rotate_node(Node *t, int dir)
|
||||
{
|
||||
// (a | b) | c -> a | (b | c)
|
||||
@@ -197,7 +210,9 @@ static void rotate_node(Node *t, int dir)
|
||||
t->child[dir] = left->child[dir];
|
||||
left->child[dir] = left->child[!dir];
|
||||
left->child[!dir] = t->child[!dir];
|
||||
t->child[!dir] = left;
|
||||
|
||||
// check that rotation didn't create (E | E)
|
||||
t->child[!dir] = simplify_eps_pair(left);
|
||||
}
|
||||
|
||||
/* return False if no work done */
|
||||
@@ -209,13 +224,7 @@ int TwoChildNode::normalize_eps(int dir)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = child[!dir];
|
||||
if (c->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
Node *c = simplify_eps_pair(child[!dir]);
|
||||
child[!dir] = child[dir];
|
||||
child[dir] = c;
|
||||
return 1;
|
||||
|
@@ -192,14 +192,14 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) {
|
||||
warn_once(prof.name);
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_unspecified &&
|
||||
!(features_supports_posix_mqueue ||
|
||||
features_supports_sysv_mqueue)) {
|
||||
warn_once(prof.name);
|
||||
// should split into warning where posix and sysv can
|
||||
// be separated from nothing being enforced
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* always generate a label and mqueue entry */
|
||||
@@ -231,10 +231,10 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
/* store perms at name match so label doesn't need
|
||||
* to be checked
|
||||
*/
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false))
|
||||
goto fail;
|
||||
/* also provide label match with perm */
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -266,10 +266,10 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
}
|
||||
|
||||
if (perms & AA_VALID_SYSV_MQ_PERMS) {
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false))
|
||||
goto fail;
|
||||
/* also provide label match with perm */
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@@ -52,13 +52,13 @@
|
||||
* kernel doesn't allow for us to control
|
||||
* - posix
|
||||
* - notify
|
||||
* - getattr/setattr
|
||||
* - labels at anything other than mqueue label, via mqueue inode.
|
||||
*/
|
||||
|
||||
#define AA_VALID_POSIX_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
|
||||
AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \
|
||||
AA_MQUEUE_OPEN)
|
||||
AA_MQUEUE_OPEN | \
|
||||
AA_MQUEUE_SETATTR | AA_MQUEUE_GETATTR)
|
||||
|
||||
/* TBD - for now make it wider than posix */
|
||||
#define AA_VALID_SYSV_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
|
||||
@@ -78,6 +78,11 @@ typedef enum mqueue_type {
|
||||
mqueue_sysv
|
||||
} mqueue_type;
|
||||
|
||||
static inline uint32_t map_mqueue_perms(uint32_t mask)
|
||||
{
|
||||
return (mask & 0x7f) |
|
||||
((mask & (AA_MQUEUE_GETATTR | AA_MQUEUE_SETATTR)) << (AA_OTHER_SHIFT - 8));
|
||||
}
|
||||
|
||||
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail);
|
||||
|
||||
|
@@ -360,8 +360,8 @@ bool network_rule::parse_port(ip_conds &entry)
|
||||
|
||||
bool network_rule::parse_address(ip_conds &entry)
|
||||
{
|
||||
if (strcmp(entry.sip, "anon") == 0) {
|
||||
entry.is_anonymous = true;
|
||||
if (strcmp(entry.sip, "none") == 0) {
|
||||
entry.is_none = true;
|
||||
return true;
|
||||
}
|
||||
entry.is_ip = true;
|
||||
@@ -405,17 +405,31 @@ network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
|
||||
{
|
||||
size_t family_index;
|
||||
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
||||
set_netperm(family_index, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
}
|
||||
size_t family_index, i;
|
||||
|
||||
move_conditionals(conds, local);
|
||||
move_conditionals(peer_conds, peer);
|
||||
free_cond_list(conds);
|
||||
free_cond_list(peer_conds);
|
||||
|
||||
if (has_local_conds() || has_peer_conds()) {
|
||||
const char *family[] = { "inet", "inet6" };
|
||||
for (i = 0; i < sizeof(family)/sizeof(family[0]); i++) {
|
||||
const struct network_tuple *mapping = NULL;
|
||||
while ((mapping = net_find_mapping(mapping, family[i], NULL, NULL))) {
|
||||
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||
set_netperm(mapping->family, mapping->type, mapping->protocol);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
||||
set_netperm(family_index, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_NET_PERMS)
|
||||
@@ -433,13 +447,34 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type
|
||||
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
|
||||
{
|
||||
const struct network_tuple *mapping = NULL;
|
||||
|
||||
move_conditionals(conds, local);
|
||||
move_conditionals(peer_conds, peer);
|
||||
free_cond_list(conds);
|
||||
free_cond_list(peer_conds);
|
||||
|
||||
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
||||
/* if inet conds and family are specified, fail if
|
||||
* family is not af_inet or af_inet6
|
||||
*/
|
||||
if ((has_local_conds() || has_peer_conds()) &&
|
||||
mapping->family != AF_INET && mapping->family != AF_INET6) {
|
||||
yyerror("network family does not support local or peer conditionals\n");
|
||||
}
|
||||
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||
set_netperm(mapping->family, mapping->type, mapping->protocol);
|
||||
}
|
||||
|
||||
if (type == NULL && network_map.empty()) {
|
||||
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
|
||||
/* if inet conds and type/protocol are
|
||||
* specified, only add rules for af_inet and
|
||||
* af_inet6
|
||||
*/
|
||||
if ((has_local_conds() || has_peer_conds()) &&
|
||||
mapping->family != AF_INET && mapping->family != AF_INET6)
|
||||
continue;
|
||||
|
||||
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||
set_netperm(mapping->family, mapping->type, mapping->protocol);
|
||||
}
|
||||
@@ -448,11 +483,6 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type
|
||||
if (network_map.empty())
|
||||
yyerror(_("Invalid network entry."));
|
||||
|
||||
move_conditionals(conds, local);
|
||||
move_conditionals(peer_conds, peer);
|
||||
free_cond_list(conds);
|
||||
free_cond_list(peer_conds);
|
||||
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_NET_PERMS)
|
||||
@@ -585,13 +615,13 @@ std::string gen_port_cond(uint16_t port)
|
||||
std::list<std::ostringstream> gen_all_ip_options(std::ostringstream &oss) {
|
||||
|
||||
std::list<std::ostringstream> all_streams;
|
||||
std::ostringstream anon, ipv4, ipv6;
|
||||
std::ostringstream none, ipv4, ipv6;
|
||||
int i;
|
||||
anon << oss.str();
|
||||
none << oss.str();
|
||||
ipv4 << oss.str();
|
||||
ipv6 << oss.str();
|
||||
|
||||
anon << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
|
||||
none << "\\x" << std::setfill('0') << std::setw(2) << std::hex << NONE_SIZE;
|
||||
|
||||
/* add a byte containing the size of the following ip */
|
||||
ipv4 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
|
||||
@@ -603,7 +633,7 @@ std::list<std::ostringstream> gen_all_ip_options(std::ostringstream &oss) {
|
||||
for (i = 0; i < 16; ++i)
|
||||
ipv6 << ".";
|
||||
|
||||
all_streams.push_back(std::move(anon));
|
||||
all_streams.push_back(std::move(none));
|
||||
all_streams.push_back(std::move(ipv4));
|
||||
all_streams.push_back(std::move(ipv6));
|
||||
|
||||
@@ -627,7 +657,7 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &st
|
||||
std::list<std::ostringstream> ip_streams;
|
||||
|
||||
for (auto &oss : streams) {
|
||||
if (entry.is_port && !(entry.is_ip && entry.is_anonymous)) {
|
||||
if (entry.is_port && !(entry.is_ip && entry.is_none)) {
|
||||
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
|
||||
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
|
||||
oss << "\\x01";
|
||||
@@ -650,8 +680,8 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &st
|
||||
if (entry.is_ip) {
|
||||
oss << gen_ip_cond(entry.ip);
|
||||
streams.push_back(std::move(oss));
|
||||
} else if (entry.is_anonymous) {
|
||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
|
||||
} else if (entry.is_none) {
|
||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << NONE_SIZE;
|
||||
streams.push_back(std::move(oss));
|
||||
} else {
|
||||
streams.splice(streams.end(), gen_all_ip_options(oss));
|
||||
@@ -898,7 +928,7 @@ static int cmp_ip_conds(ip_conds const &lhs, ip_conds const &rhs)
|
||||
res = null_strcmp(lhs.sport, rhs.sport);
|
||||
if (res)
|
||||
return res;
|
||||
return lhs.is_anonymous - rhs.is_anonymous;
|
||||
return lhs.is_none - rhs.is_none;
|
||||
}
|
||||
|
||||
static int cmp_network_map(std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> lhs,
|
||||
|
@@ -80,7 +80,7 @@
|
||||
#define CMD_LISTEN 2
|
||||
#define CMD_OPT 4
|
||||
|
||||
#define ANON_SIZE 0
|
||||
#define NONE_SIZE 0
|
||||
#define IPV4_SIZE 1
|
||||
#define IPV6_SIZE 2
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
uint16_t port;
|
||||
struct ip_address ip;
|
||||
|
||||
bool is_anonymous = false;
|
||||
bool is_none = false;
|
||||
|
||||
void free_conds() {
|
||||
if (sip)
|
||||
|
@@ -255,9 +255,11 @@ MODES {MODE_CHARS}+
|
||||
WS [[:blank:]]
|
||||
NUMBER [[:digit:]]+
|
||||
|
||||
ID_FIRST_CHARS [^ \t\r\n"!,#]
|
||||
ID_FIRST {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,|\\#)
|
||||
ID_CHARS [^ \t\r\n"!,]
|
||||
ID {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,)
|
||||
IDS {ID}+
|
||||
IDS {ID_FIRST}{ID}*
|
||||
INC_ID [^ \t\r\n"!,<>]|(,[^ \t\r\n"!,<>]|\\[ ]|\\\t|\\\"|\\!|\\,)
|
||||
INC_IDS {INC_ID}+
|
||||
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
|
||||
@@ -507,6 +509,12 @@ GT >
|
||||
yyerror(_("Variable declarations do not accept trailing commas"));
|
||||
}
|
||||
|
||||
#.*\r?\n { /* normal comment */
|
||||
DUMP_AND_DEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||
current_lineno++;
|
||||
POP();
|
||||
}
|
||||
|
||||
\\\n { DUMP_PREPROCESS; current_lineno++ ; }
|
||||
|
||||
\r?\n {
|
||||
|
@@ -1000,41 +1000,46 @@ int process_profile_policydb(Profile *prof)
|
||||
* to be supported
|
||||
*/
|
||||
|
||||
/* note: this activates fs based unix domain sockets mediation on connect */
|
||||
if (kernel_abi_version > 5 &&
|
||||
!prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_mount &&
|
||||
!prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_dbus &&
|
||||
!prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_signal &&
|
||||
!prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_ptrace &&
|
||||
!prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_networkv8 &&
|
||||
!prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_unix &&
|
||||
(!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) ||
|
||||
!prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts)))
|
||||
goto out;
|
||||
if (features_supports_userns &&
|
||||
!prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_posix_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_sysv_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_io_uring &&
|
||||
!prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
|
||||
/* don't add mediated classes to unconfined profiles */
|
||||
if (prof->flags.mode != MODE_UNCONFINED &&
|
||||
prof->flags.mode != MODE_DEFAULT_ALLOW) {
|
||||
/* note: this activates fs based unix domain sockets mediation on connect */
|
||||
if (kernel_abi_version > 5 &&
|
||||
!prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_mount &&
|
||||
!prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_dbus &&
|
||||
!prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_signal &&
|
||||
!prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_ptrace &&
|
||||
!prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_networkv8 &&
|
||||
!prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_unix &&
|
||||
(!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) ||
|
||||
!prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts)))
|
||||
goto out;
|
||||
if (features_supports_posix_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_sysv_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_io_uring &&
|
||||
!prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prof->policy.rules->rule_count > 0) {
|
||||
int xmatch_len = 0;
|
||||
|
@@ -253,13 +253,14 @@ remove_profiles() {
|
||||
retval=0
|
||||
# We filter child profiles as removing the parent will remove
|
||||
# the children
|
||||
sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
sed -e "s/ (\(enforce\|complain\|unconfined\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
LC_COLLATE=C sort | grep -v // | {
|
||||
while read -r profile ; do
|
||||
printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
|
||||
rc=$?
|
||||
if [ "$rc" -ne 0 ] ; then
|
||||
retval=$rc
|
||||
aa_log_failure_msg "Unloading profile '$profile' failed"
|
||||
fi
|
||||
done
|
||||
return "$retval"
|
||||
|
@@ -643,6 +643,18 @@ verify_binary_equality "attachment slash filtering" \
|
||||
@{FOO}=/foo
|
||||
/t @{BAR}/@{FOO} { }"
|
||||
|
||||
# verify comment at end of variable assignment is not treated as a value
|
||||
verify_binary_equality "comment at end of set var" \
|
||||
"/t { /bin/ r, }" \
|
||||
"@{BAR}=/bin/ #a tail comment
|
||||
/t { @{BAR} r, }"
|
||||
|
||||
verify_binary_equality "value like comment at end of set var" \
|
||||
"/t { /{bin/,#value} r, }" \
|
||||
"@{BAR}=bin/ \#value
|
||||
/t { /@{BAR} r, }"
|
||||
|
||||
|
||||
# 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
|
||||
|
9
parser/tst/simple_tests/mount/ok_opt_85.sd
Normal file
9
parser/tst/simple_tests/mount/ok_opt_85.sd
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
#=Description test globbed destination MR 1195
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, make-slave) -> **,
|
||||
mount options=(rw) foo -> **,
|
||||
mount fstype=tmpfs options=(rw) foo -> **,
|
||||
mount -> **,
|
||||
}
|
9
parser/tst/simple_tests/mount/ok_quoted_1.sd
Normal file
9
parser/tst/simple_tests/mount/ok_quoted_1.sd
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
#=Description basic mount rules with quoted paths
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount "" -> "/",
|
||||
mount "" -> "/tmp/",
|
||||
umount "/",
|
||||
}
|
8
parser/tst/simple_tests/network/network_bad_83.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_83.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=DESCRIPTION invalid family for inet conditionals
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network unix ip=127.0.0.1 port=1234 peer=(ip=127.0.0.1 port=1234),
|
||||
|
||||
}
|
8
parser/tst/simple_tests/network/network_bad_84.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_84.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=DESCRIPTION invalid family for inet conditionals
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network netlink ip=127.0.0.1,
|
||||
|
||||
}
|
8
parser/tst/simple_tests/network/network_bad_85.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_85.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=DESCRIPTION invalid family for inet conditionals
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network packet peer=(port=1234),
|
||||
|
||||
}
|
@@ -5,5 +5,7 @@
|
||||
/usr/bin/foo {
|
||||
network inet ip=10.0.2.1 peer=(ip=10.0.2.1),
|
||||
network inet tcp ip=192.168.2.254 peer=(ip=192.168.2.254),
|
||||
network stream ip=192.168.2.254 peer=(ip=192.168.2.254),
|
||||
network raw ip=10.0.2.1 peer=(ip=10.0.2.1),
|
||||
|
||||
}
|
||||
|
11
parser/tst/simple_tests/network/network_ok_44.sd
Normal file
11
parser/tst/simple_tests/network/network_ok_44.sd
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
#=DESCRIPTION network none ip conditional test
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network ip=none,
|
||||
network peer=(ip=none),
|
||||
network inet ip=none peer=(ip=none),
|
||||
network inet tcp ip=none peer=(ip=none),
|
||||
|
||||
}
|
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
#=Description caused an infinite loop in expr normalization
|
||||
#=EXRESULT PASS
|
||||
|
||||
# This test triggers an infinite loop bug in expr normalization
|
||||
# Note: this test might be able to be reduced more but, each element appears
|
||||
# to be required to trigger the bug.
|
||||
# that is the initial var assignment, += with the "comment" at the end
|
||||
# (which is a separate bug), the expansion in the 2nd variable and then
|
||||
# the use of the 2nd variable.
|
||||
# This seems to be due to difference in consistency check between expansion
|
||||
# at parse time and variable expansion.
|
||||
# eg. expanding @{exec_path} manually will result in a failure to parse
|
||||
# see: https://gitlab.com/apparmor/apparmor/-/issues/398
|
||||
|
||||
@{var}=*-linux-gnu*
|
||||
@{var}+=*-suse-linux* #aa:only opensuse
|
||||
|
||||
@{exec_path} = /{,@{var}/}t
|
||||
|
||||
profile test {
|
||||
|
||||
|
||||
@{exec_path} mr,
|
||||
}
|
@@ -28,6 +28,7 @@
|
||||
owner @{run}/user/*/gdm/Xauthority r,
|
||||
owner @{run}/user/*/X11/Xauthority r,
|
||||
owner @{run}/user/*/xauth_* r,
|
||||
owner /tmp/xauth_?????? r,
|
||||
|
||||
# the unix socket to use to connect to the display
|
||||
/tmp/.X11-unix/* rw,
|
||||
|
@@ -35,6 +35,13 @@
|
||||
owner /proc/@{pid}/loginuid r,
|
||||
/{,usr/}{,s}bin/unix_chkpwd Px,
|
||||
|
||||
# pam_env
|
||||
@{etc_ro}/environment r,
|
||||
|
||||
# pam_limit
|
||||
@{etc_ro}/security/limits.d/ r,
|
||||
@{etc_ro}/security/limits.d/*.conf r,
|
||||
|
||||
# gssapi
|
||||
@{etc_ro}/gss/mech r,
|
||||
@{etc_ro}/gss/mech.d/ r,
|
||||
|
@@ -98,6 +98,9 @@
|
||||
# best place -- but many profiles require it, and it is quite harmless.
|
||||
@{PROC}/sys/kernel/ngroups_max r,
|
||||
|
||||
# Used to determine if Linux is running in FIPS mode
|
||||
@{PROC}/sys/crypto/fips_enabled r,
|
||||
|
||||
# glibc's sysconf(3) routine to determine free memory, etc
|
||||
@{PROC}/meminfo r,
|
||||
@{PROC}/stat r,
|
||||
|
@@ -22,5 +22,18 @@
|
||||
|
||||
owner @{HOME}/.config/fcitx/dbus/* r,
|
||||
|
||||
# Allow access to the Fcitx portal, supported by fcitx/fcitx5
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/{,org/freedesktop/portal/}inputmethod
|
||||
interface=org.fcitx.Fcitx.InputMethod1
|
||||
member={CreateInputContext,Version}
|
||||
peer=(name=org.freedesktop.portal.Fcitx),
|
||||
|
||||
dbus (send, receive)
|
||||
bus=session
|
||||
path=/{,org/freedesktop/portal/}inputcontext/**
|
||||
interface=org.fcitx.Fcitx.InputContext1,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/fcitx-strict.d>
|
||||
|
@@ -116,6 +116,7 @@
|
||||
network netlink raw,
|
||||
|
||||
# interface details
|
||||
@{PROC}/@{pid}/net/ipv6_route r,
|
||||
@{PROC}/@{pid}/net/route r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
|
@@ -12,6 +12,7 @@
|
||||
abi <abi/4.0>,
|
||||
|
||||
/etc/samba/* r,
|
||||
/etc/gnutls/config r,
|
||||
/usr/lib*/ldb/*.so mr,
|
||||
/usr/lib*/ldb2/*.so mr,
|
||||
/usr/lib*/ldb2/modules/ldb/*.so mr,
|
||||
|
153
profiles/apparmor.d/abstractions/transmission-common
Normal file
153
profiles/apparmor.d/abstractions/transmission-common
Normal file
@@ -0,0 +1,153 @@
|
||||
# vim:syntax=apparmor
|
||||
# LOGPROF-SUGGEST: no
|
||||
# Author: Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
|
||||
include <abstractions/base>
|
||||
include <abstractions/freedesktop.org>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/openssl>
|
||||
|
||||
network inet dgram,
|
||||
network inet6 dgram,
|
||||
network netlink dgram,
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
|
||||
dbus (bind)
|
||||
bus=session
|
||||
name=com.transmissionbt.Transmission,
|
||||
dbus (bind)
|
||||
bus=session
|
||||
name=com.transmissionbt.transmission_*,
|
||||
|
||||
dbus (receive)
|
||||
bus=session
|
||||
path=/ca/desrt/dconf/Writer/user
|
||||
interface=ca.desrt.dconf.Writer
|
||||
member=Notify,
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/ca/desrt/dconf/Writer/user
|
||||
interface=ca.desrt.dconf.Writer
|
||||
member=Change
|
||||
peer=(name=ca.desrt.dconf),
|
||||
|
||||
dbus (receive)
|
||||
bus=accessibility
|
||||
path=/org/a11y/atspi/accessible/root
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=Set,
|
||||
dbus (send)
|
||||
bus=accessibility
|
||||
path=/org/a11y/atspi/accessible/root
|
||||
interface=org.a11y.atspi.Socket
|
||||
member=Embed
|
||||
peer=(name=org.a11y.atspi.Registry),
|
||||
dbus (send)
|
||||
bus=accessibility
|
||||
path=/org/a11y/atspi/registry
|
||||
interface=org.a11y.atspi.Registry
|
||||
member=GetRegisteredEvents
|
||||
peer=(name=org.a11y.atspi.Registry),
|
||||
dbus (send)
|
||||
bus=accessibility
|
||||
path=/org/a11y/atspi/registry/deviceeventcontroller
|
||||
interface=org.a11y.atspi.DeviceEventController
|
||||
member={GetDeviceEventListeners,GetKeystrokeListeners}
|
||||
peer=(name=org.a11y.atspi.Registry),
|
||||
|
||||
dbus (send)
|
||||
bus={accessibility,session}
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member={AddMatch,GetNameOwner,Hello,ReleaseName,RemoveMatch,RequestName,StartServiceByName}
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface=org.freedesktop.DBus.Introspectable
|
||||
path=/StatusNotifierWatcher
|
||||
member=Introspect
|
||||
peer=(name=org.kde.StatusNotifierWatcher),
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
path=/StatusNotifierWatcher
|
||||
member=Get
|
||||
peer=(name=org.kde.StatusNotifierWatcher),
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
path=/org/a11y/bus
|
||||
member=Get
|
||||
peer=(name=org.a11y.Bus),
|
||||
dbus (send)
|
||||
bus=system
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
path=/org/freedesktop/hostname1
|
||||
member=GetAll,
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface=org.freedesktop.Notifications
|
||||
path=/org/freedesktop/Notifications
|
||||
member={GetCapabilities,Notify},
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/gtk/Private/RemoteVolumeMonitor
|
||||
interface=org.gtk.Private.RemoteVolumeMonitor
|
||||
member={IsSupported,List},
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/gtk/vfs/Daemon
|
||||
interface=org.gtk.vfs.Daemon
|
||||
member={GetConnection,ListMonitorImplementations},
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/gtk/vfs/mount/[1-9]*
|
||||
interface=org.gtk.vfs.Mount
|
||||
member={CreateFileMonitor,Enumerate,QueryInfo},
|
||||
dbus (receive)
|
||||
bus=session
|
||||
path=/org/gtk/vfs/mounttracker
|
||||
interface=org.gtk.vfs.MountTracker
|
||||
member=Mounted,
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/gtk/vfs/mounttracker
|
||||
interface=org.gtk.vfs.MountTracker
|
||||
member={ListMountableInfo,ListMounts2,LookupMount},
|
||||
|
||||
@{PROC}/sys/kernel/random/uuid r,
|
||||
|
||||
owner @{PROC}/@{pid}/mountinfo r,
|
||||
owner @{PROC}/@{pid}/mounts r,
|
||||
|
||||
owner @{run}/user/@{uid}/gvfsd/socket-* rw,
|
||||
|
||||
@{etc_ro}/fstab r,
|
||||
|
||||
@{system_share_dirs}/hwdata/** r,
|
||||
@{system_share_dirs}/lxqt/** r,
|
||||
|
||||
owner /tmp/tr_session_id_* rwk,
|
||||
|
||||
# allow a top-level directory listing
|
||||
@{HOME}/ r,
|
||||
|
||||
owner @{HOME}/.cache/transmission/ w,
|
||||
owner @{HOME}/.cache/transmission/** rw,
|
||||
owner @{HOME}/.config/transmission/ w,
|
||||
owner @{HOME}/.config/transmission/** rw,
|
||||
|
||||
owner @{HOME}/.config/lxqt/lxqt.conf r,
|
||||
|
||||
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/ r,
|
||||
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/** rw,
|
||||
|
||||
# exclude these for now
|
||||
deny /usr/share/thumbnailers/ r,
|
||||
deny @{HOME}/.local/share/gvfs-metadata/** r,
|
||||
deny @{HOME}/.config/lxqt/** rw,
|
||||
|
||||
include if exists <abstractions/transmission-common.d>
|
@@ -13,6 +13,8 @@
|
||||
|
||||
# some services update wtmp, utmp, and lastlog with per-user
|
||||
# connection information
|
||||
/var/lib/wtmpdb/ r,
|
||||
/var/lib/wtmpdb/wtmp.db{,-journal} rwlk,
|
||||
/var/log/lastlog rwk,
|
||||
/var/log/wtmp rwk,
|
||||
/var/log/btmp rwk,
|
||||
|
12
profiles/apparmor.d/balena-etcher
Normal file
12
profiles/apparmor.d/balena-etcher
Normal file
@@ -0,0 +1,12 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile balena-etcher /usr/lib/balena-etcher/balena-etcher flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/balena-etcher>
|
||||
}
|
14
profiles/apparmor.d/chromium
Normal file
14
profiles/apparmor.d/chromium
Normal file
@@ -0,0 +1,14 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
@{chromium} = {,ungoogled-}chromium{,-browser}
|
||||
|
||||
profile chromium /usr/lib/@{chromium}/@{chromium} flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/chromium>
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile firefox /usr/lib/firefox{,-esr,-beta,-devedition,-nightly}/firefox{,-esr,-bin} flags=(unconfined) {
|
||||
profile firefox /{usr/lib/firefox{,-esr,-beta,-devedition,-nightly},opt/firefox}/firefox{,-esr,-bin} flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
12
profiles/apparmor.d/foliate
Normal file
12
profiles/apparmor.d/foliate
Normal file
@@ -0,0 +1,12 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile foliate /usr/bin/foliate flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/foliate>
|
||||
}
|
@@ -36,6 +36,9 @@ profile php-fpm /usr/sbin/php-fpm* flags=(attach_disconnected) {
|
||||
@{run}/php*-fpm.pid rw,
|
||||
@{run}/php{,-fpm}/php*-fpm.sock rwlk,
|
||||
|
||||
# LP: #2061113
|
||||
owner @{run}/systemd/notify w,
|
||||
|
||||
# to reload
|
||||
/usr/sbin/php-fpm* rix,
|
||||
|
||||
|
@@ -17,8 +17,13 @@ profile plasmashell /usr/bin/plasmashell {
|
||||
unix,
|
||||
ptrace,
|
||||
|
||||
/usr/lib/x86_64-linux-gnu/qt5/libexec/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
# allow executing QtWebEngineProcess with full permissions including userns (using profile stacking to avoid no_new_privs issues)
|
||||
/usr/lib/x86_64-linux-gnu/qt[56]/libexec/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
/usr/libexec/qt[56]/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
|
||||
# allow to execute all other programs under their own profile, or to run unconfined
|
||||
/** pux,
|
||||
|
||||
/{,**} mrwlk,
|
||||
|
||||
profile QtWebEngineProcess {
|
||||
|
@@ -4,7 +4,7 @@
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile runc /usr/sbin/runc flags=(unconfined) {
|
||||
profile runc /usr/{bin,sbin}/runc flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -16,12 +16,14 @@ include <tunables/global>
|
||||
profile samba-dcerpcd /usr/lib*/samba/{,samba/}samba-dcerpcd {
|
||||
include <abstractions/samba-rpcd>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
@{run}/{,samba/}samba-dcerpcd.pid rwk,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd mr,
|
||||
|
||||
/usr/lib*/samba/ r,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic Px -> samba-rpcd-classic,
|
||||
/usr/lib*/samba/{,samba/}rpcd_spoolss Px -> samba-rpcd-spoolss,
|
||||
|
||||
|
@@ -13,10 +13,15 @@ abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} {
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} {
|
||||
include <abstractions/samba-rpcd>
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} mr,
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/lsarpc wr,
|
||||
@{run}/samba/ncalrpc/np/mdssvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -17,8 +17,18 @@ profile samba-rpcd-classic /usr/lib*/samba/{,samba/}rpcd_classic {
|
||||
include <abstractions/samba-rpcd>
|
||||
include <abstractions/wutmp>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/srvsvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
/dev/urandom rw,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd Px -> samba-dcerpcd,
|
||||
|
||||
@{HOMEDIRS}/** lrwk,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/samba-rpcd-classic>
|
||||
}
|
||||
|
76
profiles/apparmor.d/transmission
Normal file
76
profiles/apparmor.d/transmission
Normal file
@@ -0,0 +1,76 @@
|
||||
# vim:syntax=apparmor
|
||||
# Author: Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile transmission-daemon /usr/bin/transmission-daemon flags=(complain) {
|
||||
# Don't use abstractions/transmission-common here, as the
|
||||
# access needed is narrower than the user applications
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/openssl>
|
||||
|
||||
network inet dgram,
|
||||
network inet6 dgram,
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
|
||||
owner @{PROC}/@{pid}/mounts r,
|
||||
@{PROC}/sys/kernel/random/uuid r,
|
||||
|
||||
@{run}/systemd/notify w,
|
||||
|
||||
/etc/transmission-daemon/** r,
|
||||
owner /etc/transmission-daemon/settings.json{,.tmp.*} rw,
|
||||
|
||||
owner /tmp/tr_session_id_* rwk,
|
||||
|
||||
/usr/share/transmission/web/** r,
|
||||
|
||||
owner /var/lib/transmission-daemon/.config/transmission-daemon/** rw,
|
||||
owner /var/lib/transmission-daemon/downloads/** rw,
|
||||
owner /var/lib/transmission-daemon/info/** rw,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/transmission>
|
||||
include if exists <local/transmission-daemon>
|
||||
}
|
||||
|
||||
profile transmission-cli /usr/bin/transmission-cli flags=(complain) {
|
||||
include <abstractions/transmission-common>
|
||||
include <abstractions/consoles>
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/transmission>
|
||||
include if exists <local/transmission-cli>
|
||||
}
|
||||
|
||||
profile transmission-gtk /usr/bin/transmission-gtk flags=(complain) {
|
||||
include <abstractions/transmission-common>
|
||||
include <abstractions/dbus-session-strict>
|
||||
include <abstractions/dconf>
|
||||
include <abstractions/gnome>
|
||||
|
||||
owner @{run}/user/*/dconf/user w,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/transmission>
|
||||
include if exists <local/transmission-gtk>
|
||||
}
|
||||
|
||||
profile transmission-qt /usr/bin/transmission-qt flags=(complain) {
|
||||
include <abstractions/transmission-common>
|
||||
include <abstractions/dbus-accessibility-strict>
|
||||
include <abstractions/dbus-network-manager-strict>
|
||||
include <abstractions/dbus-session-strict>
|
||||
include <abstractions/fonts>
|
||||
include <abstractions/X>
|
||||
include <abstractions/qt5>
|
||||
include <abstractions/qt5-settings-write>
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/transmission>
|
||||
include if exists <local/transmission-qt>
|
||||
}
|
@@ -8,6 +8,7 @@ profile nmbd /usr/{bin,sbin}/nmbd {
|
||||
include <abstractions/samba>
|
||||
|
||||
capability net_bind_service,
|
||||
capability sys_resource,
|
||||
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
|
||||
|
@@ -32,9 +32,6 @@ profile smbd /usr/{bin,sbin}/smbd {
|
||||
/etc/samba/* rwk,
|
||||
@{PROC}/@{pid}/mounts r,
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
/usr/etc/environment r,
|
||||
/usr/etc/security/limits.d/ r,
|
||||
/usr/etc/security/limits.d/*.conf r,
|
||||
/usr/lib*/samba/vfs/*.so mr,
|
||||
/usr/lib*/samba/auth/*.so mr,
|
||||
/usr/lib*/samba/charset/*.so mr,
|
||||
|
12
profiles/apparmor.d/wike
Normal file
12
profiles/apparmor.d/wike
Normal file
@@ -0,0 +1,12 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile wike /usr/bin/wike flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/wike>
|
||||
}
|
68
profiles/apparmor/profiles/extras/bwrap-userns-restrict
Normal file
68
profiles/apparmor/profiles/extras/bwrap-userns-restrict
Normal file
@@ -0,0 +1,68 @@
|
||||
# This profile allows almost everything and only exists to allow
|
||||
# bwrap to work on a system with user namespace restrictions
|
||||
# being enforced.
|
||||
# bwrap is allowed access to user namespaces and capabilities
|
||||
# within the user namespace, but its children do not have
|
||||
# capabilities, blocking bwrap from being able to be used to
|
||||
# arbitrarily by-pass the user namespace restrictions.
|
||||
#
|
||||
# Note: the bwrap child is stacked against the bwrap profile due to
|
||||
# bwraps use of no-new-privs
|
||||
|
||||
# disabled by default as it can break some use cases on a system that
|
||||
# doesn't have or has disable user namespace restrictions for unconfined
|
||||
# use aa-enforce to enable it
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile bwrap /usr/bin/bwrap flags=(attach_disconnected,mediate_deleted) {
|
||||
allow capability,
|
||||
# not allow all, to allow for pix stack
|
||||
# sadly we have to allow m every where to allow children to work under
|
||||
# stacking.
|
||||
allow file rwlkm /{**,},
|
||||
allow network,
|
||||
allow unix,
|
||||
allow ptrace,
|
||||
allow signal,
|
||||
allow mqueue,
|
||||
allow io_uring,
|
||||
allow userns,
|
||||
allow mount,
|
||||
allow umount,
|
||||
allow pivot_root,
|
||||
allow dbus,
|
||||
allow px /** -> bwrap//&unpriv_bwrap,
|
||||
|
||||
# the local include should not be used without understanding the userns
|
||||
# restriction.
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/bwrap-userns-restrict>
|
||||
}
|
||||
|
||||
profile unpriv_bwrap flags=(attach_disconnected,mediate_deleted) {
|
||||
# not allow all, to allow for pix stack
|
||||
allow file rwlkm /{**,},
|
||||
allow network,
|
||||
allow unix,
|
||||
allow ptrace,
|
||||
allow signal,
|
||||
allow mqueue,
|
||||
allow io_uring,
|
||||
allow userns,
|
||||
allow mount,
|
||||
allow umount,
|
||||
allow pivot_root,
|
||||
allow dbus,
|
||||
|
||||
allow pix /** -> &unpriv_bwrap,
|
||||
|
||||
audit deny capability,
|
||||
|
||||
# the local include should not be used without understanding the userns
|
||||
# restriction.
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/unpriv_bwrap>
|
||||
}
|
@@ -12,9 +12,9 @@
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
#include <tunables/global>
|
||||
include <tunables/global>
|
||||
|
||||
@{chromium} = chromium{,-browser}
|
||||
@{chromium} = {,ungoogled-}chromium{,-browser}
|
||||
|
||||
# We need 'flags=(attach_disconnected)' in newer chromium versions
|
||||
profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconnected) {
|
||||
@@ -22,10 +22,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
include <abstractions/cups-client>
|
||||
include <abstractions/dbus-session>
|
||||
include <abstractions/dbus-strict>
|
||||
include <abstractions/fonts>
|
||||
include <abstractions/gnome>
|
||||
include <abstractions/ibus>
|
||||
include <abstractions/mesa>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/user-tmp>
|
||||
include <abstractions/vulkan>
|
||||
|
||||
# This include specifies which ubuntu-browsers.d abstractions to use. Eg, if
|
||||
# you want access to productivity applications, adjust the following file
|
||||
@@ -57,14 +60,48 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
member={EnumerateDevices,GetDisplayDevice}
|
||||
peer=(label=unconfined),
|
||||
|
||||
# ???
|
||||
deny dbus (send)
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/hostname1
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=GetAll
|
||||
peer=(label=unconfined),
|
||||
|
||||
dbus (receive)
|
||||
bus=system
|
||||
path=/org/freedesktop/login1
|
||||
interface=org.freedesktop.login1.Manager
|
||||
member={SessionNew,SessionRemoved}
|
||||
peer=(label=unconfined),
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member={AddMatch,GetNameOwner,Hello,NameHasOwner,RemoveMatch,StartServiceByName}
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/portal/desktop
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=Get
|
||||
peer=(name=org.freedesktop.portal.Desktop),
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
interface=org.freedesktop.Notifications
|
||||
member={GetCapabilities,GetServerInformation}
|
||||
peer=(name=org.freedesktop.Notifications),
|
||||
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/gtk/vfs/mounttracker
|
||||
interface=org.gtk.vfs.MountTracker
|
||||
member=ListMountableInfo
|
||||
peer=(label=unconfined),
|
||||
|
||||
# Networking
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
@@ -72,30 +109,35 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
@{PROC}/@{pid}/net/ipv6_route r,
|
||||
|
||||
# Should maybe be in abstractions
|
||||
/etc/fstab r,
|
||||
/etc/mime.types r,
|
||||
/etc/mailcap r,
|
||||
/etc/mtab r,
|
||||
/etc/xdg/xubuntu/applications/defaults.list r,
|
||||
owner @{HOME}/.cache/thumbnails/** r,
|
||||
owner @{HOME}/.local/share/applications/defaults.list r,
|
||||
owner @{HOME}/.local/share/applications/mimeinfo.cache r,
|
||||
/tmp/.X[0-9]*-lock r,
|
||||
|
||||
@{PROC}/self/exe ixr,
|
||||
@{PROC}/@{pid}/fd/ r,
|
||||
@{PROC}/filesystems r,
|
||||
@{PROC}/pressure/{cpu,io,memory} r,
|
||||
@{PROC}/vmstat r,
|
||||
@{PROC}/ r,
|
||||
@{PROC}/@{pid}/task/@{tid}/stat r,
|
||||
owner @{PROC}/@{pid}/task/@{tid}/stat r,
|
||||
owner @{PROC}/@{pid}/clear_refs w,
|
||||
owner @{PROC}/@{pid}/cmdline r,
|
||||
owner @{PROC}/@{pid}/io r,
|
||||
owner @{PROC}/@{pid}/mountinfo r,
|
||||
owner @{PROC}/@{pid}/setgroups w,
|
||||
owner @{PROC}/@{pid}/{uid,gid}_map w,
|
||||
@{PROC}/@{pid}/smaps r,
|
||||
owner @{PROC}/@{pid}/smaps r,
|
||||
@{PROC}/@{pid}/stat r,
|
||||
@{PROC}/@{pid}/statm r,
|
||||
@{PROC}/@{pid}/status r,
|
||||
owner @{PROC}/@{pid}/status r,
|
||||
owner @{PROC}/@{pid}/task/@{tid}/status r,
|
||||
deny @{PROC}/@{pid}/oom_{,score_}adj w,
|
||||
@{PROC}/sys/fs/inotify/max_user_watches r,
|
||||
@{PROC}/sys/kernel/yama/ptrace_scope r,
|
||||
@{PROC}/sys/net/ipv4/tcp_fastopen r,
|
||||
|
||||
@@ -105,13 +147,24 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/sys/devices/**/uevent r,
|
||||
/sys/devices/system/cpu/cpufreq/policy*/cpuinfo_max_freq r,
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq r,
|
||||
/sys/devices/system/cpu/kernel_max r,
|
||||
/sys/devices/system/cpu/possible r,
|
||||
/sys/devices/system/cpu/present r,
|
||||
/sys/devices/system/node/node*/meminfo r,
|
||||
/sys/devices/pci[0-9]*/**/bConfigurationValue r,
|
||||
/sys/devices/pci[0-9]*/**/boot_vga r,
|
||||
/sys/devices/pci[0-9]*/**/busnum r,
|
||||
/sys/devices/pci[0-9]*/**/class r,
|
||||
/sys/devices/pci[0-9]*/**/config r,
|
||||
/sys/devices/pci[0-9]*/**/descriptors r,
|
||||
/sys/devices/pci[0-9]*/**/device r,
|
||||
/sys/devices/pci[0-9]*/**/devnum r,
|
||||
/sys/devices/pci[0-9]*/**/irq r,
|
||||
/sys/devices/pci[0-9]*/**/manufacturer r,
|
||||
/sys/devices/pci[0-9]*/**/product r,
|
||||
/sys/devices/pci[0-9]*/**/resource r,
|
||||
/sys/devices/pci[0-9]*/**/revision r,
|
||||
/sys/devices/pci[0-9]*/**/serial r,
|
||||
/sys/devices/pci[0-9]*/**/subsystem_device r,
|
||||
/sys/devices/pci[0-9]*/**/subsystem_vendor r,
|
||||
/sys/devices/pci[0-9]*/**/vendor r,
|
||||
@@ -122,6 +175,7 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/sys/devices/virtual/tty/tty*/active r,
|
||||
# This is requested, but doesn't seem to actually be needed so deny for now
|
||||
deny /run/udev/data/** r,
|
||||
deny /sys/devices/virtual/dmi/id/* r,
|
||||
|
||||
# Needed for the crash reporter
|
||||
owner @{PROC}/@{pid}/auxv r,
|
||||
@@ -132,13 +186,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/usr/share/fonts/**/*.pfb m,
|
||||
/usr/share/mime/mime.cache m,
|
||||
/usr/share/icons/**/*.cache m,
|
||||
owner /{dev,run}/shm/pulse-shm* m,
|
||||
owner /{dev,run,var/run}/shm/pulse-shm* m,
|
||||
owner @{HOME}/.local/share/mime/mime.cache m,
|
||||
owner /tmp/** m,
|
||||
|
||||
@{PROC}/sys/kernel/shmmax r,
|
||||
owner /{dev,run}/shm/{,.}org.chromium.* mrw,
|
||||
owner /{,var/}run/shm/shmfd-* mrw,
|
||||
owner /{dev,run,var/run}/shm/{,.}org.chromium.* mrw,
|
||||
owner /{dev,run,var/run}/shm/shmfd-* mrw,
|
||||
|
||||
/usr/lib/@{chromium}/*.pak mr,
|
||||
/usr/lib/@{chromium}/locales/* mr,
|
||||
@@ -149,8 +203,8 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
|
||||
# Allow ptracing ourselves and our helpers
|
||||
ptrace (trace) peer=@{profile_name},
|
||||
ptrace (trace) peer=@{profile_name}//xdgsettings,
|
||||
ptrace (trace) peer=lsb_release,
|
||||
ptrace (read, trace) peer=@{profile_name}//xdgsettings,
|
||||
ptrace (read, trace) peer=lsb_release,
|
||||
|
||||
# Make browsing directories work
|
||||
/ r,
|
||||
@@ -183,10 +237,9 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/etc/firefox/profile/bookmarks.html r,
|
||||
owner @{HOME}/.mozilla/** k,
|
||||
|
||||
# Chromium Policies
|
||||
/etc/@{chromium}/policies/** r,
|
||||
|
||||
# Chromium configuration
|
||||
/etc/@{chromium}/** r,
|
||||
# Note: "~/.pki/{,nssdb/} w" is denied by private-files abstraction
|
||||
owner @{HOME}/.pki/nssdb/* rwk,
|
||||
owner @{HOME}/.cache/chromium/ rw,
|
||||
owner @{HOME}/.cache/chromium/** rw,
|
||||
@@ -197,12 +250,18 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
owner @{HOME}/.config/chromium/Dictionaries/*.bdic mr,
|
||||
owner @{HOME}/.config/chromium/**/Dictionaries/*.bdic mr,
|
||||
|
||||
# Allow transitions to ourself and our sandbox
|
||||
# Widevine CDM plugin
|
||||
owner @{HOME}/.config/chromium/WidevineCdm/*/_platform_specific/*/libwidevinecdm.so mr,
|
||||
|
||||
# Allow transitions to ourself, our sandbox, and crash handler
|
||||
/usr/lib/@{chromium}/@{chromium} ix,
|
||||
/usr/lib/@{chromium}/chrome-sandbox cx -> sandbox,
|
||||
/usr/lib/@{chromium}/chrome_crashpad_handler Cxr -> crashpad_handler,
|
||||
|
||||
# Allow communicating with sandbox
|
||||
# Allow communicating with sandbox and crash handler
|
||||
unix (receive, send) peer=(label=@{profile_name}//sandbox),
|
||||
unix (receive, send) peer=(label=@{profile_name}//crashpad_handler),
|
||||
signal (receive) set=(cont) peer=@{profile_name}//crashpad_handler,
|
||||
|
||||
/{usr/,}bin/ps Uxr,
|
||||
/usr/lib/@{chromium}/xdg-settings Cxr -> xdgsettings,
|
||||
@@ -210,10 +269,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/usr/bin/lsb_release Pxr -> lsb_release,
|
||||
|
||||
# GSettings
|
||||
owner /{,var/}run/user/*/dconf/ rw,
|
||||
owner /{,var/}run/user/*/dconf/user rw,
|
||||
owner @{run}/user/[0-9]*/dconf/ rw,
|
||||
owner @{run}/user/[0-9]*/dconf/user rw,
|
||||
owner @{HOME}/.config/dconf/user r,
|
||||
|
||||
# GVfs
|
||||
owner @{run}/user/[0-9]*/gvfsd/socket-* rw,
|
||||
|
||||
# Magnet links
|
||||
/usr/bin/gio ixr,
|
||||
|
||||
@@ -230,7 +292,7 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/etc/ld.so.cache r,
|
||||
/etc/xdg/** r,
|
||||
/usr/bin/xdg-settings r,
|
||||
/{usr/,}lib{,32,64}/@{chromium}/xdg-settings r,
|
||||
/usr/lib/@{chromium}/xdg-settings r,
|
||||
/usr/share/applications/*.desktop r,
|
||||
/usr/share/applications/*.list r,
|
||||
|
||||
@@ -266,6 +328,8 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
/{usr/,}lib/@{multiarch}/libpthread-*.so* mr,
|
||||
/{usr/,}lib{,32,64}/libatomic.so* mr,
|
||||
/{usr/,}lib/@{multiarch}/libatomic.so* mr,
|
||||
/{usr/,}lib{,32,64}/libc.so.* mr,
|
||||
/{usr/,}lib/@{multiarch}/libc.so.* mr,
|
||||
/{usr/,}lib{,32,64}/libc-*.so* mr,
|
||||
/{usr/,}lib/@{multiarch}/libc-*.so* mr,
|
||||
/{usr/,}lib{,32,64}/libdl-*.so* mr,
|
||||
@@ -326,6 +390,32 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
|
||||
owner /tmp/** rw,
|
||||
}
|
||||
|
||||
profile crashpad_handler {
|
||||
include <abstractions/base>
|
||||
|
||||
capability sys_ptrace,
|
||||
|
||||
ptrace (read, trace) peer=chromium_browser,
|
||||
|
||||
signal (send) set=(cont) peer=chromium_browser,
|
||||
|
||||
unix (receive, send) peer=(label=chromium_browser),
|
||||
|
||||
/usr/lib/@{chromium}/chrome_crashpad_handler ixr,
|
||||
|
||||
/sys/devices/system/cpu/cpufreq/policy[0-9]*/scaling_{cur,max}_freq r,
|
||||
|
||||
@{PROC}/sys/kernel/yama/ptrace_scope r,
|
||||
|
||||
owner @{PROC}/@{pid}/fd/ r,
|
||||
owner @{PROC}/@{pid}/mem r,
|
||||
owner @{PROC}/@{pid}/stat r,
|
||||
owner @{PROC}/@{pid}/task/ r,
|
||||
owner @{PROC}/@{pid}/task/@{tid}/comm r,
|
||||
|
||||
owner @{HOME}/.config/chromium/Crash?Reports/** rwk,
|
||||
}
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/chromium_browser>
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
include <abstractions/dbus-strict>
|
||||
include <abstractions/dbus-session-strict>
|
||||
include <abstractions/dconf>
|
||||
include <abstractions/fcitx>
|
||||
include <abstractions/fonts>
|
||||
include <abstractions/gnome>
|
||||
include <abstractions/ibus>
|
||||
@@ -139,7 +140,7 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
interface=org.gtk.gio.DesktopAppInfo
|
||||
member=Launched,
|
||||
|
||||
/etc/timezone r,
|
||||
/etc/{,writable/}timezone r,
|
||||
/etc/wildmidi/wildmidi.cfg r,
|
||||
|
||||
# firefox specific
|
||||
@@ -241,7 +242,7 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
owner @{HOME}/.gnome2/firefox* rwk,
|
||||
owner @{HOME}/.cache/mozilla/{,@{MOZ_APP_NAME}/} rw,
|
||||
owner @{HOME}/.cache/mozilla/@{MOZ_APP_NAME}/** rw,
|
||||
owner @{HOME}/.cache/mozilla/@{MOZ_APP_NAME}/**/*.sqlite k,
|
||||
owner @{HOME}/.cache/mozilla/@{MOZ_APP_NAME}/**/*.sqlite{,-shm} k,
|
||||
owner @{HOME}/.config/gtk-3.0/bookmarks r,
|
||||
owner @{HOME}/.config/dconf/user w,
|
||||
owner @{run}/user/[0-9]*/dconf/ w,
|
||||
@@ -416,14 +417,17 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower
|
||||
interface=org.freedesktop.UPower
|
||||
member=EnumerateDevices
|
||||
peer=(name=org.freedesktop.UPower),
|
||||
member=EnumerateDevices,
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=GetAll,
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower/devices/*
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=GetAll
|
||||
peer=(name=org.freedesktop.UPower),
|
||||
member=GetAll,
|
||||
|
||||
# File browser
|
||||
dbus (send)
|
||||
|
65
profiles/apparmor/profiles/extras/unshare-userns-restrict
Normal file
65
profiles/apparmor/profiles/extras/unshare-userns-restrict
Normal file
@@ -0,0 +1,65 @@
|
||||
# This profile allows almost everything and only exists to allow
|
||||
# unshare to work on a system with user namespace restrictions
|
||||
# being enforced.
|
||||
# unshare is allowed access to user namespaces and capabilities
|
||||
# within the user namespace, but its children do not have
|
||||
# capabilities, blocking unshare from being able to be used to
|
||||
# arbitrarily by-pass the user namespace restrictions.
|
||||
# We restrict x mapping of any code that is unknown while unshare
|
||||
# has privilige within the namespace. To help ensure unshare can't
|
||||
# be used to attack the kernel.
|
||||
#
|
||||
# disabled by default as it can break some use cases on a system that
|
||||
# doesn't have or has disable user namespace restrictions for unconfined
|
||||
# use aa-enforce to enable it
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile unshare /usr/bin/unshare flags=(attach_disconnected) {
|
||||
# not allow all, to allow for cix transition
|
||||
# and to limit executable mapping to just unshare
|
||||
allow capability,
|
||||
allow file rwlk /{**,},
|
||||
allow network,
|
||||
allow unix,
|
||||
allow ptrace,
|
||||
allow signal,
|
||||
allow mqueue,
|
||||
allow io_uring,
|
||||
allow userns,
|
||||
allow mount,
|
||||
allow umount,
|
||||
allow pivot_root,
|
||||
allow dbus,
|
||||
audit allow cx /** -> unpriv,
|
||||
|
||||
allow file m /usr/lib/@{multiarch}/libc.so.6,
|
||||
allow file m /usr/bin/unshare,
|
||||
|
||||
# the local include should not be used without understanding the userns
|
||||
# restriction.
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/unshare-userns-restrict>
|
||||
|
||||
profile unpriv flags=(attach_disconnected) {
|
||||
# not allow all, to allow for pix stack
|
||||
allow file rwlkm /{**,},
|
||||
allow network,
|
||||
allow unix,
|
||||
allow ptrace,
|
||||
allow signal,
|
||||
allow mqueue,
|
||||
allow io_uring,
|
||||
allow userns,
|
||||
allow mount,
|
||||
allow umount,
|
||||
allow pivot_root,
|
||||
allow dbus,
|
||||
|
||||
allow pix /** -> &unshare//unpriv,
|
||||
|
||||
audit deny capability,
|
||||
}
|
||||
}
|
@@ -50,6 +50,15 @@ include <tunables/global>
|
||||
# needed when /proc is mounted with hidepid>=1
|
||||
ptrace (read,trace) peer="unconfined",
|
||||
|
||||
unix (bind) type=stream addr="@*/bus/sshd/system",
|
||||
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/login1
|
||||
interface=org.freedesktop.login1.Manager
|
||||
member=CreateSessionWithPIDFD
|
||||
peer=(label=unconfined),
|
||||
|
||||
/dev/ptmx rw,
|
||||
/dev/pts/[0-9]* rw,
|
||||
/dev/urandom r,
|
||||
|
@@ -111,8 +111,8 @@ SRC=access.c \
|
||||
mount.c \
|
||||
move_mount.c \
|
||||
named_pipe.c \
|
||||
net_finegrained_rcv.c \
|
||||
net_finegrained_snd.c \
|
||||
net_inet_rcv.c \
|
||||
net_inet_snd.c \
|
||||
net_raw.c \
|
||||
open.c \
|
||||
openat.c \
|
||||
@@ -364,10 +364,10 @@ 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}
|
||||
|
||||
userns: userns.c userns.h
|
||||
userns: userns.c pipe_helper.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
userns_setns: userns_setns.c userns.h
|
||||
userns_setns: userns_setns.c pipe_helper.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
mount: mount.c
|
||||
|
@@ -79,3 +79,16 @@ runchecktest "complain (--namespace=${ns})" pass "$aa_exec -n $ns -p $test" "$te
|
||||
|
||||
genprofile_aa_exec "$test" 0
|
||||
runchecktest "negative test: bad ns (--namespace=${ns}XXX)" fail "$aa_exec -n ${ns}XXX -p $test" "$test (enforce)"
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile --stdin <<EOF
|
||||
$test {
|
||||
all,
|
||||
}
|
||||
|
||||
:${ns}:${test} {
|
||||
all,
|
||||
}
|
||||
EOF
|
||||
runchecktest "allow all" pass "$aa_exec -p $test" "$test (enforce)"
|
||||
fi
|
||||
|
@@ -28,7 +28,14 @@ wxperm=wix
|
||||
touch $file
|
||||
chmod 777 $file # full perms so discretionary access checks succeed
|
||||
|
||||
# PASS TEST
|
||||
# PASS TEST
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "ACCESS allow all r (rwx)" pass $file r
|
||||
runchecktest "ACCESS allow all rx (rwx)" pass $file rx
|
||||
runchecktest "ACCESS allow all rwx (rwx)" pass $file rwx
|
||||
fi
|
||||
|
||||
genprofile $file:$rwxperm
|
||||
runchecktest "ACCESS file r (rwx)" pass $file r
|
||||
runchecktest "ACCESS file rx (rwx)" pass $file rx
|
||||
|
@@ -23,12 +23,13 @@ settest unix_fd_server
|
||||
disk_img=$tmpdir/disk_img
|
||||
new_root=$tmpdir/new_root/
|
||||
put_old=${new_root}put_old/
|
||||
root_was_shared="no"
|
||||
fstype="ext2"
|
||||
file=$tmpdir/file
|
||||
socket=$tmpdir/unix_fd_test
|
||||
att_dis_client=$pwd/attach_disconnected
|
||||
|
||||
. $bin/mount.inc
|
||||
|
||||
attach_disconnected_cleanup() {
|
||||
if [ ! -z "$loop_device" ]; then
|
||||
losetup -d $loop_device
|
||||
@@ -39,10 +40,7 @@ attach_disconnected_cleanup() {
|
||||
umount "$new_root"
|
||||
fi
|
||||
|
||||
if [ "$root_was_shared" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as shared'
|
||||
mount --make-shared /
|
||||
fi
|
||||
prop_cleanup
|
||||
}
|
||||
do_onexit="attach_disconnected_cleanup"
|
||||
|
||||
@@ -50,24 +48,6 @@ if [ ! -b /dev/loop0 ] ; then
|
||||
modprobe loop
|
||||
fi
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root entirely, so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily.
|
||||
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
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as private'
|
||||
mount --make-private /
|
||||
fi
|
||||
|
||||
dd if=/dev/zero of="$disk_img" bs=1024 count=512 2> /dev/null
|
||||
/sbin/mkfs -t "$fstype" -F "$disk_img" > /dev/null 2> /dev/null
|
||||
# mounting will be done by the test binary
|
||||
@@ -105,6 +85,15 @@ do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $n
|
||||
|
||||
# TODO: adding attach_disconnected.path to a replaced unconfined
|
||||
|
||||
# ALLOW ALL does not include attach_disconnected
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all" flag:attach_disconnected -- image=$att_dis_client "all"
|
||||
do_test "attach_disconnected allow all" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
genprofile "all" -- image=$att_dis_client "all"
|
||||
do_test "attach_disconnected allow all no flag" fail $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
fi
|
||||
|
||||
genprofile $file_perm unix:create $socket_perm $att_dis_client:px -- image=$att_dis_client $file_perm unix:create $socket_perm $create_dir $cap "pivot_root:ALL" "mount:ALL" flag:attach_disconnected
|
||||
|
||||
do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
@@ -45,6 +45,11 @@ run_tests()
|
||||
|
||||
# Make sure we're okay when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
gendbusprofile "all,"
|
||||
runchecktest "eavesdrop (allow all)" pass $args
|
||||
fi
|
||||
|
||||
gendbusprofile "dbus,"
|
||||
runchecktest "eavesdrop (dbus allowed)" pass $args
|
||||
|
||||
|
@@ -60,6 +60,12 @@ run_tests()
|
||||
|
||||
# Make sure send is allowed when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
message_gendbusprofile "all,"
|
||||
runtestfg "message (allow all)" pass $confined_args
|
||||
checktestfg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
message_gendbusprofile "dbus,"
|
||||
runtestfg "message (dbus allowed)" pass $confined_args
|
||||
checktestfg "compare_logs $unconfined_log eq $confined_log"
|
||||
|
@@ -92,6 +92,14 @@ run_tests()
|
||||
|
||||
# Make sure we're okay when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
service_gendbusprofile "all,"
|
||||
service_runtestbg "service (allow all)" pass $unconfined_log
|
||||
sendmethod
|
||||
sendsignal
|
||||
service_checktestbg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
service_gendbusprofile "dbus,"
|
||||
service_runtestbg "service (dbus allowed)" pass $unconfined_log
|
||||
sendmethod
|
||||
|
@@ -80,6 +80,14 @@ run_tests()
|
||||
sendmethodreturn
|
||||
ur_checktestbg
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
# All perms are granted so the logs should be equal
|
||||
ur_gendbusprofile "all,"
|
||||
ur_runtestbg "unrequested_reply (method_return, dbus allowed)" pass $confined_log
|
||||
sendmethodreturn
|
||||
ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
# All dbus perms are granted so the logs should be equal
|
||||
ur_gendbusprofile "dbus,"
|
||||
ur_runtestbg "unrequested_reply (method_return, dbus allowed)" pass $confined_log
|
||||
|
@@ -85,6 +85,32 @@ runchecktest "ENVIRON (shell script): confined/complain & sensitive env" pass ${
|
||||
# TEST environment filtering still works on setuid apps
|
||||
removeprofile
|
||||
|
||||
tmpfs_dir=${tmpdir}/tmpfs_dir
|
||||
remove_mnt() {
|
||||
mountpoint -q "$tmpfs_dir"
|
||||
if [ $? -eq 0 ] ; then
|
||||
umount "$tmpfs_dir"
|
||||
fi
|
||||
}
|
||||
do_onexit="remove_mnt"
|
||||
|
||||
# setuid apps mounted in a fs with "nosuid" option do not honor those
|
||||
# bits during execution, so run the test in a mounted tmpdir without nosuid
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,OPTIONS -T $tmpdir > /dev/null 2>&1 ; then
|
||||
output="$(${FINDMNT} -no TARGET,OPTIONS -T $tmpdir)"
|
||||
target="$(echo $output | cut -d' ' -f1)"
|
||||
options="$(echo $output | cut -d' ' -f2)"
|
||||
case "$options" in
|
||||
*nosuid* )
|
||||
echo " $target is mounted with nosuid, creating a new mountpoint..."
|
||||
setuid_helper=${tmpfs_dir}/env_check
|
||||
mkdir ${tmpfs_dir}
|
||||
mount -t tmpfs tmpfs ${tmpfs_dir}
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
cp $helper ${setuid_helper}
|
||||
chown nobody ${setuid_helper}
|
||||
chmod u+s ${setuid_helper}
|
||||
|
@@ -55,6 +55,11 @@ do_tests "no perms" fail fail
|
||||
genprofile $required_perms "qual=deny:io_uring"
|
||||
do_tests "deny perms" fail fail
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
do_tests "allow all" pass pass
|
||||
fi
|
||||
|
||||
genprofile $required_perms "io_uring"
|
||||
do_tests "generic perms" pass pass
|
||||
|
||||
|
@@ -114,6 +114,7 @@ static void usage(char *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");
|
||||
fprintf(stderr, "-t type of synthetic filesystem (e.g. proc) for mount syscall\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -121,12 +122,13 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
char *options = NULL;
|
||||
char *data = NULL;
|
||||
char *type = NULL;
|
||||
int index;
|
||||
int c;
|
||||
char *op, *source, *target, *token;
|
||||
unsigned long flags = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "o:d:h")) != -1) {
|
||||
while ((c = getopt (argc, argv, "o:d:t:h")) != -1) {
|
||||
switch (c)
|
||||
{
|
||||
case 'o':
|
||||
@@ -135,6 +137,9 @@ int main(int argc, char *argv[])
|
||||
case 'd':
|
||||
data = optarg;
|
||||
break;
|
||||
case 't':
|
||||
type = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
break;
|
||||
@@ -162,10 +167,18 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (strcmp(op, "mount") == 0) {
|
||||
if (mount(source, target, "ext2", flags, data) == -1) {
|
||||
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
|
||||
source, target, strerror(errno));
|
||||
return errno;
|
||||
if (!type) {
|
||||
if (mount(source, target, "ext2", flags, data) == -1) {
|
||||
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
|
||||
source, target, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
if (mount(source, target, type, flags, data) == -1) {
|
||||
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
|
||||
source, target, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(op, "umount") == 0) {
|
||||
if (umount(target) == -1) {
|
||||
|
30
tests/regression/apparmor/mount.inc
Normal file
30
tests/regression/apparmor/mount.inc
Normal file
@@ -0,0 +1,30 @@
|
||||
root_was_shared="no"
|
||||
root="/"
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root and mount "move" operations entirely, so attempt to
|
||||
# detect from which mount point the test is running from, and remount
|
||||
# it MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir > /dev/null 2>&1 ; then
|
||||
output="$(${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir)"
|
||||
root="$(echo $output | cut -d' ' -f1)"
|
||||
if [ "$(echo $output | cut -d' ' -f2)" == "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
|
||||
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as private"
|
||||
mount --make-private $root
|
||||
fi
|
||||
|
||||
prop_cleanup() {
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as shared"
|
||||
mount --make-shared $root
|
||||
fi
|
||||
}
|
@@ -32,7 +32,8 @@ mount_point2=$tmpdir/mountpoint2
|
||||
mount_bad=$tmpdir/mountbad
|
||||
loop_device="unset"
|
||||
fstype="ext2"
|
||||
root_was_shared="no"
|
||||
|
||||
. $bin/mount.inc
|
||||
|
||||
setup_mnt() {
|
||||
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
|
||||
@@ -59,9 +60,7 @@ mount_cleanup() {
|
||||
then
|
||||
/sbin/losetup -d ${loop_device} &> /dev/null
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
mount --make-shared /
|
||||
fi
|
||||
prop_cleanup
|
||||
}
|
||||
do_onexit="mount_cleanup"
|
||||
|
||||
@@ -81,23 +80,6 @@ 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"
|
||||
@@ -424,6 +406,34 @@ fsmount_tests() {
|
||||
fsmount_test " fsmount deny att_dis" "qual=deny:" "flag:attach_disconnected" ${should_fail}
|
||||
}
|
||||
|
||||
all_rule() {
|
||||
if [ "$(parser_supports 'all,')" != "true" ]; then
|
||||
echo " not supported by parser - skipping allow all,"
|
||||
return
|
||||
fi
|
||||
|
||||
settest mount
|
||||
genprofile "all"
|
||||
|
||||
runchecktest "MOUNT (confined allow all)" pass mount ${loop_device} ${mount_point}
|
||||
|
||||
runchecktest "UMOUNT (confined allow all)" pass umount ${loop_device} ${mount_point}
|
||||
|
||||
runchecktest "MOUNT (confined allow all remount setup)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (confined allow all remount)" pass mount ${loop_device} ${mount_point} -o remount
|
||||
remove_mnt
|
||||
|
||||
settest move_mount
|
||||
genprofile "all"
|
||||
|
||||
runchecktest "MOVE_MOUNT (confined fsmount: allow all)" pass fsmount ${loop_device} ${mount_point} ${fstype}
|
||||
remove_mnt
|
||||
|
||||
mount ${loop_device} ${mnt_source}
|
||||
runchecktest "MOVE_MOUNT (confined open_tree: allow all)" pass open_tree ${mount_point2} ${mount_point} ${fstype}
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
# TEST 1. Make sure can mount and umount unconfined
|
||||
runchecktest "MOUNT (unconfined)" pass mount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
@@ -547,6 +557,12 @@ else
|
||||
runchecktest "UMOUNT (confined cap umount:ALL)" pass umount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
|
||||
# https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1597017
|
||||
# CVE-2016-1585
|
||||
genprofile cap:sys_admin "mount:options=(rw,make-slave) -> **"
|
||||
runchecktest "MOUNT (confined cap mount -> mntpnt, CVE-2016-1585)" fail mount -t proc proc ${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
|
||||
@@ -563,6 +579,8 @@ else
|
||||
fsmount_tests tmpfs ${mount_point} tmpfs
|
||||
fsmount_tests ${loop_device} ${mount_point} ${fstype}
|
||||
open_tree_tests ${mount_point2} ${mount_point} ${fstype}
|
||||
|
||||
all_rule
|
||||
fi
|
||||
|
||||
#need tests for chroot
|
||||
|
@@ -6,9 +6,9 @@
|
||||
#published by the Free Software Foundation, version 2 of the
|
||||
#License.
|
||||
|
||||
#=NAME posix_mq
|
||||
#=NAME net_inet
|
||||
#=DESCRIPTION
|
||||
# This test verifies if mediation of posix message queues is working
|
||||
# This test verifies if finegrained inet mediation is working
|
||||
#=END
|
||||
|
||||
pwd=`dirname $0`
|
||||
@@ -18,13 +18,13 @@ bin=$pwd
|
||||
|
||||
. $bin/prologue.inc
|
||||
|
||||
#requires_kernel_features network_v8/finegrained
|
||||
requires_kernel_features network_v8/af_inet
|
||||
requires_parser_support "network ip=::1,"
|
||||
|
||||
settest net_finegrained_rcv
|
||||
settest net_inet_rcv
|
||||
|
||||
sender="$bin/net_finegrained_snd"
|
||||
receiver="$bin/net_finegrained_rcv"
|
||||
sender="$bin/net_inet_snd"
|
||||
receiver="$bin/net_inet_rcv"
|
||||
|
||||
# local ipv6 address generated according to https://www.rfc-editor.org/rfc/rfc4193.html
|
||||
#ipv6_subnet=fd74:1820:b03a:b361::/64
|
||||
@@ -47,7 +47,7 @@ do_onexit="cleanup"
|
||||
|
||||
do_test()
|
||||
{
|
||||
local desc="FINEGRAINED NETWORK ($1)"
|
||||
local desc="NETWORK INET ($1)"
|
||||
shift
|
||||
runchecktest "$desc" "$@"
|
||||
}
|
||||
@@ -65,12 +65,11 @@ do_tests()
|
||||
protocol=$8
|
||||
generate_profile=$9
|
||||
|
||||
settest net_finegrained_rcv
|
||||
settest net_inet_rcv
|
||||
$generate_profile
|
||||
do_test "$prefix - root" $expect_rcv --bind_ip $bind_ip --bind_port $bind_port --remote_ip $remote_ip --remote_port $remote_port --protocol $protocol --timeout 5 --sender $sender
|
||||
|
||||
|
||||
settest -u "foo" net_finegrained_rcv
|
||||
settest -u "foo" net_inet_rcv
|
||||
$generate_profile
|
||||
do_test "$prefix - user" $expect_rcv --bind_ip $bind_ip --bind_port $bind_port --remote_ip $remote_ip --remote_port $remote_port --protocol $protocol --timeout 5 --sender $sender
|
||||
|
||||
@@ -97,9 +96,9 @@ do_tests "ipv4 udp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remot
|
||||
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||
do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||
|
||||
setsockopt_rules="network;(setopt,getopt);ip=0.0.0.0;port=0"
|
||||
rcv_rules="network;ip=$bind_ipv4;peer=(ip=anon)"
|
||||
snd_rules="network;ip=$remote_ipv4;peer=(ip=anon)"
|
||||
setsockopt_rules="network;(setopt,getopt);ip=0.0.0.0;port=0" # INADDR_ANY
|
||||
rcv_rules="network;ip=$bind_ipv4;peer=(ip=none)"
|
||||
snd_rules="network;ip=$remote_ipv4;peer=(ip=none)"
|
||||
|
||||
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||
do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||
@@ -126,9 +125,9 @@ do_tests "ipv6 udp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remot
|
||||
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||
do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
|
||||
setsockopt_rules="network;(setopt,getopt);ip=::0;port=0"
|
||||
rcv_rules="network;ip=$bind_ipv6;peer=(ip=anon)"
|
||||
snd_rules="network;ip=$remote_ipv6;peer=(ip=anon)"
|
||||
setsockopt_rules="network;(setopt,getopt);ip=::0;port=0" # IN6ADDR_ANY_INIT
|
||||
rcv_rules="network;ip=$bind_ipv6;peer=(ip=none)"
|
||||
snd_rules="network;ip=$remote_ipv6;peer=(ip=none)"
|
||||
|
||||
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||
do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||
@@ -137,3 +136,16 @@ generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$rem
|
||||
do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv4 udp allow all" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv4 tcp allow all" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv6 udp allow all" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv6 tcp allow all" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
fi
|
@@ -9,7 +9,13 @@
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
#include "net_finegrained.h"
|
||||
#include "net_inet.h"
|
||||
|
||||
enum protocol {
|
||||
UDP,
|
||||
TCP,
|
||||
ICMP
|
||||
};
|
||||
|
||||
struct connection_info {
|
||||
char *bind_ip;
|
||||
@@ -17,17 +23,72 @@ struct connection_info {
|
||||
char *remote_ip;
|
||||
char *remote_port;
|
||||
char *protocol;
|
||||
enum protocol prot;
|
||||
int timeout;
|
||||
} net_info;
|
||||
|
||||
|
||||
int receive_udp()
|
||||
int receive_bind()
|
||||
{
|
||||
|
||||
int sock;
|
||||
char *buf;
|
||||
struct sockaddr_in local;
|
||||
struct sockaddr_in6 local6;
|
||||
|
||||
struct ip_address bind_addr;
|
||||
|
||||
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||
fprintf(stderr, "FAIL - could not parse bind ip address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(net_info.prot) {
|
||||
case UDP:
|
||||
sock = socket(bind_addr.family, SOCK_DGRAM, 0);
|
||||
break;
|
||||
case TCP:
|
||||
sock = socket(bind_addr.family, SOCK_STREAM, 0);
|
||||
break;
|
||||
case ICMP:
|
||||
sock = socket(bind_addr.family, SOCK_DGRAM, IPPROTO_ICMP);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sock < 0) {
|
||||
perror("FAIL - Socket error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int enable = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||
|
||||
if (bind_addr.family == AF_INET) {
|
||||
local = convert_to_sockaddr_in(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("FAIL - Bind error: ");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0) {
|
||||
perror("FAIL - Bind error: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (net_info.prot == TCP) {
|
||||
if (listen(sock, 5) == -1) {
|
||||
perror("FAIL - Could not listen: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int receive_udp(int sock)
|
||||
{
|
||||
|
||||
char *buf;
|
||||
int ret = -1;
|
||||
int select_return;
|
||||
|
||||
@@ -37,38 +98,6 @@ int receive_udp()
|
||||
buf = (char *) malloc(255);
|
||||
memset(buf, '\0', 255);
|
||||
|
||||
struct ip_address bind_addr;
|
||||
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||
fprintf(stderr, "FAIL - could not parse bind ip address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sock = socket(bind_addr.family, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("FAIL - Socket error: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
const int enable = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||
|
||||
if (bind_addr.family == AF_INET) {
|
||||
local = convert_to_sockaddr_in(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("FAIL - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||
{
|
||||
printf("errno %d\n", errno);
|
||||
perror("FAIL - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock, &read_set);
|
||||
FD_ZERO(&err_set);
|
||||
@@ -77,39 +106,30 @@ int receive_udp()
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||
if (select_return < 0)
|
||||
{
|
||||
if (select_return < 0) {
|
||||
perror("FAIL - Select error: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
|
||||
{
|
||||
|
||||
if (recvfrom(sock, buf, 255, 0, (struct sockaddr *)0, (unsigned int *)0) >= 1)
|
||||
{
|
||||
} else if (select_return == 0) {
|
||||
printf("FAIL - select timeout\n");
|
||||
} else if (select_return > 0 && FD_ISSET(sock, &read_set) && !FD_ISSET(sock, &err_set)) {
|
||||
if (recvfrom(sock, buf, 255, 0, NULL, NULL) >= 1) {
|
||||
//printf("MESSAGE: %s\n", buf);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printf("FAIL - recvfrom failed\n");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return(ret);
|
||||
|
||||
}
|
||||
|
||||
int receive_tcp()
|
||||
int receive_tcp(int sock)
|
||||
{
|
||||
int sock, cli_sock;
|
||||
int cli_sock;
|
||||
char *buf;
|
||||
struct sockaddr_in local;
|
||||
struct sockaddr_in6 local6;
|
||||
int ret = -1;
|
||||
int select_return;
|
||||
|
||||
@@ -119,44 +139,6 @@ int receive_tcp()
|
||||
buf = (char *) malloc(255);
|
||||
memset(buf, '\0', 255);
|
||||
|
||||
struct ip_address bind_addr;
|
||||
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||
fprintf(stderr, "FAIL - could not parse bind ip address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sock = socket(bind_addr.family, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror("FAIL - Socket error:");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
const int enable = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||
|
||||
if (bind_addr.family == AF_INET) {
|
||||
local = convert_to_sockaddr_in(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("FAIL - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||
{
|
||||
perror("FAIL - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (listen(sock, 5) == -1)
|
||||
{
|
||||
perror("FAIL - Could not listen: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock, &read_set);
|
||||
FD_ZERO(&err_set);
|
||||
@@ -165,48 +147,33 @@ int receive_tcp()
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||
if (select_return < 0)
|
||||
{
|
||||
if (select_return < 0) {
|
||||
perror("FAIL - Select failed: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
|
||||
{
|
||||
if ((cli_sock = accept(sock, NULL, NULL)) < 0)
|
||||
{
|
||||
} else if (select_return == 0) {
|
||||
printf("FAIL - select timeout\n");
|
||||
} else if (select_return > 0 && FD_ISSET(sock, &read_set) && !FD_ISSET(sock, &err_set)) {
|
||||
if ((cli_sock = accept(sock, NULL, NULL)) < 0) {
|
||||
perror("FAIL - Accept failed: ");
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (recv(cli_sock, buf, 255, 0) >= 1)
|
||||
{
|
||||
} else {
|
||||
if (recv(cli_sock, buf, 255, 0) >= 1) {
|
||||
//printf("MESSAGE: %s\n", buf);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
perror("FAIL - recv failure: ");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("FAIL - There were select failures: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int receive_icmp()
|
||||
int receive_icmp(int sock)
|
||||
{
|
||||
|
||||
int sock;
|
||||
char *buf;
|
||||
struct sockaddr_in local;
|
||||
int ret = -1;
|
||||
int select_return;
|
||||
|
||||
@@ -215,25 +182,6 @@ int receive_icmp()
|
||||
|
||||
buf = (char *) malloc(255);
|
||||
memset(buf, '\0', 255);
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) < 0)
|
||||
{
|
||||
perror("FAIL - Socket error: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
const int enable = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(atoi(net_info.bind_port));
|
||||
inet_aton(net_info.bind_ip, &local.sin_addr);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("FAIL - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock, &read_set);
|
||||
@@ -243,28 +191,21 @@ int receive_icmp()
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||
if (select_return < 0)
|
||||
{
|
||||
if (select_return < 0) {
|
||||
perror("FAIL - Select error: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
|
||||
{
|
||||
|
||||
if (recvfrom(sock, buf, 255, 0, (struct sockaddr *)0, (unsigned int *)0) >= 1)
|
||||
{
|
||||
} else if (select_return == 0) {
|
||||
printf("FAIL - select timeout\n");
|
||||
} else if (select_return > 0 && FD_ISSET(sock, &read_set) && !FD_ISSET(sock, &err_set)) {
|
||||
if (recvfrom(sock, buf, 255, 0, NULL, NULL) >= 1) {
|
||||
//printf("MESSAGE: %s\n", buf);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printf("FAIL - recvfrom failed\n");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return(ret);
|
||||
|
||||
@@ -302,7 +243,7 @@ int main(int argc, char *argv[])
|
||||
{"protocol", required_argument, 0, 'p' },
|
||||
{"timeout", required_argument, 0, 't' },
|
||||
{"sender", required_argument, 0, 's' },
|
||||
{0, 0, 0, 0 }
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv,"i:o:r:e:p:t:s:", long_options, 0)) != -1) {
|
||||
@@ -321,6 +262,14 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'p':
|
||||
net_info.protocol = optarg;
|
||||
if (strcmp(net_info.protocol, "udp") == 0)
|
||||
net_info.prot = UDP;
|
||||
else if (strcmp(net_info.protocol, "tcp") == 0)
|
||||
net_info.prot = TCP;
|
||||
else if (strcmp(net_info.protocol, "icmp") == 0)
|
||||
net_info.prot = ICMP;
|
||||
else
|
||||
printf("FAIL - Unknown protocol.\n");
|
||||
break;
|
||||
case 't':
|
||||
net_info.timeout = atoi(optarg);
|
||||
@@ -333,6 +282,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* get the server to bind/listen, so the child has something
|
||||
* to connect to if it wins the race. */
|
||||
int sockfd = receive_bind();
|
||||
if (sockfd == -1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* exec the sender */
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
@@ -357,22 +313,23 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strcmp(net_info.protocol, "udp") == 0)
|
||||
ret = receive_udp(net_info);
|
||||
else if (strcmp(net_info.protocol, "tcp") == 0)
|
||||
ret = receive_tcp(net_info);
|
||||
else if (strcmp(net_info.protocol, "icmp") == 0)
|
||||
ret = receive_icmp(net_info);
|
||||
else
|
||||
printf("FAIL - Unknown protocol.\n");
|
||||
switch(net_info.prot) {
|
||||
case UDP:
|
||||
ret = receive_udp(sockfd);
|
||||
break;
|
||||
case TCP:
|
||||
ret = receive_tcp(sockfd);
|
||||
break;
|
||||
case ICMP:
|
||||
ret = receive_icmp(sockfd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (ret == -1) {
|
||||
printf("FAIL - Receive message failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
|
||||
return 0;
|
||||
}
|
@@ -12,7 +12,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "net_finegrained.h"
|
||||
#include "net_inet.h"
|
||||
|
||||
struct connection_info {
|
||||
char *bind_ip;
|
||||
@@ -40,8 +40,7 @@ int send_udp(char *message)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sock = socket(bind_addr.family, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
if ((sock = socket(bind_addr.family, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("FAIL SND - Could not open socket: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -53,15 +52,13 @@ int send_udp(char *message)
|
||||
|
||||
if (bind_addr.family == AF_INET) {
|
||||
local = convert_to_sockaddr_in(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("FAIL SND - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0) {
|
||||
perror("FAIL SND - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -70,22 +67,19 @@ int send_udp(char *message)
|
||||
if (remote_addr.family == AF_INET) {
|
||||
remote = convert_to_sockaddr_in(remote_addr);
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote, sizeof(remote)) <= 0)
|
||||
{
|
||||
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote, sizeof(remote)) <= 0) {
|
||||
perror("FAIL SND - Send failed: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
remote6 = convert_to_sockaddr_in6(remote_addr);
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote6, sizeof(remote6)) <= 0)
|
||||
{
|
||||
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote6, sizeof(remote6)) <= 0) {
|
||||
perror("FAIL SND - Send failed: ");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
close(sock);
|
||||
return(0);
|
||||
|
||||
@@ -121,15 +115,13 @@ int send_tcp(char *message)
|
||||
|
||||
if (bind_addr.family == AF_INET) {
|
||||
local = convert_to_sockaddr_in(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("FAIL SND - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0) {
|
||||
perror("FAIL SND - Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -138,24 +130,21 @@ int send_tcp(char *message)
|
||||
if (remote_addr.family == AF_INET) {
|
||||
remote = convert_to_sockaddr_in(remote_addr);
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0)
|
||||
{
|
||||
if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0) {
|
||||
perror("FAIL SND - Could not connect: ");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
remote6 = convert_to_sockaddr_in6(remote_addr);
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
if (connect(sock, (struct sockaddr *) &remote6, sizeof(remote6)) < 0)
|
||||
{
|
||||
if (connect(sock, (struct sockaddr *) &remote6, sizeof(remote6)) < 0) {
|
||||
perror("FAIL SND - Could not connect: ");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
if (send(sock, message, strlen(message), 0) <= 0)
|
||||
{
|
||||
if (send(sock, message, strlen(message), 0) <= 0) {
|
||||
perror("FAIL SND - Send failed: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -171,8 +160,7 @@ int send_icmp(char *message)
|
||||
char packetdata[sizeof(icmp_hdr) + 4];
|
||||
|
||||
|
||||
if ((sock = socket(AF_INET | AF_INET6, SOCK_DGRAM, IPPROTO_ICMP)) < 0)
|
||||
{
|
||||
if ((sock = socket(AF_INET | AF_INET6, SOCK_DGRAM, IPPROTO_ICMP)) < 0) {
|
||||
perror("FAIL SND - Could not open socket: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -199,8 +187,7 @@ int send_icmp(char *message)
|
||||
memcpy(packetdata, &icmp_hdr, sizeof(icmp_hdr));
|
||||
memcpy(packetdata + sizeof(icmp_hdr), message, strlen(message));
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("FAIL SND - Could not bind: ");
|
||||
return(-1);
|
||||
}
|
||||
@@ -208,8 +195,7 @@ int send_icmp(char *message)
|
||||
//printf("Sending \"%s\"\n", message);
|
||||
|
||||
// Send the packet
|
||||
if(sendto(sock, packetdata, sizeof(packetdata), 0, (struct sockaddr*) &remote, sizeof(remote)) < 0)
|
||||
{
|
||||
if(sendto(sock, packetdata, sizeof(packetdata), 0, (struct sockaddr*) &remote, sizeof(remote)) < 0) {
|
||||
perror("FAIL SND - Send failed: ");
|
||||
close(sock);
|
||||
return(-1);
|
||||
@@ -231,8 +217,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int send_ret;
|
||||
|
||||
if (argc < 6)
|
||||
{
|
||||
if (argc < 6) {
|
||||
printf("Usage: %s bind_ip bind_port remote_ip remote_port proto\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
@@ -253,8 +238,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
printf("FAIL SND - Unknown protocol.\n");
|
||||
|
||||
if (send_ret == -1)
|
||||
{
|
||||
if (send_ret == -1) {
|
||||
printf("FAIL SND - Send message failed.\n");
|
||||
exit(1);
|
||||
}
|
@@ -29,3 +29,7 @@ runchecktest "RAW SOCKET (no cap)" fail
|
||||
genprofile cap:net_raw network:
|
||||
runchecktest "RAW SOCKET (cap net_raw)" pass
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "RAW SOCKET (allow all)" pass
|
||||
fi
|
||||
|
@@ -25,7 +25,8 @@ put_old=${new_root}put_old/
|
||||
bad=$tmpdir/BAD/
|
||||
proc=$new_root/proc
|
||||
fstype="ext2"
|
||||
root_was_shared="no"
|
||||
|
||||
. $bin/mount.inc
|
||||
|
||||
pivot_root_cleanup() {
|
||||
mountpoint -q "$proc"
|
||||
@@ -38,10 +39,7 @@ pivot_root_cleanup() {
|
||||
umount "$new_root"
|
||||
fi
|
||||
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as shared'
|
||||
mount --make-shared /
|
||||
fi
|
||||
prop_cleanup
|
||||
}
|
||||
do_onexit="pivot_root_cleanup"
|
||||
|
||||
@@ -50,24 +48,6 @@ if [ ! -b /dev/loop0 ] ; then
|
||||
modprobe loop
|
||||
fi
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root entirely, so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily.
|
||||
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
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as private'
|
||||
mount --make-private /
|
||||
fi
|
||||
|
||||
# Create disk image since pivot_root doesn't allow old root and new root to be
|
||||
# on the same filesystem
|
||||
dd if=/dev/zero of="$disk_img" bs=1024 count=512 2> /dev/null
|
||||
@@ -120,6 +100,11 @@ if [ "$(kernel_features mount)" != "true" -o "$(parser_supports 'mount,')" != "t
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
do_test "allow all rule" pass "$put_old" "$new_root" "$test"
|
||||
fi
|
||||
|
||||
# Ensure failure when no pivot_root perms are granted
|
||||
genprofile $cur $cap
|
||||
do_test "cap only" fail "$put_old" "$new_root" "$test"
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#define QNAME "/testmq"
|
||||
#define SHM_PATH "/unnamedsemtest"
|
||||
#define SEM_PATH "/namedsemtest"
|
||||
#define PIPENAME "/tmp/mqueuepipe";
|
||||
#define OBJ_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
|
@@ -27,6 +27,7 @@ sender="$bin/posix_mq_snd"
|
||||
receiver="$bin/posix_mq_rcv"
|
||||
queuename="/queuename"
|
||||
queuename2="/queuename2"
|
||||
pipe="/tmp/mqueuepipe"
|
||||
|
||||
user="foo"
|
||||
adduser --gecos "First Last,RoomNumber,WorkPhone,HomePhone" --no-create-home --disabled-password $user >/dev/null
|
||||
@@ -41,6 +42,7 @@ cleanup()
|
||||
{
|
||||
rm -f /dev/mqueue/$queuename
|
||||
rm -f /dev/mqueue/$queuename2
|
||||
rm -f $pipe
|
||||
deluser foo >/dev/null
|
||||
}
|
||||
do_onexit="cleanup"
|
||||
@@ -66,7 +68,7 @@ do_tests()
|
||||
do_test "$prefix" "$expect_send" $sender "$expect_recv" -c $sender -k $queuename "${rest_args[@]}"
|
||||
|
||||
# notify requires netlink permissions
|
||||
do_test "$prefix : mq_notify" "$expect_send" $sender "$expect_recv" -c $sender -k $queuename -n mq_notify "${rest_args[@]}"
|
||||
do_test "$prefix : mq_notify" "$expect_send" $sender "$expect_recv" -c $sender -k $queuename -n mq_notify -p $pipe "${rest_args[@]}"
|
||||
|
||||
do_test "$prefix : select" "$expect_open" -c $sender -k $queuename -n select "${rest_args[@]}"
|
||||
|
||||
@@ -86,13 +88,17 @@ for username in "root" "$userid" ; do
|
||||
do_tests "unconfined $username" pass pass pass pass $usercmd
|
||||
|
||||
# No mqueue perms
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "$sender:px" -- image=$sender
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "$sender:px" "$pipe:rw" -- image=$sender "$pipe:rw"
|
||||
do_tests "confined $username - no perms" fail fail fail fail $usercmd
|
||||
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "deny:mqueue" "$sender:px" -- image=$sender "deny mqueue"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "deny:mqueue" "$sender:px" "$pipe:rw" -- image=$sender "deny mqueue" "$pipe:rw"
|
||||
do_tests "confined $username - deny perms" fail fail fail fail $usercmd
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all" -- image=$sender "all"
|
||||
do_tests "confined $username - allow all" pass pass pass pass $usercmd
|
||||
fi
|
||||
|
||||
# generic mqueue
|
||||
# 2 Potential failures caused by missing other x permission in path
|
||||
@@ -102,46 +108,46 @@ for username in "root" "$userid" ; do
|
||||
# apparmor when doing "root" username tests
|
||||
# * if doing the $userid set of tests and you see
|
||||
# Permission denied in the test output
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:px" -- image=$sender "mqueue"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:px" "$pipe:rw" -- image=$sender "mqueue" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:type=posix" "$sender:px" -- image=$sender "mqueue:type=posix"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:type=posix" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:type=posix" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue type=posix" pass pass pass pass $usercmd
|
||||
|
||||
# queue name
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" -- image=$sender "mqueue:$queuename"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:$queuename" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue /name 1" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:px" -- image=$sender "mqueue:$queuename"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:$queuename" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue /name 2" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" -- image=$sender "mqueue"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" "$pipe:rw" -- image=$sender "mqueue" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue /name 3" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" -- image=$sender "mqueue:$queuename2"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:$queuename" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:$queuename2" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue /name 4" fail fail fail fail $usercmd -t 1
|
||||
|
||||
|
||||
# specific permissions
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr,setattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 1" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(read,delete,getattr,setattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(read,delete,getattr,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 2" fail fail fail fail $usercmd -t 1
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,delete,getattr,setattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,delete,getattr,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 3" fail fail fail fail $usercmd -t 1
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,getattr,setattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,getattr,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 4" fail fail fail fail $usercmd -t 1
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,setattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 5" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr)" "$sender:px" -- image=$sender "mqueue:write"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:write" "$pipe:rw"
|
||||
do_tests "confined $username - specific 6" pass pass pass pass $usercmd
|
||||
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr,setattr)" "$sender:px" -- image=$sender "mqueue:read"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete,getattr,setattr)" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:read" "$pipe:rw"
|
||||
do_tests "confined $username - specific 7" fail fail fail fail $usercmd -t 1
|
||||
|
||||
# unconfined receiver
|
||||
@@ -150,17 +156,17 @@ for username in "root" "$userid" ; do
|
||||
|
||||
|
||||
# unconfined sender
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:ux"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue" "$sender:ux" "$pipe:rw"
|
||||
do_tests "confined receiver $username - unconfined sender" pass pass pass pass $usercmd
|
||||
|
||||
|
||||
# queue label
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:label=$receiver" "$sender:px" -- image=$sender "mqueue:label=$receiver"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:label=$receiver" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:label=$receiver" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue label 1" xpass xpass xpass xpass $usercmd
|
||||
|
||||
|
||||
# queue name and label
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete):type=posix:label=$receiver:$queuename" "$sender:px" -- image=$sender "mqueue:(open,write):type=posix:label=$receiver:$queuename"
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "network:netlink" "mqueue:(create,read,delete):type=posix:label=$receiver:$queuename" "$sender:px" "$pipe:rw" -- image=$sender "mqueue:(open,write):type=posix:label=$receiver:$queuename" "$pipe:rw"
|
||||
do_tests "confined $username - mqueue label 2" xpass xpass xpass xpass $usercmd
|
||||
|
||||
# ensure we are cleaned up for next pass
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <mqueue.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
@@ -6,9 +7,11 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "posix_mq.h"
|
||||
#include "pipe_helper.h"
|
||||
|
||||
int timeout = 5; //seconds
|
||||
char *queuename = QNAME;
|
||||
char *pipepath = PIPENAME;
|
||||
|
||||
enum notify_options {
|
||||
DO_NOT_NOTIFY,
|
||||
@@ -18,10 +21,13 @@ enum notify_options {
|
||||
EPOLL
|
||||
};
|
||||
|
||||
enum notify_options notify = DO_NOT_NOTIFY;
|
||||
|
||||
int receive_message(mqd_t mqd, char needs_timeout) {
|
||||
ssize_t nbytes;
|
||||
struct mq_attr attr;
|
||||
char *buf = NULL;
|
||||
int ret = EXIT_FAILURE;
|
||||
|
||||
if (mq_getattr(mqd, &attr) == -1) {
|
||||
perror("FAIL - could not mq_getattr");
|
||||
@@ -62,20 +68,24 @@ int receive_message(mqd_t mqd, char needs_timeout) {
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
|
||||
if (mq_close(mqd) == (mqd_t) -1) {
|
||||
perror("FAIL - could not close mq");
|
||||
exit(EXIT_FAILURE);
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
if (mq_unlink(queuename) == (mqd_t) -1) {
|
||||
perror("FAIL - could unlink mq");
|
||||
exit(EXIT_FAILURE);
|
||||
perror("FAIL - could not unlink mq");
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
if (notify == MQ_NOTIFY && unlink(pipepath) == -1) {
|
||||
perror("FAIL - could not remove pipe");
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static void handle_signal(union sigval sv) {
|
||||
@@ -96,6 +106,7 @@ static void usage(char *prog_name, char *msg)
|
||||
fprintf(stderr, "-c path of the client binary\n");
|
||||
fprintf(stderr, "-u run test as specified UID\n");
|
||||
fprintf(stderr, "-t timeout in seconds\n");
|
||||
fprintf(stderr, "-p named pipe path. used by mq_notify\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -108,9 +119,15 @@ void receive_mq_notify(mqd_t mqd)
|
||||
sev.sigev_value.sival_ptr = &mqd;
|
||||
|
||||
if (mq_notify(mqd, &sev) == -1) {
|
||||
perror(" FAIL - could not mq_notify");
|
||||
exit(EXIT_FAILURE);
|
||||
perror("FAIL - could not mq_notify");
|
||||
return;
|
||||
}
|
||||
|
||||
if (write_to_pipe(pipepath) == -1) { // let sender know mq_notify is ready
|
||||
fprintf(stderr, "FAIL - could not write to pipe\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sleep(timeout);
|
||||
fprintf(stderr, "FAIL - could not mq_notify: Connection timed out\n");
|
||||
}
|
||||
@@ -127,7 +144,7 @@ void receive_select(mqd_t mqd)
|
||||
|
||||
if (select(mqd + 1, &read_fds, NULL, NULL, &tv) == -1) {
|
||||
perror("FAIL - could not select");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
} else {
|
||||
if (FD_ISSET(mqd, &read_fds))
|
||||
receive_message(mqd, 0);
|
||||
@@ -142,7 +159,7 @@ void receive_poll(mqd_t mqd)
|
||||
|
||||
if (poll(fds, 1, timeout * 1000) == -1) {
|
||||
perror("FAIL - could not poll");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
} else {
|
||||
if (fds[0].revents & POLLIN)
|
||||
receive_message(mqd, 0);
|
||||
@@ -154,7 +171,7 @@ void receive_epoll(mqd_t mqd)
|
||||
int epfd = epoll_create(1);
|
||||
if (epfd == -1) {
|
||||
perror("FAIL - could not create epoll");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
struct epoll_event ev, rev[1];
|
||||
@@ -162,12 +179,12 @@ void receive_epoll(mqd_t mqd)
|
||||
ev.data.fd = mqd;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, mqd, &ev) == -1) {
|
||||
perror("FAIL - could not add mqd to epoll");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (epoll_wait(epfd, rev, 1, timeout * 1000) == -1) {
|
||||
perror("FAIL - could not epoll_wait");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
} else {
|
||||
if (rev[0].data.fd == mqd && rev[0].events & EPOLLIN)
|
||||
receive_message(mqd, 0);
|
||||
@@ -198,17 +215,17 @@ void receive(enum notify_options notify, mqd_t mqd)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt = 0;
|
||||
enum notify_options notify = DO_NOT_NOTIFY;
|
||||
mqd_t mqd;
|
||||
char *client = NULL;
|
||||
int uid;
|
||||
int pipefd;
|
||||
struct mq_attr attr;
|
||||
attr.mq_flags = 0;
|
||||
attr.mq_maxmsg = 10;
|
||||
attr.mq_msgsize = BUF_SIZE;
|
||||
attr.mq_curmsgs = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "n:k:c:u:t:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "n:k:c:u:t:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
if (strcmp(optarg, "mq_notify") == 0)
|
||||
@@ -258,6 +275,9 @@ int main(int argc, char *argv[])
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
pipepath = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], "Unrecognized option\n");
|
||||
}
|
||||
@@ -269,11 +289,24 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (notify == MQ_NOTIFY) {
|
||||
if (mkfifo(pipepath, 0666) == -1) {
|
||||
perror("FAIL - could not mkfifo");
|
||||
goto nopipeout;
|
||||
}
|
||||
|
||||
pipefd = open_read_pipe(pipepath);
|
||||
if (pipefd == -1) {
|
||||
fprintf(stderr, "FAIL - couldn't open pipe\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* exec the client */
|
||||
int pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("FAIL - could not fork");
|
||||
exit(EXIT_FAILURE);
|
||||
goto out;
|
||||
} else if (!pid) {
|
||||
if (client == NULL) {
|
||||
usage(argv[0], "client not specified");
|
||||
@@ -282,25 +315,30 @@ int main(int argc, char *argv[])
|
||||
* in case the client will be manually executed
|
||||
*/
|
||||
}
|
||||
execl(client, client, queuename, NULL);
|
||||
printf("FAIL %d - execlp %s %s- %m\n", getuid(), client, queuename);
|
||||
if (notify == MQ_NOTIFY) {
|
||||
char strpipefd[12];
|
||||
sprintf(strpipefd, "%d", pipefd);
|
||||
execl(client, client, queuename, strpipefd, NULL);
|
||||
printf("FAIL %d - execlp %s %s %s- %m\n", getuid(), client, queuename, strpipefd);
|
||||
} else {
|
||||
execl(client, client, queuename, NULL);
|
||||
printf("FAIL %d - execlp %s %s- %m\n", getuid(), client, queuename);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
receive(notify, mqd);
|
||||
|
||||
/* when the notification fails because of timeout, it ends up here
|
||||
* so, clean up the mqueue
|
||||
* so, clean up the mqueue and exit_failure
|
||||
*/
|
||||
|
||||
if (mq_close(mqd) == (mqd_t) -1) {
|
||||
out:
|
||||
if (notify == MQ_NOTIFY && unlink(pipepath) == -1)
|
||||
perror("FAIL - could not remove pipe");
|
||||
nopipeout:
|
||||
if (mq_close(mqd) == (mqd_t) -1)
|
||||
perror("FAIL - could not close mq");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mq_unlink(queuename) == (mqd_t) -1) {
|
||||
if (mq_unlink(queuename) == (mqd_t) -1)
|
||||
perror("FAIL - could unlink mq");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@@ -1,16 +1,27 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <mqueue.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "posix_mq.h"
|
||||
#include "pipe_helper.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
mqd_t mqd;
|
||||
char *queuename = QNAME;
|
||||
int pipefd;
|
||||
|
||||
if (argc > 1) {
|
||||
queuename = argv[1];
|
||||
}
|
||||
if (argc > 2) {
|
||||
pipefd = atoi(argv[2]);
|
||||
if (read_from_pipe(pipefd) == -1) { // wait for receiver to mq_notify
|
||||
fprintf(stderr, "FAIL - could not read from pipe\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
mqd = mq_open(queuename, O_WRONLY);
|
||||
if (mqd == (mqd_t) -1) {
|
||||
perror("FAIL sender - could not open mq");
|
||||
|
@@ -235,6 +235,15 @@ runchecktest "test 12p2 -hc" fail -h -c -n 100 $helper
|
||||
runchecktest "test 12p2 -h prog" fail -h -n 100 $helper ${bin_true}
|
||||
runchecktest "test 12p2 -hc prog" fail -h -c -n 100 $helper ${bin_true}
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "test allow all" pass -n 100 ${bin_true}
|
||||
runchecktest "test allow all -c" pass -c -n 100 ${bin_true}
|
||||
runchecktest "test allow all -h" pass -h -n 100 $helper
|
||||
runchecktest "test allow all -hc" pass -h -c -n 100 $helper
|
||||
runchecktest "test allow all -h prog" pass -h -n 100 $helper ${bin_true}
|
||||
runchecktest "test allow all -hc prog" pass -h -c -n 100 $helper ${bin_true}
|
||||
fi
|
||||
|
||||
#ptraced confined app traced by profile can px
|
||||
genprofile ${bin_true}:rpx $helper:rix signal:ALL ptrace:peer=$test ptrace:peer=${bin_true} -- image=${bin_true} ${bin_true}:rix
|
||||
|
@@ -27,16 +27,38 @@ bin=$pwd
|
||||
## A. SWAP
|
||||
##
|
||||
|
||||
# check if we can run the test at all
|
||||
swap_file=$tmpdir/swapfile
|
||||
|
||||
# check if we can run the test in tmpdir
|
||||
fstype=$(stat -f --format '%T' "${tmpdir}")
|
||||
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
|
||||
exit
|
||||
# create a mountpoint not tmpfs
|
||||
mount_file=$tmpdir/mountfile
|
||||
mount_point=$tmpdir/mountpoint
|
||||
fstype="ext2"
|
||||
dd if=/dev/zero of=${mount_file} bs=1024 count=900 2> /dev/null
|
||||
/sbin/mkfs -t${fstype} -F ${mount_file} > /dev/null 2> /dev/null
|
||||
/bin/mkdir ${mount_point}
|
||||
|
||||
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
|
||||
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
|
||||
|
||||
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
|
||||
|
||||
swap_file=$mount_point/swapfile
|
||||
fi
|
||||
|
||||
swap_file=$tmpdir/swapfile
|
||||
remove_mnt() {
|
||||
mountpoint -q "${mount_point}"
|
||||
if [ $? -eq 0 ] ; then
|
||||
/bin/umount -t${fstype} ${mount_point}
|
||||
fi
|
||||
if [ -n "$loop_device" ]
|
||||
then
|
||||
/sbin/losetup -d ${loop_device} &> /dev/null
|
||||
fi
|
||||
}
|
||||
do_onexit="remove_mnt"
|
||||
|
||||
# ppc64el wants this to be larger than 640KiB
|
||||
# arm/small machines want this as small as possible
|
||||
|
@@ -35,6 +35,12 @@ runchecktest "TCP (no apparmor)" pass $port
|
||||
genprofile
|
||||
runchecktest "TCP (accept, connect) no network rules" fail $port
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
# PASS TEST - allow all
|
||||
genprofile "all"
|
||||
runchecktest "TCP (allow all)" pass $port
|
||||
fi
|
||||
|
||||
# PASS TEST - allow tcp
|
||||
genprofile network:tcp
|
||||
runchecktest "TCP (accept, connect) allow tcp" pass $port
|
||||
|
@@ -71,6 +71,11 @@ do_test()
|
||||
|
||||
desc+=" confined $test_prog"
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
$genprof "all"
|
||||
runchecktest "$desc (allow all)" pass $args
|
||||
fi
|
||||
|
||||
$genprof "unix:ALL"
|
||||
runchecktest "$desc (implicit perms)" pass $args
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/limits.h>
|
||||
#include "userns.h"
|
||||
#include "pipe_helper.h"
|
||||
|
||||
static void usage(char *pname)
|
||||
{
|
||||
|
@@ -101,6 +101,11 @@ fi
|
||||
# confined tests should have the same results if apparmor_restrict_unprivileged_userns is enabled or not
|
||||
run_confined_tests()
|
||||
{
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
generate_profile="genprofile all"
|
||||
do_test "confined allow all $1" pass pass pass pass "$generate_profile"
|
||||
fi
|
||||
|
||||
generate_profile="genprofile userns"
|
||||
do_test "confined all perms $1" pass pass fail fail "$generate_profile"
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "userns.h"
|
||||
#include "pipe_helper.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@@ -131,7 +131,7 @@ def notify_about_new_entries(logfile, filters, wait=0):
|
||||
debug_logger.info(format_event(event, logfile))
|
||||
yield (format_event(event, logfile))
|
||||
except PermissionError:
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.".format(logfile)))
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.").format(logfile))
|
||||
|
||||
else:
|
||||
print(_('Notification emitter started in the background'))
|
||||
|
@@ -89,9 +89,9 @@ LOADED_PROFILES=$("$PARSER" -N $PROFILE_DIRS) || {
|
||||
echo "$LOADED_PROFILES" | awk '
|
||||
BEGIN {
|
||||
while (getline < "'${PROFILES}'" ) {
|
||||
str = sub(/ \((enforce|complain)\)$/, "", $0);
|
||||
sub(/ \((enforce|complain|unconfined)\)$/, "", $0);
|
||||
if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
|
||||
arr[$str] = $str
|
||||
arr[$0] = $0
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -603,8 +603,8 @@ def autodep(bin_name, pname=''):
|
||||
|
||||
active_profiles.add_profile(file, pname, attachment)
|
||||
|
||||
if os.path.isfile(profile_dir + '/abi/3.0'):
|
||||
active_profiles.add_abi(file, AbiRule('abi/3.0', False, True))
|
||||
if os.path.isfile(profile_dir + '/abi/4.0'):
|
||||
active_profiles.add_abi(file, AbiRule('abi/4.0', False, True))
|
||||
if os.path.isfile(profile_dir + '/tunables/global'):
|
||||
active_profiles.add_inc_ie(file, IncludeRule('tunables/global', False, True))
|
||||
write_profile_ui_feedback(pname)
|
||||
@@ -833,9 +833,12 @@ def ask_exec(hashlog):
|
||||
raise AppArmorBug(
|
||||
'exec permissions requested for directory %s (profile %s). This should not happen - please open a bugreport!' % (exec_target, full_profile))
|
||||
|
||||
if not aa[profile].get(hat):
|
||||
if not aa.get(profile):
|
||||
continue # ignore log entries for non-existing profiles
|
||||
|
||||
if not aa[profile].get(hat):
|
||||
continue # ignore log entries for non-existing hats
|
||||
|
||||
exec_event = FileRule(exec_target, None, FileRule.ANY_EXEC, FileRule.ALL, owner=False, log_event=True)
|
||||
if is_known_rule(aa[profile][hat], 'file', exec_event):
|
||||
continue
|
||||
@@ -1797,6 +1800,9 @@ def read_profiles(ui_msg=False, skip_profiles=()):
|
||||
if os.path.isfile(full_file):
|
||||
if is_skippable_file(file):
|
||||
continue
|
||||
elif os.path.exists(f'{profile_dir}/disable/{file}'):
|
||||
aaui.UI_Info("skipping disabled profile %s" % file)
|
||||
continue
|
||||
elif file in skip_profiles:
|
||||
aaui.UI_Info("skipping profile %s" % full_file)
|
||||
continue
|
||||
|
@@ -212,7 +212,7 @@ class ReadLog:
|
||||
self.hashlog[aamode][full_profile]['io_uring'][e['denied_mask']][e['peer_profile']] = True
|
||||
return
|
||||
|
||||
elif e['class'] and e['class'] == 'mount':
|
||||
elif e['class'] and e['class'] == 'mount' or e['operation'] == 'mount':
|
||||
if e['flags'] != None:
|
||||
e['flags'] = ('=', e['flags'])
|
||||
if e['fs_type'] != None:
|
||||
|
@@ -51,7 +51,7 @@ class BaseRule(metaclass=ABCMeta):
|
||||
# Set only in the parse() class method
|
||||
self.raw_rule = None
|
||||
|
||||
def _aare_or_all(self, rulepart, partname, is_path, log_event):
|
||||
def _aare_or_all(self, rulepart, partname, is_path, log_event, empty_ok=False):
|
||||
"""checks rulepart and returns
|
||||
- (AARE, False) if rulepart is a (non-empty) string
|
||||
- (None, True) if rulepart is all_obj (typically *Rule.ALL)
|
||||
@@ -67,7 +67,7 @@ class BaseRule(metaclass=ABCMeta):
|
||||
if rulepart == self.ALL:
|
||||
return None, True
|
||||
elif isinstance(rulepart, str):
|
||||
if not rulepart.strip():
|
||||
if not rulepart.strip() and not empty_ok:
|
||||
raise AppArmorBug(
|
||||
'Passed empty %(partname)s to %(classname)s: %(rulepart)s'
|
||||
% {'partname': partname, 'classname': self.__class__.__name__, 'rulepart': str(rulepart)})
|
||||
|
@@ -15,7 +15,7 @@ import re
|
||||
|
||||
from apparmor.common import AppArmorBug, AppArmorException
|
||||
|
||||
from apparmor.regex import RE_PROFILE_MOUNT, RE_PROFILE_PATH_OR_VAR, strip_parenthesis
|
||||
from apparmor.regex import RE_PROFILE_MOUNT, strip_parenthesis, strip_quotes
|
||||
from apparmor.rule import AARE
|
||||
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
|
||||
|
||||
@@ -23,32 +23,22 @@ from apparmor.translations import init_translation
|
||||
|
||||
_ = init_translation()
|
||||
|
||||
# TODO :
|
||||
# - match correctly AARE on every field
|
||||
# - Find the actual list of supported filesystems. This one comes from /proc/filesystems. We also blindly accept fuse.*
|
||||
# - Support path that begin by { (e.g. {,/usr}/lib/...) This syntax is not a valid AARE but is used by usr.lib.snapd.snap-confine.real in Ubuntu and will currently raise an error in genprof if these lines are not modified.
|
||||
# - Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
||||
# TODO : Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
||||
|
||||
valid_fs = [
|
||||
'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs',
|
||||
'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs',
|
||||
'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay',
|
||||
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'resctrl', 'zfs', 'iso9660', 'udf', 'ntfs3',
|
||||
'nfs', 'cifs',
|
||||
]
|
||||
|
||||
flags_keywords = [
|
||||
# keep in sync with parser/mount.cc mnt_opts_table!
|
||||
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
|
||||
'mand', 'nomand', 'dirsync', 'symfollow', 'nosymfollow', 'atime', 'noatime', 'diratime', 'nodiratime', 'bind', 'B',
|
||||
'move', 'M', 'rbind', 'R', 'verbose', 'silent', 'loud', 'acl', 'noacl', 'unbindable', 'make-unbindable', 'runbindable',
|
||||
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave',
|
||||
'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
||||
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
|
||||
'([A-Za-z0-9])',
|
||||
flags_bind_mount = {'B', 'bind', 'R', 'rbind'}
|
||||
flags_change_propagation = {
|
||||
'remount', 'unbindable', 'shared', 'private', 'slave', 'runbindable', 'rshared', 'rprivate', 'rslave',
|
||||
'make-unbindable', 'make-shared', 'make-private', 'make-slave', 'make-runbindable', 'make-rshared', 'make-rprivate',
|
||||
'make-rslave'
|
||||
}
|
||||
# keep in sync with parser/mount.cc mnt_opts_table!
|
||||
flags_keywords = list(flags_bind_mount) + list(flags_change_propagation) + [
|
||||
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'mand',
|
||||
'nomand', 'dirsync', 'symfollow', 'nosymfollow', 'atime', 'noatime', 'diratime', 'nodiratime', 'move', 'M',
|
||||
'verbose', 'silent', 'loud', 'acl', 'noacl', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
||||
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser', '([A-Za-z0-9])',
|
||||
]
|
||||
join_valid_flags = '|'.join(flags_keywords)
|
||||
join_valid_fs = '|'.join(valid_fs)
|
||||
|
||||
sep = r'\s*[\s,]\s*'
|
||||
|
||||
@@ -72,9 +62,13 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?'
|
||||
# - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar)
|
||||
# - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar)
|
||||
# Thus we cannot use directly RE_PROFILE_PATH_OR_VAR
|
||||
# Destination can also be
|
||||
# - A path : /foo
|
||||
# - A globbed Path : **
|
||||
|
||||
source_fileglob_pattern = r'(\s*(?P<source_file>([/{]\S*|"[/{][^"]*"|@{\S+}\S*|"@{\S+}[^"]*")|\w+))'
|
||||
dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')'
|
||||
glob_pattern = r'(\s*(?P<%s>(([/{]|\*\*)\S*|"([/{]|\*\*)[^"]*"|@{\S+}\S*|"@{\S+}[^"]*"|"")|\w+))'
|
||||
source_fileglob_pattern = glob_pattern % 'source_file'
|
||||
dest_fileglob_pattern = glob_pattern % 'dest_file'
|
||||
|
||||
RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$')
|
||||
RE_UMOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{dest_fileglob_pattern})?\s*' + r'$')
|
||||
@@ -102,34 +96,26 @@ class MountRule(BaseRule):
|
||||
|
||||
self.operation = operation
|
||||
|
||||
self.fstype, self.all_fstype, unknown_items = check_and_split_list(fstype[1] if fstype != self.ALL else fstype, valid_fs, self.ALL, type(self).__name__, 'fstype')
|
||||
|
||||
if unknown_items:
|
||||
for it in unknown_items:
|
||||
|
||||
# Several filesystems use fuse internally and are referred as fuse.<software_name> (e.g. fuse.jmtpfs, fuse.s3fs, fuse.obexfs).
|
||||
# Since this list seems to evolve too fast for a fixed list to work in practice, we just accept fuse.*
|
||||
# See https://github.com/libfuse/libfuse/wiki/Filesystems and, https://doc.ubuntu-fr.org/fuse
|
||||
if it.startswith('fuse.') and len(it) > 5:
|
||||
continue
|
||||
|
||||
it = AARE(it, is_path=False)
|
||||
found = False
|
||||
for fs in valid_fs:
|
||||
if self._is_covered_aare(it, self.all_fstype, AARE(fs, False), self.all_fstype, 'fstype'):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
raise AppArmorException(_('Passed unknown fstype keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
||||
|
||||
self.is_fstype_equal = fstype[0] if not self.all_fstype else None
|
||||
if fstype == self.ALL or fstype[1] == self.ALL:
|
||||
self.all_fstype = True
|
||||
self.fstype = None
|
||||
self.is_fstype_equal = None
|
||||
else:
|
||||
self.all_fstype = False
|
||||
for it in fstype[1]:
|
||||
l, unused = parse_aare(it, 0, 'fstype')
|
||||
if l != len(it):
|
||||
raise AppArmorException(f'Invalid aare : {it}')
|
||||
self.fstype = fstype[1]
|
||||
self.is_fstype_equal = fstype[0]
|
||||
|
||||
self.options, self.all_options, unknown_items = check_and_split_list(options[1] if options != self.ALL else options, flags_keywords, self.ALL, type(self).__name__, 'options')
|
||||
if unknown_items:
|
||||
raise AppArmorException(_('Passed unknown options keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
||||
self.is_options_equal = options[0] if not self.all_options else None
|
||||
|
||||
self.source, self.all_source = self._aare_or_all(source, 'source', is_path=False, log_event=log_event)
|
||||
self.source, self.all_source = self._aare_or_all(source, 'source', is_path=False, log_event=log_event, empty_ok=True)
|
||||
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=False, log_event=log_event)
|
||||
|
||||
if not self.all_fstype and self.is_fstype_equal not in ('=', 'in'):
|
||||
raise AppArmorBug(f'Invalid is_fstype_equal : {self.is_fstype_equal}')
|
||||
@@ -138,11 +124,14 @@ class MountRule(BaseRule):
|
||||
if self.operation != 'mount' and not self.all_source:
|
||||
raise AppArmorException(f'Operation {self.operation} cannot have a source')
|
||||
|
||||
flags_forbidden_with_source = {'remount', 'unbindable', 'shared', 'private', 'slave', 'runbindable', 'rshared', 'rprivate', 'rslave'}
|
||||
if self.operation == 'mount' and not self.all_source and not self.all_options and flags_forbidden_with_source & self.options != set():
|
||||
raise AppArmorException(f'Operation {flags_forbidden_with_source & self.options} cannot have a source. Source = {self.source}')
|
||||
if self.operation == 'mount' and not self.all_options and flags_change_propagation & self.options != set():
|
||||
if not (self.all_source or self.all_dest):
|
||||
raise AppArmorException(f'Operation {flags_change_propagation & self.options} cannot specify a source. Source = {self.source}')
|
||||
elif not self.all_fstype:
|
||||
raise AppArmorException(f'Operation {flags_change_propagation & self.options} cannot specify a fstype. Fstype = {self.fstype}')
|
||||
|
||||
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=True, log_event=log_event)
|
||||
if self.operation == 'mount' and not self.all_options and flags_bind_mount & self.options != set() and not self.all_fstype:
|
||||
raise AppArmorException(f'Bind mount rules cannot specify a fstype. Fstype = {self.fstype}')
|
||||
|
||||
self.can_glob = not self.all_source and not self.all_dest and not self.all_options
|
||||
|
||||
@@ -169,7 +158,7 @@ class MountRule(BaseRule):
|
||||
|
||||
if r['fstype'] is not None:
|
||||
is_fstype_equal = r['fstype_equals_or_in']
|
||||
fstype = strip_parenthesis(r['fstype']).replace(',', ' ').split()
|
||||
fstype = parse_aare_list(strip_parenthesis(r['fstype']), 'fstype')
|
||||
else:
|
||||
is_fstype_equal = None
|
||||
fstype = cls.ALL
|
||||
@@ -182,12 +171,12 @@ class MountRule(BaseRule):
|
||||
options = cls.ALL
|
||||
|
||||
if operation == 'mount' and r['source_file'] is not None: # Umount cannot have a source
|
||||
source = r['source_file']
|
||||
source = strip_quotes(r['source_file'])
|
||||
else:
|
||||
source = cls.ALL
|
||||
|
||||
if r['dest_file'] is not None:
|
||||
dest = r['dest_file']
|
||||
dest = strip_quotes(r['dest_file'])
|
||||
else:
|
||||
dest = cls.ALL
|
||||
|
||||
@@ -312,6 +301,38 @@ class MountRuleset(BaseRuleset):
|
||||
'''Class to handle and store a collection of Mount rules'''
|
||||
|
||||
|
||||
|
||||
def parse_aare(s, offset, param):
|
||||
parsed = ''
|
||||
brace_count = 0
|
||||
for i, c in enumerate(s[offset:], start=offset):
|
||||
if c in [' ', ',', '\t'] and brace_count == 0:
|
||||
break
|
||||
parsed += c
|
||||
if c == '{':
|
||||
brace_count += 1
|
||||
elif c == '}':
|
||||
brace_count -= 1
|
||||
if brace_count < 0:
|
||||
raise AppArmorException(f"Unmatched closing brace in {param}: {s[offset:]}")
|
||||
offset = i
|
||||
|
||||
if brace_count != 0:
|
||||
raise AppArmorException(f"Unmatched opening brace in {param}: {s[offset:]}")
|
||||
|
||||
return offset + 1, parsed
|
||||
|
||||
|
||||
def parse_aare_list(s, param):
|
||||
res = []
|
||||
offset = 0
|
||||
while offset <= len(s):
|
||||
offset, part = parse_aare(s, offset, param)
|
||||
if part.translate(' ,\t') != '':
|
||||
res.append(part)
|
||||
return res
|
||||
|
||||
|
||||
def wrap_in_with_spaces(value):
|
||||
''' wrap 'in' keyword in spaces, and leave everything else unchanged '''
|
||||
|
||||
|
@@ -35,7 +35,7 @@ RE_ACCESS_KEYWORDS = (joint_access_keyword + # one of the access_keyword or
|
||||
r'\(' + joint_access_keyword + '(' + r'(\s|,)+' + joint_access_keyword + ')*' + r'\)' # one or more access_keyword in (...)
|
||||
)
|
||||
|
||||
RE_MQUEUE_NAME = r'(?P<%s>(/\S+|\d*))' # / + string for posix, or digits for sys
|
||||
RE_MQUEUE_NAME = r'(?P<%s>(/\S*|\d*))' # / + string for posix, or digits for sys
|
||||
RE_MQUEUE_TYPE = r'(?P<%s>(sysv|posix))' # type can be sysv or posix
|
||||
|
||||
RE_MQUEUE_DETAILS = re.compile(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user