2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
John Johansen
1d36e1f196 Prepare for AppArmor 4.0 beta4 release
- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 03:21:40 -07:00
John Johansen
22ee6c19bc Merge profiles: disable bwrap and unshare profiles by default
The bwrap and unshare profiles are special profiles in the same
vein as the unconfined profiles but they actual enforce restrictions
on the applications that are launched.

As such they have come to late in the 4.0 dev cycle to consider enabling
by default. Disable them but ship them so users or distros can easily
enable them.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/382
Signed-off-by: John Johansen <john.johansen@canonical.com>

Closes #382
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1206
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 41d4664124)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 00:17:10 -07:00
John Johansen
6198edb3d0 Merge profiles: Add profile for unshare utility
This adds an unshare profile to allow it to function on a system
with user namespace restrictions enabled.

The child task of unshare will enter into a profile without capabilities
thus preventing unshare from being able to be used to
arbitrarily by-pass the user namespace restriction.

This profile does prevent applications launch with privilege (eg.
sudo unshare ...) from functioning so it may break some use cases.

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/1204
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 2d59dc3d9b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 22:45:10 -07:00
John Johansen
4d2a171466 Merge profiles: Add profile for bwrap utility
This adds a bwrap profile to allow it to function on a system with
user namespace restrictions enabled.

The child task of bwrap will enter into a profile without capabilities
thus preventing bwrap from being able to be used to arbitrarily
by-pass user namespace restrictions.

This profile does prevent applications launch with privilege (eg.
sudo bwrap ...) from functioning so it may break some use cases.

Note: The unpriv_bwrap profile is deliberately stacked against the
bwrap profile due to bwraps uses of no-new-privileges.

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/1205
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit b6f2a3d9d2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 22:44:49 -07:00
John Johansen
e88cf3cd02 Merge profiles: adjust unconfined firefox profile to support mozilla.org download
The version of tarball version of firefox downloaded from mozilla.org
installs to /opt/firefox/firefox. Support this location so that the
firefox from the tarball works.

Note this does not support running firefox from the users home directory
in this case the user must update the profile accordingly.

Signed-off-by: John Johansen <john.johansen@canonical.com>

Fixes: https://bugs.launchpad.net/bugs/2056297
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1203
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 2dfe6aeec2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 22:39:58 -07:00
John Johansen
6f856dfee3 Merge profiles/samba*: allow /etc/gnutls/config & @{HOMEDIRS}
# abstractions/samba: allow /etc/gnutls/config

Various samba components want to read it. Without it, shares cannot be accessed.

    apparmor="DENIED" operation="open" class="file" profile="nmbd" name="/etc/gnutls/config" pid=23509 comm="nmbd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="smbd" name="/etc/gnutls/config" pid=23508 comm="smbd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24037 comm="rpcd_fsrvp" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24036 comm="rpcd_epmapper" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24038 comm="rpcd_lsad" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24041 comm="rpcd_winreg" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24039 comm="rpcd_mdssvc" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-spoolss" name="/etc/gnutls/config" pid=24040 comm="rpcd_spoolss" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-classic" name="/etc/gnutls/config" pid=24035 comm="rpcd_classic" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

# profiles/apparmor.d/samba-rpcd-classic: allow @{HOMEDIRS}

Give access to @{HOMEDIRS}, just like in usr.sbin.smbd, so that
usershares in /home/ can be accessed.

    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-classic" name="/home/user/path/to/usershare/" pid=4781 comm="rpcd_classic" requested_mask="r" denied_mask="r" fsuid=0 ouid=1000

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/379
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1200
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 5998a0021a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 14:15:52 -07:00
John Johansen
a6d8171bd6 Merge parser: fix getattr and setattr perm mapping on mqueue rules
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/377
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/378
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1197
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 88ec709aac)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:32:32 -07:00
John Johansen
26e7249f44 Merge tests: fix inet tests
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/376
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1192
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 01fcce41dc)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:30:59 -07:00
John Johansen
117d0cc444 Merge usr.sbin.sshd: Add new permissions needed on Ubuntu 24.04
Testing on noble turned these up:

`2024-03-27T00:10:28.929314-04:00 image-ubuntu64 kernel: audit: type=1400 audit(1711512628.920:155): apparmor="DENIED" operation="bind" class="net" profile="/usr/sbin/sshd" pid=1290 comm="sshd" family="unix" sock_type="stream" protocol=0 requested_mask="bind" denied_mask="bind" addr="@63cf34db7fbab75f/bus/sshd/system"`

`2024-03-27T00:41:09.791826-04:00 image-ubuntu64 kernel: audit: type=1107 audit(1711514469.771:333907): pid=703 uid=101 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager" member="CreateSessionWithPIDFD" mask="send" name="org.freedesktop.login1" pid=4528 label="/usr/sbin/sshd" peer_pid=688 peer_label="unconfined"`

Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2060100
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1196
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3aa40249cf)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:29:31 -07:00
Georgia Garcia
1c7127d30d Merge utils: allow mount destination globbing
The abstraction lxc/start-container shipped by the liblxc-common
package uses the following mount rule which was not allowed by our
regexes:

  mount options=(rw, make-slave) -> **,
  mount options=(rw, make-rslave) -> **,

Since in AppArmor regex ** includes '/' but * by itself doesn't, I'm
adding explicit support for **.

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

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/381
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1195
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit e96fdc0f5b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:23:43 -07:00
Christian Boltz
d111ddcc21 Merge firefox: allow locking of *.sqlite-shm files in user cache area
Noticed a bunch of these after a Firefox 124.0 upgrade:

`Mar 25 22:08:27 darkstar kernel: [598271.991739] audit: type=1400 audit(1711418907.493:27323): apparmor="DENIED" operation="file_lock" profile="firefox" name="/home/username/.cache/mozilla/firefox/deadbeef.default/suggest.sqlite-shm" pid=2855447 comm=4267494F5468727E6F6C2023333530 requested_mask="k" denied_mask="k" fsuid=1000 ouid=1000`

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/380
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1193
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 14572d9581)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:18:24 -07:00
John Johansen
fa26623e6d Merge Move pam-related permissions to abstractions/authentication
... instead of keeping them in the smbd profile.

For details, see c09f58a364 and
https://bugzilla.opensuse.org/show_bug.cgi?id=1220032#c12

Also replace /usr/etc/ with @{etc_ro} to that also /etc/ is covered.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1220032#c12
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1191
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit f334884787)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-03 02:14:16 -07:00
John Johansen
451bb8b235 Merge profiles: add unconfined profile for tuxedo-control-center
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2046844
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1187
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-18 23:29:01 +00:00
John Johansen
6e46631b6f Merge parser: fix issues appointed by coverity
Fix issues introduced in coverity's snapshots 75887, 70858 and 75429.
- CID 353483: Uninitialized pointer field (UNINIT_CTOR)
- CID 349572: Unsigned compared against 0 (NO_EFFECT)

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1188
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-03-18 23:27:59 +00:00
Georgia Garcia
f9527d2113 parser: fix issues appointed by coverity
Fix issues introduced in coverity's snapshots 75887, 70858 and 75429.
- CID 353483: Uninitialized pointer field (UNINIT_CTOR)
- CID 349572: Unsigned compared against 0 (NO_EFFECT)

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-18 10:36:56 -03:00
Georgia Garcia
9dc2f48773 profiles: add unconfined profile for tuxedo-control-center
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2046844
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-18 09:17:51 -03:00
32 changed files with 454 additions and 285 deletions

4
.gitignore vendored
View File

@@ -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

View File

@@ -1 +1 @@
4.0.0~beta3
4.0.0~beta4

View File

@@ -29,8 +29,6 @@
class all_rule: public prefix_rule_t {
void move_conditionals(struct cond_entry *conds);
public:
char *label;
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
virtual bool valid_prefix(const prefixes &p, const char *&error) {

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -344,8 +344,8 @@ bool parse_port_number(const char *port_entry, uint16_t *port) {
char *eptr;
unsigned long port_tmp = strtoul(port_entry, &eptr, 10);
if (port_tmp >= 0 && port_entry != eptr &&
*eptr == '\0' && port_tmp <= UINT16_MAX) {
if (port_entry != eptr && *eptr == '\0' &&
port_tmp <= UINT16_MAX) {
*port = port_tmp;
return true;
}

View File

@@ -157,7 +157,7 @@ public:
/* empty constructor used only for the profile to access
* static elements to maintain compatibility with
* AA_CLASS_NET */
network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8) { }
network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL) { }
network_rule(perms_t perms_p, struct cond_entry *conds,
struct cond_entry *peer_conds);
network_rule(perms_t perms_p, const char *family, const char *type,

View 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 -> **,
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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.

View File

@@ -19,6 +19,8 @@ profile samba-rpcd-classic /usr/lib*/samba/{,samba/}rpcd_classic {
/usr/lib*/samba/{,samba/}rpcd_classic mr,
@{HOMEDIRS}/** lrwk,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/samba-rpcd-classic>
}

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

View File

@@ -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,

View 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) {
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) {
# 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>
}

View File

@@ -241,7 +241,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,

View 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,
}
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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,7 +96,7 @@ 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"
setsockopt_rules="network;(setopt,getopt);ip=0.0.0.0;port=0" # INADDR_ANY
rcv_rules="network;ip=$bind_ipv4;peer=(ip=anon)"
snd_rules="network;ip=$remote_ipv4;peer=(ip=anon)"
@@ -126,7 +125,7 @@ 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"
setsockopt_rules="network;(setopt,getopt);ip=::0;port=0" # IN6ADDR_ANY_INIT
rcv_rules="network;ip=$bind_ipv6;peer=(ip=anon)"
snd_rules="network;ip=$remote_ipv6;peer=(ip=anon)"
@@ -135,5 +134,3 @@ do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $
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"

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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,11 +88,11 @@ 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
@@ -102,46 +104,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 +152,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

View File

@@ -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;
}

View File

@@ -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");

View File

@@ -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)
{

View File

@@ -6,7 +6,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "userns.h"
#include "pipe_helper.h"
int main(int argc, char *argv[])
{

View File

@@ -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
from apparmor.rule import AARE
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
@@ -34,7 +34,7 @@ valid_fs = [
'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',
'nfs', 'cifs', 'overlayfs', 'aufs', 'rpc_pipefs', 'msdos', 'nfs4',
]
flags_keywords = [
@@ -72,9 +72,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'$')
@@ -142,7 +146,7 @@ class MountRule(BaseRule):
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}')
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=True, log_event=log_event)
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=False, log_event=log_event)
self.can_glob = not self.all_source and not self.all_dest and not self.all_options

View File

@@ -29,6 +29,8 @@ class MountTestParse(AATest):
tests = (
# Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment
('mount -> **,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '**', False, False, False, '' )),
('mount options=(rw, shared) -> **,', MountRule('mount', MountRule.ALL, ('=', ('rw', 'shared')), MountRule.ALL, '**', 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=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, '' )),