Skip to content

Commit

Permalink
Merge pull request criblio#1589 from criblio/fix-1586-syscall-sendmms…
Browse files Browse the repository at this point in the history
…g-support

Add support for SYS_sendmmsg in wrap_scope_syscall - 1586
  • Loading branch information
michalbiesek committed Jul 18, 2023
2 parents 6ffba55 + d1f7f5c commit 53a346a
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 100 deletions.
219 changes: 120 additions & 99 deletions src/wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -3491,6 +3491,38 @@ isAnAppScopeConnection(int fd)
return FALSE;
}

/*
* Process the sedmmmsg depending on return status of operation
* and value of msgvec
*/
static void
scopeProcessSendmmsg(int sockfd, struct mmsghdr *msgvec, int rc) {
if (rc != -1) {
if (msgvec) {
scopeLog(CFG_LOG_TRACE, "fd:%d sendmmsg", sockfd);

// For UDP connections the msg is a remote addr
if (!sockIsTCP(sockfd)) {
if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in), REMOTE);
}
}

if (remotePortIsDNS(sockfd)) {
getDNSName(sockfd, msgvec->msg_hdr.msg_iov->iov_base, msgvec->msg_hdr.msg_iov->iov_len);
}

doSend(sockfd, rc, &msgvec->msg_hdr, rc, MSG);
}
} else {
setRemoteClose(sockfd, errno);
doUpdateState(NET_ERR_RX_TX, sockfd, 0, "sendmmsg", "nopath");
}
}
/*
* Note:
* The syscall function in libc is called from the loader for
Expand Down Expand Up @@ -3539,18 +3571,27 @@ wrap_scope_syscall(long number, ...)
}
return rc;
}
case SYS_sendmmsg:
{
long rc;
rc = g_fn.syscall(number, fArgs.arg[0], fArgs.arg[1],
fArgs.arg[2], fArgs.arg[3]);
if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) {
return rc;
}

scopeProcessSendmmsg((int)fArgs.arg[0], (struct mmsghdr *) fArgs.arg[1], rc);
return rc;
}

/*
* These messages are in place as they represent
* functions that use syscall() in libuv, used with node.js.
* These are functions defined in libuv/src/unix/linux-syscalls.c
* that we are otherwise interposing. The DBG call allows us to
* check to see how many of these are called and therefore
* what we are missing. So far, we only see accept4 used.
* what we are missing. So far, we only see accept4/sendmmsg used.
*/
case SYS_sendmmsg:
//DBG("syscall-sendmsg");
break;

case SYS_recvmmsg:
//DBG("syscall-recvmsg");
Expand Down Expand Up @@ -5384,39 +5425,41 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags)
WRAP_CHECK(sendmsg, -1);
rc = g_fn.sendmsg(sockfd, msg, flags);
if (rc != -1) {
size_t msg_iovlen_orig;
size_t msg_controllen_orig;
struct msghdr *msg_modify = (struct msghdr *)msg;

scopeLog(CFG_LOG_TRACE, "fd:%d sendmsg", sockfd);

// For UDP connections the msg is a remote addr
if (msg && !sockIsTCP(sockfd)) {
if (msg->msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msg->msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in), REMOTE);
if (msg) {
size_t msg_iovlen_orig;
size_t msg_controllen_orig;
struct msghdr *msg_modify = (struct msghdr *)msg;

scopeLog(CFG_LOG_TRACE, "fd:%d sendmsg", sockfd);

// For UDP connections the msg is a remote addr
if (!sockIsTCP(sockfd)) {
if (msg->msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msg->msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in), REMOTE);
}
}
}

if (g_ismusl == TRUE) {
msg_iovlen_orig = msg->msg_iovlen;
msg_modify->msg_iovlen &= 0xFFFFFFFF;
msg_controllen_orig = msg->msg_controllen;
msg_modify->msg_controllen &= 0xFFFFFFFF;
}
if (g_ismusl == TRUE) {
msg_iovlen_orig = msg->msg_iovlen;
msg_modify->msg_iovlen &= 0xFFFFFFFF;
msg_controllen_orig = msg->msg_controllen;
msg_modify->msg_controllen &= 0xFFFFFFFF;
}

if (remotePortIsDNS(sockfd)) {
getDNSName(sockfd, msg->msg_iov->iov_base, msg->msg_iov->iov_len);
}
if (remotePortIsDNS(sockfd)) {
getDNSName(sockfd, msg->msg_iov->iov_base, msg->msg_iov->iov_len);
}

doSend(sockfd, rc, msg, rc, MSG);
doSend(sockfd, rc, msg, rc, MSG);

if (g_ismusl == TRUE) {
msg_modify->msg_iovlen = msg_iovlen_orig;
msg_modify->msg_controllen = msg_controllen_orig;
if (g_ismusl == TRUE) {
msg_modify->msg_iovlen = msg_iovlen_orig;
msg_modify->msg_controllen = msg_controllen_orig;
}
}
} else {
setRemoteClose(sockfd, errno);
Expand All @@ -5435,33 +5478,11 @@ internal_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int fla
WRAP_CHECK(sendmmsg, -1);

rc = g_fn.sendmmsg(sockfd, msgvec, vlen, flags);
if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) return rc;

if (rc != -1) {
scopeLog(CFG_LOG_TRACE, "fd:%d sendmmsg", sockfd);

// For UDP connections the msg is a remote addr
if (!sockIsTCP(sockfd)) {
if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in), REMOTE);
}
}

if (remotePortIsDNS(sockfd)) {
getDNSName(sockfd, msgvec->msg_hdr.msg_iov->iov_base, msgvec->msg_hdr.msg_iov->iov_len);
}

doSend(sockfd, rc, &msgvec->msg_hdr, rc, MSG);

} else {
setRemoteClose(sockfd, errno);
doUpdateState(NET_ERR_RX_TX, sockfd, 0, "sendmmsg", "nopath");
if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) {
return rc;
}

scopeProcessSendmmsg(sockfd, msgvec, rc);
return rc;
}

Expand Down Expand Up @@ -5635,38 +5656,38 @@ recvmsg(int sockfd, struct msghdr *msg, int flags)
if (flags & MSG_PEEK) return rc;

if (rc != -1) {
size_t msg_iovlen_orig;
size_t msg_controllen_orig;
scopeLog(CFG_LOG_TRACE, "fd:%d recvmsg", sockfd);

// For UDP connections the msg is a remote addr
if (msg) {
if (msg->msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msg->msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in), REMOTE);
}
}
size_t msg_iovlen_orig;
size_t msg_controllen_orig;
scopeLog(CFG_LOG_TRACE, "fd:%d recvmsg", sockfd);

// For UDP connections the msg is a remote addr
if (msg->msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msg->msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msg->msg_name,
sizeof(struct sockaddr_in), REMOTE);
}

if (g_ismusl == TRUE) {
msg_iovlen_orig = msg->msg_iovlen;
msg->msg_iovlen &= 0xFFFFFFFF;
msg_controllen_orig = msg->msg_controllen;
msg->msg_controllen &= 0xFFFFFFFF;
}
if (g_ismusl == TRUE) {
msg_iovlen_orig = msg->msg_iovlen;
msg->msg_iovlen &= 0xFFFFFFFF;
msg_controllen_orig = msg->msg_controllen;
msg->msg_controllen &= 0xFFFFFFFF;
}

if (remotePortIsDNS(sockfd)) {
getDNSAnswer(sockfd, (char *)msg, rc, MSG);
}
if (remotePortIsDNS(sockfd)) {
getDNSAnswer(sockfd, (char *)msg, rc, MSG);
}

doRecv(sockfd, rc, msg, rc, MSG);
doAccessRights(msg);
doRecv(sockfd, rc, msg, rc, MSG);
doAccessRights(msg);

if (g_ismusl == TRUE) {
msg->msg_iovlen = msg_iovlen_orig;
msg->msg_controllen = msg_controllen_orig;
if (g_ismusl == TRUE) {
msg->msg_iovlen = msg_iovlen_orig;
msg->msg_controllen = msg_controllen_orig;
}
}
} else {
doUpdateState(NET_ERR_RX_TX, sockfd, 0, "recvmsg", "nopath");
Expand All @@ -5690,25 +5711,25 @@ recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
if (flags & MSG_PEEK) return rc;

if (rc != -1) {
scopeLog(CFG_LOG_TRACE, "fd:%d recvmmsg", sockfd);

// For UDP connections the msg is a remote addr
if (msgvec) {
if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in), REMOTE);
scopeLog(CFG_LOG_TRACE, "fd:%d recvmmsg", sockfd);

// For UDP connections the msg is a remote addr
if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in6)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in6), REMOTE);
} else if (msgvec->msg_hdr.msg_namelen >= sizeof(struct sockaddr_in)) {
doSetConnection(sockfd, (const struct sockaddr *)msgvec->msg_hdr.msg_name,
sizeof(struct sockaddr_in), REMOTE);
}

if (remotePortIsDNS(sockfd)) {
getDNSAnswer(sockfd, (char *)&msgvec->msg_hdr, rc, MSG);
}
}

if (remotePortIsDNS(sockfd)) {
getDNSAnswer(sockfd, (char *)&msgvec->msg_hdr, rc, MSG);
doRecv(sockfd, rc, &msgvec->msg_hdr, rc, MSG);
doAccessRights(&msgvec->msg_hdr);
}

doRecv(sockfd, rc, &msgvec->msg_hdr, rc, MSG);
doAccessRights(&msgvec->msg_hdr);
} else {
doUpdateState(NET_ERR_RX_TX, sockfd, 0, "recvmmsg", "nopath");
}
Expand Down
4 changes: 4 additions & 0 deletions test/integration/glibc/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ RUN gcc -g -o /opt/sig_test/sighandler /opt/sig_test/sighandler.c
COPY ./glibc/sigusrhandler.c /opt/sig_test/sigusrhandler.c
RUN gcc -g -o /opt/sig_test/sigusrhandler /opt/sig_test/sigusrhandler.c -lrt

RUN mkdir -p /opt/msg_test
COPY ./glibc/msgtest.c /opt/msg_test/msgtest.c
RUN gcc -g -o /opt/msg_test/msg_test /opt/msg_test/msgtest.c

RUN mkdir -p /opt/extract_scope && \
mkdir -p /opt/patch_libscope

Expand Down
27 changes: 27 additions & 0 deletions test/integration/glibc/msgtest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#define _GNU_SOURCE

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>

// The intention of the this test is to check handling NULL
// value in case of msg by the scope
// Calling `sendmmsg`/`recvmmsg` with empty values can be used
// for checking the support for the calls

int main() {
int sockfd, ret;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
ret = sendmmsg(sockfd, NULL, 0, 0);
fprintf(stdout, "\nsendmmsg returned %d", ret);
ret = recvmmsg(sockfd, NULL, 0, 0, NULL);
fprintf(stdout, "\nrecvmmsg returned %d", ret);

return 0;
}
15 changes: 15 additions & 0 deletions test/integration/glibc/scope-test
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,21 @@ fi

endtest

#
# verify msgtest
#

starttest msg_test_verify
cd /opt/msg_test/

scope -z ./msg_test

if [ $? -ne 0 ]; then
ERR+=1
fi

endtest

#
# verify fault_test_read_only_mem
#
Expand Down
1 change: 1 addition & 0 deletions test/integration/payload/Dockerfile.glibc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt update \
&& apt install -y \
curl \
host \
htop \
&& rm -rf /var/lib/apt/lists/*

Expand Down
2 changes: 1 addition & 1 deletion test/integration/payload/Dockerfile.musl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:latest

RUN apk add bash curl htop
RUN apk add bash curl bind htop

ENV PATH="/usr/local/scope:/usr/local/scope/bin:${PATH}"
RUN echo "export PATH=/usr/local/scope:/usr/local/scope/bin:${PATH}" >/etc/profile.d/path.sh
Expand Down
Loading

0 comments on commit 53a346a

Please sign in to comment.