i/b/log_observe: add CAP_SYSLOG for /dev/kmsg access on Jammy and above
As of Jammy, the default setting for sysctl kernel.dmesg_restrict changed from 0 -> 1. This means that CAP_SYSLOG is required for to access /dev/kmsg. Observably, on a 20.04 host (regardless of snap base), the log-observe plug was sufficient for a snap to run dmesg in confinement, but on a 22.04 host, it fails with message dmesg: read kernel buffer failed: Operation not permitted even with UID == 0 (snappy-debug output: = AppArmor = Time: Jun 26 16:29:49 Log: apparmor="DENIED" operation="capable" profile="snap.log-observe-test.test" pid=4030401 comm="dmesg" capability=34 capname="syslog" Capability: syslog ) Adding this snippet to the AA profile allows access.
This will need review from Security, as CAP_SYSLOG obviously has other implications.
Related: SNAPDENG-35243
@alexmurray appreciate the review, and everything you said makes sense.
To provide some context about the use case where this came up, it was caught in a "regression" of a third party log gathering app which had been packaged as a snap. I can look at whether that app can be configured to just gather this stuff via journald, but it may or may not be as simple as changing the approach of something completely homegrown.
Is there room for a more privileged log-control interface which would cover these types of operations? I ask because theoretically the other workaround would be to change the sysctl knob back to 0, but that of course has its own downsides (I assume there are reasons this default was changed in the first place) and a more privileged interface might let you contain those downsides to a single snap, as opposed giving privileges to multiple snaps/other applications/users across the system
Yes I would prefer perhaps a new interface rather than changing the semantics of this interface - log-control sounds like a good approach (although @pedronis is the ultimate authority on this sort of thing)
@alexmurray could we maybe add some seccomp rules to block the 'write' like commands? eg:
~syslog SYSLOG_ACTION_CONSOLE_LEVEL - -
~syslog SYSLOG_ACTION_CONSOLE_CLEAR - -
~syslog SYSLOG_ACTION_CONSOLE_OFF - -
~syslog SYSLOG_ACTION_CONSOLE_ON - -
"-observe" suffixed interfaces are not meant to give write-like permissions, so either we introduce a new interface, or need to use seccomp filtering carefully to block the write-like functionality enabled by CAP_SYSLOG, doing that though we need to be careful of the interactions with other interfaces that might have given that out for the full functionality
I am happy to refactor this PR to instead introduce a new "log-control" interface, but want to hear the answer to @bboozzoo's question first, as it may mean it is not necessary for this use case.
So I think the idea of using seccomp to limit the access to syslog() seems like a good, pragmatic solution - but it does make me a bit nervous that we may end up missing something and inadvertently turning this -observe interface into a -control interface. But then that means we just need to be thorough in the research for the implementation. So +1 from me for taking that route for now - FWIW we already take a similar approach in the base template where we allow the ioctl syscall but deny use of dangerous parameters.
If you choose to take this approach @alexclewontin can you please add a spread test that tests that a snap which plugs log-observe is denied from using syslog() with these different dangerous arguments? Thanks.
@alexmurray will do, appreciate the guidance! @pedronis I will take a crack at refactoring + adding spread test as per Alex's advice
@alexmurray
~syslog >SYSLOG_ACTION_SIZE_BUFFER But then we would want to add a test for that as well then - thoughts?
it seems to be on the safe side we do need to do that?
@alexclewontin do you think you might be able to try adding the additional denylist entry for any future/unknown syslog actions as well as an additional test for this?
Yep, sorry for delay, I am adding
my main remaining question is how the filtering will interact with snaps using interfaces that were giving cap syslog already (mostly kernel-module-*), probably low risk that; and snaps that get themselves partially out of confinement, do those manipulate the seccomp filters as well? will they be stopped to do things they were able to do so far?
hmm this is a good point - so in this case of plugging both log-observe and say kernel-module-observe we give capability syslog in the AppArmor rules for both interfaces - but then we have deny seccomp rules in the base template now for syslog() with various more dangerous arguments. As such this would then block the use of these and so a snap would have to be careful to not plug both log-observe and kernel-module-observe etc if it just wants to read the syslog etc.
Perhaps in the future some kind of priority mechanism could be developed for the seccomp filters in snap-seccomp but for now I think it best to leave it to snap authors to manage this.
@alexmurray am I confused? the new extra filtering is done in the main seccomp template afaict, not only for log-observe, so choosing interfaces wouldn't change things, no?
@pedronis yes - the base template now contains the explicit deny rules so you are right - I wonder what would happen if we added explicit allow rules to these other interfaces, whether they would override the deny rules from the base template?
@alexmurray
@pedronis yes - the base template now contains the explicit deny rules so you are right - I wonder what would happen if we added explicit allow rules to these other interfaces, whether they would override the deny rules from the base template?
my memory is that denies wins with how things are organized?
Decided with @pedronis to hold back this PR from 2.66, to allow for further thinking/testing.
Still require more thinking, moving out of 2.67 and marking blocked.
@alexmurray
@pedronis yes - the base template now contains the explicit deny rules so you are right - I wonder what would happen if we added explicit allow rules to these other interfaces, whether they would override the deny rules from the base template?
my memory is that denies wins with how things are organized?
That is my understanding as well, the more restrictive profile will win. We apply allow/deny profiles independently, in which case the deny rules should take priority. This could be different if all rules were in a single profile, and AFAIU it would depend on how they are added/ordered to libseccomp.
so the interfaces that gave already syslog capability were:
kernel_module_control.go kernel_module_observe
I'm quite sure that we don't want 'write' actions for the latter, and it's questionable why one would think to get control on syslog from the former.
We need to be ready introducing a syslog-control interface if somebody needs the 'write' parts that we are blocking here though, we would need to undo the deny bits, in similar ways we deal some conflicting rules with apparmor atm.
So from that POV I think we are ok here. I have a different wondering though that I need to address with @alexmurray
Regarding the question from @pedronis on possible conflict between this proposed new interface (with explicit deny seccomp rules) and other interfaces which may want to purposefully grant these same accesses, perhaps this can be alleviated by changing the direction here to instead use the explicit allow rules for only a subset of actions in the base template as suggested by @jslarraz and removing the blanket allow for the syslog syscall in the base template - then other more privileged interfaces can simply grant additional actions and there should be no conflict.
@alexclewontin any appetite for (unfortunately) reworking this as suggested by @jslarraz above?
This is likely at risk for 2.68 which we are intending to cut next Monday.
Moved to 2.69, the task is not ready and it as discussed on Friday 7 Feb, getting it ready in time for 2.68 is not viable.
@alexmurray Sorry for delay. I can eventually rework, but might be a few more weeks before I get to it