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