Page MenuHomeFreeBSD

if_enc: pullup for ip header if m_len == 0
Needs ReviewPublic

Authored by igor.ostapenko_pm.me on Thu, Jun 27, 8:40 PM.

Details

Reviewers
None
Group Reviewers
network
Summary
if_enc(4) can pass IPsec payload to pfil(9) with the outer header or without
it. In case of a small packet like ICMP, when mbuf cluster is not used,
everything works fine. Otherwise, the first mbuf in a chain has m_len == 0
if it is asked to strip the outer header. Both ipfw and pf usually do not
expect such situation, and they may end up reading the outer header. It
leads to unexpected behavior of the firewalls.
Test Plan
# kldload ipsec if_enc pf
# kyua test -k /usr/tests/sys/net/Kyuafile if_enc

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

I’ve been working on this PR:
[14.0 CURRENT] PF recognizes encrypted IPSec traffic as coming from WAN. | NAT with IPsec Phase 2 Networks
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273198

My initial hypothesis is that the issue mentioned is caused by a misconfiguration. But later I found that I cannot do a usual pf port forwarding for enc0 traffic. The research led me to the conclusion mentioned in the summary.

I was thinking about the place of the fix. My current reasoning is as follows:

  • it looks to be a generic thing for both main firewalls to expect non-empty first mbuf
  • adding such case handling on the firewall side could alter performance or existing stability
  • ipsec side is also could avoid changing if possible
  • if_enc itself looks to be a good place for a change, located for its users only

Another question is the way of fixing. m_pullup looks to be a good enough solution, the standard KPI. The performance optimized custom way (presumably) could be considered in future if there are business needs.

Also, it looks to be more appropriate to limit it only for the m_len == 0 cases.

“IPv4 only patch” seems to be good enough for the start of discussion.

AFAIK, firewalls were always m_pullup-ing for themselves as much as they need, regardless of which interface or layer gave them a packet. Why doesn't it work for enc?

I think it is firewall problem when it can not handle some unexpected data. Pfil hook expects that mbus has M_PKTHDR and m->m_pkthdr.len in this case should not be 0, even when m_len is 0. Thus, I think if doesn't work properly, it should be fixed in firewall.

Yeah, having such case unhandled, for years I guess, makes a feeling of some intention there. That's the source of my doubts. Thanks for sorting this out.

The next iteration goes on the pf side: https://reviews.freebsd.org/D45780