]>
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>
21 #include "memory_utils.h"
22 #include "process_utils.h"
26 #include "include/strlcpy.h"
29 lxc_log_define(af_unix
, lxc
);
31 static ssize_t
lxc_abstract_unix_set_sockaddr(struct sockaddr_un
*addr
,
37 return ret_errno(EINVAL
);
39 /* Clear address structure */
40 memset(addr
, 0, sizeof(*addr
));
42 addr
->sun_family
= AF_UNIX
;
44 len
= strlen(&path
[1]);
46 /* do not enforce \0-termination */
47 if (len
>= INT_MAX
|| len
>= sizeof(addr
->sun_path
))
48 return ret_errno(ENAMETOOLONG
);
50 /* do not enforce \0-termination */
51 memcpy(&addr
->sun_path
[1], &path
[1], len
);
55 int lxc_abstract_unix_open(const char *path
, int type
, int flags
)
57 __do_close
int fd
= -EBADF
;
60 struct sockaddr_un addr
;
62 fd
= socket(PF_UNIX
, type
| SOCK_CLOEXEC
, 0);
69 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
73 ret
= bind(fd
, (struct sockaddr
*)&addr
,
74 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
78 if (type
== SOCK_STREAM
) {
79 ret
= listen(fd
, 100);
87 void lxc_abstract_unix_close(int fd
)
92 int lxc_abstract_unix_connect(const char *path
)
94 __do_close
int fd
= -EBADF
;
97 struct sockaddr_un addr
;
99 fd
= socket(PF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
, 0);
103 len
= lxc_abstract_unix_set_sockaddr(&addr
, path
);
107 ret
= connect(fd
, (struct sockaddr
*)&addr
,
108 offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
115 int lxc_abstract_unix_send_fds_iov(int fd
, int *sendfds
, int num_sendfds
,
116 struct iovec
*iov
, size_t iovlen
)
118 __do_free
char *cmsgbuf
= NULL
;
121 struct cmsghdr
*cmsg
= NULL
;
122 size_t cmsgbufsize
= CMSG_SPACE(num_sendfds
* sizeof(int));
124 memset(&msg
, 0, sizeof(msg
));
126 cmsgbuf
= malloc(cmsgbufsize
);
132 msg
.msg_control
= cmsgbuf
;
133 msg
.msg_controllen
= cmsgbufsize
;
135 cmsg
= CMSG_FIRSTHDR(&msg
);
136 cmsg
->cmsg_level
= SOL_SOCKET
;
137 cmsg
->cmsg_type
= SCM_RIGHTS
;
138 cmsg
->cmsg_len
= CMSG_LEN(num_sendfds
* sizeof(int));
140 msg
.msg_controllen
= cmsg
->cmsg_len
;
142 memcpy(CMSG_DATA(cmsg
), sendfds
, num_sendfds
* sizeof(int));
145 msg
.msg_iovlen
= iovlen
;
148 ret
= sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
149 } while (ret
< 0 && errno
== EINTR
);
154 int lxc_abstract_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
,
155 void *data
, size_t size
)
159 .iov_base
= data
? data
: buf
,
160 .iov_len
= data
? size
: sizeof(buf
),
162 return lxc_abstract_unix_send_fds_iov(fd
, sendfds
, num_sendfds
, &iov
, 1);
165 int lxc_unix_send_fds(int fd
, int *sendfds
, int num_sendfds
, void *data
,
168 return lxc_abstract_unix_send_fds(fd
, sendfds
, num_sendfds
, data
, size
);
171 static int lxc_abstract_unix_recv_fds_iov(int fd
, int *recvfds
, int num_recvfds
,
172 struct iovec
*iov
, size_t iovlen
)
174 __do_free
char *cmsgbuf
= NULL
;
177 size_t cmsgbufsize
= CMSG_SPACE(sizeof(struct ucred
)) +
178 CMSG_SPACE(num_recvfds
* sizeof(int));
180 memset(&msg
, 0, sizeof(msg
));
182 cmsgbuf
= malloc(cmsgbufsize
);
184 return ret_errno(ENOMEM
);
186 msg
.msg_control
= cmsgbuf
;
187 msg
.msg_controllen
= cmsgbufsize
;
190 msg
.msg_iovlen
= iovlen
;
193 ret
= recvmsg(fd
, &msg
, MSG_CMSG_CLOEXEC
);
194 } while (ret
< 0 && errno
== EINTR
);
195 if (ret
< 0 || ret
== 0)
199 * If SO_PASSCRED is set we will always get a ucred message.
201 for (struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
202 if (cmsg
->cmsg_type
!= SCM_RIGHTS
)
205 memset(recvfds
, -1, num_recvfds
* sizeof(int));
207 cmsg
->cmsg_len
== CMSG_LEN(num_recvfds
* sizeof(int)) &&
208 cmsg
->cmsg_level
== SOL_SOCKET
)
209 memcpy(recvfds
, CMSG_DATA(cmsg
), num_recvfds
* sizeof(int));
216 int lxc_abstract_unix_recv_fds(int fd
, int *recvfds
, int num_recvfds
,
217 void *data
, size_t size
)
221 .iov_base
= data
? data
: buf
,
222 .iov_len
= data
? size
: sizeof(buf
),
224 return lxc_abstract_unix_recv_fds_iov(fd
, recvfds
, num_recvfds
, &iov
, 1);
227 int lxc_abstract_unix_send_credential(int fd
, void *data
, size_t size
)
229 struct msghdr msg
= {0};
231 struct cmsghdr
*cmsg
;
232 struct ucred cred
= {
233 .pid
= lxc_raw_getpid(),
237 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
240 msg
.msg_control
= cmsgbuf
;
241 msg
.msg_controllen
= sizeof(cmsgbuf
);
243 cmsg
= CMSG_FIRSTHDR(&msg
);
244 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
245 cmsg
->cmsg_level
= SOL_SOCKET
;
246 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
247 memcpy(CMSG_DATA(cmsg
), &cred
, sizeof(cred
));
252 iov
.iov_base
= data
? data
: buf
;
253 iov
.iov_len
= data
? size
: sizeof(buf
);
257 return sendmsg(fd
, &msg
, MSG_NOSIGNAL
);
260 int lxc_abstract_unix_rcv_credential(int fd
, void *data
, size_t size
)
262 struct msghdr msg
= {0};
264 struct cmsghdr
*cmsg
;
267 char cmsgbuf
[CMSG_SPACE(sizeof(cred
))] = {0};
272 msg
.msg_control
= cmsgbuf
;
273 msg
.msg_controllen
= sizeof(cmsgbuf
);
275 iov
.iov_base
= data
? data
: buf
;
276 iov
.iov_len
= data
? size
: sizeof(buf
);
280 ret
= recvmsg(fd
, &msg
, 0);
284 cmsg
= CMSG_FIRSTHDR(&msg
);
286 if (cmsg
&& cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct ucred
)) &&
287 cmsg
->cmsg_level
== SOL_SOCKET
&&
288 cmsg
->cmsg_type
== SCM_CREDENTIALS
) {
289 memcpy(&cred
, CMSG_DATA(cmsg
), sizeof(cred
));
291 if (cred
.uid
&& (cred
.uid
!= getuid() || cred
.gid
!= getgid()))
292 return log_error_errno(-1, EACCES
,
293 "Message denied for '%d/%d'",
300 int lxc_unix_sockaddr(struct sockaddr_un
*ret
, const char *path
)
306 return ret_set_errno(-1, EINVAL
);
307 if (path
[0] != '/' && path
[0] != '@')
308 return ret_set_errno(-1, EINVAL
);
310 return ret_set_errno(-1, EINVAL
);
312 if (len
+ 1 > sizeof(ret
->sun_path
))
313 return ret_set_errno(-1, EINVAL
);
315 *ret
= (struct sockaddr_un
){
316 .sun_family
= AF_UNIX
,
319 if (path
[0] == '@') {
320 memcpy(ret
->sun_path
+ 1, path
+ 1, len
);
321 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
);
324 memcpy(ret
->sun_path
, path
, len
+ 1);
325 return (int)(offsetof(struct sockaddr_un
, sun_path
) + len
+ 1);
328 int lxc_unix_connect_type(struct sockaddr_un
*addr
, int type
)
330 __do_close
int fd
= -EBADF
;
334 fd
= socket(AF_UNIX
, type
| SOCK_CLOEXEC
, 0);
336 return log_error_errno(-1, errno
,
337 "Failed to open new AF_UNIX socket");
339 if (addr
->sun_path
[0] == '\0')
340 len
= strlen(&addr
->sun_path
[1]);
342 len
= strlen(&addr
->sun_path
[0]);
344 ret
= connect(fd
, (struct sockaddr
*)addr
,
345 offsetof(struct sockaddr_un
, sun_path
) + len
);
347 return log_error_errno(-1, errno
,
348 "Failed to bind new AF_UNIX socket");
353 int lxc_unix_connect(struct sockaddr_un
*addr
)
355 return lxc_unix_connect_type(addr
, SOCK_STREAM
);
358 int lxc_socket_set_timeout(int fd
, int rcv_timeout
, int snd_timeout
)
360 struct timeval out
= {0};
363 out
.tv_sec
= snd_timeout
;
364 ret
= setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, (const void *)&out
,
369 out
.tv_sec
= rcv_timeout
;
370 ret
= setsockopt(fd
, SOL_SOCKET
, SO_RCVTIMEO
, (const void *)&out
,