]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/af_unix.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
13 #include <sys/socket.h>
14 #include <sys/syscall.h>
20 #include "memory_utils.h"
21 #include "raw_syscalls.h"
25 #include "include/strlcpy.h"
28 lxc_log_define(af_unix
, lxc
);
30 static ssize_t
lxc_abstract_unix_set_sockaddr(struct sockaddr_un
*addr
,
36 return ret_errno(EINVAL
);
38 /* Clear address structure */
39 memset(addr
, 0, sizeof(*addr
));
41 addr
->sun_family
= AF_UNIX
;
43 len
= strlen(&path
[1]);
45 /* do not enforce \0-termination */
46 if (len
>= INT_MAX
|| len
>= sizeof(addr
->sun_path
))
47 return ret_errno(ENAMETOOLONG
);
49 /* do not enforce \0-termination */
50 memcpy(&addr
->sun_path
[1], &path
[1], len
);
54 int lxc_abstract_unix_open(const char *path
, int type
, int flags
)
56 __do_close
int fd
= -EBADF
;
59 struct sockaddr_un addr
;
61 fd
= socket(PF_UNIX
, type
| SOCK_CLOEXEC
, 0);
68 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
72 ret
= bind(fd
, (struct sockaddr
*)&addr
,
73 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
77 if (type
== SOCK_STREAM
) {
78 ret
= listen(fd
, 100);
86 void lxc_abstract_unix_close(int fd
)
91 int lxc_abstract_unix_connect(const char *path
)
93 __do_close
int fd
= -EBADF
;
96 struct sockaddr_un addr
;
98 fd
= socket(PF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
102 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
106 ret
= connect(fd
, (struct sockaddr
*)&addr
,
107 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
114 int lxc_abstract_unix_send_fds_iov(int fd
, int *sendfds
, int num_sendfds
,
115 struct iovec
*iov
, size_t iovlen
)
117 __do_free
char *cmsgbuf
= NULL
;
120 struct cmsghdr
*cmsg
= NULL
;
121 size_t cmsgbufsize
= CMSG_SPACE(num_sendfds
* sizeof(int));
123 memset(&msg
, 0, sizeof(msg
));
125 cmsgbuf
= malloc(cmsgbufsize
);
131 msg
.msg_control
= cmsgbuf
;
132 msg
.msg_controllen
= cmsgbufsize
;
134 cmsg
= CMSG_FIRSTHDR(&msg
);
135 cmsg
->cmsg_level
= SOL_SOCKET
;
136 cmsg
->cmsg_type
= SCM_RIGHTS
;
137 cmsg
->cmsg_len
= CMSG_LEN(num_sendfds
* sizeof(int));
139 msg
.msg_controllen
= cmsg
->cmsg_len
;
141 memcpy(CMSG_DATA(cmsg
), sendfds
, num_sendfds
* sizeof(int));
144 msg
.msg_iovlen
= iovlen
;
147 ret
= sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
148 } while (ret
< 0 && errno
== EINTR
);
153 int lxc_abstract_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
,
154 void *data
, size_t size
)
158 .iov_base
= data
? data
: buf
,
159 .iov_len
= data
? size
: sizeof(buf
),
161 return lxc_abstract_unix_send_fds_iov(fd
, sendfds
, num_sendfds
, &iov
, 1);
164 int lxc_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
, void *data
,
167 return lxc_abstract_unix_send_fds(fd
, sendfds
, num_sendfds
, data
, size
);
170 static int lxc_abstract_unix_recv_fds_iov(int fd
, int *recvfds
, int num_recvfds
,
171 struct iovec
*iov
, size_t iovlen
)
173 __do_free
char *cmsgbuf
= NULL
;
176 size_t cmsgbufsize
= CMSG_SPACE(sizeof(struct ucred
)) +
177 CMSG_SPACE(num_recvfds
* sizeof(int));
179 memset(&msg
, 0, sizeof(msg
));
181 cmsgbuf
= malloc(cmsgbufsize
);
183 return ret_errno(ENOMEM
);
185 msg
.msg_control
= cmsgbuf
;
186 msg
.msg_controllen
= cmsgbufsize
;
189 msg
.msg_iovlen
= iovlen
;
192 ret
= recvmsg(fd
, &msg
, 0);
193 } while (ret
< 0 && errno
== EINTR
);
194 if (ret
< 0 || ret
== 0)
198 * If SO_PASSCRED is set we will always get a ucred message.
200 for (struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
201 if (cmsg
->cmsg_type
!= SCM_RIGHTS
)
204 memset(recvfds
, -1, num_recvfds
* sizeof(int));
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));
215 int lxc_abstract_unix_recv_fds(int fd
, int *recvfds
, int num_recvfds
,
216 void *data
, size_t size
)
220 .iov_base
= data
? data
: buf
,
221 .iov_len
= data
? size
: sizeof(buf
),
223 return lxc_abstract_unix_recv_fds_iov(fd
, recvfds
, num_recvfds
, &iov
, 1);
226 int lxc_abstract_unix_send_credential(int fd
, void *data
, size_t size
)
228 struct msghdr msg
= {0};
230 struct cmsghdr
*cmsg
;
231 struct ucred cred
= {
232 .pid
= lxc_raw_getpid(),
236 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
239 msg
.msg_control
= cmsgbuf
;
240 msg
.msg_controllen
= sizeof(cmsgbuf
);
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
;
246 memcpy(CMSG_DATA(cmsg
), &cred
, sizeof(cred
));
251 iov
.iov_base
= data
? data
: buf
;
252 iov
.iov_len
= data
? size
: sizeof(buf
);
256 return sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
259 int lxc_abstract_unix_rcv_credential(int fd
, void *data
, size_t size
)
261 struct msghdr msg
= {0};
263 struct cmsghdr
*cmsg
;
266 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
271 msg
.msg_control
= cmsgbuf
;
272 msg
.msg_controllen
= sizeof(cmsgbuf
);
274 iov
.iov_base
= data
? data
: buf
;
275 iov
.iov_len
= data
? size
: sizeof(buf
);
279 ret
= recvmsg(fd
, &msg
, 0);
283 cmsg
= CMSG_FIRSTHDR(&msg
);
285 if (cmsg
&& cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)) &&
286 cmsg
->cmsg_level
== SOL_SOCKET
&&
287 cmsg
->cmsg_type
== SCM_CREDENTIALS
) {
288 memcpy(&cred
, CMSG_DATA(cmsg
), sizeof(cred
));
290 if (cred
.uid
&& (cred
.uid
!= getuid() || cred
.gid
!= getgid()))
291 return log_error_errno(-1, EACCES
,
292 "Message denied for '%d/%d'",
299 int lxc_unix_sockaddr(struct sockaddr_un
*ret
, const char *path
)
305 return ret_set_errno(-1, EINVAL
);
306 if (path
[0] != '/' && path
[0] != '@')
307 return ret_set_errno(-1, EINVAL
);
309 return ret_set_errno(-1, EINVAL
);
311 if (len
+ 1 > sizeof(ret
->sun_path
))
312 return ret_set_errno(-1, EINVAL
);
314 *ret
= (struct sockaddr_un
){
315 .sun_family
= AF_UNIX
,
318 if (path
[0] == '@') {
319 memcpy(ret
->sun_path
+ 1, path
+ 1, len
);
320 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
);
323 memcpy(ret
->sun_path
, path
, len
+ 1);
324 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
327 int lxc_unix_connect_type(struct sockaddr_un
*addr
, int type
)
329 __do_close
int fd
= -EBADF
;
333 fd
= socket(AF_UNIX
, type
| SOCK_CLOEXEC
, 0);
335 return log_error_errno(-1, errno
,
336 "Failed to open new AF_UNIX socket");
338 if (addr
->sun_path
[0] == '\0')
339 len
= strlen(&addr
->sun_path
[1]);
341 len
= strlen(&addr
->sun_path
[0]);
343 ret
= connect(fd
, (struct sockaddr
*)addr
,
344 offsetof(struct sockaddr_un
, sun_path
) + len
);
346 return log_error_errno(-1, errno
,
347 "Failed to bind new AF_UNIX socket");
352 int lxc_unix_connect(struct sockaddr_un
*addr
, int type
)
354 return lxc_unix_connect_type(addr
, SOCK_STREAM
);
357 int lxc_socket_set_timeout(int fd
, int rcv_timeout
, int snd_timeout
)
359 struct timeval out
= {0};
362 out
.tv_sec
= snd_timeout
;
363 ret
= setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, (const void *)&out
,
368 out
.tv_sec
= rcv_timeout
;
369 ret
= setsockopt(fd
, SOL_SOCKET
, SO_RCVTIMEO
, (const void *)&out
,