Page MenuHomeFreeBSD

unix/*: rewrite unp_internalize() cmsg parsing cycle
ClosedPublic

Authored by glebius on Jun 1 2022, 1:55 AM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Dec 9, 2:26 AM
Unknown Object (File)
Sat, Dec 7, 11:51 PM
Unknown Object (File)
Tue, Nov 26, 11:18 AM
Unknown Object (File)
Sun, Nov 24, 4:19 PM
Unknown Object (File)
Thu, Nov 21, 7:00 AM
Unknown Object (File)
Wed, Nov 20, 10:08 AM
Unknown Object (File)
Wed, Nov 20, 10:07 AM
Unknown Object (File)
Wed, Nov 20, 10:07 AM
Subscribers

Details

Summary

Make it a complex, but a single for(;;) statement. The previous cycle
with some loop logic in the beginning and some loop logic at the end
was confusing. Both me and markj@ were misleaded to a conclusion that
some checks are unnecessary, while they actually were necessary.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

What does "unix/*:" mean in the commit title? Why not just "unix:"?

sys/kern/uipc_usrreq.c
2202
2204

Hmm, I think there is a sneaky bug here, also present in the old version.

Note that on LP64 platforms, CMSG_SPACE(0) > sizeof(struct cmsghdr), since message data is aligned to 8 bytes and sizeof(struct cmsghdr) == 12. So it's possible to have data - (char *)cm > cm->cmsg_len. That means that the calculation of datalen can underflow.

For example, set msg_controllen = CMSG_SPACE(0) and msg_control = &(struct cmsghdr){.cmsg_len = sizeof(struct cmsghdr), .cmsg_level = SOL_SOCKET, .cmsg_type = SCM_foo}.

I think in this case it's mostly harmless because the test CMSG_SPACE(newlen) > MCLBYTES below will fail, and for non SCM_RIGHTS messages, CMSG_SPACE(datalen) will equal CMSG_SPACE(0) due to 32-bit integer truncation, so the loop will break (though we do not signal an error). But we should definitely fix this.

  • Handle incorrectly filled cmsg_len
  • Add test case for this
  • Rebase it independent from my unix-dgram branch

Thanks! Looks ok to me, my commits are minor.

sys/kern/uipc_usrreq.c
2204

Can't it be part of the for loop condition?

tests/sys/kern/unix_passfd_test.c
747

This comment is too specific now, probably the second sentence can just be deleted.

774

CMSG_LEN(0) is exactly equal to sizeof(struct cmsghdr).

782

Rather than having an ifdef LP64 (I believe this is discouraged in new code since at least on CHERI, sizeof(long) != sizeof(void *)), we could use the predicate CMSG_SPACE(0) != CMSG_LEN(0) or CMSG_SPACE(0) != sizeof(struct cmsghdr).

tests/sys/kern/unix_passfd_test.c
774

Nope:

(kgdb) p sizeof(struct cmsghdr)
$1 = 12
(kgdb) p (((__uintptr_t)(sizeof(struct cmsghdr)) + 7) & ~7)
$2 = 16

Will update on the other comments today. Thanks

tests/sys/kern/unix_passfd_test.c
774

Oops, sorry, I forgot that CMSG_LEN includes alignment for the header.

glebius added inline comments.
tests/sys/kern/unix_passfd_test.c
782

Unfortunately we can't use sizeof() in preprocessor. Do you want me to code the check in C?

tests/sys/kern/unix_passfd_test.c
782

Yeah, I think checking in C is fine...

glebius added inline comments.
tests/sys/kern/unix_passfd_test.c
782

Then, I think, this is final version.

This revision is now accepted and ready to land.Jun 6 2022, 1:34 PM