]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/af_unix.c
Merge pull request #3278 from tomponline/tp-proxy-sleep
[mirror_lxc.git] / src / lxc / af_unix.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
d06245b8 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
94ac256f
CB
6#include <errno.h>
7#include <fcntl.h>
8#include <stddef.h>
ae467c54
CB
9#include <stdio.h>
10#include <stdlib.h>
b0a33c1e 11#include <string.h>
12#include <unistd.h>
b0a33c1e 13#include <sys/socket.h>
94ac256f 14#include <sys/syscall.h>
b0a33c1e 15#include <sys/un.h>
16
d38dd64a 17#include "config.h"
2dcb28a9 18#include "log.h"
83c11f1d 19#include "memory_utils.h"
d7b58715 20#include "raw_syscalls.h"
0059379f 21#include "utils.h"
2dcb28a9 22
9de31d5a
CB
23#ifndef HAVE_STRLCPY
24#include "include/strlcpy.h"
25#endif
26
ac2cecc4 27lxc_log_define(af_unix, lxc);
b0a33c1e 28
c62fb5e0 29static ssize_t lxc_abstract_unix_set_sockaddr(struct sockaddr_un *addr,
30 const char *path)
b0a33c1e 31{
ddb17f1f 32 size_t len;
b0a33c1e 33
c62fb5e0 34 if (!addr || !path) {
35 errno = EINVAL;
b0a33c1e 36 return -1;
c62fb5e0 37 }
b0a33c1e 38
aae93dd3 39 /* Clear address structure */
c62fb5e0 40 memset(addr, 0, sizeof(*addr));
b0a33c1e 41
c62fb5e0 42 addr->sun_family = AF_UNIX;
aae93dd3 43
caf3beb0 44 len = strlen(&path[1]);
c62fb5e0 45
caf3beb0 46 /* do not enforce \0-termination */
c62fb5e0 47 if (len >= INT_MAX || len >= sizeof(addr->sun_path)) {
aae93dd3
ÇO
48 errno = ENAMETOOLONG;
49 return -1;
ddb17f1f 50 }
9de31d5a
CB
51
52 /* do not enforce \0-termination */
c62fb5e0 53 memcpy(&addr->sun_path[1], &path[1], len);
54 return len;
55}
56
57int lxc_abstract_unix_open(const char *path, int type, int flags)
58{
59 int fd, ret;
60 ssize_t len;
61 struct sockaddr_un addr;
62
ad9429e5 63 fd = socket(PF_UNIX, type | SOCK_CLOEXEC, 0);
c62fb5e0 64 if (fd < 0)
65 return -1;
66
67 if (!path)
68 return fd;
69
70 len = lxc_abstract_unix_set_sockaddr(&addr, path);
71 if (len < 0) {
72 int saved_errno = errno;
73 close(fd);
74 errno = saved_errno;
75 return -1;
76 }
b0a33c1e 77
77b0073a
CB
78 ret = bind(fd, (struct sockaddr *)&addr,
79 offsetof(struct sockaddr_un, sun_path) + len + 1);
80 if (ret < 0) {
c62fb5e0 81 int saved_errno = errno;
b0a33c1e 82 close(fd);
c62fb5e0 83 errno = saved_errno;
b0a33c1e 84 return -1;
85 }
ddb17f1f 86
77b0073a
CB
87 if (type == SOCK_STREAM) {
88 ret = listen(fd, 100);
89 if (ret < 0) {
c62fb5e0 90 int saved_errno = errno;
77b0073a 91 close(fd);
c62fb5e0 92 errno = saved_errno;
77b0073a
CB
93 return -1;
94 }
b0a33c1e 95 }
96
97 return fd;
98}
99
9044b79e 100void lxc_abstract_unix_close(int fd)
b0a33c1e 101{
b0a33c1e 102 close(fd);
b0a33c1e 103}
104
aae93dd3 105int lxc_abstract_unix_connect(const char *path)
b0a33c1e 106{
77b0073a 107 int fd, ret;
c62fb5e0 108 ssize_t len;
b0a33c1e 109 struct sockaddr_un addr;
110
ad9429e5 111 fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
b0a33c1e 112 if (fd < 0)
113 return -1;
114
c62fb5e0 115 len = lxc_abstract_unix_set_sockaddr(&addr, path);
116 if (len < 0) {
117 int saved_errno = errno;
aae93dd3 118 close(fd);
c62fb5e0 119 errno = saved_errno;
aae93dd3
ÇO
120 return -1;
121 }
9de31d5a 122
77b0073a
CB
123 ret = connect(fd, (struct sockaddr *)&addr,
124 offsetof(struct sockaddr_un, sun_path) + len + 1);
125 if (ret < 0) {
9044b79e 126 int saved_errno = errno;
b0a33c1e 127 close(fd);
9044b79e 128 errno = saved_errno;
b0a33c1e 129 return -1;
130 }
131
132 return fd;
133}
134
e1726045
WB
135int lxc_abstract_unix_send_fds_iov(int fd, int *sendfds, int num_sendfds,
136 struct iovec *iov, size_t iovlen)
b0a33c1e 137{
c3e3c21a
CB
138 __do_free char *cmsgbuf = NULL;
139 int ret;
ae467c54 140 struct msghdr msg;
ae467c54 141 struct cmsghdr *cmsg = NULL;
ae467c54
CB
142 size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int));
143
144 memset(&msg, 0, sizeof(msg));
ae467c54
CB
145
146 cmsgbuf = malloc(cmsgbufsize);
9044b79e 147 if (!cmsgbuf) {
148 errno = ENOMEM;
ae467c54 149 return -1;
9044b79e 150 }
b0a33c1e 151
604f0955 152 msg.msg_control = cmsgbuf;
ae467c54 153 msg.msg_controllen = cmsgbufsize;
b0a33c1e 154
604f0955 155 cmsg = CMSG_FIRSTHDR(&msg);
604f0955
ÇO
156 cmsg->cmsg_level = SOL_SOCKET;
157 cmsg->cmsg_type = SCM_RIGHTS;
ae467c54 158 cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
b0a33c1e 159
ae467c54
CB
160 msg.msg_controllen = cmsg->cmsg_len;
161
162 memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
b0a33c1e 163
e1726045
WB
164 msg.msg_iov = iov;
165 msg.msg_iovlen = iovlen;
b0a33c1e 166
c3e3c21a
CB
167again:
168 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
169 if (ret < 0)
170 if (errno == EINTR)
171 goto again;
172
173 return ret;
b0a33c1e 174}
175
e1726045
WB
176int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
177 void *data, size_t size)
178{
179 char buf[1] = {0};
180 struct iovec iov = {
181 .iov_base = data ? data : buf,
182 .iov_len = data ? size : sizeof(buf),
183 };
184 return lxc_abstract_unix_send_fds_iov(fd, sendfds, num_sendfds, &iov,
185 1);
186}
187
5ed06d3a
CB
188int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data,
189 size_t size)
190{
191 return lxc_abstract_unix_send_fds(fd, sendfds, num_sendfds, data, size);
192}
193
dc85e31e
CB
194static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds,
195 struct iovec *iov, size_t iovlen)
b0a33c1e 196{
c3e3c21a 197 __do_free char *cmsgbuf = NULL;
ae467c54
CB
198 int ret;
199 struct msghdr msg;
ae467c54 200 struct cmsghdr *cmsg = NULL;
cdb2a47f
CB
201 size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) +
202 CMSG_SPACE(num_recvfds * sizeof(int));
ae467c54
CB
203
204 memset(&msg, 0, sizeof(msg));
ae467c54
CB
205
206 cmsgbuf = malloc(cmsgbufsize);
9044b79e 207 if (!cmsgbuf) {
208 errno = ENOMEM;
ae467c54 209 return -1;
9044b79e 210 }
b0a33c1e 211
604f0955 212 msg.msg_control = cmsgbuf;
ae467c54 213 msg.msg_controllen = cmsgbufsize;
b0a33c1e 214
dc85e31e
CB
215 msg.msg_iov = iov;
216 msg.msg_iovlen = iovlen;
b0a33c1e 217
c3e3c21a 218again:
b0a33c1e 219 ret = recvmsg(fd, &msg, 0);
c3e3c21a
CB
220 if (ret < 0) {
221 if (errno == EINTR)
222 goto again;
223
224 goto out;
225 }
226 if (ret == 0)
b0a33c1e 227 goto out;
228
cdb2a47f
CB
229 /*
230 * If SO_PASSCRED is set we will always get a ucred message.
231 */
232 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
233 if (cmsg->cmsg_type != SCM_RIGHTS)
234 continue;
235
236 memset(recvfds, -1, num_recvfds * sizeof(int));
237 if (cmsg &&
238 cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
239 cmsg->cmsg_level == SOL_SOCKET)
240 memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
241 break;
242 }
ae467c54 243
b0a33c1e 244out:
604f0955 245 return ret;
b0a33c1e 246}
247
dc85e31e
CB
248int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
249 void *data, size_t size)
250{
251 char buf[1] = {0};
252 struct iovec iov = {
253 .iov_base = data ? data : buf,
254 .iov_len = data ? size : sizeof(buf),
255 };
256 return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1);
257}
258
aae93dd3 259int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
b0a33c1e 260{
77b0073a 261 struct msghdr msg = {0};
604f0955
ÇO
262 struct iovec iov;
263 struct cmsghdr *cmsg;
b0a33c1e 264 struct ucred cred = {
0059379f 265 .pid = lxc_raw_getpid(), .uid = getuid(), .gid = getgid(),
b0a33c1e 266 };
caf3beb0
CB
267 char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
268 char buf[1] = {0};
b0a33c1e 269
604f0955
ÇO
270 msg.msg_control = cmsgbuf;
271 msg.msg_controllen = sizeof(cmsgbuf);
b0a33c1e 272
604f0955
ÇO
273 cmsg = CMSG_FIRSTHDR(&msg);
274 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
275 cmsg->cmsg_level = SOL_SOCKET;
276 cmsg->cmsg_type = SCM_CREDENTIALS;
0e391e57 277 memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
b0a33c1e 278
604f0955
ÇO
279 msg.msg_name = NULL;
280 msg.msg_namelen = 0;
b0a33c1e 281
604f0955
ÇO
282 iov.iov_base = data ? data : buf;
283 iov.iov_len = data ? size : sizeof(buf);
284 msg.msg_iov = &iov;
285 msg.msg_iovlen = 1;
b0a33c1e 286
6168ff15 287 return sendmsg(fd, &msg, MSG_NOSIGNAL);
b0a33c1e 288}
289
aae93dd3 290int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
b0a33c1e 291{
77b0073a 292 struct msghdr msg = {0};
604f0955
ÇO
293 struct iovec iov;
294 struct cmsghdr *cmsg;
b0a33c1e 295 struct ucred cred;
b0a33c1e 296 int ret;
caf3beb0
CB
297 char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
298 char buf[1] = {0};
b0a33c1e 299
604f0955
ÇO
300 msg.msg_name = NULL;
301 msg.msg_namelen = 0;
302 msg.msg_control = cmsgbuf;
303 msg.msg_controllen = sizeof(cmsgbuf);
b0a33c1e 304
604f0955
ÇO
305 iov.iov_base = data ? data : buf;
306 iov.iov_len = data ? size : sizeof(buf);
307 msg.msg_iov = &iov;
308 msg.msg_iovlen = 1;
b0a33c1e 309
310 ret = recvmsg(fd, &msg, 0);
311 if (ret <= 0)
312 goto out;
313
604f0955 314 cmsg = CMSG_FIRSTHDR(&msg);
b0a33c1e 315
604f0955 316 if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
77b0073a
CB
317 cmsg->cmsg_level == SOL_SOCKET &&
318 cmsg->cmsg_type == SCM_CREDENTIALS) {
0e391e57 319 memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred));
77b0073a
CB
320 if (cred.uid &&
321 (cred.uid != getuid() || cred.gid != getgid())) {
9044b79e 322 INFO("Message denied for '%d/%d'", cred.uid, cred.gid);
323 errno = EACCES;
324 return -1;
2dcb28a9 325 }
604f0955 326 }
9044b79e 327
b0a33c1e 328out:
604f0955 329 return ret;
b0a33c1e 330}
86ce1da1
CB
331
332int lxc_unix_sockaddr(struct sockaddr_un *ret, const char *path)
333{
334 size_t len;
335
336 len = strlen(path);
337 if (len == 0)
db1b8b0f 338 return ret_set_errno(-1, EINVAL);
86ce1da1 339 if (path[0] != '/' && path[0] != '@')
db1b8b0f 340 return ret_set_errno(-1, EINVAL);
86ce1da1 341 if (path[1] == '\0')
db1b8b0f 342 return ret_set_errno(-1, EINVAL);
86ce1da1
CB
343
344 if (len + 1 > sizeof(ret->sun_path))
db1b8b0f 345 return ret_set_errno(-1, EINVAL);
86ce1da1
CB
346
347 *ret = (struct sockaddr_un){
348 .sun_family = AF_UNIX,
349 };
350
351 if (path[0] == '@') {
352 memcpy(ret->sun_path + 1, path + 1, len);
353 return (int)(offsetof(struct sockaddr_un, sun_path) + len);
354 }
355
356 memcpy(ret->sun_path, path, len + 1);
357 return (int)(offsetof(struct sockaddr_un, sun_path) + len + 1);
358}
359
970ef13d 360int lxc_unix_connect_type(struct sockaddr_un *addr, int type)
86ce1da1
CB
361{
362 __do_close_prot_errno int fd = -EBADF;
363 int ret;
364 ssize_t len;
365
970ef13d 366 fd = socket(AF_UNIX, type | SOCK_CLOEXEC, 0);
2ac0f627
CB
367 if (fd < 0) {
368 SYSERROR("Failed to open new AF_UNIX socket");
86ce1da1 369 return -1;
2ac0f627 370 }
86ce1da1
CB
371
372 if (addr->sun_path[0] == '\0')
373 len = strlen(&addr->sun_path[1]);
374 else
375 len = strlen(&addr->sun_path[0]);
2ac0f627
CB
376
377 ret = connect(fd, (struct sockaddr *)addr,
378 offsetof(struct sockaddr_un, sun_path) + len);
379 if (ret < 0) {
380 SYSERROR("Failed to bind new AF_UNIX socket");
86ce1da1 381 return -1;
2ac0f627 382 }
86ce1da1
CB
383
384 return move_fd(fd);
385}
386
970ef13d
WB
387int lxc_unix_connect(struct sockaddr_un *addr, int type)
388{
389 return lxc_unix_connect_type(addr, SOCK_STREAM);
390}
391
86ce1da1
CB
392int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout)
393{
394 struct timeval out = {0};
395 int ret;
396
397 out.tv_sec = snd_timeout;
398 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&out,
399 sizeof(out));
400 if (ret < 0)
401 return -1;
402
403 out.tv_sec = rcv_timeout;
404 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&out,
405 sizeof(out));
406 if (ret < 0)
407 return -1;
408
409 return 0;
410}