diff options
author | Stefan Metzmacher <metze@samba.org> | 2021-02-04 16:20:13 +0100 |
---|---|---|
committer | Andreas Schneider <asn@samba.org> | 2021-02-08 19:29:57 +0100 |
commit | e896cecf1fc08d091d09fa29f1cfbfc22dab89ff (patch) | |
tree | a0e8f74fbbcb6880a08e00281746790d37563f5f | |
parent | 3c7ef4751527bd8c93d5431d9f1e36c4fe648f3d (diff) | |
download | socket_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.c | 69 |
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, |