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