I prototyped a parser fix for the deny/cont-match poisoning from my
previous comment, on top of the v5.0.2 tag.

Root cause, confirmed with the parser's own DFA state dump (-D dfa-
states): when any "deny network ..." rule is present, the mandatory
AA_CONT_MATCH stub that gen_net_rule() emits at the family+type prefix
vanishes from the compiled DFA entirely (zero states carry 0x10000000,
versus five without the deny). Two places conspire:

1. gen_net_rule() emits the prefix stub with rule_mode_t::UNSPECIFIED, so a 
deny rule emits the stub as a DENY rule; the structural cont-match bit lands in 
the state's deny mask.
2. Both deny-merge paths then clear it from the allow set: pri_update_perm()'s 
DENYMATCHFLAG branch (perms.allow &= ~amask, where the deny stub's amask 
contains the cont-match bit) and perms_t::apply_and_clear_deny() (allow &= 
~deny), which runs by default via CONTROL_DFA_FILTER_DENY.

Fix: treat the cont-match bit as structural, not grantable - a deny must
never clear it. Two small changes in parser/libapparmor_re:

  - hfa.cc, pri_update_perm() DENYMATCHFLAG branch: after clearing, restore
      perms.allow |= match->perms & amask & AA_COMPAT_CONT_MATCH;
  - hfa.h, perms_t::apply_and_clear_deny(): after clearing, restore
      allow |= deny & AA_COMPAT_CONT_MATCH;

Verification with the DFA-walking tool against the exact QRT profile
(with both deny connect rules):

                        create  bind  listen  accept  send  connect
  5.0.2 (unpatched)     DENIED  DENIED DENIED DENIED  DENIED DENIED
  5.0.2 + fix           DENIED  ALLOWED ALLOWED ALLOWED ALLOWED DENIED

(create remains DENIED because the profile does not grant it - the test-
profile fix from comment 3 is still needed; connect remains DENIED, as
the deny rule intends.)

Additional checks with the patched parser:
- Selective deny still works: "network (connect) ip=127.0.0.1 port=8080," + 
"deny network (connect) ip=10.0.0.1," allows connect to 127.0.0.1 and denies 
10.0.0.1.
- Broad grant + specific deny: "network inet stream," + "deny network (connect) 
ip=10.0.0.1," allows create/bind/connect except connect to 10.0.0.1.
- Deny-only profile still denies.
- The deny poisoning is not address-scoped: before the fix, "deny network 
(connect) ip=10.0.0.1," also broke "network (bind) ip=127.0.0.1 port=8080,". 
After the fix, the bind rule works.

Parser test suite (parser/ make tests): all test binaries that completed
passed, including the deny, minimize and xtrans suites (tst_regex,
tst_misc, tst_symtab, tst_variable, tst_lib, and tst_interface's
minimize/deny/xtrans cases). The run was not run to completion locally
because the generated equality-matrix test takes very long, but the
baseline behaves the same.

Note this does not address the beta1-era issue (missing mandatory cont-
match stub entirely for conditional inet rules) - that is fixed already
in 5.0.2 - nor the separate legacy net_allowed_af downgrade issue in
update_compat_net() (socket-type mask OR-ed into the deny mask), which
is on a different code path and still open.

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2163740

Title:
  net_inet_tcp_fastopen from ubuntu_qrt_apparmor failed on Resolute

To manage notifications about this bug go to:
https://bugs.launchpad.net/apparmor/+bug/2163740/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to