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

Audit explicit bounds enforcement for mbufs. #1980

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

Conversation

qwattash
Copy link
Contributor

Remove some explicit cheri_setbounds that are redundant with sub-object bounds, replace with an assertion.
Use the new macro PHYS_TO_DMAP_LEN.
Promote some cheri_setbounds to cheri_setboundsexact, there are some additional cases with ext_buf that would be nice to check for exact representability. From my understanding, it is not currently always the case that the buffers are representable; in particular sys/net/iflib.c has some code that uses buffer space from an array and I suspect we can not assume it is always representable, however I did not yet dig much into how it is constructed. I marked a couple of these cases with a comment for now.

sys/kern/uipc_mbuf.c Outdated Show resolved Hide resolved
sys/kern/uipc_mbuf.c Outdated Show resolved Hide resolved
@@ -1543,6 +1543,7 @@ m_extadd(struct mbuf *mb, char *buf, u_int size, m_ext_free_t freef,
KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__));

mb->m_flags |= (M_EXT | flags);
/* XXX-AM: Should we have an option to warn when these are not exact? */
Copy link
Member

Choose a reason for hiding this comment

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

Is it common that size != cheri_getlen(buf) in these cases?

Copy link
Collaborator

Choose a reason for hiding this comment

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

You can have arbitrary buffers here in theory. I just used this function yesterday to attach a 4K buffer to an mbuf in the NVMe Fabrics target code. I also use it in the fabrics target code for I/O buffers from a LUN backend sent back over the socket. In theory those can be sized as an arbitrary number of blocks (e.g. N * 512). If N is a power of 2 those would all be fine, but possibly it could be a non-power-of-2 in which case you could end up with an inexact size.

@@ -1543,6 +1543,7 @@ m_extadd(struct mbuf *mb, char *buf, u_int size, m_ext_free_t freef,
KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__));

mb->m_flags |= (M_EXT | flags);
/* XXX-AM: Should we have an option to warn when these are not exact? */
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can have arbitrary buffers here in theory. I just used this function yesterday to attach a 4K buffer to an mbuf in the NVMe Fabrics target code. I also use it in the fabrics target code for I/O buffers from a LUN backend sent back over the socket. In theory those can be sized as an arbitrary number of blocks (e.g. N * 512). If N is a power of 2 those would all be fine, but possibly it could be a non-power-of-2 in which case you could end up with an inexact size.

sys/kern/uipc_mbuf.c Show resolved Hide resolved
@@ -419,7 +419,8 @@ struct mbuf {
char m_pktdat[0];
};
};
char m_dat[0] __no_subobject_bounds; /* !M_PKTHDR, !M_EXT */
/* !M_PKTHDR, !M_EXT */
char m_dat[0] __subobject_use_remaining_size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, I think we certainly need a fair bit more explanation in the log of what we are depending on the compiler doing for m_dat and m_pktdat.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It occurs to me that I'm not sure whether the annotation is even necessary at this point. It could be a remnant of older compiler versions that did not know how to detect variable-sized arrays in certain situations. I need to check that, however I agree on the need for more context, I'll split these things into separate commits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like this annotation is still required, while m_pktdat does not require the annotation. This is quite strange and possibly a compiler bug. I kept this in a separate commit, hopefully I can drop it if I find out what is going on in LLVM.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah definitely sounds like a compiler bug. Could you file a LLVM issue?

sys/sys/mbuf.h Outdated
@@ -924,6 +925,7 @@ m_extaddref(struct mbuf *m, char *buf, u_int size, u_int *ref_cnt,

atomic_add_int(ref_cnt, 1);
m->m_flags |= M_EXT;
/* XXX-AM: Should we have an option to warn when these are not exact? */
Copy link
Collaborator

Choose a reason for hiding this comment

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

These can also be arbitrary buffers. I'm not sure the caller is going to be able to do anything though if it is not exact. For example, the cxgbe(4) driver uses this for a feature it calls buffer packing where it allocates a large (multi-page) receive buffer and the NIC packs multiple received packets into the same large buffer. The driver allocates mbufs that then use the large buffer as the backing store but only reference the subset of the buffer. You can certainly use this with 9k jumbo frames where the resulting size passed in size might not be exactly representable?

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if what we actually want is a counter for inexact bounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wonder whether we want one specific for mbufs or a general one. I provisionally added a counter specifically for inexact ext_buf bounds.

@@ -419,7 +419,8 @@ struct mbuf {
char m_pktdat[0];
Copy link
Collaborator

Choose a reason for hiding this comment

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

So why does this not need __subobject_use_remaining_size?

Copy link
Member

Choose a reason for hiding this comment

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

Should be implicit for any variable-length fields ([0] is treated as variable)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See above

@qwattash qwattash marked this pull request as ready for review February 14, 2024 14:51
Asserts that the length of a capability matches the expected length.
When the mbuf m_data is set to m_pktdat we rely on sub-object bounds to ensure
that the resulting capability has length == MHLEN. The pure-capability kernel
without sub-object bounds will ignore these cases.
When mbuf m_data is set to m_dat, rely on the compiler-generated sub-object
bounds to ensure that the resulting capability has length == MLEN.
The pure-capability kernel without sub-object bounds will ignore these cases.
Use the PHYS_TO_DMAP_LEN macro in m_apply_extpg_one() instead of explicitly
setting bounds on the direct map capability.
In most cases, it is not possible to ensure exact bounds for m_ext.
This is required by the compiler for now.
The sysctl security.cheri.mbuf_imprecise_extbuf counts the number of times a
non-representable capability is used as the buffer for an mbuf.m_ext.ext_buf.
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