2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 06:45:38 +00:00

Compare commits

..

32 Commits

Author SHA1 Message Date
John Johansen
2fc80487f7 Prepare for AppArmor 4.0 beta3 release
- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-03-17 00:55:14 -07:00
John Johansen
c87969b37c Merge profiles: Add more unconfined profiles
This adds the remaining set of unconfined profiles, from the set listed
in https://bugs.launchpad.net/ubuntu/+source/pageedit/+bug/2046844

Fixes: https://bugs.launchpad.net/ubuntu/+source/pageedit/+bug/2046844
Signed-off-by: John Johansen <john.johansen@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1186
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-17 07:27:49 +00:00
John Johansen
b68bb18860 Merge network: several fixes
This patchset includes several fixes for the inet mediation.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/374
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1183
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-17 07:22:24 +00:00
John Johansen
c47789340a Merge add unconfined profiles for geary, loupe and firefox dev versions
These applications need to use user namespaces, hence it needs an
unconfined profile when user namespaces are restricted from unconfined
like other applications in MR #1123

https://gitlab.com/apparmor/apparmor/-/merge_requests/1123

In addition this serves as a handle to uniquely identify them instead
of unconfined to peers in policy.

Bug: https://bugs.launchpad.net/bugs/2046844

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1185
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-17 07:18:03 +00:00
John Johansen
e23a3eeba5 profiles: Add more unconfined profiles
This adds the remaining set of unconfined profiles, from the set listed
in https://bugs.launchpad.net/ubuntu/+source/pageedit/+bug/2046844

Fixes: https://bugs.launchpad.net/ubuntu/+source/pageedit/+bug/2046844
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-03-17 00:16:37 -07:00
Georgia Garcia
d0fadc48cf tests: add missing rules to the inet/inet6 mediation tests
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 18:24:19 -03:00
Georgia Garcia
aec3f3b22c add unconfined profiles for geary, loupe and firefox dev versions
These applications need to use user namespaces, hence it needs an
unconfined profile when user namespaces are restricted from unconfined
like other applications in MR #1123

https://gitlab.com/apparmor/apparmor/-/merge_requests/1123

In addition this serves as a handle to uniquely identify them instead
of unconfined to peers in policy.

Bug: https://bugs.launchpad.net/bugs/2046844

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 17:44:23 -03:00
Georgia Garcia
101651c88f parser: fix af_inet feature from network to network_v8
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 16:38:10 -03:00
Georgia Garcia
efc2ec5fdd parser: fix cmp function for network rules
The network cmp function was missing the new attributes added, causing
rules to be dropped.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 16:38:10 -03:00
Georgia Garcia
b01b9895e7 parser: add ability to specify anonymous ip
If anonymous ip is specified, then the port will match anything.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 16:38:10 -03:00
Georgia Garcia
a0a0c88d9e parser: generate all ip options when ip is not specified
When the ip is not specified, then we should generate rules for ip
types: anonymous, ipv4 and ipv6. And that's the case for both local
and peer when considering recv and send permissions.

std::ostringstream does not have a copy constructor, that's why in
several places one can see streaming the string of one stream into
another.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 10:33:33 -03:00
Georgia Garcia
63676459c4 parser: encode create permission separately from the others
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 10:33:33 -03:00
Georgia Garcia
9ed04cb01e parser: introduce network label attribute
We want to be able to determine label in the future and build the
policy dfa based on its presence or not.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 10:33:33 -03:00
Georgia Garcia
2a885872a3 parser: ip size encoding should be an enum, not the ip size
According to the protocol expected by the kernel, the field
representing the ip size should be an enum instead of the actual ip
size. This is more future-proof.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 10:33:33 -03:00
Georgia Garcia
989501428e parser: initial steps into encoding protocol properly
Before the inet patches, protocol was not handled, so the information
was ignored. This patch introduces the ability to start mediating
protocol.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-15 10:33:33 -03:00
John Johansen
25f21a0758 Merge libraries/libapparmor: fix syntax in configure
We're not trying to execute a command in EXTRA_WARNINGS, so don't try to spawn
a subshell for it which gives:
```
./configure: 14770: EXTRA_WARNINGS: not found
checking whether C compiler accepts -flto-partition=none... yes
```

We can either use ${} or just $ (style). Use $ to be consistent with other
uses in the file.

Signed-off-by: Sam James <sam@gentoo.org>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1184
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-15 04:05:15 +00:00
Sam James
022af9c528 libraries/libapparmor: fix syntax in configure
We're not trying to execute a command in EXTRA_WARNINGS, so don't try to spawn
a subshell for it which gives:
```
./configure: 14770: EXTRA_WARNINGS: not found
checking whether C compiler accepts -flto-partition=none... yes
```

We can either use ${} or just $ (style). Use $ to be consistent with other
uses in the file.

Signed-off-by: Sam James <sam@gentoo.org>
2024-03-15 02:36:12 +00:00
John Johansen
9a1838016c Merge Allow pam_unix to execute unix_chkpwd
Latest pam_unix always runs /usr/sbin/unix_chkpwd instead of reading
/etc/shadow itsself. Add exec permissions to abstraction/authentication.

It also needs to read /proc/@{pid}/loginuid

Also cleanup the now-superfluous rules from the smbd profile.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1219139

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1181
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-14 21:09:59 +00:00
Christian Boltz
f4c19acfba Merge MountRule: Fix _is_covered_localvars
If `fstype==None`, `_is_covered_localvars` would trigger an exception.

This is fixed and a new testcase is added.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1182
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-03-14 12:46:01 +00:00
Maxime Bélair
dac9d08764 MountRule: Fix _is_covered_localvars 2024-03-14 12:46:01 +00:00
Christian Boltz
243162ca29 Allow pam_unix to execute unix_chkpwd
Latest pam_unix always runs /usr/sbin/unix_chkpwd instead of reading
/etc/shadow itsself. Add exec permissions to abstraction/authentication.

It also needs to read /proc/@{pid}/loginuid

Also cleanup the now-superfluous rules from the smbd profile.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1219139
2024-03-13 23:13:19 +01:00
Georgia Garcia
ae978c1953 Merge Fix test-aa-notify on openSUSE Tumbleweed (new 'last')
The new 2037-proof `last` on openSUSE Tumbleweed doesn't support the
`-1` option.

Remove it, and cut off the output manually.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1180
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-12 18:54:35 +00:00
Christian Boltz
d19db55a37 Fix test-aa-notify on openSUSE Tumbleweed (new 'last')
The new 2037-proof `last` on openSUSE Tumbleweed doesn't support the
`-1` option.

Remove it, and cut off the output manually.
2024-03-12 19:37:29 +01:00
Christian Boltz
e3d381cf91 Merge Clean superfluous openssl abstraction includes
With abstractions/openssl now being included from abstraction/base
(via the indirection of abstractions/crypto) anything already
including abstraction/base can stop including abstractions/openssl
directly.

This is a follow up to 3d1dedfa as suggested by @cboltz

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1179
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-03-12 18:12:12 +00:00
Christian Ehrhardt
aa69d9adc9 Clean superfluous openssl abstraction includes
With abstractions/openssl now being included from abstraction/base
(via the indirection of abstractions/crypto) anything already
including abstraction/base can stop including abstractions/openssl
directly.
2024-03-12 14:54:01 +01:00
John Johansen
3d1dedfa7e Merge abstractions/crypto: allow read of more common crypto configuration files
Administrators might want to define global limits (e.g. disabling
a particular feature) via configuration files, but to make that work
all confined software needs to be allowed to read those files or
otherwise the risk is to silently fall back to internal defaults.

This adds the paths usually used by gnutls and openssl to improve these kind of use cases.

Fixes: https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/2056739
Fixes: https://bugs.launchpad.net/ubuntu/+source/chrony/+bug/2056747
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1178
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-12 11:27:59 +00:00
Christian Ehrhardt
f27b1ef93a abstractions/crypto: allow read of openssl config
Administrators might want to define global limits (e.g. disabling
a particular feature) via configuration files, but to make that work
all confined software needs to be allowed to read those files or
otherwise the risk is to silently fall back to internal defaults.

This adds the abstraction already defined for openssl to
abstraction/crypto as it is about cryptography, but also because
abstraction/base includes abstraction/crypto and therefore it will
be allowed in general.
2024-03-12 08:57:12 +01:00
Christian Ehrhardt
18d6a917f8 abstractions/crypto: allow read of gnutls config
Administrators might want to define global limits (e.g. disabling
a particular feature) via configuration files, but to make that work
all confined software needs to be allowed to read those files or
otherwise the risk is to silently fall back to internal defaults.

This adds the paths usually used by gnutls to abstraction/crypto
as it is about cryptography, but also because abstraction/base
includes abstraction/crypto and therefore it will be allowed
in general.
2024-03-12 08:54:36 +01:00
Christian Boltz
d1d39d176e Merge parser(Makefile): don't ship /var in downstream packages
Should help with building /var free images downstream.

See below: https://gitlab.com/apparmor/apparmor/-/merge_requests/1167#note_1798547092

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1167
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-03-08 12:53:32 +00:00
Max Gautier
2d654477f2 parser(Makefile): dont install /var/lib/apparmor
This directory is not used anymore.
This help downstream build of /var free images.

Links: https://0pointer.net/blog/fitting-everything-together.html
2024-03-08 10:18:16 +01:00
John Johansen
66dc2cc7d0 Merge Minor improvements for MountRule to fix make check failure
Minor improvements for MountRule
- Adding support for regex in fstype
- add resctrl filesystem
- Adding support for source beginning by '{' 

This MR allows to support edge cases for MountRule e.g. source = {,/usr}/lib{,32,64,x32}/modules/ or fstype = fuse.*

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/370
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1176
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-07 19:27:03 +00:00
Maxime Bélair
021c3248f9 Minor improvements for MountRule 2024-03-07 19:27:03 +00:00
49 changed files with 510 additions and 140 deletions

View File

@@ -1 +1 @@
4.0.0~beta2 4.0.0~beta3

View File

@@ -93,7 +93,7 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
fi fi
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])]) m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC" EXTRA_CFLAGS="-Wall $EXTRA_WARNINGS -fPIC"
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror]) AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes], AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"] [EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]

View File

@@ -440,7 +440,6 @@ install-arch: $(INSTALLDEPS)
install-indep: indep install-indep: indep
install -m 755 -d $(INSTALL_CONFDIR) install -m 755 -d $(INSTALL_CONFDIR)
install -m 644 parser.conf $(INSTALL_CONFDIR) install -m 644 parser.conf $(INSTALL_CONFDIR)
install -m 755 -d ${DESTDIR}/var/lib/apparmor
install -m 755 -d $(APPARMOR_BIN_PREFIX) install -m 755 -d $(APPARMOR_BIN_PREFIX)
install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX) install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
install -m 755 profile-load $(APPARMOR_BIN_PREFIX) install -m 755 profile-load $(APPARMOR_BIN_PREFIX)

View File

@@ -252,6 +252,19 @@ const char *net_find_af_name(unsigned int af)
return NULL; return NULL;
} }
const char *net_find_protocol_name(unsigned int protocol)
{
size_t i;
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
if (network_mappings[i].protocol == protocol) {
return network_mappings[i].protocol_name;
}
}
return NULL;
}
const struct network_tuple *net_find_mapping(const struct network_tuple *map, const struct network_tuple *net_find_mapping(const struct network_tuple *map,
const char *family, const char *family,
const char *type, const char *type,
@@ -347,6 +360,10 @@ bool network_rule::parse_port(ip_conds &entry)
bool network_rule::parse_address(ip_conds &entry) bool network_rule::parse_address(ip_conds &entry)
{ {
if (strcmp(entry.sip, "anon") == 0) {
entry.is_anonymous = true;
return true;
}
entry.is_ip = true; entry.is_ip = true;
return parse_ip(entry.sip, &entry.ip); return parse_ip(entry.sip, &entry.ip);
} }
@@ -374,23 +391,24 @@ void network_rule::move_conditionals(struct cond_entry *conds, ip_conds &ip_cond
} }
} }
void network_rule::set_netperm(unsigned int family, unsigned int type) void network_rule::set_netperm(unsigned int family, unsigned int type, unsigned int protocol)
{ {
if (type > SOCK_PACKET) { if (type > SOCK_PACKET) {
/* setting mask instead of a bit */ /* setting mask instead of a bit */
network_perms[family] |= type; network_perms[family].first |= type;
} else } else
network_perms[family] |= 1 << type; network_perms[family].first |= 1 << type;
network_perms[family].second |= protocol;
} }
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds, network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
struct cond_entry *peer_conds): struct cond_entry *peer_conds):
dedup_perms_rule_t(AA_CLASS_NETV8) dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
{ {
size_t family_index; size_t family_index;
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) { for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF }); network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
set_netperm(family_index, 0xFFFFFFFF); set_netperm(family_index, 0xFFFFFFFF, 0xFFFFFFFF);
} }
move_conditionals(conds, local); move_conditionals(conds, local);
@@ -412,18 +430,18 @@ network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
network_rule::network_rule(perms_t perms_p, const char *family, const char *type, network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
const char *protocol, struct cond_entry *conds, const char *protocol, struct cond_entry *conds,
struct cond_entry *peer_conds): struct cond_entry *peer_conds):
dedup_perms_rule_t(AA_CLASS_NETV8) dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
{ {
const struct network_tuple *mapping = NULL; const struct network_tuple *mapping = NULL;
while ((mapping = net_find_mapping(mapping, family, type, protocol))) { while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol }); network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type); set_netperm(mapping->family, mapping->type, mapping->protocol);
} }
if (type == NULL && network_map.empty()) { if (type == NULL && network_map.empty()) {
while ((mapping = net_find_mapping(mapping, type, family, protocol))) { while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol }); network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type); set_netperm(mapping->family, mapping->type, mapping->protocol);
} }
} }
@@ -447,10 +465,10 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type
} }
network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type): network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type):
dedup_perms_rule_t(AA_CLASS_NETV8) dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
{ {
network_map[family].push_back({ family, type, 0xFFFFFFFF }); network_map[family].push_back({ family, type, 0xFFFFFFFF });
set_netperm(family, type); set_netperm(family, type, 0xFFFFFFFF);
if (perms_p) { if (perms_p) {
perms = perms_p; perms = perms_p;
@@ -479,7 +497,8 @@ ostream &network_rule::dump(ostream &os)
for (const auto& perm : network_perms) { for (const auto& perm : network_perms) {
unsigned int family = perm.first; unsigned int family = perm.first;
unsigned int type = perm.second; unsigned int type = perm.second.first;
unsigned int protocol = perm.second.second;
const char *family_name = net_find_af_name(family); const char *family_name = net_find_af_name(family);
if (family_name) if (family_name)
@@ -507,6 +526,12 @@ ostream &network_rule::dump(ostream &os)
os << " #" << std::hex << (type & mask); os << " #" << std::hex << (type & mask);
printf(" }"); printf(" }");
const char *protocol_name = net_find_protocol_name(protocol);
if (protocol_name)
os << " " << protocol_name;
else
os << " #" << protocol;
} }
os << ",\n"; os << ",\n";
@@ -531,14 +556,14 @@ std::string gen_ip_cond(const struct ip_address ip)
int i; int i;
if (ip.family == AF_INET) { if (ip.family == AF_INET) {
/* add a byte containing the size of the following ip */ /* add a byte containing the size of the following ip */
oss << "\\x04"; oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */ u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]); oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
} else { } else {
/* add a byte containing the size of the following ip */ /* add a byte containing the size of the following ip */
oss << "\\x10"; oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV6_SIZE;
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i)
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]); oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
} }
@@ -557,48 +582,114 @@ std::string gen_port_cond(uint16_t port)
return oss.str(); return oss.str();
} }
void network_rule::gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd) std::list<std::ostringstream> gen_all_ip_options(std::ostringstream &oss) {
std::list<std::ostringstream> all_streams;
std::ostringstream anon, ipv4, ipv6;
int i;
anon << oss.str();
ipv4 << oss.str();
ipv6 << oss.str();
anon << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
/* add a byte containing the size of the following ip */
ipv4 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
for (i = 0; i < 4; i++)
ipv4 << ".";
/* add a byte containing the size of the following ip */
ipv6 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV6_SIZE;
for (i = 0; i < 16; ++i)
ipv6 << ".";
all_streams.push_back(std::move(anon));
all_streams.push_back(std::move(ipv4));
all_streams.push_back(std::move(ipv6));
return all_streams;
}
std::list<std::ostringstream> copy_streams_list(std::list<std::ostringstream> &streams)
{ {
/* encode protocol */ std::list<std::ostringstream> streams_copy;
if (!is_cmd) { for (auto &oss : streams) {
if (entry.is_ip) { std::ostringstream oss_copy(oss.str());
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((entry.ip.family & 0xff00) >> 8); streams_copy.push_back(std::move(oss_copy));
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (entry.ip.family & 0xff); }
return streams_copy;
}
bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &streams, ip_conds &entry, bool is_peer, bool is_cmd)
{
std::string buf;
perms_t cond_perms;
std::list<std::ostringstream> ip_streams;
for (auto &oss : streams) {
if (entry.is_port && !(entry.is_ip && entry.is_anonymous)) {
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
oss << "\\x01";
else if (is_peer)
oss << "\\x02";
else
oss << "\\x00";
oss << gen_port_cond(entry.port);
} else { } else {
oss << ".."; /* port type + port number */
oss << "...";
} }
} }
if (entry.is_port) { ip_streams = std::move(streams);
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */ streams.clear();
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
oss << "\\x01";
else if (is_peer)
oss << "\\x02";
else
oss << "\\x00";
oss << gen_port_cond(entry.port); for (auto &oss : ip_streams) {
} else { if (entry.is_ip) {
/* port type + port number */ oss << gen_ip_cond(entry.ip);
if (!is_cmd) streams.push_back(std::move(oss));
oss << "."; } else if (entry.is_anonymous) {
oss << ".."; oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
streams.push_back(std::move(oss));
} else {
streams.splice(streams.end(), gen_all_ip_options(oss));
}
} }
if (entry.is_ip) { cond_perms = map_perms(perms);
oss << gen_ip_cond(entry.ip); if (!is_cmd && (label || is_peer))
} else { cond_perms = (AA_CONT_MATCH << 1);
/* encode 0 to indicate there's no ip (ip size) */
oss << "\\x00";
}
oss << "\\-x01"; /* oob separator */ for (auto &oss : streams) {
oss << default_match_pattern; /* label - not used for now */ oss << "\\x00"; /* null transition */
oss << "\\x00"; /* null transition */
buf = oss.str();
/* AA_CONT_MATCH mapping (cond_perms) only applies to perms, not audit */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false;
if (label || is_peer) {
if (!is_peer)
cond_perms = map_perms(perms);
oss << default_match_pattern; /* label - not used for now */
oss << "\\x00"; /* null transition */
buf = oss.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false;
}
}
return true;
} }
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask) { bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol) {
std::ostringstream buffer; std::ostringstream buffer;
std::string buf; std::string buf;
@@ -621,49 +712,87 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
return true; return true;
} }
if (perms & AA_PEER_NET_PERMS) { buf = buffer.str();
gen_ip_conds(buffer, peer, true, false); /* create perms need to be generated excluding the rest of the perms */
if (perms & AA_NET_CREATE) {
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR; if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms & AA_NET_CREATE) : 0,
gen_ip_conds(buffer, local, false, true);
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
} }
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
gen_ip_conds(buffer, local, false, false);
if (perms & AA_NET_LISTEN) { /* encode protocol */
std::ostringstream cmd_buffer; if (protocol > 0xffff) {
cmd_buffer << buffer.str(); buffer << "..";
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN; } else {
/* length of queue allowed - not used for now */ buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((protocol & 0xff00) >> 8);
cmd_buffer << ".."; buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (protocol & 0xff);
buf = cmd_buffer.str(); }
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, if (perms & AA_PEER_NET_PERMS) {
parseopts)) std::list<std::ostringstream> streams;
return false; std::ostringstream cmd_buffer;
cmd_buffer << buffer.str();
streams.push_back(std::move(cmd_buffer));
if (!gen_ip_conds(prof, streams, peer, true, false))
return false;
for (auto &oss : streams) {
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
} }
if (perms & AA_NET_OPT) {
std::ostringstream cmd_buffer; if (!gen_ip_conds(prof, streams, local, false, true))
cmd_buffer << buffer.str(); return false;
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT; }
/* level - not used for now */
cmd_buffer << ".."; std::list<std::ostringstream> streams;
/* socket mapping - not used for now */ std::ostringstream common_buffer;
cmd_buffer << "..";
buf = cmd_buffer.str(); common_buffer << buffer.str();
streams.push_back(std::move(common_buffer));
if (!gen_ip_conds(prof, streams, local, false, false))
return false;
if (perms & AA_NET_LISTEN) {
std::list<std::ostringstream> cmd_streams;
cmd_streams = copy_streams_list(streams);
for (auto &cmd_buffer : streams) {
std::ostringstream listen_buffer;
listen_buffer << cmd_buffer.str();
listen_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
/* length of queue allowed - not used for now */
listen_buffer << "..";
buf = listen_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
} }
} }
if (perms & AA_NET_OPT) {
std::list<std::ostringstream> cmd_streams;
cmd_streams = copy_streams_list(streams);
for (auto &cmd_buffer : streams) {
std::ostringstream opt_buffer;
opt_buffer << cmd_buffer.str();
opt_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
/* level - not used for now */
opt_buffer << "..";
/* socket mapping - not used for now */
opt_buffer << "..";
buf = opt_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false;
}
}
return true; return true;
} }
@@ -679,17 +808,18 @@ int network_rule::gen_policy_re(Profile &prof)
for (const auto& perm : network_perms) { for (const auto& perm : network_perms) {
unsigned int family = perm.first; unsigned int family = perm.first;
unsigned int type = perm.second; unsigned int type = perm.second.first;
unsigned int protocol = perm.second.second;
if (type > 0xffff) { if (type > 0xffff) {
if (!gen_net_rule(prof, family, type)) if (!gen_net_rule(prof, family, type, protocol))
goto fail; goto fail;
} else { } else {
int t; int t;
/* generate rules for types that are set */ /* generate rules for types that are set */
for (t = 0; t < 16; t++) { for (t = 0; t < 16; t++) {
if (type & (1 << t)) { if (type & (1 << t)) {
if (!gen_net_rule(prof, family, t)) if (!gen_net_rule(prof, family, t, protocol))
goto fail; goto fail;
} }
} }
@@ -760,13 +890,27 @@ void network_rule::update_compat_net(void)
} }
} }
static int cmp_network_map(std::unordered_map<unsigned int, perms_t> lhs, static int cmp_ip_conds(ip_conds const &lhs, ip_conds const &rhs)
std::unordered_map<unsigned int, perms_t> rhs) {
int res = null_strcmp(lhs.sip, rhs.sip);
if (res)
return res;
res = null_strcmp(lhs.sport, rhs.sport);
if (res)
return res;
return lhs.is_anonymous - rhs.is_anonymous;
}
static int cmp_network_map(std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> lhs,
std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> rhs)
{ {
int res; int res;
size_t family_index; size_t family_index;
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) { for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
res = lhs[family_index] - rhs[family_index]; res = lhs[family_index].first - rhs[family_index].first;
if (res)
return res;
res = lhs[family_index].second - rhs[family_index].second;
if (res) if (res)
return res; return res;
} }
@@ -779,5 +923,14 @@ int network_rule::cmp(rule_t const &rhs) const
if (res) if (res)
return res; return res;
network_rule const &nrhs = rule_cast<network_rule const &>(rhs); network_rule const &nrhs = rule_cast<network_rule const &>(rhs);
return cmp_network_map(network_perms, nrhs.network_perms); res = cmp_network_map(network_perms, nrhs.network_perms);
if (res)
return res;
res = cmp_ip_conds(local, nrhs.local);
if (res)
return res;
res = cmp_ip_conds(peer, nrhs.peer);
if (res)
return res;
return null_strcmp(label, nrhs.label);
}; };

View File

@@ -26,6 +26,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <list>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@@ -79,6 +80,10 @@
#define CMD_LISTEN 2 #define CMD_LISTEN 2
#define CMD_OPT 4 #define CMD_OPT 4
#define ANON_SIZE 0
#define IPV4_SIZE 1
#define IPV6_SIZE 2
struct network_tuple { struct network_tuple {
const char *family_name; const char *family_name;
unsigned int family; unsigned int family;
@@ -127,6 +132,8 @@ public:
uint16_t port; uint16_t port;
struct ip_address ip; struct ip_address ip;
bool is_anonymous = false;
void free_conds() { void free_conds() {
if (sip) if (sip)
free(sip); free(sip);
@@ -139,10 +146,11 @@ class network_rule: public dedup_perms_rule_t {
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond); void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
public: public:
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map; std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
std::unordered_map<unsigned int, perms_t> network_perms; std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> network_perms;
ip_conds peer; ip_conds peer;
ip_conds local; ip_conds local;
char *label;
bool has_local_conds(void) { return local.sip || local.sport; } bool has_local_conds(void) { return local.sip || local.sport; }
bool has_peer_conds(void) { return peer.sip || peer.sport; } bool has_peer_conds(void) { return peer.sip || peer.sport; }
@@ -178,9 +186,9 @@ public:
} }
}; };
void gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd); bool gen_ip_conds(Profile &prof, std::list<std::ostringstream> &streams, ip_conds &entry, bool is_peer, bool is_cmd);
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask); bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol);
void set_netperm(unsigned int family, unsigned int type); void set_netperm(unsigned int family, unsigned int type, unsigned int protocol);
void update_compat_net(void); void update_compat_net(void);
bool parse_address(ip_conds &entry); bool parse_address(ip_conds &entry);
bool parse_port(ip_conds &entry); bool parse_port(ip_conds &entry);

View File

@@ -921,7 +921,7 @@ void set_supported_features()
"network_v8"); "network_v8");
features_supports_inet = features_intersect(kernel_features, features_supports_inet = features_intersect(kernel_features,
policy_features, policy_features,
"network/af_inet"); "network_v8/af_inet");
features_supports_unix = features_intersect(kernel_features, features_supports_unix = features_intersect(kernel_features,
policy_features, policy_features,
"network/af_unix"); "network/af_unix");

View File

@@ -31,6 +31,10 @@
/{usr/,}lib/@{multiarch}/security/pam_*.so mr, /{usr/,}lib/@{multiarch}/security/pam_*.so mr,
/{usr/,}lib/@{multiarch}/security/ r, /{usr/,}lib/@{multiarch}/security/ r,
# pam_unix
owner /proc/@{pid}/loginuid r,
/{,usr/}{,s}bin/unix_chkpwd Px,
# gssapi # gssapi
@{etc_ro}/gss/mech r, @{etc_ro}/gss/mech r,
@{etc_ro}/gss/mech.d/ r, @{etc_ro}/gss/mech.d/ r,

View File

@@ -13,6 +13,9 @@
abi <abi/4.0>, abi <abi/4.0>,
# Global config of openssl
include <abstractions/openssl>
@{etc_ro}/gcrypt/hwf.deny r, @{etc_ro}/gcrypt/hwf.deny r,
@{etc_ro}/gcrypt/random.conf r, @{etc_ro}/gcrypt/random.conf r,
@{PROC}/sys/crypto/fips_enabled r, @{PROC}/sys/crypto/fips_enabled r,
@@ -24,4 +27,8 @@
/etc/crypto-policies/*/*.txt r, /etc/crypto-policies/*/*.txt r,
/usr/share/crypto-policies/*/*.txt r, /usr/share/crypto-policies/*/*.txt r,
# Global gnutls config
@{etc_ro}/gnutls/config r,
@{etc_ro}/gnutls/pkcs11.conf r,
include if exists <abstractions/crypto.d> include if exists <abstractions/crypto.d>

View File

@@ -50,7 +50,6 @@
include <abstractions/kde-icon-cache-write> include <abstractions/kde-icon-cache-write>
include <abstractions/kde> include <abstractions/kde>
include <abstractions/nameservice> # for IceProcessMessages () from libICE.so (called by libQtCore.so) include <abstractions/nameservice> # for IceProcessMessages () from libICE.so (called by libQtCore.so)
include <abstractions/openssl>
include <abstractions/qt5> include <abstractions/qt5>
include <abstractions/recent-documents-write> include <abstractions/recent-documents-write>
include <abstractions/X> include <abstractions/X>

View File

@@ -4,7 +4,7 @@
abi <abi/4.0>, abi <abi/4.0>,
include <tunables/global> include <tunables/global>
profile firefox /usr/lib/firefox{,-esr}/firefox{,-esr} flags=(unconfined) { profile firefox /usr/lib/firefox{,-esr,-beta,-devedition,-nightly}/firefox{,-esr,-bin} flags=(unconfined) {
userns, userns,
# Site-specific additions and overrides. See local/README for details. # Site-specific additions and overrides. See local/README for details.

12
profiles/apparmor.d/geary Normal file
View 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 geary /usr/bin/geary flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/geary>
}

View 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 goldendict /usr/bin/goldendict flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/goldendict>
}

View 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 kchmviewer /usr/bin/kchmviewer flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/kchmviewer>
}

12
profiles/apparmor.d/loupe Normal file
View 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 loupe /usr/bin/loupe flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/loupe>
}

View 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 notepadqq /{{usr/bin,etc/alternatives}/notepadqq,usr/lib/notepadqq/notepadqq.sh} flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/notepadqq>
}

View 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 pageedit /usr/bin/pageedit flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/pageedit>
}

View File

@@ -11,8 +11,6 @@ profile php-fpm /usr/sbin/php-fpm* flags=(attach_disconnected) {
include <abstractions/nameservice> include <abstractions/nameservice>
# common php files and support files that php needs # common php files and support files that php needs
include <abstractions/php> include <abstractions/php>
# read openssl configuration
include <abstractions/openssl>
# read the system certificates # read the system certificates
include <abstractions/ssl_certs> include <abstractions/ssl_certs>

View 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 privacybrowser /usr/bin/privacybrowser flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/privacybrowser>
}

View 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 qmapshack /usr/bin/qmapshack flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/qmapshack>
}

View 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 qutebrowser /usr/bin/qutebrowser flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/qutebrowser>
}

View 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 rssguard /usr/bin/rssguard flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/rssguard>
}

View File

@@ -6,7 +6,6 @@ profile samba-bgqd /usr/lib*/samba/{,samba/}samba-bgqd {
include <abstractions/base> include <abstractions/base>
include <abstractions/cups-client> include <abstractions/cups-client>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/samba> include <abstractions/samba>
signal receive set=term peer=smbd, signal receive set=term peer=smbd,

View File

@@ -22,7 +22,6 @@ profile syslog-ng /{usr/,}{bin,sbin}/syslog-ng {
include <abstractions/consoles> include <abstractions/consoles>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/mysql> include <abstractions/mysql>
include <abstractions/openssl>
include <abstractions/python> include <abstractions/python>
include <abstractions/hosts_access> include <abstractions/hosts_access>

13
profiles/apparmor.d/scide Normal file
View File

@@ -0,0 +1,13 @@
# 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>
#supercollider-ide
profile scide /usr/bin/scide flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/scide>
}

View File

@@ -0,0 +1,35 @@
# apparmor.d - Full set of apparmor profiles
# Copyright (C) 2019-2021 Mikhail Morfikov
# SPDX-License-Identifier: GPL-2.0-only
# The apparmor.d project comes with several variables and abstractions
# that are not part of upstream AppArmor yet. Therefore this profile was
# adopted to use abstractions and variables that are available.
# Copyright (C) Christian Boltz 2024
abi <abi/4.0>,
include <tunables/global>
profile unix-chkpwd /{,usr/}{,s}bin/unix_chkpwd {
include <abstractions/base>
include <abstractions/nameservice>
# To write records to the kernel auditing log.
capability audit_write,
network netlink raw,
/{,usr/}{,s}bin/unix_chkpwd mr,
/etc/shadow r,
# systemd userdb, used in nspawn
/run/host/userdb/*.user r,
/run/host/userdb/*.user-privileged r,
# file_inherit
owner /dev/tty[0-9]* rw,
include if exists <local/unix-chkpwd>
}

View File

@@ -19,7 +19,6 @@ profile dovecot-auth /usr/lib*/dovecot/auth {
include <abstractions/base> include <abstractions/base>
include <abstractions/mysql> include <abstractions/mysql>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/wutmp> include <abstractions/wutmp>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>

View File

@@ -17,7 +17,6 @@ profile dovecot-dict /usr/lib*/dovecot/dict {
include <abstractions/base> include <abstractions/base>
include <abstractions/mysql> include <abstractions/mysql>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>
capability setuid, capability setuid,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
profile dovecot-imap-login /usr/lib*/dovecot/imap-login { profile dovecot-imap-login /usr/lib*/dovecot/imap-login {
include <abstractions/base> include <abstractions/base>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>
include <abstractions/openssl>
capability setuid, capability setuid,
capability sys_chroot, capability sys_chroot,

View File

@@ -18,7 +18,6 @@ profile dovecot-lmtp /usr/lib*/dovecot/lmtp {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>
include <abstractions/openssl>
include <abstractions/ssl_certs> include <abstractions/ssl_certs>
include <abstractions/ssl_keys> include <abstractions/ssl_keys>

View File

@@ -19,7 +19,6 @@ include <tunables/global>
profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login { profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login {
include <abstractions/base> include <abstractions/base>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>
include <abstractions/openssl>
capability setuid, capability setuid,
capability sys_chroot, capability sys_chroot,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login { profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login {
include <abstractions/base> include <abstractions/base>
include <abstractions/dovecot-common> include <abstractions/dovecot-common>
include <abstractions/openssl>
capability setuid, capability setuid,
capability sys_chroot, capability sys_chroot,

View File

@@ -16,7 +16,6 @@ include <tunables/ntpd>
profile ntpd /usr/{bin,sbin}/{,open}ntpd flags=(attach_disconnected) { profile ntpd /usr/{bin,sbin}/{,open}ntpd flags=(attach_disconnected) {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/ssl_certs> include <abstractions/ssl_certs>
include <abstractions/xad> include <abstractions/xad>

View File

@@ -8,7 +8,6 @@ profile smbd /usr/{bin,sbin}/smbd {
include <abstractions/consoles> include <abstractions/consoles>
include <abstractions/cups-client> include <abstractions/cups-client>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/samba> include <abstractions/samba>
include <abstractions/user-tmp> include <abstractions/user-tmp>
include <abstractions/wutmp> include <abstractions/wutmp>
@@ -50,7 +49,6 @@ profile smbd /usr/{bin,sbin}/smbd {
/usr/share/samba/** r, /usr/share/samba/** r,
/usr/{bin,sbin}/smbd mr, /usr/{bin,sbin}/smbd mr,
/usr/{bin,sbin}/smbldap-useradd Px, /usr/{bin,sbin}/smbldap-useradd Px,
/usr/sbin/unix_chkpwd Px,
/var/cache/samba/** rwk, /var/cache/samba/** rwk,
/var/{cache,lib}/samba/printing/printers.tdb mrw, /var/{cache,lib}/samba/printing/printers.tdb mrw,
/var/lib/nscd/netgroup r, /var/lib/nscd/netgroup r,
@@ -63,8 +61,6 @@ profile smbd /usr/{bin,sbin}/smbd {
@{run}/samba/ncalrpc/** rw, @{run}/samba/ncalrpc/** rw,
/var/spool/samba/** rw, /var/spool/samba/** rw,
owner /proc/@{pid}/loginuid r,
@{HOMEDIRS}/** lrwk, @{HOMEDIRS}/** lrwk,
/var/lib/samba/usershares/{,**} lrwk, /var/lib/samba/usershares/{,**} lrwk,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
profile postfix-proxymap /usr/lib/postfix/{bin/,sbin/,}proxymap { profile postfix-proxymap /usr/lib/postfix/{bin/,sbin/,}proxymap {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/postfix-common> include <abstractions/postfix-common>
/etc/my.cnf r, /etc/my.cnf r,

View File

@@ -18,7 +18,6 @@ profile postfix-smtp /usr/lib/postfix/{bin/,sbin/,}smtp {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/postfix-common> include <abstractions/postfix-common>
include <abstractions/openssl>
capability dac_override, capability dac_override,
capability dac_read_search, capability dac_read_search,

View File

@@ -18,7 +18,6 @@ profile postfix-smtpd /usr/lib/postfix/{bin/,sbin/,}smtpd {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/postfix-common> include <abstractions/postfix-common>
include <abstractions/openssl>
include <abstractions/ssl_certs> include <abstractions/ssl_certs>
include <abstractions/ssl_keys> include <abstractions/ssl_keys>

View File

@@ -17,7 +17,6 @@ include <tunables/global>
profile postfix-tlsmgr /usr/lib/postfix/{bin/,sbin/,}tlsmgr { profile postfix-tlsmgr /usr/lib/postfix/{bin/,sbin/,}tlsmgr {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/postfix-common> include <abstractions/postfix-common>
/usr/lib/postfix/{bin/,sbin/,}tlsmgr mrix, /usr/lib/postfix/{bin/,sbin/,}tlsmgr mrix,

View File

@@ -26,7 +26,6 @@ include <tunables/global>
profile dhclient /{usr/,}sbin/dhclient { profile dhclient /{usr/,}sbin/dhclient {
include <abstractions/base> include <abstractions/base>
include <abstractions/bash> include <abstractions/bash>
include <abstractions/openssl>
include <abstractions/nameservice> include <abstractions/nameservice>
capability net_raw, capability net_raw,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
include <abstractions/base> include <abstractions/base>
include <abstractions/consoles> include <abstractions/consoles>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
capability setgid, capability setgid,
capability setuid, capability setuid,

View File

@@ -13,7 +13,6 @@ include <tunables/global>
profile clamd /usr/sbin/clamd { profile clamd /usr/sbin/clamd {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
capability setgid, capability setgid,
capability setuid, capability setuid,

View File

@@ -13,7 +13,6 @@ include <tunables/global>
profile haproxy /usr/sbin/haproxy { profile haproxy /usr/sbin/haproxy {
include <abstractions/base> include <abstractions/base>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/openssl>
capability net_admin, capability net_admin,
capability net_bind_service, capability net_bind_service,
capability setgid, capability setgid,

View File

@@ -20,7 +20,6 @@ include <tunables/global>
include <abstractions/kerberosclient> include <abstractions/kerberosclient>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/perl> include <abstractions/perl>
include <abstractions/openssl>
capability kill, capability kill,
capability net_bind_service, capability net_bind_service,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/authentication> include <abstractions/authentication>
include <abstractions/user-mail> include <abstractions/user-mail>
include <abstractions/openssl>
/dev/urandom r, /dev/urandom r,
/tmp/* rwl, /tmp/* rwl,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/authentication> include <abstractions/authentication>
include <abstractions/user-mail> include <abstractions/user-mail>
include <abstractions/openssl>
/dev/urandom r , /dev/urandom r ,
/tmp/.* rwl , /tmp/.* rwl ,

View File

@@ -17,7 +17,6 @@ include <tunables/global>
include <abstractions/nameservice> include <abstractions/nameservice>
include <abstractions/authentication> include <abstractions/authentication>
include <abstractions/user-mail> include <abstractions/user-mail>
include <abstractions/openssl>
/dev/urandom r , /dev/urandom r ,
/tmp/.* rwl , /tmp/.* rwl ,

View File

@@ -97,16 +97,20 @@ do_tests "ipv4 udp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remot
generate_profile="genprofile network $sender:px -- image=$sender network" 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" do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)" 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)"
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" do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)" 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 tcp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile" do_tests "ipv4 tcp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)" generate_profile="genprofile network;(connect,receive,send);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 specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile" do_tests "ipv4 udp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)" generate_profile="genprofile network;(connect,receive,send);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 tcp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile" do_tests "ipv4 tcp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
removeprofile removeprofile
@@ -122,10 +126,14 @@ do_tests "ipv6 udp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remot
generate_profile="genprofile network $sender:px -- image=$sender network" 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" do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)" 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)"
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" do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)" 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 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile" do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"

View File

@@ -16,7 +16,7 @@ import re
from apparmor.common import AppArmorBug, AppArmorException 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, RE_PROFILE_PATH_OR_VAR, strip_parenthesis
# from apparmor.rule import AARE from apparmor.rule import AARE
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
from apparmor.translations import init_translation from apparmor.translations import init_translation
@@ -25,7 +25,7 @@ _ = init_translation()
# TODO : # TODO :
# - match correctly AARE on every field # - match correctly AARE on every field
# - Find the actual list of supported filesystems. This one comes from /proc/filesystems # - 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. # - 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. # - 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.
@@ -33,8 +33,10 @@ valid_fs = [
'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs', 'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs',
'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs', 'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs',
'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay', 'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay',
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'resctrl', 'zfs', 'iso9660', 'udf', 'ntfs3',
'nfs', 'cifs',
] ]
flags_keywords = [ flags_keywords = [
# keep in sync with parser/mount.cc mnt_opts_table! # 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', 'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
@@ -43,16 +45,19 @@ flags_keywords = [
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave', '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', 'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser', 'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
'([A-Za-z0-9]|AARE)', # TODO: handle AARE '([A-Za-z0-9])',
] ]
join_valid_flags = '|'.join(flags_keywords) join_valid_flags = '|'.join(flags_keywords)
join_valid_fs = '|'.join(valid_fs) join_valid_fs = '|'.join(valid_fs)
sep = r'\s*[\s,]\s*' sep = r'\s*[\s,]\s*'
# We aim to be a bit more restrictive than \S+ used in regex.py
FS_AARE = r'([][".*@{}\w^-]+)'
fs_type_pattern = r'\b(?P<fstype_or_vfstype>fstype|vfstype)\b\s*(?P<fstype_equals_or_in>=|in)\s*'\ fs_type_pattern = r'\b(?P<fstype_or_vfstype>fstype|vfstype)\b\s*(?P<fstype_equals_or_in>=|in)\s*'\
r'(?P<fstype>\(\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\)|'\ r'(?P<fstype>\(\s*(' + FS_AARE + r')(' + sep + r'(' + FS_AARE + r'))*\s*\)|'\
r'\{\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\}|(\s*' + join_valid_fs + r'))'\ r'\{\s*(' + FS_AARE + r')(' + sep + r'(' + FS_AARE + r'))*\s*\}|(\s*' + FS_AARE + r'))'\
option_pattern = r'\s*(\boption(s?)\b\s*(?P<options_equals_or_in>=|in)\s*'\ option_pattern = r'\s*(\boption(s?)\b\s*(?P<options_equals_or_in>=|in)\s*'\
@@ -63,9 +68,12 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?'
# Source can either be # Source can either be
# - A path : /foo # - A path : /foo
# - A globbed Path : {,/usr}/lib{,32,64,x32}/modules/
# - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar) # - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar)
# - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar) # - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar)
source_fileglob_pattern = r'(\s*' + (RE_PROFILE_PATH_OR_VAR % 'source_file')[:-1] + r'|' + r'\w+' + r'))' # Thus we cannot use directly RE_PROFILE_PATH_OR_VAR
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')' dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')'
RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$') RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$')
@@ -95,8 +103,25 @@ class MountRule(BaseRule):
self.operation = operation 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') 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: if unknown_items:
raise AppArmorException(_('Passed unknown fstype keyword to %s: %s') % (type(self).__name__, ' '.join(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 self.is_fstype_equal = fstype[0] if not self.all_fstype else None
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') 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')
@@ -213,8 +238,15 @@ class MountRule(BaseRule):
return False return False
if self.is_options_equal != other_rule.is_options_equal: if self.is_options_equal != other_rule.is_options_equal:
return False return False
if not self._is_covered_list(self.fstype, self.all_fstype, other_rule.fstype, other_rule.all_fstype, 'fstype'):
return False for o_it in other_rule.fstype or []:
found = False
for s_it in self.fstype or []:
if self._is_covered_aare(AARE(s_it, False), self.all_fstype, AARE(o_it, False), other_rule.all_fstype, 'fstype'):
found = True
if not found:
return False
if not self._is_covered_list(self.options, self.all_options, other_rule.options, other_rule.all_options, 'options'): if not self._is_covered_list(self.options, self.all_options, other_rule.options, other_rule.all_options, 'options'):
return False return False
if not self._is_covered_aare(self.source, self.all_source, other_rule.source, other_rule.all_source, 'source'): if not self._is_covered_aare(self.source, self.all_source, other_rule.source, other_rule.all_source, 'source'):

View File

@@ -140,7 +140,8 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoc
if 'SUDO_USER' in os.environ: if 'SUDO_USER' in os.environ:
username = os.environ.get('SUDO_USER') username = os.environ.get('SUDO_USER')
return_code, output = cmd(['last', '-1', username, '--time-format', 'iso']) return_code, output = cmd(['last', username, '--time-format', 'iso'])
output = output.split('\n')[0] # the first line is enough
# example of output: # example of output:
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout # ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
if output.startswith(username): if output.startswith(username):

View File

@@ -30,7 +30,9 @@ class MountTestParse(AATest):
tests = ( tests = (
# Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment # Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment
('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )), ('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )), ('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.obex*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ("bpf")), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )),
('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )), ('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )), ('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '' )), ('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '' )),
@@ -45,8 +47,8 @@ class MountTestParse(AATest):
('mount fstype in (ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')), ('mount fstype in (ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
('mount fstype in (ext3, ext4) option in (ro, rbind) /a, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', MountRule.ALL, False, False, False, ' #cmt')), ('mount fstype in (ext3, ext4) option in (ro, rbind) /a, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', MountRule.ALL, False, False, False, ' #cmt')),
('mount fstype=(ext3, ext4) option=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')), ('mount fstype=(ext3, ext4) option=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
('mount options=(rw, rbind) /usr/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,', ('mount options=(rw, rbind) {,/usr}/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,',
MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '/usr/lib{,32,64,x32}/modules/', MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '{,/usr}/lib{,32,64,x32}/modules/',
'/tmp/snap.rootfs_*{,/usr}/lib/modules/', '/tmp/snap.rootfs_*{,/usr}/lib/modules/',
False, False, False, '' )), False, False, False, '' )),
('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )), ('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
@@ -207,6 +209,16 @@ class MountIsCoveredTest(AATest):
self.assertTrue(obj.is_covered(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL))) self.assertTrue(obj.is_covered(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
self.assertFalse(obj.is_equal(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL))) self.assertFalse(obj.is_equal(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
def test_is_covered_regex(self):
obj = MountRule('mount', ('=', ('sys*', 'fuse.*')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
tests = [
('mount', ('=', ('sysfs', 'fuse.s3fs')), ('=', ('ro')), 'tmpfs', MountRule.ALL),
('mount', ('=', ('sysfs', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
]
for test in tests:
self.assertTrue(obj.is_covered(MountRule(*test)))
self.assertFalse(obj.is_equal(MountRule(*test)))
def test_is_notcovered(self): def test_is_notcovered(self):
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*') obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
tests = [ tests = [
@@ -231,6 +243,12 @@ class MountIsCoveredTest(AATest):
self.assertFalse(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_covered(MountRule(*test)))
self.assertFalse(obj.is_equal(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test)))
def test_is_not_covered_fs_options(self):
obj = MountRule('mount', MountRule.ALL, ('=', ('ro')), 'tmpfs', MountRule.ALL)
test = ('mount', MountRule.ALL, ('=', ('rw')), 'procfs', MountRule.ALL)
self.assertFalse(obj.is_covered(MountRule(*test)))
self.assertFalse(obj.is_equal(MountRule(*test)))
setup_all_loops(__name__) setup_all_loops(__name__)
if __name__ == '__main__': if __name__ == '__main__':