From 313f750c3edf3798abe52aea0c91f1e9f14f3a48 Mon Sep 17 00:00:00 2001
From: hoelscher <jens.hoelscher@fh-muenster.de>
Date: Tue, 13 Oct 2015 16:24:59 +0200
Subject: [PATCH] Add check for all fields in sctp_recvmsg

---
 gtests/net/packetdrill/run_system_call.c      | 235 +++++++++++++++++-
 .../tests/bsd/sctp/sctp_recvmsg.pkt           |  23 +-
 2 files changed, 247 insertions(+), 11 deletions(-)

diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 535d2b93..cf947c92 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -3055,10 +3055,243 @@ static int syscall_sctp_sendmsg(struct state *state, struct syscall_spec *syscal
 #endif
 }
 
+#if defined(__FreeBSD__) || defined(__Linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
+static int check_sctp_sndrcvinfo(struct sctp_sndrcvinfo_expr *expr,
+				 struct sctp_sndrcvinfo *sctp_sndrcvinfo, 
+				 char** error) {
+	if (expr->sinfo_stream->type != EXPR_ELLIPSIS) {
+		u16 sinfo_stream;
+
+		if (get_u16(expr->sinfo_stream, &sinfo_stream, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_stream != sinfo_stream) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_stream: expected: %hu actual: %hu",
+				 sinfo_stream, sctp_sndrcvinfo->sinfo_stream);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_ssn->type != EXPR_ELLIPSIS) {
+		u16 sinfo_ssn;
+
+		if (get_u16(expr->sinfo_ssn, &sinfo_ssn, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_ssn != sinfo_ssn) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_ssn: expected: %hu actual: %hu",
+				 sinfo_ssn, sctp_sndrcvinfo->sinfo_ssn);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_flags->type != EXPR_ELLIPSIS) {
+		u16 sinfo_flags;
+
+		if (get_u16(expr->sinfo_flags, &sinfo_flags, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_flags != sinfo_flags) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_flags: expected: %hu actual: %hu",
+				 sinfo_flags, sctp_sndrcvinfo->sinfo_flags);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_ppid->type != EXPR_ELLIPSIS) {
+		u32 sinfo_ppid;
+
+		if (get_u32(expr->sinfo_ppid, &sinfo_ppid, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_ppid != sinfo_ppid) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_ppid: expected: %u actual: %u",
+				 sinfo_ppid, sctp_sndrcvinfo->sinfo_ppid);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_context->type != EXPR_ELLIPSIS) {
+		u32 sinfo_context;
+
+		if (get_u32(expr->sinfo_context, &sinfo_context, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_context != sinfo_context) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_context: expected: %u actual: %u",
+				 sinfo_context, sctp_sndrcvinfo->sinfo_context);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_timetolive->type != EXPR_ELLIPSIS) {
+		u32 sinfo_timetolive;
+
+		if (get_u32(expr->sinfo_timetolive, &sinfo_timetolive, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_timetolive != sinfo_timetolive) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_timetolive: expected: %u actual: %u",
+				 sinfo_timetolive, sctp_sndrcvinfo->sinfo_timetolive);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_tsn->type != EXPR_ELLIPSIS) {
+		u32 sinfo_tsn;
+
+		if (get_u32(expr->sinfo_tsn, &sinfo_tsn, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_tsn != sinfo_tsn) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_tsn: expected: %u actual: %u",
+				 sinfo_tsn, sctp_sndrcvinfo->sinfo_tsn);
+			return STATUS_ERR;
+		}
+	}
+	if (expr->sinfo_cumtsn->type != EXPR_ELLIPSIS) {
+		u32 sinfo_cumtsn;
+
+		if (get_u32(expr->sinfo_cumtsn, &sinfo_cumtsn, error)) {
+			return STATUS_ERR;
+		}
+		if (sctp_sndrcvinfo->sinfo_cumtsn != sinfo_cumtsn) {
+			asprintf(error, "sctp_sndrcvinfo.sinfo_cumtsn: expected: %u actual: %u",
+				 sinfo_cumtsn, sctp_sndrcvinfo->sinfo_cumtsn);
+			return STATUS_ERR;
+		}
+	}
+	return STATUS_OK;
+}
+#endif
+
 static int syscall_sctp_recvmsg(struct state *state, struct syscall_spec *syscall,
-			struct expression_list *args, char **error)
+				struct expression_list *args,
+				char **error)
 {
+#if defined(__FreeBSD__) || defined(__Linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
+	int script_fd, live_fd, live_msg_flags, result;
+	void *msg;
+	u32 len;
+	struct sockaddr live_from;
+	socklen_t live_fromlen;
+	struct sctp_sndrcvinfo live_sinfo;
+	struct expression *len_expr, *script_sinfo_expr, *script_msg_flags_expr;
+	struct expression *script_fromlen_expr, *script_from_expr;
+
+	if (check_arg_count(args, 7, error))
+		return STATUS_ERR;
+	if (s32_arg(args, 0, &script_fd, error))
+		return STATUS_ERR;
+	if (to_live_fd(state, script_fd, &live_fd, error))
+		return STATUS_ERR;
+	if (ellipsis_arg(args, 1, error))
+		return STATUS_ERR;
+	len_expr = get_arg(args, 2, error);
+	if (get_u32(len_expr, &len, error))
+		return STATUS_ERR;
+
+	msg = calloc(len, 1);
+	assert(msg != NULL);
+
+	begin_syscall(state, syscall);
+	result = sctp_recvmsg(live_fd, msg, len, (struct sockaddr*) &live_from,
+			      &live_fromlen, &live_sinfo, &live_msg_flags);
+	free(msg);
+	
+	if (end_syscall(state, syscall, CHECK_EXACT, result, error)) {
+		return STATUS_ERR;
+	}
+
+	script_from_expr = get_arg(args, 3, error);
+	if (script_from_expr->type != EXPR_ELLIPSIS) {
+		struct sockaddr *script_addr;
+		if (script_from_expr->type == EXPR_SOCKET_ADDRESS_IPV4) {
+			script_addr = (struct sockaddr*)script_from_expr->value.socket_address_ipv4;
+		} else if( script_from_expr->type == EXPR_SOCKET_ADDRESS_IPV6) {
+			script_addr = (struct sockaddr*)script_from_expr->value.socket_address_ipv6;
+		} else {
+			asprintf(error, "sctp_recvmsg fromlen: can't check sctp_recvmsg from");
+			return STATUS_ERR;			
+		}
+		if (script_addr->sa_family != live_from.sa_family) {
+			asprintf(error, "sctp_recvmsg from.sa_family: expected: %d actual: %d",
+				 script_addr->sa_family, live_from.sa_family);
+			return STATUS_ERR;
+		}
+		switch(script_addr->sa_family) {
+		case AF_INET: 
+			{
+				struct sockaddr_in *script_sockaddr = (struct sockaddr_in*)script_addr;
+				struct sockaddr_in *live_sockaddr = (struct sockaddr_in*)&live_from;
+				if (live_sockaddr->sin_port != script_sockaddr->sin_port) {
+					asprintf(error, "sctp_recvmsg from.sinport. expected: %d actual %d",
+						ntohs(script_sockaddr->sin_port), ntohs(live_sockaddr->sin_port));
+					return STATUS_ERR;
+				}
+				if (live_sockaddr->sin_addr.s_addr != script_sockaddr->sin_addr.s_addr) {
+					int len = strnlen(inet_ntoa(script_sockaddr->sin_addr), 16);
+					char *expected_addr = malloc(sizeof(char) * len);
+					memcpy(expected_addr, inet_ntoa(script_sockaddr->sin_addr), len);
+					asprintf(error, "sctp_recvmsg from.sin_addr. expected: %s actual %s",
+						expected_addr, inet_ntoa(live_sockaddr->sin_addr));
+					free(expected_addr);
+					return STATUS_ERR;
+				}
+			}
+			break;
+		case AF_INET6: 
+			{
+				struct sockaddr_in6 *script_sockaddr = (struct sockaddr_in6*)script_addr;
+				struct sockaddr_in6 *live_sockaddr = (struct sockaddr_in6*)&live_from;
+				if (live_sockaddr->sin6_port != script_sockaddr->sin6_port) {
+					asprintf(error, "sctp_recvmsg from.sinport. expected: %d actual %d",
+						ntohs(script_sockaddr->sin6_port), ntohs(live_sockaddr->sin6_port));
+					return STATUS_ERR;
+				}
+				if (live_sockaddr->sin6_addr.s6_addr != script_sockaddr->sin6_addr.s6_addr) {
+					char expected_addr[INET6_ADDRSTRLEN];
+					char live_addr[INET6_ADDRSTRLEN];
+					inet_ntop(AF_INET6, &script_sockaddr->sin6_addr, expected_addr, INET6_ADDRSTRLEN);
+					inet_ntop(AF_INET6, &live_sockaddr->sin6_addr, live_addr, INET6_ADDRSTRLEN);
+					asprintf(error, "sctp_recvmsg from.sin6_addr. expected: %s actual %s",
+						 expected_addr, live_addr);
+					return STATUS_ERR;
+				}
+			}
+			break;
+		}
+
+	}
+
+	script_fromlen_expr = get_arg(args, 4, error);
+	if (script_fromlen_expr->type != EXPR_ELLIPSIS) {
+		int script_fromlen;
+		if (get_s32(script_fromlen_expr, &script_fromlen, error))
+			return STATUS_ERR;
+		if (script_fromlen != live_fromlen) {
+			asprintf(error, "sctp_recvmsg fromlen: expected: %d actual: %d",
+				 script_fromlen, live_fromlen);
+			return STATUS_ERR;
+		}
+	}
+
+	script_sinfo_expr = get_arg(args, 5, error);
+	if (script_sinfo_expr->type != EXPR_ELLIPSIS) {
+		if (check_sctp_sndrcvinfo(script_sinfo_expr->value.sctp_sndrcvinfo, &live_sinfo, error)) {
+			return STATUS_ERR;
+		}
+	}
+	script_msg_flags_expr = get_arg(args, 6, error);
+	if (script_msg_flags_expr->type != EXPR_ELLIPSIS) {
+		int script_msg_flags;
+		if (get_s32(script_msg_flags_expr, &script_msg_flags, error))
+			return STATUS_ERR;
+		if (script_msg_flags != live_msg_flags) {
+			asprintf(error, "sctp_recvmsg msg_flags: expected: %d actual: %d",
+				 script_msg_flags, live_msg_flags);
+			return STATUS_ERR;
+		}
+	}
 	return STATUS_OK;
+#else
+	asprintf(error, "sctp_sendmsg is not supported");
+	return STATUS_ERR;
+#endif
 }
 
 /* A dispatch table with all the system calls that we support... */
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt
index 47795008..c4df4023 100644
--- a/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt
+++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_recvmsg.pkt
@@ -8,20 +8,23 @@
 +0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
 +0.1 < sctp: COOKIE_ACK[flgs=0]
 +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
+//sctp_recvmsg(int sd, void * msg, size_t len, struct sockaddr * from, socklen_t * fromlen, struct sctp_sndrcvinfo* sinfo, int * msg_flags);
 
 +0.0 < sctp: DATA[flgs=BE, len=1016, tsn=1, sid=0, ssn=0, ppid=0]
-+0.0 > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]]
-
-//ssize_t sctp_recvmsg(int sd, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags);
-
-+0.0 sctp_recvmsg(3, ..., 1000, ..., ..., {sinfo_stream=..., sinfo_ssn=..., sinfo_flags=..., sinfo_ppid=...,
-sinfo_context=..., sinfo_timetolive=..., sinfo_tsn=..., sinfo_cumtsn=...}, 0) = 1000
+*    > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]]
++0.0 sctp_recvmsg(3, ..., 1000, ..., ..., ..., 8) = 1000
 
 +0.0 < sctp: DATA[flgs=BE, len=1016, tsn=2, sid=0, ssn=1, ppid=0]
-+0.0 > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]]
-+0.0 sctp_sendmsg(3, ..., 1000, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}, ...,  0) = 1000
+*    > sctp: SACK[flgs=0, cum_tsn=2, a_rwnd=..., gaps=[], dups=[]]
++0.0 sctp_recvmsg(3, ..., 1000, ..., ..., {sinfo_stream=0, sinfo_ssn=1, sinfo_flags=0,
+sinfo_ppid=0, sinfo_context=0, sinfo_timetolive=0, sinfo_tsn=2, sinfo_cumtsn=2}, 8) = 1000
+
++0.0 < sctp: DATA[flgs=BE, len=1016, tsn=3, sid=0, ssn=2, ppid=0]
+*    > sctp: SACK[flgs=0, cum_tsn=3, a_rwnd=..., gaps=[], dups=[]]
++0.0 sctp_recvmsg(3, ..., 1000, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.0.2.1")}, 16,
+{sinfo_stream=0, sinfo_ssn=2, sinfo_flags=0, sinfo_ppid=0, sinfo_context=0, sinfo_timetolive=0, sinfo_tsn=3, sinfo_cumtsn=3}, 8) = 1000
 
-+0.0 close(3)
-+0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.0 close(3) = 0
++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=3]
 +0.1 < sctp: SHUTDOWN_ACK[flgs=0]
 +0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]
-- 
GitLab