Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pf: Fix for purecap kernel with subobject bounds #2282

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

RoundofThree
Copy link
Member

The issues that this PR fixes were found by fuzzing.

Tagging @YiChenChai.

…c_qstats_v0

The struct sizes are used to generate IOCTL code numbers.
In CHERI purecap, the struct sizes of pfioc_qstats_v1 and
pfioc_qstats_v0 are identical, causing a compile error.
@@ -1918,6 +1918,7 @@ struct pfioc_qstats_v1 {
* written entirely in terms of the v0 or v1 type.
*/
u_int32_t version; /* Requested version of stats struct */
void *pad;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not prefer this method of dealing with this issue. Just #ifdef out the v0 constant in the various switch statements instead for purecap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on how you do freebsd64 (or freebsd32) you may still need the native ABI to have unique ioctl numbers for these. Though it looks like there's no compat support for these currently. I know @kprovost discovered this encoding collision a while ago but don't recall what he thought the best fix was.

@@ -1478,10 +1478,10 @@ pf_normalize_tcp(struct pfi_kkif *kif, struct mbuf *m, int ipoff,
(tcp_get_flags(th) & (TH_RES1|TH_RES2|TH_RES2)) != 0) {
u_int16_t ov, nv;

ov = *(u_int16_t *)(&th->th_ack + 1);
ov = *(u_int16_t *)(__unbounded_addressof(th->th_ack) + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe we should just not require subobject bounds on any members of struct tcphdr? There's really no good reason to narrow bounds to any individual members of this structure. I worry that other places will be doing this same trick to cope with the 12 bit flags field, so would rather fix it in the definition of struct tcphdr if possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, there's always good reason to narrow bounds, you never know when a pointer to a member might be being passed around.

Better would be to have (__)tcp_[gs]et_flags16 or something that just peeks/pokes each field and shifts everything around.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you don't even need the set, just the get, as you just want to get the uint16_t that contains all the changed flag bits, in host order.

Copy link
Member

@jrtc27 jrtc27 Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the following works:

ntohs(((uint16_t)th->th_off << 12) | ((uint16_t)th->th_x2 << 8) | th->th_flags)

https://godbolt.org/z/sT7abM6Kh

@@ -1598,7 +1598,7 @@ struct pf_pdesc {
#ifdef INET6
struct icmp6_hdr icmp6;
#endif /* INET6 */
char any[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__subobject_use_container_bounds?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though really this is extremely pointless a member. One should just be casting a pointer to the union to a char * instead.

Copy link
Member

@jrtc27 jrtc27 Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given there are only the following four uses in sys that I can find:

origin/dev:sys/netpfil/pf/pf.c:3667:     m_copyback(m, off, hdrlen, pd->hdr.any);
origin/dev:sys/netpfil/pf/pf.c:5240:         m_copyback(m, off, hdrlen, pd->hdr.any);
origin/dev:sys/netpfil/pf/pf.c:5290:     m_copyback(m, off, hdrlen, pd->hdr.any);
origin/dev:sys/netpfil/pf/pf.c:5524:         m_copyback(m, off, hdrlen, pd->hdr.any);

I'd rather see the code be less dodgy and cast instead. This is something that can be upstreamed.

@@ -296,7 +296,7 @@ struct pf_addr {
u_int8_t addr8[16];
u_int16_t addr16[8];
u_int32_t addr32[4];
}; /* 128-bit address */
} __no_subobject_bounds; /* 128-bit address */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no "why" in the commit message for this change. Presumably pointers to the union members are being cast to others, or turned back into a struct pf_addr? But I don't know the details to know whether this is the right thing to be doing (likely it points at crappy code elsewhere we should fix upstream).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular I know @kprovost discovered some issues upstream where the code was dodgy by trying out a purecap kernel a while back, but don't know if those all got polished and committed. I'd rather not paper over bad code with opt-out annotations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the issues I found did get pushed upstream, but some I just papered over as well. I need to dig up that tree and see what did and did not make it in.

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.

4 participants