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

Compare commits

..

57 Commits

Author SHA1 Message Date
John Johansen
b0eb95457b Prepare for AppArmor 4.0.1 release
AppArmor 4.0.1 will be the official release superseding the 4.0.0 tag
the only change being it adds a regression test for CVE-2016-1585

- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:59:30 -07:00
John Johansen
5ad4efec50 Merge regression tests: add mount test for CVE-2016-1585
Add infrastructure for calling the mount test binary with an fstype
instead of using the default hardcoded ext2 type, and then use that in a
test that exercises CVE-2016-1585, ensuring that mounting a procfs
filesystem isn't permitted when the only mount rule is

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

to try to ensure that the generated and enforced policy is restricted to
what is intended.

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1597017

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1211
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 93c4c6fb9f)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:58:31 -07:00
John Johansen
a635a86e1d Prepare for AppArmor 4.0 release
- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:55:33 -07:00
John Johansen
c8e25e4689 Merge parser: add network inet mediation documentation to apparmor.d
This updates the man page for the recent inet mediation patch.

This is an extension of MR 1202, it adds a patch that changes the anonymous ip address anon to be ip address none which is a better fit.

This patch adds documentation of the recent network changes which extended all network rules to support access permissions, and added address and port matching for inet and inet6 families.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1213
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit ab9e6311f3)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:54:23 -07:00
John Johansen
68dd052873 Merge parser: inet conditionals should only generate rules for inet family
When a family is specified in the network rules, we have to make sure
the conditionals match the family. A netlink rule should not be able
to specify ip and port for local and remote (peer) sockets, for example.

When type or protocol is specified in network rules along with inet
conditionals, we should only generate rules for the families that
support those conditionals.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/384
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

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

(cherry picked from commit a0acf7785d)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:53:41 -07:00
John Johansen
4cef932170 Merge profiles: add unconfined wike profile
Wike (deb package/compiled version) does not run in Ubuntu 24.04
due to some interference between apparmor and webkit.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1212
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3c43c314dc)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:53:30 -07:00
John Johansen
8108a217a3 Merge profiles: add unconfined foliate profile
Foliate is using user namespaces via bwrap. For now add an unconfined
profile to support it.

Fixes: https://github.com/johnfactotum/foliate/issues/1271
Fixes: https://bugs.launchpad.net/bugs/2060767
Signed-off-by: John Johansen <john.johansen@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1209
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 0aa689dbf7)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:53:10 -07:00
John Johansen
2284e99613 Merge Updates to the chromium_browser profile
This is a retargeting of [my MR in apparmor-profiles](https://gitlab.com/apparmor/apparmor-profiles/-/merge_requests/58).

The most significant change is the addition of a `crashpad_handler` subprofile, to factor out some permissions that the browser proper does not need. The remainder is mostly updates from my normal usage monitoring.

I have recorded below examples of the AppArmor log messages that motivated the updates. They are listed in the order in which they appear in the overall diff:

#### +abstractions/fonts
`Jun 30 16:45:42 testvm kernel: [ 4956.877581] audit: type=1400 audit(1688157942.647:127): apparmor="DENIED" operation="mknod" profile="chromium_browser" name="/home/username/.cache/fontconfig/af531e44-9f34-43fa-a244-e0ea9a6dc5f1-le64.cache-7.TMP-VbjHEy" pid=2136 comm="chromium" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000`

#### +abstractions/mesa
`May 30 21:08:36 testvm kernel: [ 9893.605107] audit: type=1400 audit(1685495316.380:1708): apparmor="ALLOWED" operation="file_lock" profile="chromium_browser" name="/home/username/.cache/mesa_shader_cache/6b/ce9f90908044cb4d4dabc34d81bf24b2fbda0a.tmp" pid=5879 comm="chromiu:disk$0" requested_mask="k" denied_mask="k" fsuid=1000 ouid=1000`

#### +abstractions/vulcan
`May 30 22:35:36 testvm kernel: [1544761.278181] audit: type=1400 audit(1685500536.387:22272): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt_min_freq_mhz" pid=963194 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### -deny dbus path=/org/freedesktop/hostname1
`Jun 13 19:16:35 image-ubuntu64 kernel: [78978.711877] audit: type=1107 audit(1686698195.982:2339): pid=540 uid=102 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/hostname1" interface="org.freedesktop.DBus.Properties" member="GetAll" mask="send" name=":1.369" pid=17766 label="chromium_browser" peer_pid=17975 peer_label="unconfined"`

#### +dbus path=/org/freedesktop/login1
`Jun 12 21:45:36 testvm kernel: [ 1518.318643] audit: type=1107 audit(1686620736.127:67): pid=540 uid=102 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal"  bus="system" path="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager" member="SessionNew" name=":1.1" mask="receive" pid=3378 label="chromium_browser" peer_pid=565 peer_label="unconfined"`

`Jun 12 21:40:03 testvm kernel: [ 1185.247117] audit: type=1107 audit(1686620403.059:66): pid=540 uid=102 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal"  bus="system" path="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager" member="SessionRemoved" name=":1.1" mask="receive" pid=3378 label="chromium_browser" peer_pid=565 peer_label="unconfined"`

#### +dbus path=/org/freedesktop/DBus
`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="AddMatch" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="GetNameOwner" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="Hello" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="NameHasOwner" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="RemoveMatch" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

`Jun  2 00:02:39 image-ubuntu64 dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="StartServiceByName" mask="send" name="org.freedesktop.DBus" pid=34637 label="chromium_browser" peer_label="unconfined"`

#### +dbus path=/org/freedesktop/portal/desktop
`Jun  2 00:02:39 testvm dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/portal/desktop" interface="org.freedesktop.DBus.Properties" member="Get" mask="send" name="org.freedesktop.portal.Desktop" pid=34637 label="chromium_browser" peer_pid=10595 peer_label="unconfined"`

#### +dbus path=/org/freedesktop/Notifications
`Jun  2 00:02:39 testvm dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/Notifications" interface="org.freedesktop.Notifications" member="GetCapabilities" mask="send" name="org.freedesktop.Notifications" pid=34637 label="chromium_browser" peer_pid=10438 peer_label="unconfined"`

`Jun  2 00:02:39 testvm dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/Notifications" interface="org.freedesktop.Notifications" member="GetServerInformation" mask="send" name="org.freedesktop.Notifications" pid=34637 label="chromium_browser" peer_pid=10438 peer_label="unconfined"`

#### +dbus path=/org/gtk/vfs/mounttracker
`Jun  2 00:02:39 testvm dbus-daemon[10113]: apparmor="ALLOWED" operation="dbus_method_call"  bus="session" path="/org/gtk/vfs/mounttracker" interface="org.gtk.vfs.MountTracker" member="ListMountableInfo" mask="send" name=":1.9" pid=34637 label="chromium_browser" peer_pid=10331 peer_label="unconfined"`

#### +/etc/fstab
`Jun 19 00:12:34 testvm kernel: [3192175.541293] audit: type=1400 audit(1687147954.193:127452): apparmor="DENIED" operation="open" profile="chromium_browser" name="/etc/fstab" pid=1541844 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0`

#### +~/.cache/thumbnails
`Jun 28 14:31:34 testvm kernel: [4021314.484388] audit: type=1400 audit(1687977094.903:128621): apparmor="DENIED" operation="open" profile="chromium_browser" name="/home/username/.cache/thumbnails/normal/5ff3c24d6d3b35a6ea92e12c71c487f9.png" pid=1781421 comm="pool-chromium" requested_mask="r" denied_mask="r" fsuid=1002 ouid=1002`

`Jun 28 14:31:34 testvm kernel: [4021314.484975] audit: type=1400 audit(1687977094.903:128622): apparmor="DENIED" operation="open" profile="chromium_browser" name="/home/username/.cache/thumbnails/normal/5ff3c24d6d3b35a6ea92e12c71c487f9.png" pid=1781421 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1002 ouid=1002`

#### -/proc/$PID/fd/
This rule appears to have been used by the crash handler, so I've moved it to the new `crashpad_handler` subprofile. I have not observed the normal browser process(es) attempting this access.

#### +/proc/pressure/{cpu,io,memory}
`May 30 22:44:26 testvm kernel: [1545291.245886] audit: type=1400 audit(1685501066.352:22355): apparmor="DENIED" operation="open" profile="chromium_browser" name="/proc/pressure/cpu" pid=741817 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0`

`May 30 22:44:26 testvm kernel: [1545291.245903] audit: type=1400 audit(1685501066.352:22356): apparmor="DENIED" operation="open" profile="chromium_browser" name="/proc/pressure/io" pid=741817 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0`

`May 30 22:44:26 testvm kernel: [1545291.245912] audit: type=1400 audit(1685501066.352:22357): apparmor="DENIED" operation="open" profile="chromium_browser" name="/proc/pressure/memory" pid=741817 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1002 ouid=0`

#### +/proc/$PID/clear_refs
`May 30 18:32:55 testvm kernel: [  552.316554] audit: type=1400 audit(1685485975.161:305): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/proc/1950/clear_refs" pid=1950 comm="MemoryInfra" requested_mask="w" denied_mask="w" fsuid=1000 ouid=1000`

#### +/proc/$PID/mountinfo
`Jun 19 00:12:34 testvm kernel: [3192175.541221] audit: type=1400 audit(1687147954.193:127451): apparmor="DENIED" operation="open" profile="chromium_browser" name="/proc/1541844/mountinfo" pid=1541844 comm="gmain" requested_mask="r" denied_mask="r" fsuid=1002 ouid=1002`

#### +/proc/sys/fs/inotify/max_user_watches
`May 30 18:32:26 testvm kernel: [  523.274479] audit: type=1400 audit(1685485946.109:288): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/proc/sys/fs/inotify/max_user_watches" pid=1972 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### +/sys/devices/system/cpu/{kernel_max,possible,present}
`May 30 18:32:26 testvm kernel: [  523.287063] audit: type=1400 audit(1685485946.125:290): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/sys/devices/system/cpu/kernel_max" pid=1971 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`May 30 18:32:26 testvm kernel: [  523.287107] audit: type=1400 audit(1685485946.125:291): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/sys/devices/system/cpu/possible" pid=1971 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`May 30 18:32:26 testvm kernel: [  523.287607] audit: type=1400 audit(1685485946.125:297): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/sys/devices/system/cpu/present" pid=1972 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### +/sys/devices/pci[0-9]*/**/{bConfigurationValue,boot_vga,busnum}
`2023-07-03T04:40:49.955727-04:00 testsys kernel: [28353.647821] audit: type=1400 audit(1688373649.948:152): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/bConfigurationValue" pid=5585 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`Jul  4 00:10:52 testvm kernel: [  405.584960] audit: type=1400 audit(1688443852.472:148): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:02.0/boot_vga" pid=2057 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`2023-07-03T04:40:49.955731-04:00 testsys kernel: [28353.647923] audit: type=1400 audit(1688373649.948:153): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/busnum" pid=5585 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### +/sys/devices/pci[0-9]*/**/{descriptors,devnum}
`2023-07-02T21:29:22.067669-04:00 testsys kernel: [ 2465.760458] audit: type=1400 audit(1688347762.063:71): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.0/usb2/descriptors" pid=2276 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`2023-07-02T21:29:22.071708-04:00 testsys kernel: [ 2465.762364] audit: type=1400 audit(1688347762.067:75): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/descriptors" pid=2276 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`2023-07-02T21:29:22.071721-04:00 testsys kernel: [ 2465.763437] audit: type=1400 audit(1688347762.067:78): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-6/1-6.3/descriptors" pid=2276 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`2023-07-03T04:40:49.955736-04:00 testsys kernel: [28353.648042] audit: type=1400 audit(1688373649.948:154): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/devnum" pid=5585 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### +/sys/devices/pci[0-9]*/**/{manufacturer,product}
`2023-07-03T04:40:49.955694-04:00 testsys kernel: [28353.647497] audit: type=1400 audit(1688373649.948:150): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/manufacturer" pid=5585 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`2023-07-03T04:40:49.955721-04:00 testsys kernel: [28353.647661] audit: type=1400 audit(1688373649.948:151): apparmor="DENIED" operation="open" profile="chromium_browser" name="/sys/devices/pci0000:00/0000:00:1d.3/usb5/5-2/product" pid=5585 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### +/sys/devices/pci[0-9]*/**/serial
(lost the log entry for this one)

#### +deny /sys/devices/virtual/dmi/id/*
`May 30 18:38:58 testvm kernel: [  915.363204] audit: type=1400 audit(1685486338.202:390): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/sys/devices/virtual/dmi/id/sys_vendor" pid=2158 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

`May 30 18:38:58 testvm kernel: [  915.363521] audit: type=1400 audit(1685486338.202:391): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/sys/devices/virtual/dmi/id/product_name" pid=2158 comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

These sysfs paths yield the make and model of your system, so their access is questionable from a privacy perspective.

#### +{dev,var/run} in shm paths
Can't be replaced with `@{run}` as this does not include `/dev`.

#### +ptrace (read)
`May 31 04:47:35 testvm kernel: [1567080.438164] audit: type=1400 audit(1685522855.581:124669): apparmor="DENIED" operation="ptrace" profile="chromium_browser" pid=1145702 comm="ThreadPoolForeg" requested_mask="read" denied_mask="read" peer="chromium_browser//xdgsettings"`

Figured I'd add read access proactively to `lsb_release` as well. Holding back on adding it to self for now.

#### /etc/@{chromium}/policies/** -> /etc/@{chromium}/**
`May 30 21:25:44 testvm kernel: [10922.020981] audit: type=1400 audit(1685496344.792:2031): apparmor="ALLOWED" operation="open" profile="chromium_browser" name="/etc/chromium/master_preferences" pid=6465 comm="chromium" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0`

#### Note: "~/.pki/... denied by private-files abstraction"
`May 30 21:29:13 testvm kernel: [11130.436441] audit: type=1400 audit(1685496553.206:2105): apparmor="ALLOWED" operation="mkdir" profile="chromium_browser" name="/home/username/.pki/" pid=7344 comm="ThreadPoolForeg" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000`

`May 30 21:29:13 testvm kernel: [11130.437992] audit: type=1400 audit(1685496553.206:2106): apparmor="ALLOWED" operation="mkdir" profile="chromium_browser" name="/home/username/.pki/nssdb/" pid=7344 comm="ThreadPoolForeg" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000`

Something else will need to create these directories.

#### +Widevine
`May 31 04:46:52 testvm kernel: [1567036.849155] audit: type=1400 audit(1685522811.993:124665): apparmor="DENIED" operation="file_mmap" profile="chromium_browser" name="/home/username/.config/chromium/WidevineCdm/4.10.2557.0/_platform_specific/linux_x64/libwidevinecdm.so" pid=1145723 comm="chromium" requested_mask="m" denied_mask="m" fsuid=1002 ouid=1002`

#### +GVfs
`Jun 13 19:16:35 testvm kernel: [78978.537455] audit: type=1400 audit(1686698195.810:2337): apparmor="DENIED" operation="connect" profile="chromium_browser" name="/run/user/1000/gvfsd/socket-EpT3MyPP" pid=17766 comm="chromium" requested_mask="wr" denied_mask="wr" fsuid=1000 ouid=1000`

#### +/lib/libc.so
`May 30 18:02:25 testvm kernel: [  868.340300] audit: type=1400 audit(1685484145.031:80): apparmor="ALLOWED" operation="open" profile="chromium_browser//chromium_browser_sandbox" name="/lib/x86_64-linux-gnu/libc.so.6" pid=2405 comm="chrome-sandbox" requested_mask="r" denied_mask="r" fsuid=0 ouid=0`

`May 30 18:02:25 testvm kernel: [  868.340363] audit: type=1400 audit(1685484145.031:81): apparmor="ALLOWED" operation="file_mmap" profile="chromium_browser//chromium_browser_sandbox" name="/lib/x86_64-linux-gnu/libc.so.6" pid=2405 comm="chrome-sandbox" requested_mask="rm" denied_mask="rm" fsuid=0 ouid=0`

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1208
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit a1afe3265c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:52:32 -07:00
John Johansen
f763c44cd0 Merge Add profiles for the Transmission family of Bittorrent clients
This covers the various forms of the Transmission BT client. I've tested the `-gtk` one most thoroughly, and run through an ISO download with each of the other three.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1190
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 30a45ba82f)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:51:32 -07:00
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
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
86 changed files with 1499 additions and 466 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~beta2
4.0.1

View File

@@ -93,7 +93,7 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
fi
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])
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]

View File

@@ -440,7 +440,6 @@ install-arch: $(INSTALLDEPS)
install-indep: indep
install -m 755 -d $(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 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
install -m 755 profile-load $(APPARMOR_BIN_PREFIX)

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

@@ -148,7 +148,14 @@ B<CAPABILITY LIST> = ( I<CAPABILITY> )+
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
capabilities(7))
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<NETWORK ACCESS EXPR> ] [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ] [ I<NETWORK LOCAL EXPR> ] [ I<NETWORK PEER EXPR> ]
B<NETWORK ACCESS EXPR> = ( I<NETWORK ACCESS> | I<NETWORK ACCESS LIST> )
B<NETWORK ACCESS> = ( 'create' | 'bind' | 'listen' | 'accept' | 'connect' | 'shutdown' | 'getattr' | 'setattr' | 'getopt' | 'setopt' | 'send' | 'receive' | 'r' | 'w' | 'rw' )
Some access modes are incompatible with some rules.
B<NETWORK ACCESS LIST> = '(' I<NETWORK ACCESS> ( [','] I<NETWORK ACCESS> )* ')'
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | 'mctp' ) ','
@@ -156,6 +163,22 @@ B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
B<PROTOCOL> = ( 'tcp' | 'udp' | 'icmp' )
B<NETWORK LOCAL EXPR> = ( I<NETWORK IP COND> | I<NETWORK PORT COND> )*
Each cond can appear at most once.
B<NETWORK PEER EXPR> = 'peer' '=' '(' ( I<NETWORK IP COND> | I<NETWORK PORT COND> )+ ')'
Each cond can appear at most once.
B<NETWORK IP COND> = 'ip' '=' ( 'none' | I<NETWORK IPV4> | I<NETWORK IPV6> )
B<NETWORK PORT COND> = 'port' '=' ( I<NETWORK PORT> )
B<NETWORK IPV4> = IPv4, represented by four 8-bit decimal numbers separated by '.'
B<NETWORK IPV6> = IPv6, represented by eight groups of four hexadecimal numbers separated by ':'. Shortened representation of contiguous zeros is allowed by using '::'
B<NETWORK PORT> = 16-bit number ranging from 0 to 65535
B<MOUNT RULE> = ( I<MOUNT> | I<REMOUNT> | I<UMOUNT> )
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ '-E<gt>' [ I<MOUNTPOINT FILEGLOB> ]
@@ -912,11 +935,10 @@ and other operations that are typically reserved for the root user.
=head2 Network Rules
AppArmor supports simple coarse grained network mediation. The network
rule restrict all socket(2) based operations. The mediation done is
a coarse-grained check on whether a socket of a given type and family
can be created, read, or written. There is no mediation based of port
number or protocol beyond tcp, udp, and raw. Network netlink(7) rules may
AppArmor supports simple coarse grained network mediation. The
network rule restrict all socket(2) based operations. The mediation
done is a coarse-grained check on whether a socket of a given type and
family can be created, read, or written. Network netlink(7) rules may
only specify type 'dgram' and 'raw'.
AppArmor network rules are accumulated so that the granted network
@@ -933,6 +955,48 @@ eg.
network inet6 tcp, #allow access to tcp only for inet6 addresses
network netlink raw, #allow access to AF_NETLINK SOCK_RAW
=head3 Network permissions
Network rule permissions are implied when a rule does not explicitly
state an access list. By default if a rule does not have an access
list all permissions that are compatible with the specified set of
local and peer conditionals are implied.
The create, bind, listen, shutdown, getattr, setattr, getopt, and
setopt permissions are local socket permissions. They are only applied
to the local socket and can't be specified in rules that have a peer
conditional. The accept permission applies to the combination of a
local and peer socket. The connect, send, and receive permissions are
peer socket permissions.
=head3 Mediation of inet/inet6 family
AppArmor supports fine grained mediation of the inet and inet6
families by using the ip and port conditionals. The ip conditional
accepts both IPv4 and IPv6 using the regular representation of four
octets separated by '.' for IPv4 and eight groups of four hexadecimal
numbers separated by ':' for IPv6. Contiguous leading zeros can be
replaced by '::' once. On a connected socket, the sender and receiver
don't need to be specified in the recvfrom and sendto system calls. In
that case, and with unbounded sockets, the IP address is none, or
unknown. Unknown or Unbound IP addresses are represented in policy by the
'none' keyword. When the ip conditional is omitted, then all IP
addresses will be allowed: IPv4, IPv6 and none. If INADDR_ANY or
in6addr_any is used, then the ip conditional can be omitted or they
can be represented by:
network ip=::, #allow in6addr_any
network ip=0.0.0.0; #allow INADDR_ANY
The network rules support the specification of local and remote IP
addresses and ports.
network ip=127.0.0.1 port=8080,
network peer=(ip=10.139.15.23 port=8081),
network ip=fd74:1820:b03a:b361::cf32 peer=(ip=fd74:1820:b03a:b361::a0f9),
network port=8080 peer=(port=8081),
network ip=127.0.0.1 port=8080 peer=(ip=10.139.15.23 port=8081),
=head2 Mount Rules
AppArmor supports mount mediation and allows specifying filesystem types and

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

@@ -252,6 +252,19 @@ const char *net_find_af_name(unsigned int af)
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 char *family,
const char *type,
@@ -331,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;
}
@@ -347,6 +360,10 @@ bool network_rule::parse_port(ip_conds &entry)
bool network_rule::parse_address(ip_conds &entry)
{
if (strcmp(entry.sip, "none") == 0) {
entry.is_none = true;
return true;
}
entry.is_ip = true;
return parse_ip(entry.sip, &entry.ip);
}
@@ -374,30 +391,45 @@ 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) {
/* setting mask instead of a bit */
network_perms[family] |= type;
network_perms[family].first |= type;
} 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,
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;
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
set_netperm(family_index, 0xFFFFFFFF);
}
size_t family_index, i;
move_conditionals(conds, local);
move_conditionals(peer_conds, peer);
free_cond_list(conds);
free_cond_list(peer_conds);
if (has_local_conds() || has_peer_conds()) {
const char *family[] = { "inet", "inet6" };
for (i = 0; i < sizeof(family)/sizeof(family[0]); i++) {
const struct network_tuple *mapping = NULL;
while ((mapping = net_find_mapping(mapping, family[i], NULL, NULL))) {
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type, mapping->protocol);
}
}
} else {
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
set_netperm(family_index, 0xFFFFFFFF, 0xFFFFFFFF);
}
}
if (perms_p) {
perms = perms_p;
if (perms & ~AA_VALID_NET_PERMS)
@@ -412,29 +444,45 @@ 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,
const char *protocol, struct cond_entry *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;
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type);
}
if (type == NULL && network_map.empty()) {
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type);
}
}
if (network_map.empty())
yyerror(_("Invalid network entry."));
move_conditionals(conds, local);
move_conditionals(peer_conds, peer);
free_cond_list(conds);
free_cond_list(peer_conds);
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
/* if inet conds and family are specified, fail if
* family is not af_inet or af_inet6
*/
if ((has_local_conds() || has_peer_conds()) &&
mapping->family != AF_INET && mapping->family != AF_INET6) {
yyerror("network family does not support local or peer conditionals\n");
}
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type, mapping->protocol);
}
if (type == NULL && network_map.empty()) {
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
/* if inet conds and type/protocol are
* specified, only add rules for af_inet and
* af_inet6
*/
if ((has_local_conds() || has_peer_conds()) &&
mapping->family != AF_INET && mapping->family != AF_INET6)
continue;
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
set_netperm(mapping->family, mapping->type, mapping->protocol);
}
}
if (network_map.empty())
yyerror(_("Invalid network entry."));
if (perms_p) {
perms = perms_p;
if (perms & ~AA_VALID_NET_PERMS)
@@ -447,10 +495,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):
dedup_perms_rule_t(AA_CLASS_NETV8)
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
{
network_map[family].push_back({ family, type, 0xFFFFFFFF });
set_netperm(family, type);
set_netperm(family, type, 0xFFFFFFFF);
if (perms_p) {
perms = perms_p;
@@ -479,7 +527,8 @@ ostream &network_rule::dump(ostream &os)
for (const auto& perm : network_perms) {
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);
if (family_name)
@@ -507,6 +556,12 @@ ostream &network_rule::dump(ostream &os)
os << " #" << std::hex << (type & mask);
printf(" }");
const char *protocol_name = net_find_protocol_name(protocol);
if (protocol_name)
os << " " << protocol_name;
else
os << " #" << protocol;
}
os << ",\n";
@@ -531,14 +586,14 @@ std::string gen_ip_cond(const struct ip_address ip)
int i;
if (ip.family == AF_INET) {
/* 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 */
for (i = 0; i < 4; i++)
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
} else {
/* 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)
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
}
@@ -557,48 +612,114 @@ std::string gen_port_cond(uint16_t port)
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 none, ipv4, ipv6;
int i;
none << oss.str();
ipv4 << oss.str();
ipv6 << oss.str();
none << "\\x" << std::setfill('0') << std::setw(2) << std::hex << NONE_SIZE;
/* add a byte containing the size of the following ip */
ipv4 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
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(none));
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 */
if (!is_cmd) {
if (entry.is_ip) {
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((entry.ip.family & 0xff00) >> 8);
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (entry.ip.family & 0xff);
std::list<std::ostringstream> streams_copy;
for (auto &oss : streams) {
std::ostringstream oss_copy(oss.str());
streams_copy.push_back(std::move(oss_copy));
}
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_none)) {
/* 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 {
oss << "..";
/* port type + port number */
oss << "...";
}
}
if (entry.is_port) {
/* 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";
ip_streams = std::move(streams);
streams.clear();
oss << gen_port_cond(entry.port);
} else {
/* port type + port number */
if (!is_cmd)
oss << ".";
oss << "..";
for (auto &oss : ip_streams) {
if (entry.is_ip) {
oss << gen_ip_cond(entry.ip);
streams.push_back(std::move(oss));
} else if (entry.is_none) {
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << NONE_SIZE;
streams.push_back(std::move(oss));
} else {
streams.splice(streams.end(), gen_all_ip_options(oss));
}
}
if (entry.is_ip) {
oss << gen_ip_cond(entry.ip);
} else {
/* encode 0 to indicate there's no ip (ip size) */
oss << "\\x00";
}
cond_perms = map_perms(perms);
if (!is_cmd && (label || is_peer))
cond_perms = (AA_CONT_MATCH << 1);
oss << "\\-x01"; /* oob separator */
oss << default_match_pattern; /* label - not used for now */
oss << "\\x00"; /* null transition */
for (auto &oss : streams) {
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::string buf;
@@ -621,49 +742,87 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
return true;
}
if (perms & AA_PEER_NET_PERMS) {
gen_ip_conds(buffer, peer, true, false);
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
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,
buf = buffer.str();
/* create perms need to be generated excluding the rest of the perms */
if (perms & AA_NET_CREATE) {
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,
parseopts))
return false;
}
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
gen_ip_conds(buffer, local, false, false);
if (perms & AA_NET_LISTEN) {
std::ostringstream cmd_buffer;
cmd_buffer << buffer.str();
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
/* length of queue allowed - not used for now */
cmd_buffer << "..";
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,
parseopts))
return false;
/* encode protocol */
if (protocol > 0xffff) {
buffer << "..";
} else {
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((protocol & 0xff00) >> 8);
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (protocol & 0xff);
}
if (perms & AA_PEER_NET_PERMS) {
std::list<std::ostringstream> streams;
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;
cmd_buffer << buffer.str();
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
/* level - not used for now */
cmd_buffer << "..";
/* socket mapping - not used for now */
cmd_buffer << "..";
buf = cmd_buffer.str();
if (!gen_ip_conds(prof, streams, local, false, true))
return false;
}
std::list<std::ostringstream> streams;
std::ostringstream common_buffer;
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),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
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;
}
@@ -679,17 +838,18 @@ int network_rule::gen_policy_re(Profile &prof)
for (const auto& perm : network_perms) {
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 (!gen_net_rule(prof, family, type))
if (!gen_net_rule(prof, family, type, protocol))
goto fail;
} else {
int t;
/* generate rules for types that are set */
for (t = 0; t < 16; t++) {
if (type & (1 << t)) {
if (!gen_net_rule(prof, family, t))
if (!gen_net_rule(prof, family, t, protocol))
goto fail;
}
}
@@ -760,13 +920,27 @@ void network_rule::update_compat_net(void)
}
}
static int cmp_network_map(std::unordered_map<unsigned int, perms_t> lhs,
std::unordered_map<unsigned int, perms_t> rhs)
static int cmp_ip_conds(ip_conds const &lhs, ip_conds const &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_none - rhs.is_none;
}
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;
size_t 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)
return res;
}
@@ -779,5 +953,14 @@ int network_rule::cmp(rule_t const &rhs) const
if (res)
return res;
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 <sys/types.h>
#include <sys/stat.h>
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -79,6 +80,10 @@
#define CMD_LISTEN 2
#define CMD_OPT 4
#define NONE_SIZE 0
#define IPV4_SIZE 1
#define IPV6_SIZE 2
struct network_tuple {
const char *family_name;
unsigned int family;
@@ -127,6 +132,8 @@ public:
uint16_t port;
struct ip_address ip;
bool is_none = false;
void free_conds() {
if (sip)
free(sip);
@@ -139,17 +146,18 @@ class network_rule: public dedup_perms_rule_t {
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
public:
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 local;
char *label;
bool has_local_conds(void) { return local.sip || local.sport; }
bool has_peer_conds(void) { return peer.sip || peer.sport; }
/* 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,
@@ -178,9 +186,9 @@ public:
}
};
void gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd);
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask);
void set_netperm(unsigned int family, unsigned int type);
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, unsigned int protocol);
void set_netperm(unsigned int family, unsigned int type, unsigned int protocol);
void update_compat_net(void);
bool parse_address(ip_conds &entry);
bool parse_port(ip_conds &entry);

View File

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

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

@@ -0,0 +1,8 @@
#
#=DESCRIPTION invalid family for inet conditionals
#=EXRESULT FAIL
#
/usr/bin/foo {
network unix ip=127.0.0.1 port=1234 peer=(ip=127.0.0.1 port=1234),
}

View File

@@ -0,0 +1,8 @@
#
#=DESCRIPTION invalid family for inet conditionals
#=EXRESULT FAIL
#
/usr/bin/foo {
network netlink ip=127.0.0.1,
}

View File

@@ -0,0 +1,8 @@
#
#=DESCRIPTION invalid family for inet conditionals
#=EXRESULT FAIL
#
/usr/bin/foo {
network packet peer=(port=1234),
}

View File

@@ -5,5 +5,7 @@
/usr/bin/foo {
network inet ip=10.0.2.1 peer=(ip=10.0.2.1),
network inet tcp ip=192.168.2.254 peer=(ip=192.168.2.254),
network stream ip=192.168.2.254 peer=(ip=192.168.2.254),
network raw ip=10.0.2.1 peer=(ip=10.0.2.1),
}

View File

@@ -0,0 +1,11 @@
#
#=DESCRIPTION network none ip conditional test
#=EXRESULT PASS
#
/usr/bin/foo {
network ip=none,
network peer=(ip=none),
network inet ip=none peer=(ip=none),
network inet tcp ip=none peer=(ip=none),
}

View File

@@ -31,6 +31,17 @@
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
/{usr/,}lib/@{multiarch}/security/ r,
# pam_unix
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

@@ -13,6 +13,9 @@
abi <abi/4.0>,
# Global config of openssl
include <abstractions/openssl>
@{etc_ro}/gcrypt/hwf.deny r,
@{etc_ro}/gcrypt/random.conf r,
@{PROC}/sys/crypto/fips_enabled r,
@@ -24,4 +27,8 @@
/etc/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>

View File

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

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

@@ -0,0 +1,153 @@
# vim:syntax=apparmor
# LOGPROF-SUGGEST: no
# Author: Daniel Richard G. <skunk@iSKUNK.ORG>
include <abstractions/base>
include <abstractions/freedesktop.org>
include <abstractions/nameservice>
include <abstractions/openssl>
network inet dgram,
network inet6 dgram,
network netlink dgram,
network inet stream,
network inet6 stream,
dbus (bind)
bus=session
name=com.transmissionbt.Transmission,
dbus (bind)
bus=session
name=com.transmissionbt.transmission_*,
dbus (receive)
bus=session
path=/ca/desrt/dconf/Writer/user
interface=ca.desrt.dconf.Writer
member=Notify,
dbus (send)
bus=session
path=/ca/desrt/dconf/Writer/user
interface=ca.desrt.dconf.Writer
member=Change
peer=(name=ca.desrt.dconf),
dbus (receive)
bus=accessibility
path=/org/a11y/atspi/accessible/root
interface=org.freedesktop.DBus.Properties
member=Set,
dbus (send)
bus=accessibility
path=/org/a11y/atspi/accessible/root
interface=org.a11y.atspi.Socket
member=Embed
peer=(name=org.a11y.atspi.Registry),
dbus (send)
bus=accessibility
path=/org/a11y/atspi/registry
interface=org.a11y.atspi.Registry
member=GetRegisteredEvents
peer=(name=org.a11y.atspi.Registry),
dbus (send)
bus=accessibility
path=/org/a11y/atspi/registry/deviceeventcontroller
interface=org.a11y.atspi.DeviceEventController
member={GetDeviceEventListeners,GetKeystrokeListeners}
peer=(name=org.a11y.atspi.Registry),
dbus (send)
bus={accessibility,session}
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={AddMatch,GetNameOwner,Hello,ReleaseName,RemoveMatch,RequestName,StartServiceByName}
peer=(name=org.freedesktop.DBus),
dbus (send)
bus=session
interface=org.freedesktop.DBus.Introspectable
path=/StatusNotifierWatcher
member=Introspect
peer=(name=org.kde.StatusNotifierWatcher),
dbus (send)
bus=session
interface=org.freedesktop.DBus.Properties
path=/StatusNotifierWatcher
member=Get
peer=(name=org.kde.StatusNotifierWatcher),
dbus (send)
bus=session
interface=org.freedesktop.DBus.Properties
path=/org/a11y/bus
member=Get
peer=(name=org.a11y.Bus),
dbus (send)
bus=system
interface=org.freedesktop.DBus.Properties
path=/org/freedesktop/hostname1
member=GetAll,
dbus (send)
bus=session
interface=org.freedesktop.Notifications
path=/org/freedesktop/Notifications
member={GetCapabilities,Notify},
dbus (send)
bus=session
path=/org/gtk/Private/RemoteVolumeMonitor
interface=org.gtk.Private.RemoteVolumeMonitor
member={IsSupported,List},
dbus (send)
bus=session
path=/org/gtk/vfs/Daemon
interface=org.gtk.vfs.Daemon
member={GetConnection,ListMonitorImplementations},
dbus (send)
bus=session
path=/org/gtk/vfs/mount/[1-9]*
interface=org.gtk.vfs.Mount
member={CreateFileMonitor,Enumerate,QueryInfo},
dbus (receive)
bus=session
path=/org/gtk/vfs/mounttracker
interface=org.gtk.vfs.MountTracker
member=Mounted,
dbus (send)
bus=session
path=/org/gtk/vfs/mounttracker
interface=org.gtk.vfs.MountTracker
member={ListMountableInfo,ListMounts2,LookupMount},
@{PROC}/sys/kernel/random/uuid r,
owner @{PROC}/@{pid}/mountinfo r,
owner @{PROC}/@{pid}/mounts r,
owner @{run}/user/@{uid}/gvfsd/socket-* rw,
@{etc_ro}/fstab r,
@{system_share_dirs}/hwdata/** r,
@{system_share_dirs}/lxqt/** r,
owner /tmp/tr_session_id_* rwk,
# allow a top-level directory listing
@{HOME}/ r,
owner @{HOME}/.cache/transmission/ w,
owner @{HOME}/.cache/transmission/** rw,
owner @{HOME}/.config/transmission/ w,
owner @{HOME}/.config/transmission/** rw,
owner @{HOME}/.config/lxqt/lxqt.conf r,
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/ r,
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/** rw,
# exclude these for now
deny /usr/share/thumbnailers/ r,
deny @{HOME}/.local/share/gvfs-metadata/** r,
deny @{HOME}/.config/lxqt/** rw,
include if exists <abstractions/transmission-common.d>

View File

@@ -4,7 +4,7 @@
abi <abi/4.0>,
include <tunables/global>
profile firefox /usr/lib/firefox{,-esr}/firefox{,-esr} 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

@@ -0,0 +1,12 @@
# This profile allows everything and only exists to give the
# application a name instead of having the label "unconfined"
abi <abi/4.0>,
include <tunables/global>
profile foliate /usr/bin/foliate flags=(unconfined) {
userns,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/foliate>
}

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>
# common php files and support files that php needs
include <abstractions/php>
# read openssl configuration
include <abstractions/openssl>
# read the system certificates
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/cups-client>
include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/samba>
signal receive set=term peer=smbd,

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

@@ -22,7 +22,6 @@ profile syslog-ng /{usr/,}{bin,sbin}/syslog-ng {
include <abstractions/consoles>
include <abstractions/nameservice>
include <abstractions/mysql>
include <abstractions/openssl>
include <abstractions/python>
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,76 @@
# vim:syntax=apparmor
# Author: Daniel Richard G. <skunk@iSKUNK.ORG>
abi <abi/4.0>,
include <tunables/global>
profile transmission-daemon /usr/bin/transmission-daemon flags=(complain) {
# Don't use abstractions/transmission-common here, as the
# access needed is narrower than the user applications
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/openssl>
network inet dgram,
network inet6 dgram,
network inet stream,
network inet6 stream,
owner @{PROC}/@{pid}/mounts r,
@{PROC}/sys/kernel/random/uuid r,
@{run}/systemd/notify w,
/etc/transmission-daemon/** r,
owner /etc/transmission-daemon/settings.json{,.tmp.*} rw,
owner /tmp/tr_session_id_* rwk,
/usr/share/transmission/web/** r,
owner /var/lib/transmission-daemon/.config/transmission-daemon/** rw,
owner /var/lib/transmission-daemon/downloads/** rw,
owner /var/lib/transmission-daemon/info/** rw,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/transmission>
include if exists <local/transmission-daemon>
}
profile transmission-cli /usr/bin/transmission-cli flags=(complain) {
include <abstractions/transmission-common>
include <abstractions/consoles>
# Site-specific additions and overrides. See local/README for details.
include if exists <local/transmission>
include if exists <local/transmission-cli>
}
profile transmission-gtk /usr/bin/transmission-gtk flags=(complain) {
include <abstractions/transmission-common>
include <abstractions/dbus-session-strict>
include <abstractions/dconf>
include <abstractions/gnome>
owner @{run}/user/*/dconf/user w,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/transmission>
include if exists <local/transmission-gtk>
}
profile transmission-qt /usr/bin/transmission-qt flags=(complain) {
include <abstractions/transmission-common>
include <abstractions/dbus-accessibility-strict>
include <abstractions/dbus-network-manager-strict>
include <abstractions/dbus-session-strict>
include <abstractions/fonts>
include <abstractions/X>
include <abstractions/qt5>
include <abstractions/qt5-settings-write>
# Site-specific additions and overrides. See local/README for details.
include if exists <local/transmission>
include if exists <local/transmission-qt>
}

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

@@ -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/mysql>
include <abstractions/nameservice>
include <abstractions/openssl>
include <abstractions/wutmp>
include <abstractions/dovecot-common>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@@ -12,7 +12,7 @@
abi <abi/4.0>,
#include <tunables/global>
include <tunables/global>
@{chromium} = chromium{,-browser}
@@ -22,10 +22,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
include <abstractions/cups-client>
include <abstractions/dbus-session>
include <abstractions/dbus-strict>
include <abstractions/fonts>
include <abstractions/gnome>
include <abstractions/ibus>
include <abstractions/mesa>
include <abstractions/nameservice>
include <abstractions/user-tmp>
include <abstractions/vulkan>
# This include specifies which ubuntu-browsers.d abstractions to use. Eg, if
# you want access to productivity applications, adjust the following file
@@ -57,14 +60,48 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
member={EnumerateDevices,GetDisplayDevice}
peer=(label=unconfined),
# ???
deny dbus (send)
dbus (send)
bus=system
path=/org/freedesktop/hostname1
interface=org.freedesktop.DBus.Properties
member=GetAll
peer=(label=unconfined),
dbus (receive)
bus=system
path=/org/freedesktop/login1
interface=org.freedesktop.login1.Manager
member={SessionNew,SessionRemoved}
peer=(label=unconfined),
dbus (send)
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={AddMatch,GetNameOwner,Hello,NameHasOwner,RemoveMatch,StartServiceByName}
peer=(name=org.freedesktop.DBus),
dbus (send)
bus=session
path=/org/freedesktop/portal/desktop
interface=org.freedesktop.DBus.Properties
member=Get
peer=(name=org.freedesktop.portal.Desktop),
dbus (send)
bus=session
path=/org/freedesktop/Notifications
interface=org.freedesktop.Notifications
member={GetCapabilities,GetServerInformation}
peer=(name=org.freedesktop.Notifications),
dbus (send)
bus=session
path=/org/gtk/vfs/mounttracker
interface=org.gtk.vfs.MountTracker
member=ListMountableInfo
peer=(label=unconfined),
# Networking
network inet stream,
network inet6 stream,
@@ -72,30 +109,35 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
@{PROC}/@{pid}/net/ipv6_route r,
# Should maybe be in abstractions
/etc/fstab r,
/etc/mime.types r,
/etc/mailcap r,
/etc/mtab r,
/etc/xdg/xubuntu/applications/defaults.list r,
owner @{HOME}/.cache/thumbnails/** r,
owner @{HOME}/.local/share/applications/defaults.list r,
owner @{HOME}/.local/share/applications/mimeinfo.cache r,
/tmp/.X[0-9]*-lock r,
@{PROC}/self/exe ixr,
@{PROC}/@{pid}/fd/ r,
@{PROC}/filesystems r,
@{PROC}/pressure/{cpu,io,memory} r,
@{PROC}/vmstat r,
@{PROC}/ r,
@{PROC}/@{pid}/task/@{tid}/stat r,
owner @{PROC}/@{pid}/task/@{tid}/stat r,
owner @{PROC}/@{pid}/clear_refs w,
owner @{PROC}/@{pid}/cmdline r,
owner @{PROC}/@{pid}/io r,
owner @{PROC}/@{pid}/mountinfo r,
owner @{PROC}/@{pid}/setgroups w,
owner @{PROC}/@{pid}/{uid,gid}_map w,
@{PROC}/@{pid}/smaps r,
owner @{PROC}/@{pid}/smaps r,
@{PROC}/@{pid}/stat r,
@{PROC}/@{pid}/statm r,
@{PROC}/@{pid}/status r,
owner @{PROC}/@{pid}/status r,
owner @{PROC}/@{pid}/task/@{tid}/status r,
deny @{PROC}/@{pid}/oom_{,score_}adj w,
@{PROC}/sys/fs/inotify/max_user_watches r,
@{PROC}/sys/kernel/yama/ptrace_scope r,
@{PROC}/sys/net/ipv4/tcp_fastopen r,
@@ -105,13 +147,24 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/sys/devices/**/uevent r,
/sys/devices/system/cpu/cpufreq/policy*/cpuinfo_max_freq r,
/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq r,
/sys/devices/system/cpu/kernel_max r,
/sys/devices/system/cpu/possible r,
/sys/devices/system/cpu/present r,
/sys/devices/system/node/node*/meminfo r,
/sys/devices/pci[0-9]*/**/bConfigurationValue r,
/sys/devices/pci[0-9]*/**/boot_vga r,
/sys/devices/pci[0-9]*/**/busnum r,
/sys/devices/pci[0-9]*/**/class r,
/sys/devices/pci[0-9]*/**/config r,
/sys/devices/pci[0-9]*/**/descriptors r,
/sys/devices/pci[0-9]*/**/device r,
/sys/devices/pci[0-9]*/**/devnum r,
/sys/devices/pci[0-9]*/**/irq r,
/sys/devices/pci[0-9]*/**/manufacturer r,
/sys/devices/pci[0-9]*/**/product r,
/sys/devices/pci[0-9]*/**/resource r,
/sys/devices/pci[0-9]*/**/revision r,
/sys/devices/pci[0-9]*/**/serial r,
/sys/devices/pci[0-9]*/**/subsystem_device r,
/sys/devices/pci[0-9]*/**/subsystem_vendor r,
/sys/devices/pci[0-9]*/**/vendor r,
@@ -122,6 +175,7 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/sys/devices/virtual/tty/tty*/active r,
# This is requested, but doesn't seem to actually be needed so deny for now
deny /run/udev/data/** r,
deny /sys/devices/virtual/dmi/id/* r,
# Needed for the crash reporter
owner @{PROC}/@{pid}/auxv r,
@@ -132,13 +186,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/usr/share/fonts/**/*.pfb m,
/usr/share/mime/mime.cache m,
/usr/share/icons/**/*.cache m,
owner /{dev,run}/shm/pulse-shm* m,
owner /{dev,run,var/run}/shm/pulse-shm* m,
owner @{HOME}/.local/share/mime/mime.cache m,
owner /tmp/** m,
@{PROC}/sys/kernel/shmmax r,
owner /{dev,run}/shm/{,.}org.chromium.* mrw,
owner /{,var/}run/shm/shmfd-* mrw,
owner /{dev,run,var/run}/shm/{,.}org.chromium.* mrw,
owner /{dev,run,var/run}/shm/shmfd-* mrw,
/usr/lib/@{chromium}/*.pak mr,
/usr/lib/@{chromium}/locales/* mr,
@@ -149,8 +203,8 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
# Allow ptracing ourselves and our helpers
ptrace (trace) peer=@{profile_name},
ptrace (trace) peer=@{profile_name}//xdgsettings,
ptrace (trace) peer=lsb_release,
ptrace (read, trace) peer=@{profile_name}//xdgsettings,
ptrace (read, trace) peer=lsb_release,
# Make browsing directories work
/ r,
@@ -183,10 +237,9 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/etc/firefox/profile/bookmarks.html r,
owner @{HOME}/.mozilla/** k,
# Chromium Policies
/etc/@{chromium}/policies/** r,
# Chromium configuration
/etc/@{chromium}/** r,
# Note: "~/.pki/{,nssdb/} w" is denied by private-files abstraction
owner @{HOME}/.pki/nssdb/* rwk,
owner @{HOME}/.cache/chromium/ rw,
owner @{HOME}/.cache/chromium/** rw,
@@ -197,12 +250,18 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
owner @{HOME}/.config/chromium/Dictionaries/*.bdic mr,
owner @{HOME}/.config/chromium/**/Dictionaries/*.bdic mr,
# Allow transitions to ourself and our sandbox
# Widevine CDM plugin
owner @{HOME}/.config/chromium/WidevineCdm/*/_platform_specific/*/libwidevinecdm.so mr,
# Allow transitions to ourself, our sandbox, and crash handler
/usr/lib/@{chromium}/@{chromium} ix,
/usr/lib/@{chromium}/chrome-sandbox cx -> sandbox,
/usr/lib/@{chromium}/chrome_crashpad_handler Cxr -> crashpad_handler,
# Allow communicating with sandbox
# Allow communicating with sandbox and crash handler
unix (receive, send) peer=(label=@{profile_name}//sandbox),
unix (receive, send) peer=(label=@{profile_name}//crashpad_handler),
signal (receive) set=(cont) peer=@{profile_name}//crashpad_handler,
/{usr/,}bin/ps Uxr,
/usr/lib/@{chromium}/xdg-settings Cxr -> xdgsettings,
@@ -210,10 +269,13 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/usr/bin/lsb_release Pxr -> lsb_release,
# GSettings
owner /{,var/}run/user/*/dconf/ rw,
owner /{,var/}run/user/*/dconf/user rw,
owner @{run}/user/[0-9]*/dconf/ rw,
owner @{run}/user/[0-9]*/dconf/user rw,
owner @{HOME}/.config/dconf/user r,
# GVfs
owner @{run}/user/[0-9]*/gvfsd/socket-* rw,
# Magnet links
/usr/bin/gio ixr,
@@ -230,7 +292,7 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/etc/ld.so.cache r,
/etc/xdg/** r,
/usr/bin/xdg-settings r,
/{usr/,}lib{,32,64}/@{chromium}/xdg-settings r,
/usr/lib/@{chromium}/xdg-settings r,
/usr/share/applications/*.desktop r,
/usr/share/applications/*.list r,
@@ -266,6 +328,8 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
/{usr/,}lib/@{multiarch}/libpthread-*.so* mr,
/{usr/,}lib{,32,64}/libatomic.so* mr,
/{usr/,}lib/@{multiarch}/libatomic.so* mr,
/{usr/,}lib{,32,64}/libc.so.* mr,
/{usr/,}lib/@{multiarch}/libc.so.* mr,
/{usr/,}lib{,32,64}/libc-*.so* mr,
/{usr/,}lib/@{multiarch}/libc-*.so* mr,
/{usr/,}lib{,32,64}/libdl-*.so* mr,
@@ -326,6 +390,32 @@ profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconne
owner /tmp/** rw,
}
profile crashpad_handler {
include <abstractions/base>
capability sys_ptrace,
ptrace (read, trace) peer=chromium_browser,
signal (send) set=(cont) peer=chromium_browser,
unix (receive, send) peer=(label=chromium_browser),
/usr/lib/@{chromium}/chrome_crashpad_handler ixr,
/sys/devices/system/cpu/cpufreq/policy[0-9]*/scaling_{cur,max}_freq r,
@{PROC}/sys/kernel/yama/ptrace_scope r,
owner @{PROC}/@{pid}/fd/ r,
owner @{PROC}/@{pid}/mem r,
owner @{PROC}/@{pid}/stat r,
owner @{PROC}/@{pid}/task/ r,
owner @{PROC}/@{pid}/task/@{tid}/comm r,
owner @{HOME}/.config/chromium/Crash?Reports/** rwk,
}
# Site-specific additions and overrides. See local/README for details.
include if exists <local/chromium_browser>
}

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

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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,

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

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

@@ -114,6 +114,7 @@ static void usage(char *prog_name)
fprintf(stderr, "Options are:\n");
fprintf(stderr, "-o flags sent to the mount syscall\n");
fprintf(stderr, "-d data sent to the mount syscall\n");
fprintf(stderr, "-t type of synthetic filesystem (e.g. proc) for mount syscall\n");
exit(1);
}
@@ -121,12 +122,13 @@ int main(int argc, char *argv[])
{
char *options = NULL;
char *data = NULL;
char *type = NULL;
int index;
int c;
char *op, *source, *target, *token;
unsigned long flags = 0;
while ((c = getopt (argc, argv, "o:d:h")) != -1) {
while ((c = getopt (argc, argv, "o:d:t:h")) != -1) {
switch (c)
{
case 'o':
@@ -135,6 +137,9 @@ int main(int argc, char *argv[])
case 'd':
data = optarg;
break;
case 't':
type = optarg;
break;
case 'h':
usage(argv[0]);
break;
@@ -162,10 +167,18 @@ int main(int argc, char *argv[])
}
if (strcmp(op, "mount") == 0) {
if (mount(source, target, "ext2", flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
if (!type) {
if (mount(source, target, "ext2", flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
}
} else {
if (mount(source, target, type, flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
}
}
} else if (strcmp(op, "umount") == 0) {
if (umount(target) == -1) {

View File

@@ -547,6 +547,12 @@ else
runchecktest "UMOUNT (confined cap umount:ALL)" pass umount ${loop_device} ${mount_point}
remove_mnt
# https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1597017
# CVE-2016-1585
genprofile cap:sys_admin "mount:options=(rw,make-slave) -> **"
runchecktest "MOUNT (confined cap mount -> mntpnt, CVE-2016-1585)" fail mount -t proc proc ${mount_point}
remove_mnt
# MR:https://gitlab.com/apparmor/apparmor/-/merge_requests/1054
# https://bugs.launchpad.net/apparmor/+bug/2023814
# https://bugzilla.opensuse.org/show_bug.cgi?id=1211989

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,16 +96,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"
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" # INADDR_ANY
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"
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"
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"
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"
removeprofile
@@ -122,10 +125,12 @@ 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"
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" # IN6ADDR_ANY_INIT
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"
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"

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,8 +15,8 @@ import re
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.regex import RE_PROFILE_MOUNT, RE_PROFILE_PATH_OR_VAR, strip_parenthesis
# from apparmor.rule import AARE
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
from apparmor.translations import init_translation
@@ -25,7 +25,7 @@ _ = init_translation()
# TODO :
# - 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.
# - 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',
'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',
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'resctrl', 'zfs', 'iso9660', 'udf', 'ntfs3',
'nfs', 'cifs', 'overlayfs', 'aufs', 'rpc_pipefs', 'msdos', 'nfs4',
]
flags_keywords = [
# keep in sync with parser/mount.cc mnt_opts_table!
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
@@ -43,16 +45,19 @@ flags_keywords = [
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave',
'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
'([A-Za-z0-9]|AARE)', # TODO: handle AARE
'([A-Za-z0-9])',
]
join_valid_flags = '|'.join(flags_keywords)
join_valid_fs = '|'.join(valid_fs)
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*'\
r'(?P<fstype>\(\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\)|'\
r'\{\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\}|(\s*' + join_valid_fs + r'))'\
r'(?P<fstype>\(\s*(' + FS_AARE + r')(' + sep + r'(' + FS_AARE + r'))*\s*\)|'\
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*'\
@@ -63,10 +68,17 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?'
# Source can either be
# - A path : /foo
# - A globbed Path : {,/usr}/lib{,32,64,x32}/modules/
# - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /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'))'
dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')'
# Thus we cannot use directly RE_PROFILE_PATH_OR_VAR
# Destination can also be
# - A path : /foo
# - A globbed Path : **
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'$')
@@ -95,8 +107,25 @@ class MountRule(BaseRule):
self.operation = operation
self.fstype, self.all_fstype, unknown_items = check_and_split_list(fstype[1] if fstype != self.ALL else fstype, valid_fs, self.ALL, type(self).__name__, 'fstype')
if unknown_items:
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.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')
@@ -117,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
@@ -213,8 +242,15 @@ class MountRule(BaseRule):
return False
if self.is_options_equal != other_rule.is_options_equal:
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'):
return False
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:
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:
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
if output.startswith(username):

View File

@@ -29,8 +29,12 @@ 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=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 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, '' )),
@@ -45,8 +49,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) 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 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/',
('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/',
'/tmp/snap.rootfs_*{,/usr}/lib/modules/',
False, False, False, '' )),
('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
@@ -207,6 +211,16 @@ class MountIsCoveredTest(AATest):
self.assertTrue(obj.is_covered(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):
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
tests = [
@@ -231,6 +245,12 @@ class MountIsCoveredTest(AATest):
self.assertFalse(obj.is_covered(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__)
if __name__ == '__main__':

View File

@@ -492,6 +492,7 @@ syntax_failure = (
'network/network_ok_41.sd',
'network/network_ok_42.sd',
'network/network_ok_43.sd',
'network/network_ok_44.sd',
'network/perms/ok_accept_1.sd',
'network/perms/ok_accept_2.sd',
'network/perms/ok_attr_1.sd',