diff --git a/profiles/apparmor.d/lsof b/profiles/apparmor.d/lsof new file mode 100644 index 000000000..754c009b3 --- /dev/null +++ b/profiles/apparmor.d/lsof @@ -0,0 +1,52 @@ +# Last Modified: Mon Jan 20 20:17:22 2025 +abi , + +include + +#------------------------------------------------------------------ +# Copyright (C) 2025 Canonical Ltd. +# +# Author: Nicolas Campuzano Jimenez +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +#------------------------------------------------------------------ +# vim: ft=apparmor +# + +profile lsof /usr/bin/lsof flags=(attach_disconnected.path=/aa_disconnected/) { + include + include + + /usr/bin/lsof mr, + + capability sys_ptrace, + capability dac_read_search, + capability dac_override, + ptrace read, + + mqueue getattr type=posix, + + / r, + + /**/ r, + + @{PROC} r, + @{PROC}/locks r, + @{PROC}/@{pids}/fd/ r, + @{PROC}/@{pids}/fdinfo/* r, + @{PROC}/@{pids}/lock r, + @{PROC}/@{pids}/mounts r, + @{PROC}/@{pids}/stat r, + @{PROC}/@{pids}/task/ r, + @{PROC}/@{pids}/task/@{tid}/fd/ r, + @{PROC}/@{pids}/task/@{tid}/fdinfo/* r, + @{PROC}/@{pids}/task/@{tid}/maps r, + @{PROC}/@{pids}/task/@{tid}/stat r, + + @{PROC}/@{pid}/net/* r, + + include if exists +} + diff --git a/tests/profiles/lsof/task.yaml b/tests/profiles/lsof/task.yaml new file mode 100644 index 000000000..00773fd45 --- /dev/null +++ b/tests/profiles/lsof/task.yaml @@ -0,0 +1,206 @@ +summary: stress test for the lsof profile +execute: | + ########### + ## SETUP ## + ########### + # Create character device (check it doesn't exist!!) + [ -e /dev/mem ] || sudo mknod /dev/mem c 1 1 # major 1-> memory device; #minor 1-> DMA + # make sure we can run lsof -d mem later + sudo chmod 660 /dev/mem + + # Create loopback test device (check it doesn't exist either!) + [ -e /dev/loop10 ] || sudo mknod /dev/loop10 b 7 10 # major 1 -> loopback device; #minor10 -> instance 10 of device driver; shouldn't be in use. + dd if=/dev/zero of=/tmp/test.img bs=1M count=10 # Fill /tmp/test.img with 10MB of 0's + sudo losetup /dev/loop10 /tmp/test.img # mount /tmp/test.img on /dev/loop10 so it looks like a block device + + # Create character test device (check again!) + [ -e /dev/char-test ] || sudo mknod /dev/char-test c 99 1 # this major shouldn't be defined, should be a useless device just for extra testing + + + ########### + ## TESTS ## + ########### + + # List all open files attached to /, recursively + # sudo lsof +D / + # these 2 could be combined in one (-i -U) to list all UNIX sockets and network files + sudo lsof -i + sudo lsof -U + # these 5 could be combined ( -d mem,mmap,txt,CHR,BLK) for mapped, memory-mapped, binaries, character & block devices) + sudo lsof -d mem + sudo lsof -d mmap + sudo lsof -d txt + sudo lsof -d CHR + sudo lsof -d BLK + + ############################# + # Test Deleted but Open Files + ############################# + # Create a test file and open it in the background + echo "test data" > /tmp/deleted-file + sleep 1 + tail -f /tmp/deleted-file & # Keep file open in background + TAIL_PID=$! + sleep 2 + # Delete the file while it's in use + rm /tmp/deleted-file + + # See if lsof still detects it + sudo lsof | grep -F "/tmp/deleted-file (deleted)" + + # Cleanup + kill $TAIL_PID + + + ############################## + # Start a temporary web server + ############################## + python3 -m http.server 8080 & + PYTHON_PID=$! + sleep 2 + # Check what process is using port 8080 + sudo lsof -i :8080 + + # Cleanup + kill $PYTHON_PID + + #################### + # Test Named Pipe + #################### + # Open a named pipe + mkfifo /tmp/testpipe + # open the pipe for r/w so that it remains open + exec 3<> /tmp/testpipe + # Check lsof dislays open pipe + sudo lsof +E | tee /tmp/lsof.log | grep /tmp/testpipe || grep FIFO /tmp/lsof.log + # Cleanup + exec 3<&- # Close fd 3 + rm /tmp/testpipe + + + ##################### + # Open network sockets + ##################### + # Start a temporary web server + python3 -m http.server 8080 & + sleep 1 + PYTHON_PID=$! + sleep 1 + # Check what process is using port 8080 + sudo lsof -i :8080 + sleep 1 + # Cleanup + kill $PYTHON_PID + + # ################################### + # Process deletes its own binary + echo -e '#!/bin/bash\nrm -- "$0"\nsleep 60' > /tmp/self-delete.sh + chmod +x /tmp/self-delete.sh + + # Run it in the background + /tmp/self-delete.sh & + SCRIPT_PID=$! + sleep 2 + # Check if `lsof` can still track it + echo "Process PID: $SCRIPT_PID" + sudo lsof -p $SCRIPT_PID + + # Cleanup + kill $SCRIPT_PID 2>/dev/null + + + ################# + # Zombie process + ################# + # Create a process that turns into a zombie + bash -c 'sleep 10 & wait $!' & + PARENT_PID=$! + + # Wait a moment and check for zombies + sleep 2 + ps -ef | grep defunct + sudo lsof -p $PARENT_PID + + # Cleanup + kill $PARENT_PID 2>/dev/null + + ########################### + # Encrypted loopback device + ########################### + # Create an encrypted loopback device + dd if=/dev/zero of=/tmp/encrypted.img bs=1M count=30 + sudo losetup /dev/loop20 /tmp/encrypted.img + echo "securest passphrase" | sudo cryptsetup luksFormat /dev/loop20 --key-file=- + echo "securest passphrase" | sudo cryptsetup luksOpen /dev/loop20 encdev --key-file=- + + # Mount it and check open files + sudo mkfs.ext4 /dev/mapper/encdev + mkdir -p /mnt/encrypted + sudo mount /dev/mapper/encdev /mnt/encrypted + sleep 2 + echo "test data" > /mnt/encrypted/testfile + # Start tail in the background and capture the correct PID + exec 3