1d9f0492fSopenharmony_ci/* 2d9f0492fSopenharmony_ci* Copyright (c) 2021 Huawei Device Co., Ltd. 3d9f0492fSopenharmony_ci* Licensed under the Apache License, Version 2.0 (the "License"); 4d9f0492fSopenharmony_ci* you may not use this file except in compliance with the License. 5d9f0492fSopenharmony_ci* You may obtain a copy of the License at 6d9f0492fSopenharmony_ci* 7d9f0492fSopenharmony_ci* http://www.apache.org/licenses/LICENSE-2.0 8d9f0492fSopenharmony_ci* 9d9f0492fSopenharmony_ci* Unless required by applicable law or agreed to in writing, software 10d9f0492fSopenharmony_ci* distributed under the License is distributed on an "AS IS" BASIS, 11d9f0492fSopenharmony_ci* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d9f0492fSopenharmony_ci* See the License for the specific language governing permissions and 13d9f0492fSopenharmony_ci* limitations under the License. 14d9f0492fSopenharmony_ci*/ 15d9f0492fSopenharmony_ci 16d9f0492fSopenharmony_ci#include "fd_holder_internal.h" 17d9f0492fSopenharmony_ci#include <errno.h> 18d9f0492fSopenharmony_ci#include <stdio.h> 19d9f0492fSopenharmony_ci#include "beget_ext.h" 20d9f0492fSopenharmony_ci#include "securec.h" 21d9f0492fSopenharmony_ci 22d9f0492fSopenharmony_ci#ifndef PAGE_SIZE 23d9f0492fSopenharmony_ci#define PAGE_SIZE (4096U) 24d9f0492fSopenharmony_ci#endif 25d9f0492fSopenharmony_ci 26d9f0492fSopenharmony_ciint BuildControlMessage(struct msghdr *msghdr, int *fds, int fdCount, bool sendUcred) 27d9f0492fSopenharmony_ci{ 28d9f0492fSopenharmony_ci if (msghdr == NULL || (fdCount > 0 && fds == NULL)) { 29d9f0492fSopenharmony_ci BEGET_LOGE("Build control message with invalid parameter"); 30d9f0492fSopenharmony_ci return -1; 31d9f0492fSopenharmony_ci } 32d9f0492fSopenharmony_ci 33d9f0492fSopenharmony_ci if (fdCount > 0) { 34d9f0492fSopenharmony_ci msghdr->msg_controllen = CMSG_SPACE(sizeof(int) * fdCount); 35d9f0492fSopenharmony_ci } else { 36d9f0492fSopenharmony_ci msghdr->msg_controllen = 0; 37d9f0492fSopenharmony_ci } 38d9f0492fSopenharmony_ci 39d9f0492fSopenharmony_ci if (sendUcred) { 40d9f0492fSopenharmony_ci msghdr->msg_controllen += CMSG_SPACE(sizeof(struct ucred)); 41d9f0492fSopenharmony_ci } 42d9f0492fSopenharmony_ci 43d9f0492fSopenharmony_ci msghdr->msg_control = calloc(1, ((msghdr->msg_controllen == 0) ? 1 : msghdr->msg_controllen)); 44d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(msghdr->msg_control != NULL, return -1, "Failed to build control message"); 45d9f0492fSopenharmony_ci 46d9f0492fSopenharmony_ci struct cmsghdr *cmsg = NULL; 47d9f0492fSopenharmony_ci cmsg = CMSG_FIRSTHDR(msghdr); 48d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(cmsg != NULL, return -1, "Failed to build cmsg"); 49d9f0492fSopenharmony_ci 50d9f0492fSopenharmony_ci if (fdCount > 0) { 51d9f0492fSopenharmony_ci cmsg->cmsg_level = SOL_SOCKET; 52d9f0492fSopenharmony_ci cmsg->cmsg_type = SCM_RIGHTS; 53d9f0492fSopenharmony_ci cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount); 54d9f0492fSopenharmony_ci int ret = memcpy_s(CMSG_DATA(cmsg), cmsg->cmsg_len, fds, sizeof(int) * fdCount); 55d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(ret == 0, free(msghdr->msg_control); 56d9f0492fSopenharmony_ci msghdr->msg_control = NULL; 57d9f0492fSopenharmony_ci return -1, "Control message is not valid"); 58d9f0492fSopenharmony_ci // build ucred info 59d9f0492fSopenharmony_ci cmsg = CMSG_NXTHDR(msghdr, cmsg); 60d9f0492fSopenharmony_ci } 61d9f0492fSopenharmony_ci 62d9f0492fSopenharmony_ci if (sendUcred) { 63d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(cmsg != NULL, free(msghdr->msg_control); 64d9f0492fSopenharmony_ci msghdr->msg_control = NULL; 65d9f0492fSopenharmony_ci return -1, "Control message is not valid"); 66d9f0492fSopenharmony_ci 67d9f0492fSopenharmony_ci struct ucred *ucred; 68d9f0492fSopenharmony_ci cmsg->cmsg_level = SOL_SOCKET; 69d9f0492fSopenharmony_ci cmsg->cmsg_type = SCM_CREDENTIALS; 70d9f0492fSopenharmony_ci cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 71d9f0492fSopenharmony_ci ucred = (struct ucred*) CMSG_DATA(cmsg); 72d9f0492fSopenharmony_ci ucred->pid = getpid(); 73d9f0492fSopenharmony_ci ucred->uid = getuid(); 74d9f0492fSopenharmony_ci ucred->gid = getgid(); 75d9f0492fSopenharmony_ci } 76d9f0492fSopenharmony_ci return 0; 77d9f0492fSopenharmony_ci} 78d9f0492fSopenharmony_ci 79d9f0492fSopenharmony_ciSTATIC int *GetFdsFromMsg(size_t *outFdCount, pid_t *requestPid, struct msghdr msghdr) 80d9f0492fSopenharmony_ci{ 81d9f0492fSopenharmony_ci if ((msghdr.msg_flags) & MSG_TRUNC) { 82d9f0492fSopenharmony_ci BEGET_LOGE("Message was truncated when receiving fds"); 83d9f0492fSopenharmony_ci return NULL; 84d9f0492fSopenharmony_ci } 85d9f0492fSopenharmony_ci 86d9f0492fSopenharmony_ci struct cmsghdr *cmsg = NULL; 87d9f0492fSopenharmony_ci int *fds = NULL; 88d9f0492fSopenharmony_ci size_t fdCount = 0; 89d9f0492fSopenharmony_ci for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { 90d9f0492fSopenharmony_ci if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { 91d9f0492fSopenharmony_ci fds = (int*)CMSG_DATA(cmsg); 92d9f0492fSopenharmony_ci fdCount = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); 93d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(fdCount <= MAX_HOLD_FDS, return NULL, "Too many fds returned."); 94d9f0492fSopenharmony_ci } 95d9f0492fSopenharmony_ci if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && 96d9f0492fSopenharmony_ci cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { 97d9f0492fSopenharmony_ci // Ignore credentials 98d9f0492fSopenharmony_ci if (requestPid != NULL) { 99d9f0492fSopenharmony_ci struct ucred *ucred = (struct ucred*)CMSG_DATA(cmsg); 100d9f0492fSopenharmony_ci *requestPid = ucred->pid; 101d9f0492fSopenharmony_ci } 102d9f0492fSopenharmony_ci continue; 103d9f0492fSopenharmony_ci } 104d9f0492fSopenharmony_ci } 105d9f0492fSopenharmony_ci int *outFds = NULL; 106d9f0492fSopenharmony_ci if (fds != NULL && fdCount > 0) { 107d9f0492fSopenharmony_ci outFds = calloc(fdCount + 1, sizeof(int)); 108d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(outFds != NULL, return NULL, "Failed to allocate memory for fds"); 109d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(memcpy_s(outFds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) == 0, 110d9f0492fSopenharmony_ci free(outFds); return NULL, "Failed to copy fds"); 111d9f0492fSopenharmony_ci } 112d9f0492fSopenharmony_ci *outFdCount = fdCount; 113d9f0492fSopenharmony_ci return outFds; 114d9f0492fSopenharmony_ci} 115d9f0492fSopenharmony_ci 116d9f0492fSopenharmony_ci// This function will allocate memory to store FDs 117d9f0492fSopenharmony_ci// Remember to delete when not used anymore. 118d9f0492fSopenharmony_ciint *ReceiveFds(int sock, struct iovec iovec, size_t *outFdCount, bool nonblock, pid_t *requestPid) 119d9f0492fSopenharmony_ci{ 120d9f0492fSopenharmony_ci CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + 121d9f0492fSopenharmony_ci CMSG_SPACE(sizeof(int) * MAX_HOLD_FDS)) control; 122d9f0492fSopenharmony_ci 123d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(sizeof(control) <= PAGE_SIZE, return NULL, "Too many fds, out of memory"); 124d9f0492fSopenharmony_ci 125d9f0492fSopenharmony_ci struct msghdr msghdr = { 126d9f0492fSopenharmony_ci .msg_iov = &iovec, 127d9f0492fSopenharmony_ci .msg_iovlen = 1, 128d9f0492fSopenharmony_ci .msg_control = &control, 129d9f0492fSopenharmony_ci .msg_controllen = sizeof(control), 130d9f0492fSopenharmony_ci .msg_flags = 0, 131d9f0492fSopenharmony_ci }; 132d9f0492fSopenharmony_ci 133d9f0492fSopenharmony_ci int flags = MSG_CMSG_CLOEXEC | MSG_TRUNC; 134d9f0492fSopenharmony_ci if (nonblock) { 135d9f0492fSopenharmony_ci flags |= MSG_DONTWAIT; 136d9f0492fSopenharmony_ci } 137d9f0492fSopenharmony_ci ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sock, &msghdr, flags)); 138d9f0492fSopenharmony_ci BEGET_ERROR_CHECK(rc >= 0, return NULL, "Failed to get fds from remote, err = %d", errno); 139d9f0492fSopenharmony_ci return GetFdsFromMsg(outFdCount, requestPid, msghdr); 140d9f0492fSopenharmony_ci}