Skip to main content
Topic solved
This topic has been marked as solved and requires no further attention.
Topic: [SOLVED] Apparmor runit sysinit script prints weird errors despite working (Read 788 times) previous topic - next topic
0 Members and 2 Guests are viewing this topic.

[SOLVED] Apparmor runit sysinit script prints weird errors despite working

After installing and enabling Apparmor on my system I got some weird output when booting that I can't understand. If anyone is willing to help me with this/research this with me, I would greatly appreciate it. My init system is runit.

How I got to here:

So I installed the packages
Code: [Select]
sudo pacman -S apparmor apparmor-runit
Enabled apparmor's enforce mode in /etc/rc/apparmor.conf and added
Code: [Select]
lsm=landlock,lockdown,yama,apparmor,bpf
to the kernel parameters in /etc/default/grub.

I made sure the audit daemon and rules  (ctl) were enabled in runit and rebooted.

The issue:

My machine booted just fine but soon my console was flooded with messages of the type
Code: [Select]
* Load profile enforce: /etc/apparmor.d/usr.sbin.winbindd
File  not found, skipping...
(one for each profile), ending with
Code: [Select]
/usr/lib/rc/functions: line 82: /run/sv.d/failed/: Is a directory
followed by the login prompt.

What I got so far:

Delving into the sysinit script /etc/rc/sysinit/96-apparmor, the last error in the functions file is obviously caused by a failed call of
Code: [Select]
(( rc || $? )) && stat_die
since stat_die is called without any arguments.

Everything else is weird. This is the for loop that prints the above pairs of lines (one for every profile) in the sysinit script
Code: [Select]
for profile in /etc/apparmor.d/*; do
  if [[ -f "$profile" ]]; then
    printf '* Load profile %s: %sn' "$APPARMOR" "$profile"
    apparmor_parser -a "$AACOMPLAIN" "$profile"
  fi
done
So the printf command prints the first line and the apparmor_parser command prints the second line.
Digging through the apparmor source code, this error happens on line 1652 of parser/parser_main.c:
Code: [Select]
if (profilename && stat(profilename, &stat_file) == -1) {
  last_error = errno;
  PERROR("File %s not found, skipping...n", profilename);
  if (abort_on_error)
    break;
  goto cleanup;
}
appearing as if an empty string had been passed to apparmor_parser??
My confussion is even greater since after these 52 error messages, every profile appears to be loaded properly, as verified by aa-status and some testing with firejail. How is this possible, since the
Code: [Select]
goto cleanup;
line clearly skips the loading of the profile into memory?

My guess (not tested yet) is that the empty "$AACOMPLAIN" in the sysinit script somehow gets interpreted as an empty string since the filename in the error message appears to be empty (note the %s), generating one extra line of error (besides the silent success when the profile is loaded).

Does anybody have more insight on this (non)issue? Possible fixes?

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #1
It's entirely possible that the service just failed a bunch of times in a row, runit kept trying to restart it, and then it eventually worked after something finished initializing.

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #2
My guess (not tested yet) is that the empty "$AACOMPLAIN" in the sysinit script somehow gets interpreted as an empty string since the filename in the error message appears to be empty (note the %s), generating one extra line of error (besides the silent success when the profile is loaded).
You can add
Code: [Select]
set -x
before the call to apparmor_parser or change the shebang to
Code: [Select]
#!/bin/sh -x
to enable the execution trace, which will output each command before execution to stderr, preceeded by the value of PS4.

You can also add something like
Code: [Select]
printf "AACOMPLAIN=[%s], profile=[%s]\n" "$AACOMPLAIN" "$profile"
before the call to apparmor_parser to output the contents of those variables.

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #3
Thank you both a lot for your suggestions.

Developments:

Setting
Code: [Select]
set -x
and commenting out the
Code: [Select]
# . /etc/rc/apparmor.conf
so I could control the value of the variable by just passing them to the script's environment revealed a lot. Indeed the "$AACOMPLAIN" in
Code: [Select]
apparmor_parser -a "$AACOMPLAIN" "$profile"
in the init script was the root of the problem. If APPARMOR is set to complain, then the apparmor_parser call gets interpreted correctly as
Code: [Select]
apparmor_parser -a -C "winbindd"
However, if APPARMOR=enforce, setting $AACOMPLAIN to an empty string, then the call gets interpreted as
Code: [Select]
apparmor_parser -a '' "winbindd"
Notice the empty string that gets passed as an argument, producing the error message that was confusing me. Also notice the surrounding quotes around the second argument!
Indeed, running simply
Code: [Select]
apparmor_parser -a ''
in the terminal reproduces the error message I've been seeing in the tty:
Code: [Select]
File  not found, skipping...
(note there are two spaces between File and not, since %s gets replaced by an empty string).

 Solution:

The simplest solution I could find was to simply remove the double quotations marks around the variables in the apparmor_parser call. Actually removing the quotation marks around $AACOMPLAIN alone fixes the issue completely. The line in the sysinit script then looks like this
Code: [Select]
apparmor_parser -a $AACOMPLAIN "$profile"
If I run
Code: [Select]
aa-teardown
APPARMOR=enforce ./96-apparmor start
it returns the expected output (one line for each profile)
Code: [Select]
* Load profile enforce: /etc/apparmor.d/usr.sbin.winbindd

Removing the quotes around the second argument has no effect that I see (since bash just interprets it as a string anyway).
I assume this is not some trickery with my custom bash settings, since it happens in Stage 1, before the login shell along with its profile files gets loaded (??)

Is it possible to make this change to the repositories or is there a better fix? I don't want to rely on changing system files manually in case they get overwritten during an upgrade, but getting 52 errors severely crowds my tty and makes me a bit nervous. I am willing to contribute this simple change myself if you are too busy.

Other observations

Another note, the shebang is actually
Code: [Select]
#!/bin/bash
I use dash as my /bin/sh and replacing the shebang with /bin/sh  breaks the /usr/lib/rc/functions script in line 128.

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #4
Just pushed a fix to testing you may want to check if it fixes the issue.
You are expected to use bash as /bin/sh in Arch so not really the distribution's problem.

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #5
Thanks, installed the package manually from gremlins and after minor testing it appears to work well.
Will mark as solved after I get a chance to reboot and everything works well.

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #6
I pushed a second fix for another error that I didn't see on line 41

 

Re: Apparmor runit sysinit script prints weird errors despite working

Reply #7
Yes I see, but the fix was hard to find since you also changed indent width from 4 to 2 in the script, so the diff was all red :D

In any case, I tested the newest change and the reboot went well with only the expected output in the tty. Thank you all very much for fixing this.