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