Skip to content

Various fixes for fragmentation handling and error handling - #10

Open
hapenner wants to merge 6 commits into
aixoss:masterfrom
hapenner:hp/frag-ref-fixes
Open

hapenner wants to merge 6 commits into
aixoss:masterfrom
hapenner:hp/frag-ref-fixes

Conversation

@hapenner

Copy link
Copy Markdown

No description provided.

frpr_ipv4hdr() masked away the IP_MF bit before checking whether the
fragment's data length was a multiple of 8. That check is only valid
for non-final fragments; the last fragment of a datagram legitimately
has a remainder length. As a result, any fragmented packet whose final
fragment wasn't an exact multiple of 8 bytes was incorrectly flagged
FI_BAD and dropped/logged as malformed.

Capture the MF bit (morefrag) before masking it off and only enforce
the %8 rule when more fragments follow.
frflushlist() recursed into a rule's sub-group list but discarded the
count of rules freed, so the group-defining rule's fr_ref was never
decremented as members were flushed. Separately, the SIOCINAFR/SIOCINIFR
(add) and SIOCRMAFR/SIOCRMIFR (remove) ioctl paths never adjusted
fg->fg_head->fr_ref when a rule belonging to a named group was added or
removed individually.

Left unfixed, fr_ref on a group head can drift out of sync with its
live member count: too high leaves the group head permanently stuck at
EBUSY and undeletable (rule leak); too low risks freeing the group head
while a member still references it (use-after-free).

Now frflushlist() applies the recursive call's return value to fp->fr_ref,
and the ioctl add/remove paths increment/decrement fg_head->fr_ref to
match.
- ip_lookup.c / ip_pool.c: include <netinet/in.h> before <net/if.h> to
  satisfy AIX system header dependencies (net/if.h expects types from
  netinet/in.h to already be visible).
- radix.c: drop 'static' from rn_satisfies_leaf(), rn_lexobetter(), and
  rn_new_radix_mask() (declarations and definitions) so they are visible
  as global symbols, which the AIX kernel-extension export/link step
  requires.
…BUCKET

fr_state_maxbucket (the per-hash-bucket cap enforced when inserting new
state entries) was hardcoded to initialize to 0 directly in ip_state.c,
unlike other state-table tunables (e.g. IPSTATE_MAX) which are routed
through an #ifndef/#define macro so a build can override them with
-D<NAME>=<value>. Add IPSTATE_MAXBUCKET (default 0, preserving current
behavior since fr_stateinit() recomputes a real cap when it sees 0) and
initialize fr_state_maxbucket from it, for consistency and buildtime
configurability.
checkrev() unconditionally compared the running kernel module's version
string against the userland tool's compiled-in IPL_VERSION and returned
-1 on any mismatch, which was producing false-positive failures and
blocking userland tools (ipf, ippool, ipnat, etc.) from operating even
against a compatible kernel module. Wrap the comparison in #ifdef
CHECK_IPL_VERSION (undefined by default) so checkrev() succeeds unless a
build explicitly opts back into the strict check.
…er tools

load_pool.c, load_poolnode.c, and remove_pool.c treated every ioctl
failure identically (perror + return -1), which collapsed genuinely
unexpected errors together with expected, benign conditions:
  - EEXIST: pool/node already exists (e.g. re-running a config load)
  - EBUSY:  pool still referenced by an active rule, can't remove yet
  - ESRCH:  pool doesn't exist, nothing to remove
  - ENOENT: node isn't in the pool, nothing to remove
This made idempotent or repeated configuration operations abort with a
generic, alarming error instead of a clear warning. Each of these errno
values now gets a specific warning message and returns errno itself;
genuinely unexpected errors still fall through to the original
perror()+return -1 path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant