Skip to content

[DFSan] Fix recvmsg wrapper to support MSG_TRUNC flag. #92599

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

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions compiler-rt/lib/dfsan/dfsan_custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1901,17 +1901,27 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
}

static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg,
int flags) {
dfsan_set_label(0, msg, sizeof(*msg));
dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
for (size_t i = 0; bytes_written > 0; ++i) {
assert(i < msg->msg_iovlen);
for (size_t i = 0; i < msg->msg_iovlen; ++i) {
struct iovec *iov = &msg->msg_iov[i];
size_t iov_written =
bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
size_t iov_written = iov->iov_len;

// When MSG_TRUNC is not set, we want to avoid setting 0 label on bytes that
// may not have changed, using bytes_written to bound the 0 label write.
// When MSG_TRUNC flag is set, bytes_written may be larger than the buffer,
// and should not be used as a bound.
if (!(MSG_TRUNC & flags)) {
if (bytes_written < iov->iov_len) {
iov_written = bytes_written;
}
bytes_written -= iov_written;
}

dfsan_set_label(0, iov->iov_base, iov_written);
bytes_written -= iov_written;
}
}

Expand All @@ -1923,7 +1933,7 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
for (int i = 0; i < ret; ++i) {
dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr, flags);
}
*ret_label = 0;
return ret;
Expand All @@ -1947,7 +1957,7 @@ SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
ssize_t ret = recvmsg(sockfd, msg, flags);
if (ret >= 0)
clear_msghdr_labels(ret, msg);
clear_msghdr_labels(ret, msg, flags);
*ret_label = 0;
return ret;
}
Expand Down
67 changes: 47 additions & 20 deletions compiler-rt/test/dfsan/custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,26 +768,53 @@ void test_recvmsg() {
ssize_t sent = sendmsg(sockfds[0], &smsg, 0);
assert(sent > 0);

char rbuf[128];
struct iovec riovs[2] = {{&rbuf[0], 4}, {&rbuf[4], 4}};
struct msghdr rmsg = {};
rmsg.msg_iov = riovs;
rmsg.msg_iovlen = 2;

dfsan_set_label(i_label, rbuf, sizeof(rbuf));
dfsan_set_label(i_label, &rmsg, sizeof(rmsg));

DEFINE_AND_SAVE_ORIGINS(rmsg)

ssize_t received = recvmsg(sockfds[1], &rmsg, 0);
assert(received == sent);
assert(memcmp(sbuf, rbuf, 8) == 0);
ASSERT_ZERO_LABEL(received);
ASSERT_READ_ZERO_LABEL(&rmsg, sizeof(rmsg));
ASSERT_READ_ZERO_LABEL(&rbuf[0], 8);
ASSERT_READ_LABEL(&rbuf[8], 1, i_label);

ASSERT_SAVED_ORIGINS(rmsg)
{
char rpbuf[2];
struct iovec peek_iov;
peek_iov.iov_base = rpbuf;
peek_iov.iov_len = 2;

struct msghdr peek_header = {};
peek_header.msg_iov = &peek_iov;
peek_header.msg_iovlen = 1;

dfsan_set_label(i_label, rpbuf, sizeof(rpbuf));
dfsan_set_label(i_label, &peek_header, sizeof(peek_header));

DEFINE_AND_SAVE_ORIGINS(peek_header)

ssize_t received = recvmsg(sockfds[1], &peek_header, MSG_PEEK | MSG_TRUNC);
assert(received == sent);
assert(memcmp(sbuf, rpbuf, 2) == 0);
ASSERT_ZERO_LABEL(received);
ASSERT_READ_ZERO_LABEL(&peek_header, sizeof(peek_header));
ASSERT_READ_ZERO_LABEL(&rpbuf[0], 0);

ASSERT_SAVED_ORIGINS(peek_header)
}

{
char rbuf[128];
struct iovec riovs[2] = {{&rbuf[0], 4}, {&rbuf[4], 4}};
struct msghdr rmsg = {};
rmsg.msg_iov = riovs;
rmsg.msg_iovlen = 2;

dfsan_set_label(i_label, rbuf, sizeof(rbuf));
dfsan_set_label(i_label, &rmsg, sizeof(rmsg));

DEFINE_AND_SAVE_ORIGINS(rmsg)

ssize_t received = recvmsg(sockfds[1], &rmsg, 0);
assert(received == sent);
assert(memcmp(sbuf, rbuf, 8) == 0);
ASSERT_ZERO_LABEL(received);
ASSERT_READ_ZERO_LABEL(&rmsg, sizeof(rmsg));
ASSERT_READ_ZERO_LABEL(&rbuf[0], 8);
ASSERT_READ_LABEL(&rbuf[8], 1, i_label);

ASSERT_SAVED_ORIGINS(rmsg)
}

close(sockfds[0]);
close(sockfds[1]);
Expand Down
Loading