From e5ed979ce10e35ee4908ca1652161f7649782bf7 Mon Sep 17 00:00:00 2001 From: valoq Date: Sat, 23 Nov 2024 22:03:42 +0100 Subject: [PATCH 01/18] add profile for swayimg (#612) * add profile for swayimg * fix exec --- apparmor.d/profiles-s-z/swayimg | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 apparmor.d/profiles-s-z/swayimg diff --git a/apparmor.d/profiles-s-z/swayimg b/apparmor.d/profiles-s-z/swayimg new file mode 100644 index 00000000..a3ed158b --- /dev/null +++ b/apparmor.d/profiles-s-z/swayimg @@ -0,0 +1,23 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 valoq +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/swayimg +profile swayimg @{exec_path} { + include + include + include + include + + @{exec_path} mr, + + owner @{user_config_dirs}/swayimg/** r, + + include if exists +} + +# vim:syntax=apparmor From 3cc7f82d300e7a3490bd52a2aeb2b85986ddcffd Mon Sep 17 00:00:00 2001 From: odomingao Date: Sun, 24 Nov 2024 15:23:06 -0300 Subject: [PATCH 02/18] Fix typo --- apparmor.d/tunables/multiarch.d/extensions | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/apparmor.d/tunables/multiarch.d/extensions b/apparmor.d/tunables/multiarch.d/extensions index 956e8c25..d3d56934 100644 --- a/apparmor.d/tunables/multiarch.d/extensions +++ b/apparmor.d/tunables/multiarch.d/extensions @@ -311,24 +311,24 @@ @{video_ext} += 3[gG]2 # 3g2 # Subtitles -@{suntitles_ext} = [aA][qQ][tT] # aqt -@{suntitles_ext} += [aA][sS][sS] # ass -@{suntitles_ext} += [gG][sS][uU][bB] # gsub -@{suntitles_ext} += [uU][sS][fF] # usf -@{suntitles_ext} += [pP][aA][cC] # pac -@{suntitles_ext} += [pP][jJ][sS] # pjs -@{suntitles_ext} += [pP][sS][bB] # psb -@{suntitles_ext} += [rR][tT] # rt -@{suntitles_ext} += [sS][bB][vV] # sbv -@{suntitles_ext} += [sS][mM][iI] # smi -@{suntitles_ext} += [sS][rR][tT] # srt -@{suntitles_ext} += [sS][sS][aA] # ssa -@{suntitles_ext} += [sS][sS][fF] # ssf -@{suntitles_ext} += [sS][tT][lL] # stl -@{suntitles_ext} += [sS][uU][bB] # sub -@{suntitles_ext} += [tT][t][mM][lL] # ttml -@{suntitles_ext} += [tT][t][xX][tT] # ttxt -@{suntitles_ext} += [vV][tT][t] # vtt +@{subtitles_ext} = [aA][qQ][tT] # aqt +@{subtitles_ext} += [aA][sS][sS] # ass +@{subtitles_ext} += [gG][sS][uU][bB] # gsub +@{subtitles_ext} += [uU][sS][fF] # usf +@{subtitles_ext} += [pP][aA][cC] # pac +@{subtitles_ext} += [pP][jJ][sS] # pjs +@{subtitles_ext} += [pP][sS][bB] # psb +@{subtitles_ext} += [rR][tT] # rt +@{subtitles_ext} += [sS][bB][vV] # sbv +@{subtitles_ext} += [sS][mM][iI] # smi +@{subtitles_ext} += [sS][rR][tT] # srt +@{subtitles_ext} += [sS][sS][aA] # ssa +@{subtitles_ext} += [sS][sS][fF] # ssf +@{subtitles_ext} += [sS][tT][lL] # stl +@{subtitles_ext} += [sS][uU][bB] # sub +@{subtitles_ext} += [tT][t][mM][lL] # ttml +@{subtitles_ext} += [tT][t][xX][tT] # ttxt +@{subtitles_ext} += [vV][tT][t] # vtt # Images @{image_ext} = [aA][pP][nN][gG] # apng From 212b8dcf54357974c603c925a1207b591f995a47 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Fri, 29 Nov 2024 15:34:10 +0000 Subject: [PATCH 03/18] feat(profile): improve some core profiles. --- apparmor.d/groups/systemd/networkctl | 5 ++-- apparmor.d/profiles-a-f/cgrulesengd | 36 ++++++++++------------------ apparmor.d/profiles-a-f/chsh | 4 +++- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/apparmor.d/groups/systemd/networkctl b/apparmor.d/groups/systemd/networkctl index a4bab2be..ce81686a 100644 --- a/apparmor.d/groups/systemd/networkctl +++ b/apparmor.d/groups/systemd/networkctl @@ -27,11 +27,10 @@ profile networkctl @{exec_path} flags=(attach_disconnected) { unix (bind) type=stream addr=@@{udbus}/bus/networkctl/system, #aa:dbus talk bus=system name=org.freedesktop.network1 label=systemd-networkd - # No label available - dbus send bus=system path=/org/freedesktop/network@{int} + dbus send bus=system path=/org/freedesktop/network1{,/**} interface=org.freedesktop.DBus.Properties member=Get - peer=(name=org.freedesktop.network@{int}), + peer=(name=org.freedesktop.network1), @{exec_path} mr, diff --git a/apparmor.d/profiles-a-f/cgrulesengd b/apparmor.d/profiles-a-f/cgrulesengd index 08b1d83b..6f31a43d 100644 --- a/apparmor.d/profiles-a-f/cgrulesengd +++ b/apparmor.d/profiles-a-f/cgrulesengd @@ -12,19 +12,9 @@ profile cgrulesengd @{exec_path} { include include - # For creating Unix domain sockets/IPC sockets: - # socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR) = 3 - # ... - # bind(3, {sa_family=AF_NETLINK, nl_pid=13284, nl_groups=0x000001}, 12) = -1 EPERM (Operation - # not permitted) - capability net_admin, - - # To remove the following errors: - # readlink("/proc/12/exe", 0x7ffc9fa85cd0, 4096) = -1 EACCES (Permission denied) - capability sys_ptrace, - - # To be able to read the /proc/ files of all processes in the system. capability dac_read_search, + capability net_admin, + capability sys_ptrace, network netlink dgram, @@ -32,22 +22,22 @@ profile cgrulesengd @{exec_path} { @{exec_path} mr, - @{sys}/fs/cgroup/**/tasks w, + + /etc/cgconfig.conf r, + /etc/cgconfig.d/{,*} r, + + /etc/cgrules.conf r, + /etc/cgrules.d/{,*} r, + + owner @{run}/cgred.socket w, + + @{sys}/fs/cgroup/** rw, @{PROC}/ r, @{PROC}/@{pids}/cmdline r, @{PROC}/@{pids}/task/ r, - owner @{PROC}/@{pid}/mounts r, @{PROC}/cgroups r, - - @{sys}/fs/cgroup/unified/cgroup.controllers r, - - owner @{run}/cgred.socket w, - - /etc/cgconfig.conf r, - /etc/cgrules.conf r, - /etc/cgconfig.d/ r, - + owner @{PROC}/@{pid}/mounts r, include if exists } diff --git a/apparmor.d/profiles-a-f/chsh b/apparmor.d/profiles-a-f/chsh index f8a2af5c..e124e4d1 100644 --- a/apparmor.d/profiles-a-f/chsh +++ b/apparmor.d/profiles-a-f/chsh @@ -26,11 +26,13 @@ profile chsh @{exec_path} { /etc/shells r, + /etc/.chsh.@{rand6} rw, /etc/passwd rw, /etc/passwd- w, - /etc/passwd+ rw, /etc/passwd.@{pid} w, /etc/passwd.lock wl -> /etc/passwd.@{pid}, + /etc/passwd.OLD wl -> /etc/passwd, + /etc/passwd+ rw, /etc/shadow r, From 94bf2495e3805167b73235062d1f0b44ce1ca9b0 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Fri, 29 Nov 2024 15:41:54 +0000 Subject: [PATCH 04/18] feat(profile): needrestart improve mqueue rule. --- apparmor.d/profiles-m-r/needrestart | 2 +- tests/bats/needrestart.bats | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apparmor.d/profiles-m-r/needrestart b/apparmor.d/profiles-m-r/needrestart index f5722ed3..cc411ef8 100644 --- a/apparmor.d/profiles-m-r/needrestart +++ b/apparmor.d/profiles-m-r/needrestart @@ -22,7 +22,7 @@ profile needrestart @{exec_path} flags=(attach_disconnected) { ptrace (read), - mqueue r type=posix /, + mqueue (r,getattr) type=posix /, @{exec_path} mrix, diff --git a/tests/bats/needrestart.bats b/tests/bats/needrestart.bats index 567f8c77..4676b36a 100644 --- a/tests/bats/needrestart.bats +++ b/tests/bats/needrestart.bats @@ -5,10 +5,6 @@ load common -setup_file() { - skip "mqueue raised despite the rule being present. See https://gitlab.com/apparmor/apparmor/-/issues/362" -} - @test "needrestart: List outdated processes" { needrestart } From 3690a4c327118efd325f05582e4a8d35baca5fb0 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Wed, 11 Dec 2024 22:54:28 +0100 Subject: [PATCH 05/18] fix: apparmor parser inside snap. --- apparmor.d/profiles-a-f/apparmor_parser | 1 + apparmor.d/profiles-s-z/snap-seccomp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apparmor.d/profiles-a-f/apparmor_parser b/apparmor.d/profiles-a-f/apparmor_parser index 19c0f690..dc15d48b 100644 --- a/apparmor.d/profiles-a-f/apparmor_parser +++ b/apparmor.d/profiles-a-f/apparmor_parser @@ -17,6 +17,7 @@ profile apparmor_parser @{exec_path} flags=(attach_disconnected) { @{exec_path} mr, + @{lib_dirs}/@{multiarch}/** mr, @{lib_dirs}/snapd/apparmor.d/{,**} r, @{lib_dirs}/snapd/apparmor/{,**} r, diff --git a/apparmor.d/profiles-s-z/snap-seccomp b/apparmor.d/profiles-s-z/snap-seccomp index 6b0917f8..e7660f7b 100644 --- a/apparmor.d/profiles-s-z/snap-seccomp +++ b/apparmor.d/profiles-s-z/snap-seccomp @@ -14,6 +14,8 @@ profile snap-seccomp @{exec_path} { include include + capability dac_read_search, + network netlink raw, @{exec_path} mr, From 14e9fea29a28cd4049ba3542e1d38209ed3e5914 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Wed, 11 Dec 2024 23:17:27 +0100 Subject: [PATCH 06/18] feat: improve dbus integration for chsh, better handling of generic needrestart. --- .github/local/needrestart | 2 ++ .github/workflows/main.yml | 1 + apparmor.d/profiles-a-f/chsh | 8 +++++++- apparmor.d/profiles-m-r/needrestart | 3 +-- apparmor.d/profiles-s-z/snapd | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .github/local/needrestart diff --git a/.github/local/needrestart b/.github/local/needrestart new file mode 100644 index 00000000..33b23e01 --- /dev/null +++ b/.github/local/needrestart @@ -0,0 +1,2 @@ + + /var/lib/waagent/** r, diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c7a76f87..75fa5c05 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -94,6 +94,7 @@ jobs: sudo apt-get install -y \ apparmor-profiles apparmor-utils \ bats bats-support + sudo install -Dm0644 .github/local/needrestart /etc/apparmor.d/local/needrestart - name: Install apparmor.d run: | diff --git a/apparmor.d/profiles-a-f/chsh b/apparmor.d/profiles-a-f/chsh index e124e4d1..bf2b92a9 100644 --- a/apparmor.d/profiles-a-f/chsh +++ b/apparmor.d/profiles-a-f/chsh @@ -10,18 +10,24 @@ include @{exec_path} = @{bin}/chsh profile chsh @{exec_path} { include - include include + include + include include include capability audit_write, capability chown, capability fsetid, + capability net_admin, capability setuid, network netlink raw, + unix type=stream addr=@@{udbus}/bus/chsh/system, + + #aa:dbus talk bus=system name=org.freedesktop.home1 label=systemd-homed + @{exec_path} mr, /etc/shells r, diff --git a/apparmor.d/profiles-m-r/needrestart b/apparmor.d/profiles-m-r/needrestart index cc411ef8..56f95b58 100644 --- a/apparmor.d/profiles-m-r/needrestart +++ b/apparmor.d/profiles-m-r/needrestart @@ -26,6 +26,7 @@ profile needrestart @{exec_path} flags=(attach_disconnected) { @{exec_path} mrix, + @{bin}/* r, @{sh_path} rix, @{bin}/dpkg-query rpx, @{bin}/fail2ban-server rPx, @@ -42,8 +43,6 @@ profile needrestart @{exec_path} flags=(attach_disconnected) { @{lib}/needrestart/* rPx, /usr/share/debconf/frontend rix, - @{bin}/networkd-dispatcher r, - @{bin}/gettext.sh r, /usr/share/needrestart/{,**} r, /usr/share/unattended-upgrades/unattended-upgrade-shutdown r, diff --git a/apparmor.d/profiles-s-z/snapd b/apparmor.d/profiles-s-z/snapd index 63a1568b..fe24ed06 100644 --- a/apparmor.d/profiles-s-z/snapd +++ b/apparmor.d/profiles-s-z/snapd @@ -93,6 +93,7 @@ profile snapd @{exec_path} { @{lib_dirs}/snapd/snap-update-ns rPx, /usr/share/bash-completion/{,**} r, + /usr/share/dbus-1/{system,session}.d.d/snapd.{system,session}-services.conf* rw, /usr/share/dbus-1/{system,session}.d/{,snapd*} r, /usr/share/dbus-1/services/*snap* r, /usr/share/polkit-1/actions/{,**/} r, From c7030f16a681b8f6272845ee758c4d4ac822c01e Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Wed, 11 Dec 2024 23:24:14 +0100 Subject: [PATCH 07/18] feat(profile): minor update. --- apparmor.d/groups/network/networkd-dispatcher | 3 ++- apparmor.d/profiles-a-f/flatpak | 7 +++++- apparmor.d/profiles-g-l/iotop | 24 ++++++++----------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apparmor.d/groups/network/networkd-dispatcher b/apparmor.d/groups/network/networkd-dispatcher index 63291093..45fbf76a 100644 --- a/apparmor.d/groups/network/networkd-dispatcher +++ b/apparmor.d/groups/network/networkd-dispatcher @@ -21,8 +21,9 @@ profile networkd-dispatcher @{exec_path} { @{exec_path} mr, @{bin}/ r, - @{bin}/networkctl rPx, + @{bin}/chronyc rPx, @{bin}/ls rix, + @{bin}/networkctl rPx, @{bin}/sed rix, @{lib}/networkd-dispatcher/routable.d/postfix rix, diff --git a/apparmor.d/profiles-a-f/flatpak b/apparmor.d/profiles-a-f/flatpak index 7368d7c3..bc21a583 100644 --- a/apparmor.d/profiles-a-f/flatpak +++ b/apparmor.d/profiles-a-f/flatpak @@ -62,7 +62,12 @@ profile flatpak @{exec_path} flags=(attach_disconnected,mediate_deleted,complain owner @{HOME}/.var/ w, owner @{HOME}/.var/app/{,**} rw, - owner @{user_documents_dirs}/ rw, + # Can create dotfile directories for any app + owner @{user_cache_dirs}/*/ w, + owner @{user_config_dirs}/*/ w, + owner @{user_share_dirs}/*/ w, + owner @{user_games_dirs}/{,**/} w, + owner @{user_documents_dirs}/ w, owner @{user_cache_dirs}/flatpak/{,**} rw, owner @{user_config_dirs}/pulse/client.conf r, diff --git a/apparmor.d/profiles-g-l/iotop b/apparmor.d/profiles-g-l/iotop index c53b4656..d85b0244 100644 --- a/apparmor.d/profiles-g-l/iotop +++ b/apparmor.d/profiles-g-l/iotop @@ -10,32 +10,28 @@ include @{exec_path} = @{bin}/iotop profile iotop @{exec_path} { include - include include + include - # Needed? - audit deny capability net_admin, - - # To set processes' priorities capability sys_nice, - @{exec_path} r, - @{bin}/python3.@{int} r, + network netlink raw, - @{bin}/file rix, + @{exec_path} r, @{bin}/ r, + @{bin}/file rix, + @{bin}/python3.@{int} r, + + /etc/magic r, @{PROC}/ r, - @{PROC}/vmstat r, - owner @{PROC}/@{pid}/mounts r, - owner @{PROC}/@{pid}/fd/ r, @{PROC}/@{pids}/cmdline r, @{PROC}/@{pids}/task/ r, @{PROC}/sys/kernel/pid_max r, - - # For file - /etc/magic r, + @{PROC}/vmstat r, + owner @{PROC}/@{pid}/fd/ r, + owner @{PROC}/@{pid}/mounts r, include if exists } From c8b1751f37289da85eeaa4d0d5081e07594d7125 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Wed, 11 Dec 2024 23:29:44 +0100 Subject: [PATCH 08/18] fix(profile): snap integration with dbus. --- apparmor.d/profiles-s-z/snapd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apparmor.d/profiles-s-z/snapd b/apparmor.d/profiles-s-z/snapd index fe24ed06..0a9b332d 100644 --- a/apparmor.d/profiles-s-z/snapd +++ b/apparmor.d/profiles-s-z/snapd @@ -93,8 +93,7 @@ profile snapd @{exec_path} { @{lib_dirs}/snapd/snap-update-ns rPx, /usr/share/bash-completion/{,**} r, - /usr/share/dbus-1/{system,session}.d.d/snapd.{system,session}-services.conf* rw, - /usr/share/dbus-1/{system,session}.d/{,snapd*} r, + /usr/share/dbus-1/{system,session}.d/{,snapd*} rw, /usr/share/dbus-1/services/*snap* r, /usr/share/polkit-1/actions/{,**/} r, From 64ed654fdfa79a4c5ceba0454d26d31143f0daeb Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 12 Dec 2024 18:26:16 +0100 Subject: [PATCH 09/18] fix(profile): cron communication with dbus. --- apparmor.d/groups/cron/cron | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apparmor.d/groups/cron/cron b/apparmor.d/groups/cron/cron index 4ce618ef..25549a39 100644 --- a/apparmor.d/groups/cron/cron +++ b/apparmor.d/groups/cron/cron @@ -27,6 +27,8 @@ profile cron @{exec_path} flags=(attach_disconnected) { ptrace (read) peer=unconfined, + unix bind type=stream addr=@@{udbus}/bus/cron/system, + @{exec_path} mr, @{sh_path} rix, From c8cbeac9b245290efb1adb97c5240092c43c3df0 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 12 Dec 2024 21:34:18 +0000 Subject: [PATCH 10/18] fix(profile): snapd --- apparmor.d/profiles-s-z/snapd | 1 + 1 file changed, 1 insertion(+) diff --git a/apparmor.d/profiles-s-z/snapd b/apparmor.d/profiles-s-z/snapd index 0a9b332d..250005f5 100644 --- a/apparmor.d/profiles-s-z/snapd +++ b/apparmor.d/profiles-s-z/snapd @@ -68,6 +68,7 @@ profile snapd @{exec_path} { @{sh_path} rix, @{bin}/apparmor_parser rPx, @{bin}/cp rix, + @{bin}/getent rix, @{bin}/gzip rix, @{bin}/journalctl rPx, @{bin}/kmod rPx, From 6dcb6c0362fd6abd5464b637aa9f33b4db8fc5fc Mon Sep 17 00:00:00 2001 From: odomingao Date: Fri, 6 Dec 2024 09:41:35 -0300 Subject: [PATCH 11/18] Add wttrbar --- apparmor.d/profiles-s-z/wttrbar | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 apparmor.d/profiles-s-z/wttrbar diff --git a/apparmor.d/profiles-s-z/wttrbar b/apparmor.d/profiles-s-z/wttrbar new file mode 100644 index 00000000..37933679 --- /dev/null +++ b/apparmor.d/profiles-s-z/wttrbar @@ -0,0 +1,26 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 odomingao +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/wttrbar +profile wttrbar @{exec_path} { + include + include + + network inet dgram, + network inet6 dgram, + network inet stream, + network inet6 stream, + + @{exec_path} mr, + + owner /tmp/wttrbar--wttr.in.json rw, + + include if exists +} + +# vim:syntax=apparmor From 3721d12a5d2a4bd555f9adea2881e488ff6167f6 Mon Sep 17 00:00:00 2001 From: Besanon Date: Fri, 13 Dec 2024 18:06:59 +0100 Subject: [PATCH 12/18] more lxqt-files (#613) * Create abstraction for lxqt desktop group first file for the LXQT 2.0 desktop group * Update lxqt * xdg-desktop abstraction added * removing tabs * Create startlxqt starter file for LXQT Desktop * Create startlxqt * fixing startlxqt I use sddm as display manager I cant remove the other file - only use graphical env., sorry After startlxqt i would add 2 lines to sddm to enable the start of LXQT desktop * Delete apparmor.d/profiles-s-z/startlxqt * indented by 2 spaces (like other entries) * Update sddm Enable sddm to start an lxqt desktop session * Create lxqt-session lxqt-session to be started by startlxqt. Display manager: sddm * Update lxqt-session * Update lxqt-session * removed trailing whitespace * Update kscreen_backend_launcher to support lxqt desktop is needed for several complaints: DENIED kscreen_backend_launcher open owner @{user_config_dirs}/lxqt/lxqt.conf comm=kscreen_backend requested_mask=r denied_mask=r DENIED kscreen_backend_launcher open /usr/share/lxqt/lxqt.conf comm=kscreen_backend requested_mask=r denied_mask=r DENIED kscreen_backend_launcher open owner @{user_config_dirs}/lxqt/session.conf comm=kscreen_backend requested_mask=r denied_mask=r DENIED kscreen_backend_launcher open /usr/share/lxqt/session.conf comm=kscreen_backend requested_mask=r denied_mask=r * Update lxqt-session * Create lxqt-panel * Update lxqt-panel * Update lxqt-panel * Update lxqt-panel * fix conflicting x * Update lxqt-panel add child-open * remove include you think its too permissive to have app-launcher-user here, right? * Update lxqt-panel add needed programs * Update lxqt-panel turning back to layout of corresponding xfce file. * Create lxqt-globalkeysd * Create lxqt-about * Create lxqt-leave * Create lxqt-runner * Update lxqt-leave * Update lxqt-runner * Update lxqt-globalkeysd * remove video in lxqt-about * Update lxqt-about * Update lxqt-runner * remove abstr. in lxqt-globalkeysd * remove abstr. in lxqt-runner * remove abstr. in lxqt-leave * Create lxqt-config-notificationd * Create lxqt-config-locale * Create lxqt-config-printer * Create lxqt-config-file-associations * Create lxqt-config-powermanagement * enable wayland-session for lxqt 2.1 startlxqtwayland for starting the session, support for labwc and kwin_wayland * Update lxqt-config-printer * Update lxqt-config-powermanagement * Update sddm * Update sddm * adapt pci-rules ok, havent seen this profile yet. I will change that in lxqt-powermanagement as well and check the other profiles * Update lxqt-config-powermanagement * Update lxqt-config-powermanagement * Update lxqt-config-powermanagement * Update lxqt-config-powermanagement --- apparmor.d/groups/kde/sddm | 4 ++ .../groups/lxqt/lxqt-config-file-associations | 36 ++++++++++++++++ apparmor.d/groups/lxqt/lxqt-config-locale | 40 +++++++++++++++++ .../groups/lxqt/lxqt-config-notificationd | 34 +++++++++++++++ .../groups/lxqt/lxqt-config-powermanagement | 43 +++++++++++++++++++ apparmor.d/groups/lxqt/lxqt-config-printer | 24 +++++++++++ 6 files changed, 181 insertions(+) create mode 100644 apparmor.d/groups/lxqt/lxqt-config-file-associations create mode 100644 apparmor.d/groups/lxqt/lxqt-config-locale create mode 100644 apparmor.d/groups/lxqt/lxqt-config-notificationd create mode 100644 apparmor.d/groups/lxqt/lxqt-config-powermanagement create mode 100644 apparmor.d/groups/lxqt/lxqt-config-printer diff --git a/apparmor.d/groups/kde/sddm b/apparmor.d/groups/kde/sddm index d8adff56..8e491bb2 100644 --- a/apparmor.d/groups/kde/sddm +++ b/apparmor.d/groups/kde/sddm @@ -40,6 +40,7 @@ profile sddm @{exec_path} flags=(attach_disconnected,mediate_deleted) { ptrace (trace) peer=@{profile_name}, signal (receive) set=(hup) peer=@{p_systemd}, + signal (send) set=(kill, term) peer=labwc, signal (send) set=(kill, term) peer=lxqt-session, signal (send) set=(kill, term) peer=startplasma, signal (send) set=(kill, term) peer=xorg, @@ -47,6 +48,7 @@ profile sddm @{exec_path} flags=(attach_disconnected,mediate_deleted) { signal (send) set=(term) peer=kwin_wayland, signal (send) set=(term) peer=sddm-greeter, signal (send) set=(term) peer=startplasma-wayland, + signal (send) set=(term) peer=startlxqtwayland, dbus receive bus=system path=/org/freedesktop/DisplayManager/Seat@{int} interface=org.freedesktop.DBus.Introspectable @@ -95,7 +97,9 @@ profile sddm @{exec_path} flags=(attach_disconnected,mediate_deleted) { @{bin}/kwalletd{5,6} rPx, @{bin}/kwin_wayland rPx, @{bin}/sddm-greeter{,-qt6} rPx, + @{bin}/labwc rPx, @{bin}/startlxqt rPx, + @{bin}/startlxqtwayland rPx, @{bin}/startplasma-wayland rPx, @{bin}/startplasma-x11 rPx, @{bin}/sway rPUx, diff --git a/apparmor.d/groups/lxqt/lxqt-config-file-associations b/apparmor.d/groups/lxqt/lxqt-config-file-associations new file mode 100644 index 00000000..4232f1c7 --- /dev/null +++ b/apparmor.d/groups/lxqt/lxqt-config-file-associations @@ -0,0 +1,36 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 Alexandre Pujol +# Copyright (C) 2024 Besanon +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/lxqt-config-file-associations +profile lxqt-config-file-associations @{exec_path} { + include + include + include + + @{exec_path} mr, + + /etc/machine-id r, + + owner @{user_config_dirs}/ r, + owner @{user_config_dirs}/mimeapps* rwk, + owner @{user_config_dirs}/lxqt-* rwk, + owner @{user_config_dirs}/lxqt/ r, + owner @{user_config_dirs}/lxqt/#@{int} rwk, + owner @{user_config_dirs}/lxqt/lxqt-config-file-associations.conf.lock rwk, + owner @{user_config_dirs}/lxqt/lxqt-config-file-associations.conf kl -> @{user_config_dirs}/lxqt/#@{int}, + owner @{user_config_dirs}/lxqt/lxqt-config-file-associations.conf.@{rand6} rwkl -> @{user_config_dirs}/lxqt/#@{int}, + + owner /tmp/#@{int} rwk, + + /dev/tty rw, + + include if exists +} + +# vim:syntax=apparmor diff --git a/apparmor.d/groups/lxqt/lxqt-config-locale b/apparmor.d/groups/lxqt/lxqt-config-locale new file mode 100644 index 00000000..c7c868c1 --- /dev/null +++ b/apparmor.d/groups/lxqt/lxqt-config-locale @@ -0,0 +1,40 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 Alexandre Pujol +# Copyright (C) 2024 Besanon +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/lxqt-config-locale +profile lxqt-config-locale @{exec_path} { + include + include + include + + @{exec_path} mr, + + /etc/machine-id r, + + owner @{user_config_dirs}/lxqt/* r, + owner @{user_config_dirs}/lxqt/#@{int} rw, + owner @{user_config_dirs}/lxqt/lxqt-config.conf.lock rwk, + owner @{user_config_dirs}/lxqt/lxqt-config.conf.@{rand6} rw, + owner @{user_config_dirs}/lxqt/lxqt-config.conf.@{rand6} l -> @{user_config_dirs}/lxqt/#@{int}, + owner @{user_config_dirs}/lxqt/lxqt-config-locale.conf l -> @{user_config_dirs}/lxqt/#@{int}, + owner @{user_config_dirs}/lxqt/lxqt-config-locale.conf.@{rand6} rw, + owner @{user_config_dirs}/lxqt/lxqt-config-locale.conf.@{rand6} l -> @{user_config_dirs}/lxqt/#@{int}, + owner @{user_config_dirs}/lxqt/lxqt-config-locale.conf.lock rwk, + owner @{user_config_dirs}/lxqt/session.conf.lock rwk, + owner @{user_config_dirs}/lxqt/session.conf.@{rand6} rw, + owner @{user_config_dirs}/lxqt/session.conf.@{rand6} l -> @{user_config_dirs}/lxqt/#@{int}, + + owner /tmp/@{int} r, + + /dev/tty rw, + + include if exists +} + +# vim:syntax=apparmor diff --git a/apparmor.d/groups/lxqt/lxqt-config-notificationd b/apparmor.d/groups/lxqt/lxqt-config-notificationd new file mode 100644 index 00000000..63b2eb67 --- /dev/null +++ b/apparmor.d/groups/lxqt/lxqt-config-notificationd @@ -0,0 +1,34 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 Alexandre Pujol +# Copyright (C) 2024 Besanon +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/lxqt-config-notificationd +profile lxqt-config-notificationd @{exec_path} { + include + include + include + + @{exec_path} mr, + + /etc/machine-id r, + + /var/lib/dbus/machine-id r, + + owner @{user_config_dirs}/lxqt/#@{int} rw, + owner @{user_config_dirs}/lxqt/notifications.conf.lock rwk, + owner @{user_config_dirs}/lxqt/notifications.conf.@{rand6} rw, + owner @{user_config_dirs}/lxqt/notifications.conf.@{rand6} l -> @{user_config_dirs}/lxqt/#@{int}, + + owner /tmp/#@{int} r, + + /dev/tty rw, + + include if exists +} + +# vim:syntax=apparmor diff --git a/apparmor.d/groups/lxqt/lxqt-config-powermanagement b/apparmor.d/groups/lxqt/lxqt-config-powermanagement new file mode 100644 index 00000000..4b96ccb3 --- /dev/null +++ b/apparmor.d/groups/lxqt/lxqt-config-powermanagement @@ -0,0 +1,43 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 Alexandre Pujol +# Copyright (C) 2024 Besanon +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/lxqt-config-powermanagement +profile lxqt-config-powermanagement @{exec_path} { + include + include + include + include + + @{exec_path} mr, + + /etc/machine-id r, + + owner @{user_config_dirs}/lxqt/#@{int} rw, + owner @{user_config_dirs}/lxqt/lxqt-powermanagement.conf.lock rwk, + owner @{user_config_dirs}/lxqt/lxqt-powermanagement.conf.@{rand6} rw, + owner @{user_config_dirs}/lxqt/lxqt-powermanagement.conf.@{rand6} l -> @{user_config_dirs}/lxqt/#@{int}, + + @{sys}/class/leds/ r, + @{sys}/devices/@{pci}/backlight/**/{,max_,actual_}brightness rw, + @{sys}/devices/@{pci}/backlight/**/{uevent,type,enabled} r, + @{sys}/devices/@{pci}/backlight/**/brightness rw, + @{sys}/devices/@{pci}/drm/card@{int}/**/{,max_,actual_}brightness rw, + @{sys}/devices/@{pci}/drm/card@{int}/**/{uevent,type,enabled} r, + @{sys}/devices/@{pci}/drm/card@{int}/**/brightness rw, + @{sys}/devices/@{pci}/*_backlight/{,max_,actual_}brightness rw, + @{sys}/devices/@{pci}/*_backlight/{uevent,type,enabled} r, + + owner /tmp/@{int} r, + + /dev/tty rw, + + include if exists +} + +# vim:syntax=apparmor diff --git a/apparmor.d/groups/lxqt/lxqt-config-printer b/apparmor.d/groups/lxqt/lxqt-config-printer new file mode 100644 index 00000000..f4c38e94 --- /dev/null +++ b/apparmor.d/groups/lxqt/lxqt-config-printer @@ -0,0 +1,24 @@ +# apparmor.d - Full set of apparmor profiles +# Copyright (C) 2024 Alexandre Pujol +# Copyright (C) 2024 Besanon +# SPDX-License-Identifier: GPL-2.0-only + +abi , + +include + +@{exec_path} = @{bin}/lxqt-config-printer +profile lxqt-config-printer @{exec_path} { + include + include + + @{exec_path} mr, + + owner /tmp/@{int} r, + + /dev/tty rw, + + include if exists +} + +# vim:syntax=apparmor From 313f2f7f2cace447c8f2420bcdc62bd283e76030 Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Mon, 18 Nov 2024 23:14:39 +0000 Subject: [PATCH 13/18] Create profile_check.py --- tests/profile_check.py | 463 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100644 tests/profile_check.py diff --git a/tests/profile_check.py b/tests/profile_check.py new file mode 100644 index 00000000..5cc39d6b --- /dev/null +++ b/tests/profile_check.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only + +# KNOWN ISSUES: +# No guards for file type - expects AppArmor +# Diffirent suggestions for single line are mutually exclusive +# Suggestion could point to changed profile name, based on other suggestion + +import sys +import argparse +import pathlib +import shlex +import json +from copy import deepcopy + +def sanitizeProfileName(name): + + if name.startswith('/') or name.startswith('@{'): + name = pathlib.Path(name).stem + + if ' ' in name: + name = re.sub(r'\s+', '-', name) + + return name + +def makeLocalIdentity(nestingStacker_): + + newStacker = [] + for i in nestingStacker_: + i = sanitizeProfileName(i) + newStacker.append(i) + + identity = '_'.join(newStacker) # separate each (sub)profile identity with underscores + + return identity + +def getCurrentProfile(stacker): + + if stacker: + profile = stacker[-1] + else: + profile = None + + return profile + +def handleFileMessages(l, file, profile, lineNum): + + wholeFileAccessProfiles = ( +# '', + ) + suggestOwner = ( # TODO: switch to AARE + r'^@{HOME}', + r'^/home/\w+/', + r'^/run/user/\d+/', + r'^/tmp/', + r'^/var/tmp/', + r'^/dev/shm/', + ) + + lG = l.groupdict() + reason_ = None + if lG.get('path'): + if lG.get('path').startswith('/**') and profile not in wholeFileAccessProfiles: + severity_ = 'ERROR' + reason_ = 'Whole filesystem access is too broad' + suggestion_ = None + + for r in suggestOwner: + if re.match(r, lG.get('path')) and not lG.get('owner'): + indentRe = re.match(r'^\s+', l.group()) + if indentRe: + indent = indentRe.group() + else: + indent = '' + + severity_ = 'NOTICE' + reason_ = "'owner' is likely required" + suggestion_ = indent + 'owner ' + l.group().lstrip() + break + + elif lG.get('bare_file') and profile not in wholeFileAccessProfiles: + severity_ = 'ERROR' + reason_ = 'Whole filesystem access is too broad' + suggestion_ = None + + if reason_: # something matched + msg = ({'filename': file, + 'profile': profile, + 'severity': severity_, + 'line': lineNum, + 'reason': reason_, + 'suggestion': suggestion_}) + else: + msg = None + + return msg + +def readApparmorFile(fullpath): + '''AA file could contain multiple AA profiles''' + headers = ( + '# AppArmor.d - Full set of apparmor profiles', + '# Copyright (C) ', + '# SPDX-License-Identifier: GPL-2.0-only', + ) + + file_data = {} + fileVars = {} + nestingStacker = [] + duplicateProfilesCounter = [] + localExists = {} + localExists_eol = {} + messages = [] + exceptionMsg = None + line = None + gotAbi = False + gotHeaders = {} + gotAttach = False + isAfterProfileStart = False + try: + with open(fullpath, 'r') as f: + for n,line in enumerate(f, start=1): + if isAfterProfileStart: + isAfterProfileStart = False + expectedIndent = len(nestingStacker) * ' ' + indentRe = re.match(r'^\s+', line) + if indentRe: + indent = indentRe.group() + else: + indent = '' + + if indent != expectedIndent: + spacesCount = len(nestingStacker) * 2 + nesingCount = len(nestingStacker) + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': f"Expected {spacesCount} spaces for {nesingCount} nesting", + 'suggestion': f"{expectedIndent}{line}"}) + + if line.endswith(' \n'): + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': "Redundant trailing whitespace", + 'suggestion': line.rstrip()}) + + if '\t' in line: + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': "Tabs are not allowed", + 'suggestion': line.replace('\t', '')}) + + if len(gotHeaders) < 3 and not nestingStacker: + for nH,i in enumerate(headers): + if line.startswith(i): + gotHeaders[nH] = True + + if RE_ABI.search(line): + gotAbi = line + + elif RE_PROFILE_START.search(line) or RE_PROFILE_HAT_DEF.search(line): + isAfterProfileStart = True + m = parse_profile_start_line(line, fullpath) + if m.get('profile'): + nestingStacker.append(m.get('profile')) # set early + + if m.get('attachment') != '@{exec_path}' and not gotAttach: # can be only singular + gotAttach = True + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': "'@{exec_path}' must be defined as main path attachment", + 'suggestion': None}) + + profileMsg = {'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': "A short named profile must be defined", + 'suggestion': None} + if m.get('plainprofile'): + messages.append(profileMsg) + elif m.get('namedprofile'): + if m.get('namedprofile').startswith('/'): + messages.append(profileMsg) + + if m.get('flags'): + m['flags'] = set(shlex.split(m.pop('flags').replace(',', ''))) + if 'complain' in m['flags']: + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'WARNING', + 'line': n, + 'reason': "'complain' flag must be defined in 'dists/flags'", + 'suggestion': None}) + else: + m['flags'] = set() + + if m.get('profile'): + duplicateProfilesCounter.append(m.get('profile')) + profileIdentity = '//'.join(nestingStacker) + file_data[profileIdentity] = m + + elif RE_PROFILE_VARIABLE.search(line): + lineV = RE_PROFILE_VARIABLE.search(line).groups() + + name = strip_quotes(lineV[0]) + operation = lineV[1] + val = separate_vars(lineV[2]) + if fileVars.get(name): + fileVars[name].update(set(val)) + if operation == '=': + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'DEGRADED', + 'line': n, + 'reason': "Tunable must be appended with '+='", + 'suggestion': None}) + else: + fileVars[name] = set(val) + if operation == '+=': + messages.append({'filename': fullpath, + 'profile': getCurrentProfile(nestingStacker), + 'severity': 'DEGRADED', + 'line': n, + 'reason': "Tunable must be defined with '='", + 'suggestion': None}) + + elif RE_INCLUDE.search(line): + if nestingStacker: + profileIdentity = '//'.join(nestingStacker) + localIdentity = makeLocalIdentity(nestingStacker) + localValue = f'include if exists ' # commented out will also match + if localValue in line: + localExists[profileIdentity] = localValue + + # Handle file entries + elif RE_PROFILE_FILE_ENTRY.search(line): + lineF = RE_PROFILE_FILE_ENTRY.search(line) + fileMsg = handleFileMessages(lineF, fullpath, getCurrentProfile(nestingStacker), n) + if fileMsg: + messages.append(fileMsg) + + elif RE_PROFILE_END.search(line): + if getCurrentProfile(nestingStacker): + if not nestingStacker: + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'DEGRADED', + 'line': n, + 'reason': "Unbalanced parenthesis?", # not fully covered + 'suggestion': None}) + else: + profileIdentity = '//'.join(nestingStacker) + localExists_eol[profileIdentity] = n + del nestingStacker[-1] # remove last + + except PermissionError: + exceptionMsg = 'Unable to read the file (PermissionError)' + + except UnicodeDecodeError: + exceptionMsg = 'Unable to read the file (UnicodeDecodeError)' + + except FileNotFoundError: + exceptionMsg = 'No such file or directory (FileNotFoundError)' + + if exceptionMsg: + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'NOTICE', + 'line': None, + 'reason': exceptionMsg, + 'suggestion': None}) + + # Ensure proper header is present + if len(gotHeaders) < 3: + combinedHeader = '\n'.join(headers) + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'WARNING', + 'line': 1, + 'reason': 'No proper header', + 'suggestion': combinedHeader}) + + # Ensure ABI is present + changeAbi = False + abi = 'abi ,' + if gotAbi: + if gotAbi.strip() != abi: + changeAbi = True + else: + changeAbi = True + + if changeAbi: + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'WARNING', + 'line': None, + 'reason': 'ABI is required', + 'suggestion': abi}) + + # Ensure trailing vim syntax + if line: + trailingSyntax = '# vim:syntax=apparmor' + if line != trailingSyntax: + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'WARNING', + 'line': None, + 'reason': 'No trailing syntax hint', + 'suggestion': trailingSyntax}) + + # Assign variables to profile attachments as paths and assign filenames + for p,d in deepcopy(file_data).items(): + file_data[p]['filename'] = fullpath + attachment = d.get('attachment') + if attachment: + if attachment.startswith('@{'): + if fileVars.get(attachment): + file_data[p]['attach_paths'] = fileVars[attachment] # incoming set + else: + messages.append({'filename': fullpath, + 'profile': p, + 'severity': 'ERROR', + 'line': None, + 'reason': f"Unknown global variable as profile attachment: {attachment}", + 'suggestion': None}) + + else: + if isinstance(file_data[p].get('attachment'), set): + raise ValueError("Expecting 'str' or 'None', not 'set'") + file_data[p]['attach_paths'] = {file_data[p]['attachment']} + + # Check if profile block does not have corresponding 'local' include + for p,d in file_data.items(): + if not localExists.get(p): # not found previously + if '//' in p: + identity = p.split('//') + else: + identity = [p] + + localIdentity = makeLocalIdentity(identity) + filename = file_data[p]['filename'] + messages.append({'filename': filename, + 'profile': p, + 'severity': 'WARNING', + 'line': localExists_eol.get(p), # None? Unbalanced parenthesis? + 'reason': "The (sub)profile block does not have expected 'local' include", + 'suggestion': f'include if exists '}) + + # Track multiple definitions inside single file + for profile in duplicateProfilesCounter: + counter = duplicateProfilesCounter.count(profile) + if counter >= 2: + messages.append({'filename': fullpath, + 'profile': profile, + 'severity': 'DEGRADED', + 'line': None, + 'reason': "Profile has been defined {counter} times in the same file", + 'suggestion': None}) + + return (messages, file_data) + +def findAllProfileFilenames(profile_dir): + + profiles = set() + for path in pathlib.Path(profile_dir).iterdir(): + if path.is_file() and not is_skippable_file(path): + profiles.add(path.resolve()) + + # Not default, dig deeper + if not profiles: + nestedDirs = ( + 'groups', + 'profiles-a-f', + 'profiles-g-l', + 'profiles-m-r', + 'profiles-s-z', + ) + for d in nestedDirs: + dirpath = pathlib.Path(pathlib.Path(profile_dir).resolve(), pathlib.Path(d)) + for p in dirpath.rglob("*"): + if p.is_file(): + profiles.add(p) + + return profiles + +def handleArgs(): + """DEGRADED are purposed for fatal errors - when the profile set will fail to load entirely""" + + allSeverities = ['DEBUG', 'NOTICE', 'WARNING', 'ERROR', 'CRITICAL', 'DEGRADED'] + aaRoot = '/etc/apparmor.d' + + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--aa-root-dir', action='store', + default=aaRoot, + help='Target different AppArmor root directory rather than default') + parser.add_argument('-p', '--profile', action='append', + help='Handle only specified profile') +# parser.add_argument('-s', '--severity', action='append', +# choices=allSeverities, +# help='Handle only specified severity event') + + args = parser.parse_args() + +# if not args.severity: +# args.severity = allSeverities + + return args + +def main(argv): + + args = handleArgs() + + messages = [] + + profile_dir = args.aa_root_dir + if not args.profile: + profiles = findAllProfileFilenames(profile_dir) + else: + profiles = set() + for p in args.profile: + absolutePath = pathlib.Path(p).resolve() + profiles.add(absolutePath) + + profile_data = {} + for path in sorted(profiles): + readApparmorFile_Out = readApparmorFile(path) + profilesInFile = readApparmorFile_Out[1] + messages.extend(readApparmorFile_Out[0]) + profile_data.update(profilesInFile) + + for m in messages: + m['filename'] = str(m.get('filename')) + print(json.dumps(m, indent=2)) + + if messages: + sys.exit(1) + + return None + +if __name__ == '__main__': + '''Safeguard errors does NOT cover loosening existing profiles after loading!''' + try: + from apparmor.regex import * + from apparmor.aa import is_skippable_file + from apparmor.rule.file import FileRule, FileRuleset + from apparmor.common import convert_regexp + try: + from apparmor.rule.variable import separate_vars + except ModuleNotFoundError: + from apparmor.aa import separate_vars + + except ModuleNotFoundError: + raise ModuleNotFoundError(f"""Can't find 'python3-apparmor' package! Install with: +$ sudo apt install python3-apparmor""") + + main(sys.argv) From 21b60b4fa3f931bdc19c07e010a0dd3e59d7e1e8 Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Mon, 18 Nov 2024 23:31:22 +0000 Subject: [PATCH 14/18] Update profile_check.py --- tests/profile_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/profile_check.py b/tests/profile_check.py index 5cc39d6b..00f98ec0 100644 --- a/tests/profile_check.py +++ b/tests/profile_check.py @@ -445,7 +445,7 @@ def main(argv): return None if __name__ == '__main__': - '''Safeguard errors does NOT cover loosening existing profiles after loading!''' + try: from apparmor.regex import * from apparmor.aa import is_skippable_file From 679df325de9d2cd2dbf43083e01598f2285b569c Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:49:49 +0000 Subject: [PATCH 15/18] polishing --- tests/profile_check.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/profile_check.py b/tests/profile_check.py index 00f98ec0..ed431628 100644 --- a/tests/profile_check.py +++ b/tests/profile_check.py @@ -49,9 +49,11 @@ def handleFileMessages(l, file, profile, lineNum): # '', ) suggestOwner = ( # TODO: switch to AARE - r'^@{HOME}', + r'^@{HOME}/', r'^/home/\w+/', + r'^@{run}/user/@{uid}/', r'^/run/user/\d+/', + r'^@{tmp}/', r'^/tmp/', r'^/var/tmp/', r'^/dev/shm/', @@ -60,7 +62,7 @@ def handleFileMessages(l, file, profile, lineNum): lG = l.groupdict() reason_ = None if lG.get('path'): - if lG.get('path').startswith('/**') and profile not in wholeFileAccessProfiles: + if lG.get('path').startswith('/**') and profile not in wholeFileAccessProfiles: # false positives severity_ = 'ERROR' reason_ = 'Whole filesystem access is too broad' suggestion_ = None @@ -84,12 +86,12 @@ def handleFileMessages(l, file, profile, lineNum): suggestion_ = None if reason_: # something matched - msg = ({'filename': file, - 'profile': profile, - 'severity': severity_, - 'line': lineNum, - 'reason': reason_, - 'suggestion': suggestion_}) + msg = {'filename': file, + 'profile': profile, + 'severity': severity_, + 'line': lineNum, + 'reason': reason_, + 'suggestion': suggestion_} else: msg = None @@ -98,7 +100,7 @@ def handleFileMessages(l, file, profile, lineNum): def readApparmorFile(fullpath): '''AA file could contain multiple AA profiles''' headers = ( - '# AppArmor.d - Full set of apparmor profiles', + '# apparmor.d - Full set of apparmor profiles', '# Copyright (C) ', '# SPDX-License-Identifier: GPL-2.0-only', ) @@ -129,14 +131,14 @@ def readApparmorFile(fullpath): indent = '' if indent != expectedIndent: - spacesCount = len(nestingStacker) * 2 - nesingCount = len(nestingStacker) + spacesCount = len(nestingStacker) * 2 + nestingCount = len(nestingStacker) messages.append({'filename': fullpath, 'profile': getCurrentProfile(nestingStacker), 'severity': 'WARNING', 'line': n, - 'reason': f"Expected {spacesCount} spaces for {nesingCount} nesting", - 'suggestion': f"{expectedIndent}{line}"}) + 'reason': f"Expected {spacesCount} spaces for {nestingCount} nesting", + 'suggestion': f"{expectedIndent}{line.lstrip()}"}) if line.endswith(' \n'): messages.append({'filename': fullpath, @@ -152,7 +154,7 @@ def readApparmorFile(fullpath): 'severity': 'WARNING', 'line': n, 'reason': "Tabs are not allowed", - 'suggestion': line.replace('\t', '')}) + 'suggestion': line.replace('\t', ' ')}) if len(gotHeaders) < 3 and not nestingStacker: for nH,i in enumerate(headers): From 3030c28c05604b4f1b669d80f6df1e10b404a9ff Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:57:13 +0000 Subject: [PATCH 16/18] Update profile_check.py --- tests/profile_check.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/profile_check.py b/tests/profile_check.py index ed431628..c793543e 100644 --- a/tests/profile_check.py +++ b/tests/profile_check.py @@ -13,6 +13,21 @@ import shlex import json from copy import deepcopy +try: + from apparmor.regex import * + from apparmor.aa import is_skippable_file + from apparmor.rule.file import FileRule, FileRuleset + from apparmor.common import convert_regexp + try: + from apparmor.rule.variable import separate_vars + except ImportError: + from apparmor.aa import separate_vars + + LIBAPPARMOR = True + +except ImportError: + LIBAPPARMOR = False + def sanitizeProfileName(name): if name.startswith('/') or name.startswith('@{'): @@ -118,6 +133,7 @@ def readApparmorFile(fullpath): gotHeaders = {} gotAttach = False isAfterProfileStart = False + lastLineNum = None try: with open(fullpath, 'r') as f: for n,line in enumerate(f, start=1): @@ -262,6 +278,8 @@ def readApparmorFile(fullpath): localExists_eol[profileIdentity] = n del nestingStacker[-1] # remove last + lastLineNum = n + except PermissionError: exceptionMsg = 'Unable to read the file (PermissionError)' @@ -308,12 +326,12 @@ def readApparmorFile(fullpath): # Ensure trailing vim syntax if line: - trailingSyntax = '# vim:syntax=apparmor' + trailingSyntax = '# vim:syntax=apparmor\n' if line != trailingSyntax: messages.append({'filename': fullpath, 'profile': None, 'severity': 'WARNING', - 'line': None, + 'line': lastLineNum, 'reason': 'No trailing syntax hint', 'suggestion': trailingSyntax}) @@ -448,18 +466,8 @@ def main(argv): if __name__ == '__main__': - try: - from apparmor.regex import * - from apparmor.aa import is_skippable_file - from apparmor.rule.file import FileRule, FileRuleset - from apparmor.common import convert_regexp - try: - from apparmor.rule.variable import separate_vars - except ModuleNotFoundError: - from apparmor.aa import separate_vars - - except ModuleNotFoundError: - raise ModuleNotFoundError(f"""Can't find 'python3-apparmor' package! Install with: + if not LIBAPPARMOR: + raise ImportError(f"""Can't find 'python3-apparmor' package! Install with: $ sudo apt install python3-apparmor""") main(sys.argv) From 8f4b3304075325f09b5d5d199597db1c1660fc0f Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Sat, 23 Nov 2024 18:35:53 +0000 Subject: [PATCH 17/18] Update profile_check.py --- tests/profile_check.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/profile_check.py b/tests/profile_check.py index c793543e..90f5b56b 100644 --- a/tests/profile_check.py +++ b/tests/profile_check.py @@ -456,6 +456,9 @@ def main(argv): profile_data.update(profilesInFile) for m in messages: + if m.get('suggestion'): + if m['suggestion'].endswith('\n'): + m['suggestion'] = m.get('suggestion').removesuffix('\n') m['filename'] = str(m.get('filename')) print(json.dumps(m, indent=2)) From edaa45067abd5f18fa702ca3f08897d93425bbc5 Mon Sep 17 00:00:00 2001 From: nobody43 <15267739+nobody43@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:54:17 +0000 Subject: [PATCH 18/18] fix exec_path bug, ignore skipable files --- tests/profile_check.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/profile_check.py b/tests/profile_check.py index 90f5b56b..9b61e636 100644 --- a/tests/profile_check.py +++ b/tests/profile_check.py @@ -186,14 +186,8 @@ def readApparmorFile(fullpath): if m.get('profile'): nestingStacker.append(m.get('profile')) # set early - if m.get('attachment') != '@{exec_path}' and not gotAttach: # can be only singular + if m.get('attachment') == '@{exec_path}' and not gotAttach: # can be only singular gotAttach = True - messages.append({'filename': fullpath, - 'profile': getCurrentProfile(nestingStacker), - 'severity': 'WARNING', - 'line': n, - 'reason': "'@{exec_path}' must be defined as main path attachment", - 'suggestion': None}) profileMsg = {'filename': fullpath, 'profile': getCurrentProfile(nestingStacker), @@ -324,6 +318,15 @@ def readApparmorFile(fullpath): 'reason': 'ABI is required', 'suggestion': abi}) + # Ensure singular '@{exec_path}' + if not gotAttach: + messages.append({'filename': fullpath, + 'profile': None, + 'severity': 'WARNING', + 'line': None, + 'reason': "'@{exec_path}' must be defined as main path attachment", + 'suggestion': None}) + # Ensure trailing vim syntax if line: trailingSyntax = '# vim:syntax=apparmor\n' @@ -450,10 +453,11 @@ def main(argv): profile_data = {} for path in sorted(profiles): - readApparmorFile_Out = readApparmorFile(path) - profilesInFile = readApparmorFile_Out[1] - messages.extend(readApparmorFile_Out[0]) - profile_data.update(profilesInFile) + if not is_skippable_file(path): + readApparmorFile_Out = readApparmorFile(path) + profilesInFile = readApparmorFile_Out[1] + messages.extend(readApparmorFile_Out[0]) + profile_data.update(profilesInFile) for m in messages: if m.get('suggestion'):