Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/src/exec_nopty.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2009-2023 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <sys/wait.h>
24
#include <sys/ioctl.h>
25
26
#if defined(HAVE_STDINT_H)
27
# include <stdint.h>
28
#elif defined(HAVE_INTTYPES_H)
29
# include <inttypes.h>
30
#endif
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <unistd.h>
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <signal.h>
38
#include <termios.h> /* for struct winsize on HP-UX */
39
40
#include <sudo.h>
41
#include <sudo_exec.h>
42
#include <sudo_plugin.h>
43
#include <sudo_plugin_int.h>
44
45
static void handle_sigchld_nopty(struct exec_closure *ec);
46
47
/*
48
* Handle window size change events.
49
*/
50
static void
51
handle_sigwinch(struct exec_closure *ec, int fd)
52
{
53
struct winsize wsize;
54
debug_decl(handle_sigwinch, SUDO_DEBUG_EXEC);
55
56
if (fd != -1 && ioctl(fd, TIOCGWINSZ, &wsize) == 0) {
57
if (wsize.ws_row != ec->rows || wsize.ws_col != ec->cols) {
58
/* Log window change event. */
59
log_winchange(ec, wsize.ws_row, wsize.ws_col);
60
61
/* Update rows/cols. */
62
ec->rows = wsize.ws_row;
63
ec->cols = wsize.ws_col;
64
}
65
}
66
}
67
68
/* Note: this is basically the same as mon_errpipe_cb() in exec_monitor.c */
69
static void
70
errpipe_cb(int fd, int what, void *v)
71
{
72
struct exec_closure *ec = v;
73
ssize_t nread;
74
int errval;
75
debug_decl(errpipe_cb, SUDO_DEBUG_EXEC);
76
77
/*
78
* Read errno from child or EOF when command is executed.
79
* Note that the error pipe is *blocking*.
80
*/
81
nread = read(fd, &errval, sizeof(errval));
82
switch (nread) {
83
case -1:
84
if (errno != EAGAIN && errno != EINTR) {
85
if (ec->cstat->val == CMD_INVALID) {
86
/* XXX - need a way to distinguish non-exec error. */
87
ec->cstat->type = CMD_ERRNO;
88
ec->cstat->val = errno;
89
}
90
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
91
"%s: failed to read error pipe", __func__);
92
sudo_ev_loopbreak(ec->evbase);
93
}
94
break;
95
default:
96
if (nread == 0) {
97
/* The error pipe closes when the command is executed. */
98
sudo_debug_printf(SUDO_DEBUG_INFO, "EOF on error pipe");
99
} else {
100
/* Errno value when child is unable to execute command. */
101
sudo_debug_printf(SUDO_DEBUG_INFO, "errno from child: %s",
102
strerror(errval));
103
ec->cstat->type = CMD_ERRNO;
104
ec->cstat->val = errval;
105
}
106
sudo_ev_del(ec->evbase, ec->backchannel_event);
107
close(fd);
108
break;
109
}
110
debug_return;
111
}
112
113
/* Signal callback */
114
static void
115
signal_cb_nopty(int signo, int what, void *v)
116
{
117
struct sudo_ev_siginfo_container *sc = v;
118
struct exec_closure *ec = sc->closure;
119
char signame[SIG2STR_MAX];
120
pid_t si_pgrp;
121
debug_decl(signal_cb_nopty, SUDO_DEBUG_EXEC);
122
123
if (ec->cmnd_pid == -1)
124
debug_return;
125
126
if (sig2str(signo, signame) == -1)
127
(void)snprintf(signame, sizeof(signame), "%d", signo);
128
sudo_debug_printf(SUDO_DEBUG_DIAG,
129
"%s: evbase %p, command: %d, signo %s(%d), cstat %p",
130
__func__, ec->evbase, (int)ec->cmnd_pid, signame, signo, ec->cstat);
131
132
switch (signo) {
133
case SIGCHLD:
134
handle_sigchld_nopty(ec);
135
if (ec->cmnd_pid == -1) {
136
/* Command exited or was killed, exit event loop. */
137
sudo_ev_loopexit(ec->evbase);
138
}
139
debug_return;
140
case SIGWINCH:
141
handle_sigwinch(ec, io_fds[SFD_USERTTY]);
142
FALLTHROUGH;
143
#ifdef SIGINFO
144
case SIGINFO:
145
#endif
146
case SIGINT:
147
case SIGQUIT:
148
case SIGTSTP:
149
/*
150
* Only forward user-generated signals not sent by a process other than
151
* the command itself or a member of the command's process group (but
152
* only when either sudo or the command is the process group leader).
153
* Signals sent by the kernel may include SIGTSTP when the user presses
154
* ^Z. Curses programs often trap ^Z and send SIGTSTP to their own
155
* process group, so we don't want to send an extra SIGTSTP.
156
*/
157
if (!USER_SIGNALED(sc->siginfo))
158
debug_return;
159
if (sc->siginfo->si_pid != 0) {
160
if (sc->siginfo->si_pid == ec->cmnd_pid)
161
debug_return;
162
si_pgrp = getpgid(sc->siginfo->si_pid);
163
if (si_pgrp != -1) {
164
if (si_pgrp == ec->cmnd_pid || si_pgrp == ec->sudo_pid)
165
debug_return;
166
}
167
}
168
break;
169
default:
170
/*
171
* Do not forward signals sent by the command itself or a member of the
172
* command's process group (but only when either sudo or the command is
173
* the process group leader). We don't want the command to indirectly
174
* kill itself. For example, this can happen with some versions of
175
* reboot that call kill(-1, SIGTERM) to kill all other processes.
176
*/
177
if (USER_SIGNALED(sc->siginfo) && sc->siginfo->si_pid != 0) {
178
if (sc->siginfo->si_pid == ec->cmnd_pid)
179
debug_return;
180
si_pgrp = getpgid(sc->siginfo->si_pid);
181
if (si_pgrp != -1) {
182
if (si_pgrp == ec->cmnd_pid || si_pgrp == ec->sudo_pid)
183
debug_return;
184
}
185
}
186
break;
187
}
188
189
/* Send signal to command. */
190
if (signo == SIGALRM) {
191
terminate_command(ec->cmnd_pid, false);
192
} else if (kill(ec->cmnd_pid, signo) != 0) {
193
sudo_warn("kill(%d, SIG%s)", (int)ec->cmnd_pid, signame);
194
}
195
196
debug_return;
197
}
198
199
/*
200
* Fill in the non-event part of the exec closure.
201
*/
202
static void
203
init_exec_closure(struct exec_closure *ec, struct command_status *cstat,
204
struct command_details *details, const struct user_details *user_details)
205
{
206
debug_decl(init_exec_closure, SUDO_DEBUG_EXEC);
207
208
/* Fill in the non-event part of the closure. */
209
memset(ec, 0, sizeof(*ec));
210
ec->sudo_pid = getpid();
211
ec->ppgrp = getpgrp();
212
ec->cstat = cstat;
213
ec->details = details;
214
ec->rows = user_details->ts_rows;
215
ec->cols = user_details->ts_cols;
216
217
debug_return;
218
}
219
220
/*
221
* Allocate and set events for the signal pipe and error pipe.
222
*/
223
static void
224
init_exec_events(struct exec_closure *ec, struct sudo_event_base *evbase,
225
int errfd)
226
{
227
debug_decl(init_exec_events, SUDO_DEBUG_EXEC);
228
229
/* Setup event base and events. */
230
ec->evbase = evbase;
231
232
/* Event for command status via errfd. */
233
ec->backchannel_event = sudo_ev_alloc(errfd,
234
SUDO_EV_READ|SUDO_EV_PERSIST, errpipe_cb, ec);
235
if (ec->backchannel_event == NULL)
236
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
237
if (sudo_ev_add(ec->evbase, ec->backchannel_event, NULL, false) == -1)
238
sudo_fatal("%s", U_("unable to add event to queue"));
239
sudo_debug_printf(SUDO_DEBUG_INFO, "error pipe fd %d\n", errfd);
240
241
/* Events for local signals. */
242
ec->sigint_event = sudo_ev_alloc(SIGINT,
243
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
244
if (ec->sigint_event == NULL)
245
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
246
if (sudo_ev_add(ec->evbase, ec->sigint_event, NULL, false) == -1)
247
sudo_fatal("%s", U_("unable to add event to queue"));
248
249
ec->sigquit_event = sudo_ev_alloc(SIGQUIT,
250
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
251
if (ec->sigquit_event == NULL)
252
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
253
if (sudo_ev_add(ec->evbase, ec->sigquit_event, NULL, false) == -1)
254
sudo_fatal("%s", U_("unable to add event to queue"));
255
256
ec->sigtstp_event = sudo_ev_alloc(SIGTSTP,
257
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
258
if (ec->sigtstp_event == NULL)
259
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
260
if (sudo_ev_add(ec->evbase, ec->sigtstp_event, NULL, false) == -1)
261
sudo_fatal("%s", U_("unable to add event to queue"));
262
263
ec->sigterm_event = sudo_ev_alloc(SIGTERM,
264
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
265
if (ec->sigterm_event == NULL)
266
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
267
if (sudo_ev_add(ec->evbase, ec->sigterm_event, NULL, false) == -1)
268
sudo_fatal("%s", U_("unable to add event to queue"));
269
270
ec->sighup_event = sudo_ev_alloc(SIGHUP,
271
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
272
if (ec->sighup_event == NULL)
273
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
274
if (sudo_ev_add(ec->evbase, ec->sighup_event, NULL, false) == -1)
275
sudo_fatal("%s", U_("unable to add event to queue"));
276
277
ec->sigalrm_event = sudo_ev_alloc(SIGALRM,
278
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
279
if (ec->sigalrm_event == NULL)
280
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
281
if (sudo_ev_add(ec->evbase, ec->sigalrm_event, NULL, false) == -1)
282
sudo_fatal("%s", U_("unable to add event to queue"));
283
284
ec->sigpipe_event = sudo_ev_alloc(SIGPIPE,
285
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
286
if (ec->sigpipe_event == NULL)
287
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
288
if (sudo_ev_add(ec->evbase, ec->sigpipe_event, NULL, false) == -1)
289
sudo_fatal("%s", U_("unable to add event to queue"));
290
291
ec->sigusr1_event = sudo_ev_alloc(SIGUSR1,
292
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
293
if (ec->sigusr1_event == NULL)
294
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
295
if (sudo_ev_add(ec->evbase, ec->sigusr1_event, NULL, false) == -1)
296
sudo_fatal("%s", U_("unable to add event to queue"));
297
298
ec->sigusr2_event = sudo_ev_alloc(SIGUSR2,
299
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
300
if (ec->sigusr2_event == NULL)
301
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
302
if (sudo_ev_add(ec->evbase, ec->sigusr2_event, NULL, false) == -1)
303
sudo_fatal("%s", U_("unable to add event to queue"));
304
305
ec->sigchld_event = sudo_ev_alloc(SIGCHLD,
306
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
307
if (ec->sigchld_event == NULL)
308
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
309
if (sudo_ev_add(ec->evbase, ec->sigchld_event, NULL, false) == -1)
310
sudo_fatal("%s", U_("unable to add event to queue"));
311
312
ec->sigcont_event = sudo_ev_alloc(SIGCONT,
313
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
314
if (ec->sigcont_event == NULL)
315
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
316
if (sudo_ev_add(ec->evbase, ec->sigcont_event, NULL, false) == -1)
317
sudo_fatal("%s", U_("unable to add event to queue"));
318
319
#ifdef SIGINFO
320
ec->siginfo_event = sudo_ev_alloc(SIGINFO,
321
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
322
if (ec->siginfo_event == NULL)
323
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
324
if (sudo_ev_add(ec->evbase, ec->siginfo_event, NULL, false) == -1)
325
sudo_fatal("%s", U_("unable to add event to queue"));
326
#endif
327
328
ec->sigwinch_event = sudo_ev_alloc(SIGWINCH,
329
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
330
if (ec->sigwinch_event == NULL)
331
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
332
if (sudo_ev_add(ec->evbase, ec->sigwinch_event, NULL, false) == -1)
333
sudo_fatal("%s", U_("unable to add event to queue"));
334
335
/* Set the default event base. */
336
sudo_ev_base_setdef(ec->evbase);
337
338
debug_return;
339
}
340
341
/*
342
* Read an iobuf that is ready.
343
*/
344
static void
345
read_callback(int fd, int what, void *v)
346
{
347
struct io_buffer *iob = v;
348
struct sudo_event_base *evbase = sudo_ev_get_base(iob->revent);
349
ssize_t n;
350
debug_decl(read_callback, SUDO_DEBUG_EXEC);
351
352
n = read(fd, iob->buf + iob->len, sizeof(iob->buf) - iob->len);
353
switch (n) {
354
case -1:
355
if (errno == EAGAIN || errno == EINTR) {
356
/* Not an error, retry later. */
357
break;
358
}
359
/* Treat read error as fatal and close the fd. */
360
sudo_debug_printf(SUDO_DEBUG_ERROR,
361
"error reading fd %d: %s", fd, strerror(errno));
362
FALLTHROUGH;
363
case 0:
364
/* got EOF */
365
if (n == 0) {
366
sudo_debug_printf(SUDO_DEBUG_INFO,
367
"read EOF from fd %d", fd);
368
}
369
safe_close(fd);
370
ev_free_by_fd(evbase, fd);
371
/* If writer already consumed the buffer, close it too. */
372
if (iob->wevent != NULL && iob->off == iob->len) {
373
safe_close(sudo_ev_get_fd(iob->wevent));
374
ev_free_by_fd(evbase, sudo_ev_get_fd(iob->wevent));
375
iob->off = iob->len = 0;
376
}
377
break;
378
default:
379
sudo_debug_printf(SUDO_DEBUG_INFO,
380
"read %zd bytes from fd %d", n, fd);
381
if (!iob->action(iob->buf + iob->len, (unsigned int)n, iob)) {
382
terminate_command(iob->ec->cmnd_pid, false);
383
iob->ec->cmnd_pid = -1;
384
}
385
iob->len += (unsigned int)n;
386
/* Disable reader if buffer is full. */
387
if (iob->len == sizeof(iob->buf))
388
sudo_ev_del(evbase, iob->revent);
389
/* Enable writer now that there is new data in the buffer. */
390
if (iob->wevent != NULL) {
391
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
392
sudo_fatal("%s", U_("unable to add event to queue"));
393
}
394
break;
395
}
396
397
debug_return;
398
}
399
400
/*
401
* Write an iobuf that is ready.
402
*/
403
static void
404
write_callback(int fd, int what, void *v)
405
{
406
struct io_buffer *iob = v;
407
struct sudo_event_base *evbase = sudo_ev_get_base(iob->wevent);
408
ssize_t n;
409
debug_decl(write_callback, SUDO_DEBUG_EXEC);
410
411
n = write(fd, iob->buf + iob->off, iob->len - iob->off);
412
if (n == -1) {
413
switch (errno) {
414
case EPIPE:
415
case EBADF:
416
/* other end of pipe closed */
417
sudo_debug_printf(SUDO_DEBUG_INFO,
418
"unable to write %u bytes to fd %d",
419
iob->len - iob->off, fd);
420
/* Close reader if there is one. */
421
if (iob->revent != NULL) {
422
safe_close(sudo_ev_get_fd(iob->revent));
423
ev_free_by_fd(evbase, sudo_ev_get_fd(iob->revent));
424
}
425
safe_close(fd);
426
ev_free_by_fd(evbase, fd);
427
break;
428
case EINTR:
429
case EAGAIN:
430
/* Not an error, retry later. */
431
break;
432
default:
433
/* XXX - need a way to distinguish non-exec error. */
434
iob->ec->cstat->type = CMD_ERRNO;
435
iob->ec->cstat->val = errno;
436
sudo_debug_printf(SUDO_DEBUG_ERROR,
437
"error writing fd %d: %s", fd, strerror(errno));
438
sudo_ev_loopbreak(evbase);
439
break;
440
}
441
} else {
442
sudo_debug_printf(SUDO_DEBUG_INFO,
443
"wrote %zd bytes to fd %d", n, fd);
444
iob->off += (unsigned int)n;
445
/* Disable writer and reset the buffer if fully consumed. */
446
if (iob->off == iob->len) {
447
iob->off = iob->len = 0;
448
sudo_ev_del(evbase, iob->wevent);
449
/* Forward the EOF from reader to writer. */
450
if (iob->revent == NULL) {
451
safe_close(fd);
452
ev_free_by_fd(evbase, fd);
453
}
454
}
455
/*
456
* Enable reader if buffer is not full but avoid reading
457
* /dev/tty if the command is no longer running.
458
*/
459
if (iob->revent != NULL && iob->len != sizeof(iob->buf)) {
460
if (!USERTTY_EVENT(iob->revent) || iob->ec->cmnd_pid != -1) {
461
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
462
sudo_fatal("%s", U_("unable to add event to queue"));
463
}
464
}
465
}
466
467
debug_return;
468
}
469
470
/*
471
* If std{in,out,err} are not connected to a terminal, interpose
472
* ourselves using a pipe. Fills in io_pipe[][].
473
*/
474
static void
475
interpose_pipes(struct exec_closure *ec, const char *tty, int io_pipe[3][2])
476
{
477
bool interpose[3] = { false, false, false };
478
struct plugin_container *plugin;
479
const pid_t pgrp = getpgrp();
480
bool want_winch = false;
481
struct stat sb;
482
debug_decl(interpose_pipes, SUDO_DEBUG_EXEC);
483
484
/*
485
* Determine whether any of std{in,out,err} or window size changes
486
* should be logged.
487
*/
488
TAILQ_FOREACH(plugin, &io_plugins, entries) {
489
if (plugin->u.io->log_stdin)
490
interpose[STDIN_FILENO] = true;
491
if (plugin->u.io->log_stdout)
492
interpose[STDOUT_FILENO] = true;
493
if (plugin->u.io->log_stderr)
494
interpose[STDERR_FILENO] = true;
495
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 12)) {
496
if (plugin->u.io->change_winsize)
497
want_winch = true;
498
}
499
}
500
501
/*
502
* If stdin, stdout or stderr is not the user's tty and logging is
503
* enabled, use a pipe to interpose ourselves.
504
*/
505
if (interpose[STDIN_FILENO]) {
506
if (!fd_matches_pgrp(STDIN_FILENO, pgrp, &sb)) {
507
sudo_debug_printf(SUDO_DEBUG_INFO,
508
"stdin not user's tty, creating a pipe");
509
if (pipe2(io_pipe[STDIN_FILENO], O_CLOEXEC) != 0)
510
sudo_fatal("%s", U_("unable to create pipe"));
511
io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
512
log_stdin, read_callback, write_callback, ec);
513
}
514
}
515
if (interpose[STDOUT_FILENO]) {
516
if (!fd_matches_pgrp(STDOUT_FILENO, pgrp, &sb)) {
517
sudo_debug_printf(SUDO_DEBUG_INFO,
518
"stdout not user's tty, creating a pipe");
519
if (pipe2(io_pipe[STDOUT_FILENO], O_CLOEXEC) != 0)
520
sudo_fatal("%s", U_("unable to create pipe"));
521
io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
522
log_stdout, read_callback, write_callback, ec);
523
}
524
}
525
if (interpose[STDERR_FILENO]) {
526
if (!fd_matches_pgrp(STDERR_FILENO, pgrp, &sb)) {
527
sudo_debug_printf(SUDO_DEBUG_INFO,
528
"stderr not user's tty, creating a pipe");
529
if (pipe2(io_pipe[STDERR_FILENO], O_CLOEXEC) != 0)
530
sudo_fatal("%s", U_("unable to create pipe"));
531
io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
532
log_stderr, read_callback, write_callback, ec);
533
}
534
}
535
if (want_winch) {
536
/* Need /dev/tty for SIGWINCH handling. */
537
io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR);
538
}
539
}
540
541
/*
542
* Execute a command and wait for it to finish.
543
*/
544
void
545
exec_nopty(struct command_details *details,
546
const struct user_details *user_details,
547
struct sudo_event_base *evbase, struct command_status *cstat)
548
{
549
int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } };
550
int errpipe[2], intercept_sv[2] = { -1, -1 };
551
struct exec_closure ec;
552
sigset_t set, oset;
553
debug_decl(exec_nopty, SUDO_DEBUG_EXEC);
554
555
/*
556
* The policy plugin's session init must be run before we fork
557
* or certain pam modules won't be able to track their state.
558
*/
559
if (policy_init_session(details) != true)
560
sudo_fatalx("%s", U_("policy plugin failed session initialization"));
561
562
/* Fill in exec closure. */
563
init_exec_closure(&ec, cstat, details, user_details);
564
565
/*
566
* We use a pipe to get errno if execve(2) fails in the child.
567
*/
568
if (pipe2(errpipe, O_CLOEXEC) != 0)
569
sudo_fatal("%s", U_("unable to create pipe"));
570
571
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_SUBCMDS)) {
572
if (!ISSET(details->flags, CD_USE_PTRACE)) {
573
/*
574
* Allocate a socketpair for communicating with sudo_intercept.so.
575
* This must be inherited across exec, hence no FD_CLOEXEC.
576
*/
577
if (socketpair(PF_UNIX, SOCK_STREAM, 0, intercept_sv) == -1)
578
sudo_fatal("%s", U_("unable to create sockets"));
579
}
580
}
581
582
/* Interpose std{in,out,err} with pipes if logging I/O. */
583
interpose_pipes(&ec, user_details->tty, io_pipe);
584
585
/*
586
* Block signals until we have our handlers setup in the parent so
587
* we don't miss SIGCHLD if the command exits immediately.
588
*/
589
sigfillset(&set);
590
sigprocmask(SIG_BLOCK, &set, &oset);
591
592
/* Check for early termination or suspend signals before we fork. */
593
if (sudo_terminated(cstat)) {
594
sigprocmask(SIG_SETMASK, &oset, NULL);
595
debug_return;
596
}
597
598
#ifdef HAVE_SELINUX
599
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
600
if (selinux_relabel_tty(details->tty, -1) == -1) {
601
cstat->type = CMD_ERRNO;
602
cstat->val = errno;
603
debug_return;
604
}
605
selinux_audit_role_change();
606
}
607
#endif
608
609
ec.cmnd_pid = sudo_debug_fork();
610
switch (ec.cmnd_pid) {
611
case -1:
612
sudo_fatal("%s", U_("unable to fork"));
613
break;
614
case 0:
615
/* child */
616
close(errpipe[0]);
617
if (intercept_sv[0] != -1)
618
close(intercept_sv[0]);
619
/* Replace stdin/stdout/stderr with pipes as needed and exec. */
620
if (io_pipe[STDIN_FILENO][0] != -1) {
621
if (dup3(io_pipe[STDIN_FILENO][0], STDIN_FILENO, 0) == -1)
622
sudo_fatal("dup3");
623
close(io_pipe[STDIN_FILENO][0]);
624
close(io_pipe[STDIN_FILENO][1]);
625
}
626
if (io_pipe[STDOUT_FILENO][0] != -1) {
627
if (dup3(io_pipe[STDOUT_FILENO][1], STDOUT_FILENO, 0) == -1)
628
sudo_fatal("dup3");
629
close(io_pipe[STDOUT_FILENO][0]);
630
close(io_pipe[STDOUT_FILENO][1]);
631
}
632
if (io_pipe[STDERR_FILENO][0] != -1) {
633
if (dup3(io_pipe[STDERR_FILENO][1], STDERR_FILENO, 0) == -1)
634
sudo_fatal("dup3");
635
close(io_pipe[STDERR_FILENO][0]);
636
close(io_pipe[STDERR_FILENO][1]);
637
}
638
exec_cmnd(details, &oset, intercept_sv[1], errpipe[1]);
639
while (write(errpipe[1], &errno, sizeof(int)) == -1) {
640
if (errno != EINTR)
641
break;
642
}
643
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);
644
_exit(EXIT_FAILURE);
645
/* NOTREACHED */
646
}
647
sudo_debug_printf(SUDO_DEBUG_INFO, "executed %s, pid %d", details->command,
648
(int)ec.cmnd_pid);
649
/* Close the other end of the pipes and socketpairs. */
650
if (io_pipe[STDIN_FILENO][0] != -1)
651
close(io_pipe[STDIN_FILENO][0]);
652
if (io_pipe[STDOUT_FILENO][1] != -1)
653
close(io_pipe[STDOUT_FILENO][1]);
654
if (io_pipe[STDERR_FILENO][1] != -1)
655
close(io_pipe[STDERR_FILENO][1]);
656
close(errpipe[1]);
657
if (intercept_sv[1] != -1)
658
close(intercept_sv[1]);
659
660
/* No longer need execfd. */
661
if (details->execfd != -1) {
662
close(details->execfd);
663
details->execfd = -1;
664
}
665
666
/* Set command timeout if specified. */
667
if (ISSET(details->flags, CD_SET_TIMEOUT))
668
alarm(details->timeout);
669
670
/* Allocate and set signal events and the error pipe event. */
671
init_exec_events(&ec, evbase, errpipe[0]);
672
673
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_SUBCMDS)) {
674
int rc = 1;
675
676
/* Create event and closure for intercept mode. */
677
ec.intercept = intercept_setup(intercept_sv[0], ec.evbase, details);
678
if (ec.intercept == NULL) {
679
rc = -1;
680
} else if (ISSET(details->flags, CD_USE_PTRACE)) {
681
/* Try to seize control of the command using ptrace(2). */
682
rc = exec_ptrace_seize(ec.cmnd_pid);
683
if (rc == 0) {
684
/* There is another tracer present. */
685
CLR(details->flags, CD_INTERCEPT|CD_LOG_SUBCMDS|CD_USE_PTRACE);
686
}
687
}
688
if (rc == -1)
689
terminate_command(ec.cmnd_pid, false);
690
}
691
692
/* Enable any I/O log events. */
693
add_io_events(&ec);
694
695
/* Restore signal mask now that signal handlers are setup. */
696
sigprocmask(SIG_SETMASK, &oset, NULL);
697
698
/*
699
* Non-pty event loop.
700
* Wait for command to exit, handles signals and the error pipe.
701
*/
702
if (sudo_ev_dispatch(ec.evbase) == -1)
703
sudo_warn("%s", U_("error in event loop"));
704
if (sudo_ev_got_break(ec.evbase)) {
705
/* error from callback */
706
sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
707
/* kill command */
708
terminate_command(ec.cmnd_pid, false);
709
ec.cmnd_pid = -1;
710
}
711
712
#ifdef HAVE_SELINUX
713
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
714
if (selinux_restore_tty() != 0)
715
sudo_warnx("%s", U_("unable to restore tty label"));
716
}
717
#endif
718
719
/* Flush any remaining output. */
720
del_io_events(true);
721
722
/* Free things up. */
723
free_io_bufs();
724
free_exec_closure(&ec);
725
726
debug_return;
727
}
728
729
/*
730
* Wait for command status after receiving SIGCHLD.
731
* If the command exits, fill in cstat and stop the event loop.
732
* If the command stops, save the tty pgrp, suspend sudo, then restore
733
* the tty pgrp when sudo resumes.
734
*/
735
static void
736
handle_sigchld_nopty(struct exec_closure *ec)
737
{
738
pid_t pid;
739
int status;
740
char signame[SIG2STR_MAX];
741
debug_decl(handle_sigchld_nopty, SUDO_DEBUG_EXEC);
742
743
/* There may be multiple children in intercept mode. */
744
for (;;) {
745
do {
746
pid = waitpid(-1, &status, __WALL|WUNTRACED|WNOHANG);
747
} while (pid == -1 && errno == EINTR);
748
switch (pid) {
749
case -1:
750
if (errno != ECHILD) {
751
sudo_warn(U_("%s: %s"), __func__, "waitpid");
752
debug_return;
753
}
754
FALLTHROUGH;
755
case 0:
756
/* Nothing left to wait for. */
757
debug_return;
758
}
759
760
if (WIFSTOPPED(status)) {
761
const int signo = WSTOPSIG(status);
762
763
if (sig2str(signo, signame) == -1)
764
(void)snprintf(signame, sizeof(signame), "%d", signo);
765
sudo_debug_printf(SUDO_DEBUG_INFO,
766
"%s: process %d stopped, SIG%s", __func__, (int)pid, signame);
767
768
if (ISSET(ec->details->flags, CD_USE_PTRACE)) {
769
/* If not a group-stop signal, just continue. */
770
if (!exec_ptrace_stopped(pid, status, ec->intercept))
771
continue;
772
}
773
774
/* If the main command is suspended, suspend sudo too. */
775
if (pid == ec->cmnd_pid) {
776
sudo_suspend_parent(signo, ec->sudo_pid, ec->ppgrp,
777
ec->cmnd_pid, ec, log_suspend);
778
}
779
} else {
780
if (WIFSIGNALED(status)) {
781
if (sig2str(WTERMSIG(status), signame) == -1) {
782
(void)snprintf(signame, sizeof(signame), "%d",
783
WTERMSIG(status));
784
}
785
sudo_debug_printf(SUDO_DEBUG_INFO,
786
"%s: process %d killed, SIG%s", __func__,
787
(int)pid, signame);
788
} else if (WIFEXITED(status)) {
789
sudo_debug_printf(SUDO_DEBUG_INFO,
790
"%s: process %d exited: %d", __func__,
791
(int)pid, WEXITSTATUS(status));
792
} else {
793
sudo_debug_printf(SUDO_DEBUG_WARN,
794
"%s: unexpected wait status 0x%x for process %d",
795
__func__, status, (int)pid);
796
}
797
798
/* Only store exit status of the main command. */
799
if (pid != ec->cmnd_pid)
800
continue;
801
802
/* Don't overwrite execve() failure with command exit status. */
803
if (ec->cstat->type == CMD_INVALID) {
804
ec->cstat->type = CMD_WSTATUS;
805
ec->cstat->val = status;
806
} else {
807
sudo_debug_printf(SUDO_DEBUG_WARN,
808
"%s: not overwriting command status %d,%d with %d,%d",
809
__func__, ec->cstat->type, ec->cstat->val,
810
CMD_WSTATUS, status);
811
}
812
ec->cmnd_pid = -1;
813
}
814
}
815
}
816
817