File: | src/sbin/swapctl/swapctl.c |
Warning: | line 394, column 18 Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: swapctl.c,v 1.26 2020/02/11 18:16:38 jca Exp $ */ |
2 | /* $NetBSD: swapctl.c,v 1.9 1998/07/26 20:23:15 mycroft Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1996, 1997 Matthew R. Green |
6 | * All rights reserved. |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 | * SUCH DAMAGE. |
28 | */ |
29 | |
30 | /* |
31 | * swapctl command: |
32 | * -A add all devices listed as `sw' in /etc/fstab |
33 | * -t [blk|noblk] if -A, add either all block device or all non-block |
34 | * devices |
35 | * -a <path> add this device |
36 | * -d <path> remove this swap device |
37 | * -l list swap devices |
38 | * -s short listing of swap devices |
39 | * -k use kilobytes |
40 | * -p <pri> use this priority |
41 | * -c <path> change priority |
42 | * |
43 | * or, if invoked as "swapon" (compatibility mode): |
44 | * |
45 | * -a all devices listed as `sw' in /etc/fstab |
46 | * -t same as -t above (feature not present in old |
47 | * swapon(8) command) |
48 | * <dev> add this device |
49 | */ |
50 | |
51 | #include <sys/stat.h> |
52 | #include <sys/swap.h> |
53 | #include <sys/wait.h> |
54 | |
55 | #include <unistd.h> |
56 | #include <err.h> |
57 | #include <errno(*__errno()).h> |
58 | #include <stdio.h> |
59 | #include <stdlib.h> |
60 | #include <limits.h> |
61 | #include <string.h> |
62 | #include <fstab.h> |
63 | #include <util.h> |
64 | |
65 | #include "swapctl.h" |
66 | |
67 | int command; |
68 | |
69 | /* |
70 | * Commands for swapctl(8). These are mutually exclusive. |
71 | */ |
72 | #define CMD_A0x01 0x01 /* process /etc/fstab */ |
73 | #define CMD_a0x02 0x02 /* add a swap file/device */ |
74 | #define CMD_c0x04 0x04 /* change priority of a swap file/device */ |
75 | #define CMD_d0x08 0x08 /* delete a swap file/device */ |
76 | #define CMD_l0x10 0x10 /* list swap files/devices */ |
77 | #define CMD_s0x20 0x20 /* summary of swap files/devices */ |
78 | |
79 | #define SET_COMMAND(cmd)do { if (command) usage(); command = (cmd); } while (0) \ |
80 | do { \ |
81 | if (command) \ |
82 | usage(); \ |
83 | command = (cmd); \ |
84 | } while (0) |
85 | |
86 | /* |
87 | * Commands that require a "path" argument at the end of the command |
88 | * line, and the ones which require that none exist. |
89 | */ |
90 | #define REQUIRE_PATH(0x02 | 0x04 | 0x08) (CMD_a0x02 | CMD_c0x04 | CMD_d0x08) |
91 | #define REQUIRE_NOPATH(0x01 | 0x10 | 0x20) (CMD_A0x01 | CMD_l0x10 | CMD_s0x20) |
92 | |
93 | /* |
94 | * Option flags, and the commands with which they are valid. |
95 | */ |
96 | int kflag; /* display in 1K blocks */ |
97 | #define KFLAG_CMDS(0x10 | 0x20) (CMD_l0x10 | CMD_s0x20) |
98 | |
99 | int pflag; /* priority was specified */ |
100 | #define PFLAG_CMDS(0x01 | 0x02 | 0x04) (CMD_A0x01 | CMD_a0x02 | CMD_c0x04) |
101 | |
102 | char *tflag; /* swap device type (blk or noblk) */ |
103 | #define TFLAG_CMDS(0x01) (CMD_A0x01) |
104 | |
105 | int pri; /* uses 0 as default pri */ |
106 | |
107 | static void change_priority(char *); |
108 | static void add_swap(char *); |
109 | static void del_swap(char *); |
110 | static void do_fstab(void); |
111 | static void usage(void); |
112 | static int swapon_command(int, char **); |
113 | |
114 | extern char *__progname; /* from crt0.o */ |
115 | |
116 | int |
117 | main(int argc, char *argv[]) |
118 | { |
119 | const char *errstr; |
120 | int c; |
121 | |
122 | if (strcmp(__progname, "swapon") == 0) |
123 | return swapon_command(argc, argv); |
124 | |
125 | while ((c = getopt(argc, argv, "Aacdlkp:st:")) != -1) { |
126 | switch (c) { |
127 | case 'A': |
128 | SET_COMMAND(CMD_A)do { if (command) usage(); command = (0x01); } while (0); |
129 | break; |
130 | |
131 | case 'a': |
132 | SET_COMMAND(CMD_a)do { if (command) usage(); command = (0x02); } while (0); |
133 | break; |
134 | |
135 | case 'c': |
136 | SET_COMMAND(CMD_c)do { if (command) usage(); command = (0x04); } while (0); |
137 | break; |
138 | |
139 | case 'd': |
140 | SET_COMMAND(CMD_d)do { if (command) usage(); command = (0x08); } while (0); |
141 | break; |
142 | |
143 | case 'l': |
144 | SET_COMMAND(CMD_l)do { if (command) usage(); command = (0x10); } while (0); |
145 | break; |
146 | |
147 | case 'k': |
148 | kflag = 1; |
149 | break; |
150 | |
151 | case 'p': |
152 | pflag = 1; |
153 | pri = strtonum(optarg, 0, INT_MAX0x7fffffff, &errstr); |
154 | if (errstr) |
155 | errx(1, "-p %s: %s", errstr, optarg); |
156 | break; |
157 | |
158 | case 's': |
159 | SET_COMMAND(CMD_s)do { if (command) usage(); command = (0x20); } while (0); |
160 | break; |
161 | |
162 | case 't': |
163 | if (tflag != NULL((void *)0)) |
164 | usage(); |
165 | tflag = optarg; |
166 | break; |
167 | |
168 | default: |
169 | usage(); |
170 | /* NOTREACHED */ |
171 | } |
172 | } |
173 | |
174 | argv += optind; |
175 | argc -= optind; |
176 | |
177 | /* Did the user specify a command? */ |
178 | if (command == 0) { |
179 | if (argc == 0) |
180 | SET_COMMAND(CMD_l)do { if (command) usage(); command = (0x10); } while (0); |
181 | else |
182 | usage(); |
183 | } |
184 | |
185 | switch (argc) { |
186 | case 0: |
187 | if (command & REQUIRE_PATH(0x02 | 0x04 | 0x08)) |
188 | usage(); |
189 | break; |
190 | |
191 | case 1: |
192 | if (command & REQUIRE_NOPATH(0x01 | 0x10 | 0x20)) |
193 | usage(); |
194 | break; |
195 | |
196 | default: |
197 | usage(); |
198 | } |
199 | |
200 | /* To change priority, you have to specify one. */ |
201 | if ((command == CMD_c0x04) && pflag == 0) |
202 | usage(); |
203 | |
204 | /* Sanity-check -t */ |
205 | if (tflag != NULL((void *)0)) { |
206 | if (command != CMD_A0x01) |
207 | usage(); |
208 | if (strcmp(tflag, "blk") != 0 && |
209 | strcmp(tflag, "noblk") != 0) |
210 | usage(); |
211 | } |
212 | |
213 | /* Dispatch the command. */ |
214 | switch (command) { |
215 | case CMD_l0x10: |
216 | list_swap(pri, kflag, pflag, 1); |
217 | break; |
218 | |
219 | case CMD_s0x20: |
220 | list_swap(pri, kflag, pflag, 0); |
221 | break; |
222 | |
223 | case CMD_c0x04: |
224 | change_priority(argv[0]); |
225 | break; |
226 | |
227 | case CMD_a0x02: |
228 | add_swap(argv[0]); |
229 | break; |
230 | |
231 | case CMD_d0x08: |
232 | del_swap(argv[0]); |
233 | break; |
234 | |
235 | case CMD_A0x01: |
236 | do_fstab(); |
237 | break; |
238 | } |
239 | |
240 | return (0); |
241 | } |
242 | |
243 | /* |
244 | * swapon_command: emulate the old swapon(8) program. |
245 | */ |
246 | int |
247 | swapon_command(int argc, char **argv) |
248 | { |
249 | int ch, fiztab = 0; |
250 | |
251 | while ((ch = getopt(argc, argv, "at:")) != -1) { |
252 | switch (ch) { |
253 | case 'a': |
254 | fiztab = 1; |
255 | break; |
256 | case 't': |
257 | if (tflag != NULL((void *)0)) |
258 | usage(); |
259 | tflag = optarg; |
260 | break; |
261 | default: |
262 | goto swapon_usage; |
263 | } |
264 | } |
265 | argc -= optind; |
266 | argv += optind; |
267 | |
268 | if (fiztab) { |
269 | if (argc) |
270 | goto swapon_usage; |
271 | /* Sanity-check -t */ |
272 | if (tflag != NULL((void *)0)) { |
273 | if (strcmp(tflag, "blk") != 0 && |
274 | strcmp(tflag, "noblk") != 0) |
275 | usage(); |
276 | } |
277 | do_fstab(); |
278 | return (0); |
279 | } else if (argc == 0 || tflag != NULL((void *)0)) |
280 | goto swapon_usage; |
281 | |
282 | while (argc) { |
283 | add_swap(argv[0]); |
284 | argc--; |
285 | argv++; |
286 | } |
287 | return (0); |
288 | |
289 | swapon_usage: |
290 | fprintf(stderr(&__sF[2]), "usage: %s -a | path\n", __progname); |
291 | return (1); |
292 | } |
293 | |
294 | /* |
295 | * change_priority: change the priority of a swap device. |
296 | */ |
297 | void |
298 | change_priority(char *path) |
299 | { |
300 | |
301 | if (swapctl(SWAP_CTL5, path, pri) == -1) |
302 | warn("%s", path); |
303 | } |
304 | |
305 | /* |
306 | * add_swap: add the pathname to the list of swap devices. |
307 | */ |
308 | void |
309 | add_swap(char *path) |
310 | { |
311 | |
312 | if (swapctl(SWAP_ON1, path, pri) == -1) |
313 | if (errno(*__errno()) != EBUSY16) |
314 | err(1, "%s", path); |
315 | } |
316 | |
317 | /* |
318 | * del_swap: remove the pathname from the list of swap devices. |
319 | */ |
320 | void |
321 | del_swap(char *path) |
322 | { |
323 | |
324 | if (swapctl(SWAP_OFF2, path, pri) == -1) |
325 | err(1, "%s", path); |
326 | } |
327 | |
328 | void |
329 | do_fstab(void) |
330 | { |
331 | struct fstab *fp; |
332 | char *s; |
333 | long priority; |
334 | struct stat st; |
335 | mode_t rejecttype = 0; |
336 | int gotone = 0; |
337 | |
338 | /* |
339 | * Select which mount point types to reject, depending on the |
340 | * value of the -t parameter. |
341 | */ |
342 | if (tflag != NULL((void *)0)) { |
343 | if (strcmp(tflag, "blk") == 0) |
344 | rejecttype = S_IFREG0100000; |
345 | else if (strcmp(tflag, "noblk") == 0) |
346 | rejecttype = S_IFBLK0060000; |
347 | } |
348 | |
349 | #define PRIORITYEQ"priority=" "priority=" |
350 | #define NFSMNTPT"nfsmntpt=" "nfsmntpt=" |
351 | #define PATH_MOUNT"/sbin/mount_nfs" "/sbin/mount_nfs" |
352 | while ((fp = getfsent()) != NULL((void *)0)) { |
353 | const char *spec; |
354 | |
355 | if (strcmp(fp->fs_type, "sw") != 0) |
356 | continue; |
357 | |
358 | spec = fp->fs_spec; |
359 | |
360 | if ((s = strstr(fp->fs_mntops, PRIORITYEQ"priority=")) != NULL((void *)0)) { |
361 | s += sizeof(PRIORITYEQ"priority=") - 1; |
362 | priority = atol(s); |
363 | } else |
364 | priority = pri; |
365 | |
366 | if ((s = strstr(fp->fs_mntops, NFSMNTPT"nfsmntpt=")) != NULL((void *)0)) { |
367 | char *t; |
368 | pid_t pid; |
369 | int status; |
370 | |
371 | /* |
372 | * Skip this song and dance if we're only |
373 | * doing block devices. |
374 | */ |
375 | if (rejecttype == S_IFREG0100000) |
376 | continue; |
377 | |
378 | t = strpbrk(s, ","); |
379 | if (t != 0) |
380 | *t = '\0'; |
381 | spec = strdup(s + strlen(NFSMNTPT"nfsmntpt=")); |
382 | if (spec == NULL((void *)0)) |
383 | err(1, "strdup"); |
384 | |
385 | if (t != 0) |
386 | *t = ','; |
387 | |
388 | if (strlen(spec) == 0) { |
389 | warnx("empty mountpoint"); |
390 | free((char *)spec); |
391 | continue; |
392 | } |
393 | |
394 | switch (pid = vfork()) { |
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function | |
395 | case -1: /* error */ |
396 | err(1, "vfork"); |
397 | case 0: |
398 | execl(PATH_MOUNT"/sbin/mount_nfs", PATH_MOUNT"/sbin/mount_nfs", fp->fs_spec, spec, |
399 | (char *)NULL((void *)0)); |
400 | err(1, "execl"); |
401 | } |
402 | while (waitpid(pid, &status, 0) == -1) |
403 | if (errno(*__errno()) != EINTR4) |
404 | err(1, "waitpid"); |
405 | if (status != 0) { |
406 | warnx("%s: mount failed", fp->fs_spec); |
407 | free((char *)spec); |
408 | continue; |
409 | } |
410 | } else if (isduid(spec, 0)) { |
411 | if (rejecttype == S_IFBLK0060000) |
412 | continue; |
413 | } else { |
414 | /* |
415 | * Determine blk-ness. Don't even consider a |
416 | * mountpoint outside /dev as a block device. |
417 | */ |
418 | if (rejecttype == S_IFREG0100000) { |
419 | if (strncmp("/dev/", spec, 5) != 0) |
420 | continue; |
421 | } |
422 | if (stat(spec, &st) == -1) { |
423 | warn("%s", spec); |
424 | continue; |
425 | } |
426 | if ((st.st_mode & S_IFMT0170000) == rejecttype) |
427 | continue; |
428 | |
429 | /* |
430 | * Do not allow fancy objects to be swap areas. |
431 | */ |
432 | if (!S_ISREG(st.st_mode)((st.st_mode & 0170000) == 0100000) && |
433 | !S_ISBLK(st.st_mode)((st.st_mode & 0170000) == 0060000)) |
434 | continue; |
435 | } |
436 | |
437 | if (swapctl(SWAP_ON1, spec, (int)priority) == -1) { |
438 | if (errno(*__errno()) != EBUSY16) |
439 | warn("%s", spec); |
440 | } else { |
441 | gotone = 1; |
442 | printf("%s: adding %s as swap device at priority %d\n", |
443 | __progname, fp->fs_spec, (int)priority); |
444 | } |
445 | |
446 | if (spec != fp->fs_spec) |
447 | free((char *)spec); |
448 | } |
449 | if (gotone == 0) |
450 | exit(1); |
451 | } |
452 | |
453 | void |
454 | usage(void) |
455 | { |
456 | |
457 | fprintf(stderr(&__sF[2]), "usage: %s -A [-p priority] [-t blk | noblk]\n", |
458 | __progname); |
459 | fprintf(stderr(&__sF[2]), " %s -a [-p priority] path\n", __progname); |
460 | fprintf(stderr(&__sF[2]), " %s -c -p priority path\n", __progname); |
461 | fprintf(stderr(&__sF[2]), " %s -d path\n", __progname); |
462 | fprintf(stderr(&__sF[2]), " %s [[-l] | -s] [-k]\n", __progname); |
463 | exit(1); |
464 | } |