summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2021-02-04 16:20:13 +0100
committerAndreas Schneider <asn@samba.org>2021-02-08 19:29:57 +0100
commite896cecf1fc08d091d09fa29f1cfbfc22dab89ff (patch)
treea0e8f74fbbcb6880a08e00281746790d37563f5f
parent3c7ef4751527bd8c93d5431d9f1e36c4fe648f3d (diff)
downloadsocket_wrapper-e896cecf1fc08d091d09fa29f1cfbfc22dab89ff.tar.gz
socket_wrapper-e896cecf1fc08d091d09fa29f1cfbfc22dab89ff.tar.xz
socket_wrapper-e896cecf1fc08d091d09fa29f1cfbfc22dab89ff.zip
swrap: fix fd-passing without 4 padding bytes
We noticed the problem on 32 bit platforms and sending a single application fd, the hidden pipe-fd doesn't fit into the padding bytes. This can also happen on 64 bit platforms and an even number of application fds. Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r--src/socket_wrapper.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index e8c2d6c..ece3493 100644
--- a/src/socket_wrapper.c
+++ b/src/socket_wrapper.c
@@ -5962,8 +5962,48 @@ static ssize_t swrap_sendmsg_after_unix(struct msghdr *msg_tmp,
static int swrap_recvmsg_before_unix(struct msghdr *msg_in,
struct msghdr *msg_tmp)
{
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ const size_t cm_extra_space = CMSG_SPACE(sizeof(int));
+ uint8_t *cm_data = NULL;
+ size_t cm_data_space = 0;
+
*msg_tmp = *msg_in;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_in->msg_controllen=%zu",
+ (size_t)msg_in->msg_controllen);
+
+ /* Nothing to do */
+ if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) {
+ return 0;
+ }
+
+ /*
+ * We need to give the kernel a bit more space in order
+ * recv the pipe fd, added by swrap_sendmsg_before_unix()).
+ * swrap_recvmsg_after_unix() will hide it again.
+ */
+ cm_data_space = msg_in->msg_controllen;
+ if (cm_data_space < (INT32_MAX - cm_extra_space)) {
+ cm_data_space += cm_extra_space;
+ }
+ cm_data = calloc(1, cm_data_space);
+ if (cm_data == NULL) {
+ return -1;
+ }
+ memcpy(cm_data, msg_in->msg_control, msg_in->msg_controllen);
+
+ msg_tmp->msg_controllen = cm_data_space;
+ msg_tmp->msg_control = cm_data;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_tmp->msg_controllen=%zu",
+ (size_t)msg_tmp->msg_controllen);
return 0;
+#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ *msg_tmp = *msg_in;
+ return 0;
+#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
}
static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp,
@@ -5976,9 +6016,14 @@ static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp,
size_t cm_data_space = 0;
int rc = -1;
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_tmp->msg_controllen=%zu",
+ (size_t)msg_tmp->msg_controllen);
+
/* Nothing to do */
if (msg_tmp->msg_controllen == 0 || msg_tmp->msg_control == NULL) {
- goto done;
+ *msg_out = *msg_tmp;
+ return ret;
}
for (cmsg = CMSG_FIRSTHDR(msg_tmp);
@@ -6006,15 +6051,27 @@ static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp,
}
/*
- * msg_tmp->msg_control is still the buffer of the caller.
+ * msg_tmp->msg_control was created by swrap_recvmsg_before_unix()
+ * and msg_out->msg_control is still the buffer of the caller.
*/
- memcpy(msg_tmp->msg_control, cm_data, cm_data_space);
- msg_tmp->msg_controllen = cm_data_space;
+ SAFE_FREE(msg_tmp->msg_control);
+ msg_tmp->msg_control = msg_out->msg_control;
+ msg_tmp->msg_controllen = msg_out->msg_controllen;
+ *msg_out = *msg_tmp;
+
+ cm_data_space = MIN(cm_data_space, msg_out->msg_controllen);
+ memcpy(msg_out->msg_control, cm_data, cm_data_space);
+ msg_out->msg_controllen = cm_data_space;
SAFE_FREE(cm_data);
-done:
-#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_out->msg_controllen=%zu",
+ (size_t)msg_out->msg_controllen);
+ return ret;
+#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
*msg_out = *msg_tmp;
return ret;
+#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
}
static ssize_t swrap_sendmsg_before(int fd,