Merge utils: ignore peer when parsing logs for non-peer access modes

utils: ignore peer when parsing logs for non-peer access modes

Some access modes (create, setopt, getopt, bind, shutdown, listen,
getattr, setattr) cannot be used with a peer in network rules.

Due to how auditing is implemented in the kernel, the peer information
might be available in the log (as faddr= but not daddr=), which causes
a failure in log parsing.

When parsing the log, check if that's the case and ignore the peer,
avoiding the exception on the NetworkRule constructor.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/427

Reported-by: Evan Caville <evan.caville@canonical.com>

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

Closes #427
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1314
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: John Johansen <john@jjmx.net>
This commit is contained in:
John Johansen 2024-08-30 23:17:08 +00:00
commit ab5f180b08
5 changed files with 31 additions and 2 deletions

View file

@ -0,0 +1 @@
[ 310.308737] audit: type=1400 audit(1724847289.985:631): apparmor="ALLOWED" operation="getsockname" class="net" profile="/usr/bin/wg" pid=15374 comm="wg" laddr=::ffff:127.0.0.1 lport=53131 faddr=::ffff:127.0.0.1 fport=51821 saddr=::ffff:127.0.0.1 src=53131 family="inet6" sock_type="dgram" protocol=17 requested="getattr" denied="getattr"

View file

@ -0,0 +1,20 @@
START
File: testcase_network_12.in
Event type: AA_RECORD_ALLOWED
Audit ID: 1724847289.985:631
Operation: getsockname
Mask: getattr
Denied Mask: getattr
Profile: /usr/bin/wg
Command: wg
PID: 15374
Network family: inet6
Socket type: dgram
Protocol: udp
Local addr: ::ffff:127.0.0.1
Foreign addr: ::ffff:127.0.0.1
Local port: 53131
Foreign port: 51821
Class: net
Epoch: 1724847289
Audit subid: 631

View file

@ -0,0 +1,4 @@
/usr/bin/wg {
network (getattr) inet6 dgram ip=::ffff:127.0.0.1 port=53131,
}

View file

@ -75,6 +75,8 @@ RE_NETWORK_DETAILS = re.compile(
+ '(' + RE_PEER_EXPR + r')?\s*'
+ r'$')
non_peer_accesses = {'create', 'bind', 'listen', 'shutdown', 'getattr', 'setattr', 'getopt', 'setopt'}
class NetworkRule(BaseRule):
"""Class to handle and store a single network rule"""
@ -121,8 +123,8 @@ class NetworkRule(BaseRule):
if self.peer_expr != self.ALL and 'ip' in self.peer_expr and not is_valid_ip(self.peer_expr['ip']):
raise AppArmorException(f'Invalid ip: {self.peer_expr["ip"]}')
if not self.all_accesses and self.peer_expr != self.ALL and self.accesses & {'create', 'bind', 'listen', 'shutdown', 'getattr', 'setattr', 'getopt', 'setopt'}:
raise AppArmorException('Cannot use a peer_expr and an access in {create, bind, listen, shutdown, getattr, setattr, getopt, setopt} simultaneously')
if not self.all_accesses and self.peer_expr != self.ALL and self.accesses & non_peer_accesses:
raise AppArmorException('Cannot use a peer_expr and an access in the set (%s) simultaneously' % ', '.join(non_peer_accesses))
self.domain = None
self.all_domains = False
@ -300,6 +302,8 @@ class NetworkRule(BaseRule):
@classmethod
def from_hashlog(cls, hl):
for access, family, sock_type, protocol, local_event, peer_event in BaseRule.generate_rules_from_hashlog(hl, 6):
if access and set(access.split()) & non_peer_accesses:
peer_event = (None, None)
yield cls(access, family, sock_type, local_event, peer_event, log_event=True)