Commit | Line | Data |
---|---|---|
b17231c6 | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2011 David Goulet <dgoulet@efficios.com> |
b17231c6 | 3 | * |
c922647d | 4 | * SPDX-License-Identifier: LGPL-2.1-only |
b17231c6 | 5 | * |
b17231c6 DG |
6 | */ |
7 | ||
8 | #ifndef _COMPAT_SOCKET_H | |
9 | #define _COMPAT_SOCKET_H | |
10 | ||
28f23191 JG |
11 | #include <common/macros.hpp> |
12 | ||
b17231c6 DG |
13 | #include <sys/socket.h> |
14 | #include <sys/un.h> | |
9bc1a4b4 | 15 | #include <unistd.h> |
b17231c6 | 16 | |
fbb1fd3a | 17 | #ifndef MSG_NOSIGNAL |
28f23191 JG |
18 | #ifdef SO_NOSIGPIPE |
19 | #define MSG_NOSIGNAL SO_NOSIGPIPE | |
20 | #endif | |
fbb1fd3a MJ |
21 | #endif |
22 | ||
23 | #if defined(MSG_NOSIGNAL) | |
28f23191 | 24 | static inline ssize_t lttng_recvmsg_nosigpipe(int sockfd, struct msghdr *msg) |
fbb1fd3a MJ |
25 | { |
26 | return recvmsg(sockfd, msg, MSG_NOSIGNAL); | |
27 | } | |
28 | #else | |
29 | ||
c9e313bc | 30 | #include <common/compat/errno.hpp> |
fbb1fd3a | 31 | |
28f23191 JG |
32 | #include <signal.h> |
33 | ||
34 | static inline ssize_t lttng_recvmsg_nosigpipe(int sockfd, struct msghdr *msg) | |
fbb1fd3a MJ |
35 | { |
36 | ssize_t received; | |
37 | int saved_err; | |
38 | sigset_t sigpipe_set, pending_set, old_set; | |
39 | int sigpipe_was_pending; | |
40 | ||
41 | /* | |
42 | * Discard the SIGPIPE from send(), not disturbing any SIGPIPE | |
43 | * that might be already pending. If a bogus SIGPIPE is sent to | |
44 | * the entire process concurrently by a malicious user, it may | |
45 | * be simply discarded. | |
46 | */ | |
47 | if (sigemptyset(&pending_set)) { | |
48 | return -1; | |
49 | } | |
50 | /* | |
51 | * sigpending returns the mask of signals that are _both_ | |
52 | * blocked for the thread _and_ pending for either the thread or | |
53 | * the entire process. | |
54 | */ | |
55 | if (sigpending(&pending_set)) { | |
56 | return -1; | |
57 | } | |
58 | sigpipe_was_pending = sigismember(&pending_set, SIGPIPE); | |
59 | /* | |
60 | * If sigpipe was pending, it means it was already blocked, so | |
61 | * no need to block it. | |
62 | */ | |
63 | if (!sigpipe_was_pending) { | |
64 | if (sigemptyset(&sigpipe_set)) { | |
65 | return -1; | |
66 | } | |
67 | if (sigaddset(&sigpipe_set, SIGPIPE)) { | |
68 | return -1; | |
69 | } | |
70 | if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) { | |
71 | return -1; | |
72 | } | |
73 | } | |
74 | ||
75 | /* Send and save errno. */ | |
76 | received = recvmsg(sockfd, msg, 0); | |
77 | saved_err = errno; | |
78 | ||
79 | if (received == -1 && errno == EPIPE && !sigpipe_was_pending) { | |
80 | struct timespec timeout = { 0, 0 }; | |
81 | int ret; | |
82 | ||
83 | do { | |
28f23191 | 84 | ret = sigtimedwait(&sigpipe_set, NULL, &timeout); |
fbb1fd3a MJ |
85 | } while (ret == -1 && errno == EINTR); |
86 | } | |
87 | if (!sigpipe_was_pending) { | |
88 | if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) { | |
89 | return -1; | |
90 | } | |
91 | } | |
92 | /* Restore send() errno */ | |
93 | errno = saved_err; | |
94 | ||
95 | return received; | |
96 | } | |
97 | #endif | |
98 | ||
9bc1a4b4 JG |
99 | #ifdef __sun__ |
100 | ||
28f23191 JG |
101 | #ifndef CMSG_ALIGN |
102 | #ifdef _CMSG_DATA_ALIGN | |
103 | #define CMSG_ALIGN(len) _CMSG_DATA_ALIGN(len) | |
104 | #else | |
105 | /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */ | |
106 | #define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1)) | |
107 | #endif | |
108 | #ifndef CMSG_SPACE | |
109 | #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len)) | |
110 | #endif | |
111 | #ifndef CMSG_LEN | |
112 | #define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) | |
113 | #endif | |
114 | #endif | |
9bc1a4b4 JG |
115 | |
116 | #include <ucred.h> | |
fbb1fd3a | 117 | |
28f23191 | 118 | static inline int getpeereid(int s, uid_t *euid, gid_t *gid) |
9bc1a4b4 JG |
119 | { |
120 | int ret = 0; | |
121 | ucred_t *ucred = NULL; | |
122 | ||
123 | ret = getpeerucred(s, &ucred); | |
124 | if (ret == -1) { | |
125 | goto end; | |
126 | } | |
127 | ||
128 | ret = ucred_geteuid(ucred); | |
129 | if (ret == -1) { | |
130 | goto free; | |
131 | } | |
132 | *euid = ret; | |
133 | ||
134 | ret = ucred_getrgid(ucred); | |
135 | if (ret == -1) { | |
136 | goto free; | |
137 | } | |
138 | *gid = ret; | |
139 | ||
140 | ret = 0; | |
141 | free: | |
142 | ucred_free(ucred); | |
143 | end: | |
144 | return ret; | |
145 | } | |
146 | #endif /* __sun__ */ | |
147 | ||
9bc1a4b4 | 148 | #if defined(__linux__) || defined(__CYGWIN__) |
b17231c6 DG |
149 | |
150 | #define LTTNG_SOCK_CREDS SCM_CREDENTIALS | |
b17231c6 | 151 | |
e665dfbc | 152 | using lttng_sock_cred = struct ucred; |
b17231c6 | 153 | |
1268b9d6 DG |
154 | #define LTTNG_SOCK_SET_UID_CRED(c, u) LTTNG_REF(c)->uid = u |
155 | #define LTTNG_SOCK_SET_GID_CRED(c, g) LTTNG_REF(c)->gid = g | |
156 | #define LTTNG_SOCK_SET_PID_CRED(c, p) LTTNG_REF(c)->pid = p | |
157 | ||
158 | #define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid | |
159 | #define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid | |
160 | #define LTTNG_SOCK_GET_PID_CRED(c) LTTNG_REF(c)->pid | |
b17231c6 | 161 | |
9bc1a4b4 | 162 | #elif (defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__)) |
b17231c6 | 163 | |
d27c42b8 MD |
164 | struct lttng_sock_cred { |
165 | uid_t uid; | |
166 | gid_t gid; | |
ba66a850 | 167 | pid_t pid; |
d27c42b8 | 168 | }; |
b17231c6 | 169 | |
d27c42b8 | 170 | typedef struct lttng_sock_cred lttng_sock_cred; |
b17231c6 | 171 | |
de559cf1 MJ |
172 | #define LTTNG_SOCK_SET_UID_CRED(c, u) LTTNG_REF(c)->uid = u |
173 | #define LTTNG_SOCK_SET_GID_CRED(c, g) LTTNG_REF(c)->gid = g | |
9bc1a4b4 | 174 | #define LTTNG_SOCK_SET_PID_CRED(c, p) LTTNG_REF(c)->pid = p |
de559cf1 | 175 | |
d27c42b8 MD |
176 | #define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid |
177 | #define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid | |
9bc1a4b4 | 178 | #define LTTNG_SOCK_GET_PID_CRED(c) LTTNG_REF(c)->pid |
28105b32 | 179 | |
9bc1a4b4 | 180 | #ifdef __APPLE__ |
28105b32 | 181 | |
28f23191 | 182 | static inline int lttng_get_unix_socket_peer_pid(int socket_fd, pid_t *pid) |
9bc1a4b4 | 183 | { |
9730eb85 MJ |
184 | socklen_t pid_len = (socklen_t) sizeof(*pid); |
185 | ||
9bc1a4b4 | 186 | /* The getsockopt LOCAL_PEERPID option is available since macOS 10.8. */ |
9730eb85 | 187 | return getsockopt(socket_fd, SOL_LOCAL, LOCAL_PEERPID, pid, &pid_len); |
9bc1a4b4 | 188 | } |
28105b32 | 189 | |
9bc1a4b4 | 190 | #elif defined(__sun__) |
11a2fd46 | 191 | |
9bc1a4b4 | 192 | /* Use the getpeerucreds interface on Solaris. */ |
28f23191 | 193 | static inline int lttng_get_unix_socket_peer_pid(int socket_fd, pid_t *pid) |
28105b32 MJ |
194 | { |
195 | int ret = 0; | |
196 | ucred_t *ucred = NULL; | |
197 | ||
198 | ret = getpeerucred(s, &ucred); | |
199 | if (ret == -1) { | |
200 | goto end; | |
201 | } | |
202 | ||
ba66a850 JG |
203 | ret = ucred_getpid(ucred); |
204 | if (ret == -1) { | |
205 | goto free; | |
206 | } | |
ba66a850 | 207 | |
9bc1a4b4 | 208 | *pid = ret; |
28105b32 MJ |
209 | ret = 0; |
210 | free: | |
211 | ucred_free(ucred); | |
212 | end: | |
213 | return ret; | |
214 | } | |
215 | ||
9bc1a4b4 JG |
216 | #elif defined(__FreeBSD__) |
217 | ||
218 | #include <sys/ucred.h> | |
219 | ||
28f23191 | 220 | static inline int lttng_get_unix_socket_peer_pid(int socket_fd, pid_t *pid) |
9bc1a4b4 JG |
221 | { |
222 | int ret; | |
223 | struct xucred sock_creds = {}; | |
5219e670 | 224 | socklen_t sock_creds_len = (socklen_t) sizeof(sock_creds); |
9bc1a4b4 JG |
225 | |
226 | /* Only available in FreeBSD 13.0 and up. */ | |
28f23191 | 227 | ret = getsockopt(socket_fd, SOL_LOCAL, LOCAL_PEERCRED, &sock_creds, &sock_creds_len); |
9bc1a4b4 JG |
228 | if (ret) { |
229 | goto end; | |
230 | } | |
231 | ||
232 | *pid = sock_creds.cr_pid; | |
233 | end: | |
234 | return ret; | |
235 | } | |
236 | ||
237 | #endif /* __APPLE__ */ | |
238 | ||
28f23191 | 239 | static inline int lttng_get_unix_socket_peer_creds(int socket_fd, struct lttng_sock_cred *creds) |
9bc1a4b4 JG |
240 | { |
241 | int ret; | |
242 | ||
243 | /* This is a BSD extension that is supported by Cygwin. */ | |
244 | ret = getpeereid(socket_fd, &creds->uid, &creds->gid); | |
245 | if (ret) { | |
246 | goto end; | |
247 | } | |
248 | ||
249 | /* | |
250 | * Getting a peer's PID is a bit more troublesome as it is platform | |
251 | * specific. | |
252 | */ | |
253 | ret = lttng_get_unix_socket_peer_pid(socket_fd, &creds->pid); | |
254 | end: | |
255 | return ret; | |
256 | } | |
257 | ||
258 | #else | |
259 | #error "Please add support for your OS." | |
260 | #endif /* __linux__ , __FreeBSD__, __APPLE__ */ | |
28105b32 | 261 | |
b17231c6 | 262 | #endif /* _COMPAT_SOCKET_H */ |