VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/mkrawsock.c

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/* $Id: mkrawsock.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * Auxiliary server to create raw-sockets when debugging unprivileged.
4 */
5
6/*
7 * Copyright (C) 2013-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#ifdef __linux__
29#define _GNU_SOURCE
30#endif
31
32#ifdef __sun__
33#if __STDC_VERSION__ - 0 >= 199901L
34#define _XOPEN_SOURCE 600
35#else
36#define _XOPEN_SOURCE 500
37#endif
38#define __EXTENSIONS__ 1
39#endif
40
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <sys/socket.h>
44#include <sys/un.h>
45#include <netinet/in.h>
46#ifdef __linux__
47#include <linux/icmp.h> /* for ICMP_FILTER */
48#endif
49#include <errno.h>
50#include <fcntl.h>
51#include <pwd.h>
52#include <signal.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58
59static void handler(int sig);
60static void serve(int s);
61static int mkrawsock(int family);
62
63volatile sig_atomic_t signaled = 0;
64
65int
66main(int argc, char **argv)
67{
68 struct sigaction sa;
69 struct sockaddr_un sux; /* because solaris */
70 struct passwd *pw;
71 size_t pathlen;
72 char *slash;
73 int s, client;
74 int status;
75
76 memset(&sux, 0, sizeof(sux));
77 sux.sun_family = AF_UNIX;
78
79 if (getuid() == 0) {
80 if (argc != 2) {
81 fprintf(stderr, "username required when run as root\n");
82 return EXIT_FAILURE;
83 }
84
85 errno = 0;
86 pw = getpwnam(argv[1]);
87 if (pw == NULL) {
88 perror("getpwnam");
89 return EXIT_FAILURE;
90 }
91 if (pw->pw_uid == 0) {
92 fprintf(stderr, "%s is superuser\n", pw->pw_name);
93 return EXIT_FAILURE;
94 }
95 }
96 else {
97 errno = 0;
98 pw = getpwuid(getuid());
99 if (pw == NULL) {
100 perror("getpwuid");
101 return EXIT_FAILURE;
102 }
103 }
104
105 pathlen = snprintf(sux.sun_path, sizeof(sux.sun_path),
106 "/tmp/.vbox-%s-aux/mkrawsock", pw->pw_name);
107 if (pathlen > sizeof(sux.sun_path)) {
108 fprintf(stderr, "socket pathname truncated\n");
109 return EXIT_FAILURE;
110 }
111
112 slash = strrchr(sux.sun_path, '/');
113 if (slash == NULL) {
114 fprintf(stderr, "%s: no directory separator\n", sux.sun_path);
115 return EXIT_FAILURE;
116 }
117
118 *slash = '\0';
119
120 status = mkdir(sux.sun_path, 0700);
121 if (status == 0) {
122 status = chown(sux.sun_path, pw->pw_uid, pw->pw_gid);
123 if (status < 0) {
124 perror("chown");
125 return EXIT_FAILURE;
126 }
127 }
128 else if (errno != EEXIST) {
129 perror("mkdir");
130 return EXIT_FAILURE;
131 }
132 else {
133 int dirfd;
134 struct stat st;
135
136 dirfd = open(sux.sun_path, O_RDONLY, O_DIRECTORY);
137 if (dirfd < 0) {
138 perror(sux.sun_path);
139 return EXIT_FAILURE;
140 }
141
142 status = fstat(dirfd, &st);
143 close(dirfd);
144
145 if (status < 0) {
146 perror(sux.sun_path);
147 return EXIT_FAILURE;
148 }
149
150 if (st.st_uid != pw->pw_uid) {
151 fprintf(stderr, "%s: exists but not owned by %s\n",
152 sux.sun_path, pw->pw_name);
153 return EXIT_FAILURE;
154 }
155
156 if ((st.st_mode & 0777) != 0700) {
157 fprintf(stderr, "%s: bad mode %04o\n",
158 sux.sun_path, (unsigned int)(st.st_mode & 0777));
159 return EXIT_FAILURE;
160 }
161 }
162
163 *slash = '/';
164
165#if 0
166 status = unlink(sux.sun_path);
167 if (status < 0 && errno != ENOENT) {
168 perror("unlink");
169 }
170#endif
171
172 s = socket(PF_UNIX, SOCK_STREAM, 0);
173 if (s < 0) {
174 perror("socket");
175 return EXIT_FAILURE;
176 }
177
178 status = bind(s, (struct sockaddr *)&sux,
179 (sizeof(sux) - sizeof(sux.sun_path)
180 + strlen(sux.sun_path) + 1));
181 if (status < 0) {
182 perror(sux.sun_path);
183 close(s);
184 return EXIT_FAILURE;
185 }
186
187 status = chown(sux.sun_path, pw->pw_uid, pw->pw_gid);
188 if (status < 0) {
189 perror("chown");
190 close(s);
191 return EXIT_FAILURE;
192 }
193
194 status = chmod(sux.sun_path, 0600);
195 if (status < 0) {
196 perror("chmod");
197 close(s);
198 return EXIT_FAILURE;
199 }
200
201 status = listen(s, 1);
202 if (status < 0) {
203 perror("listen");
204 close(s);
205 return EXIT_FAILURE;
206 }
207
208 memset(&sa, 0, sizeof(sa));
209 sa.sa_handler = handler;
210 sigemptyset(&sa.sa_mask);
211
212 sigaction(SIGINT, &sa, NULL);
213 sigaction(SIGTERM, &sa, NULL);
214
215 while (!signaled) {
216 client = accept(s, NULL, 0);
217 if (client < 0) {
218 perror("accept");
219 continue;
220 }
221
222 serve(client);
223 close(client);
224 }
225
226 close(s);
227 status = unlink(sux.sun_path);
228 if (status < 0) {
229 perror("unlink");
230 }
231
232 return EXIT_SUCCESS;
233}
234
235
236static void
237handler(int sig)
238{
239 signaled = 1;
240}
241
242
243static void
244serve(int client)
245{
246#ifdef SO_PEERCRED
247 struct ucred cr;
248 socklen_t crlen;
249#endif
250 ssize_t nread, nsent;
251 struct msghdr mh;
252 struct iovec iov[1];
253 char buf[1];
254 struct cmsghdr *cmh;
255 char cmsg[CMSG_SPACE(sizeof(int))];
256 int fd;
257 int status;
258
259#ifdef SO_PEERCRED
260 crlen = sizeof(cr);
261 status = getsockopt(client, SOL_SOCKET, SO_PEERCRED, &cr, &crlen);
262 if (status < 0) {
263 perror("SO_PEERCRED");
264 return;
265 }
266
267 fprintf(stderr, "request from pid %lu uid %lu ",
268 (unsigned long)cr.pid, (unsigned long)cr.uid);
269#endif
270
271 nread = read(client, buf, 1);
272 if (nread < 0) {
273 perror("recv");
274 return;
275 }
276
277 fd = -1;
278 switch (buf[0]) {
279
280 case '4':
281 fprintf(stderr, "for ICMPv4 socket\n");
282 fd = mkrawsock(PF_INET);
283 break;
284
285 case '6':
286 fprintf(stderr, "for ICMPv6 socket\n");
287 fd = mkrawsock(PF_INET6);
288 break;
289
290 default:
291 fprintf(stderr, "bad request 0x%02x\n", (unsigned int)buf[0]);
292 return;
293 }
294
295 if (fd < 0) {
296 buf[0] = '\0'; /* NAK */
297 nsent = write(client, buf, 1);
298 (void)nsent;
299 return;
300 }
301
302 memset(&mh, 0, sizeof(mh));
303 memset(cmsg, 0, sizeof(cmsg));
304
305 iov[0].iov_base = buf;
306 iov[0].iov_len = 1;
307
308 mh.msg_iov = iov;
309 mh.msg_iovlen = 1;
310 mh.msg_control = cmsg;
311 mh.msg_controllen = sizeof(cmsg);
312
313 cmh = CMSG_FIRSTHDR(&mh);
314 cmh->cmsg_level = SOL_SOCKET;
315 cmh->cmsg_type = SCM_RIGHTS;
316 cmh->cmsg_len = CMSG_LEN(sizeof(fd));
317 *((int *) CMSG_DATA(cmh)) = fd;
318
319 nsent = sendmsg(client, &mh, 0);
320 if (nsent < 0) {
321 perror("sendmsg");
322 }
323
324 close(fd);
325}
326
327
328static int
329mkrawsock(int family)
330{
331 int fd;
332
333 if (family == PF_INET) {
334 fd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
335 if (fd < 0) {
336 perror("IPPROTO_ICMP");
337 return -1;
338 }
339 }
340 else {
341 fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
342 if (fd < 0) {
343 perror("IPPROTO_ICMPV6");
344 return -1;
345 }
346 }
347
348 return fd;
349}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette