Bug Summary

File:src/usr.bin/mail/tty.c
Warning:line 161, column 2
Address of stack memory associated with local variable 'oldtio' is still referred to by the global variable 'tty' upon returning to the caller. This will be a dangling reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tty.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/mail/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mail/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/mail/tty.c
1/* $OpenBSD: tty.c,v 1.22 2019/06/28 13:35:02 deraadt Exp $ */
2/* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */
3
4/*
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. 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 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Mail -- a mail program
35 *
36 * Generally useful tty stuff.
37 */
38
39#include "rcv.h"
40#include "extern.h"
41#include <sys/ioctl.h>
42#include <errno(*__errno()).h>
43#include <fcntl.h>
44
45#define TABWIDTH8 8
46
47struct tty {
48 int fdin;
49 int fdout;
50 int flags;
51#define TTY_ALTWERASE0x1 0x1
52#define TTY_ERR0x2 0x2
53 cc_t *keys;
54 char *buf;
55 size_t size;
56 size_t len;
57 size_t cursor;
58};
59
60static void tty_flush(struct tty *);
61static int tty_getc(struct tty *);
62static int tty_insert(struct tty *, int, int);
63static void tty_putc(struct tty *, int);
64static void tty_reset(struct tty *);
65static void tty_visc(struct tty *, int);
66
67static struct tty tty;
68static volatile sig_atomic_t ttysignal; /* Interrupted by a signal? */
69
70/*
71 * Read all relevant header fields.
72 */
73int
74grabh(struct header *hp, int gflags)
75{
76 struct termios newtio, oldtio;
77#ifdef TIOCEXT((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((96)))
78 int extproc;
79 int flag;
80#endif
81 struct sigaction savetstp;
82 struct sigaction savettou;
83 struct sigaction savettin;
84 struct sigaction act;
85 char *s;
86 int error;
87
88 sigemptyset(&act.sa_mask);
89 act.sa_flags = SA_RESTART0x0002;
90 act.sa_handler__sigaction_u.__sa_handler = SIG_DFL(void (*)(int))0;
91 (void)sigaction(SIGTSTP18, &act, &savetstp);
92 (void)sigaction(SIGTTOU22, &act, &savettou);
93 (void)sigaction(SIGTTIN21, &act, &savettin);
94 error = 1;
95 memset(&tty, 0, sizeof(tty));
96 tty.fdin = fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
;
1
Assuming '__isthreaded' is 0
2
'?' condition is true
97 tty.fdout = fileno(stdout)(!__isthreaded ? (((&__sF[1]))->_file) : (fileno)((&
__sF[1])))
;
3
'?' condition is true
98 if (tcgetattr(tty.fdin, &oldtio) == -1) {
4
Assuming the condition is false
5
Taking false branch
99 warn("tcgetattr");
100 return(-1);
101 }
102 tty.keys = oldtio.c_cc;
103 if (oldtio.c_lflag & ALTWERASE0x00000200)
6
Assuming the condition is false
7
Taking false branch
104 tty.flags |= TTY_ALTWERASE0x1;
105
106 newtio = oldtio;
107 newtio.c_lflag &= ~(ECHO0x00000008 | ICANON0x00000100);
108 newtio.c_cc[VMIN16] = 1;
109 newtio.c_cc[VTIME17] = 0;
110 if (tcsetattr(tty.fdin, TCSADRAIN1, &newtio) == -1) {
8
Assuming the condition is false
9
Taking false branch
111 warn("tcsetattr");
112 return(-1);
113 }
114
115#ifdef TIOCEXT((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((96)))
116 extproc = ((oldtio.c_lflag & EXTPROC0x00000800) ? 1 : 0);
10
Assuming the condition is false
11
'?' condition is false
117 if (extproc
11.1
'extproc' is 0
) {
12
Taking false branch
118 flag = 0;
119 if (ioctl(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
, TIOCEXT((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((96)))
, &flag) == -1)
120 warn("TIOCEXT: off");
121 }
122#endif
123 if (gflags & GTO1) {
13
Assuming the condition is false
14
Taking false branch
124 s = readtty("To: ", detract(hp->h_to, 0));
125 if (s == NULL((void *)0))
126 goto out;
127 hp->h_to = extract(s, GTO1);
128 }
129 if (gflags & GSUBJECT2) {
15
Assuming the condition is false
16
Taking false branch
130 s = readtty("Subject: ", hp->h_subject);
131 if (s == NULL((void *)0))
132 goto out;
133 hp->h_subject = s;
134 }
135 if (gflags & GCC4) {
17
Assuming the condition is false
18
Taking false branch
136 s = readtty("Cc: ", detract(hp->h_cc, 0));
137 if (s == NULL((void *)0))
138 goto out;
139 hp->h_cc = extract(s, GCC4);
140 }
141 if (gflags & GBCC8) {
19
Assuming the condition is false
20
Taking false branch
142 s = readtty("Bcc: ", detract(hp->h_bcc, 0));
143 if (s == NULL((void *)0))
144 goto out;
145 hp->h_bcc = extract(s, GBCC8);
146 }
147 error = 0;
148out:
149 (void)sigaction(SIGTSTP18, &savetstp, NULL((void *)0));
150 (void)sigaction(SIGTTOU22, &savettou, NULL((void *)0));
151 (void)sigaction(SIGTTIN21, &savettin, NULL((void *)0));
152#ifdef TIOCEXT((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((96)))
153 if (extproc
20.1
'extproc' is 0
) {
21
Taking false branch
154 flag = 1;
155 if (ioctl(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
, TIOCEXT((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((96)))
, &flag) == -1)
156 warn("TIOCEXT: on");
157 }
158#endif
159 if (tcsetattr(tty.fdin, TCSADRAIN1, &oldtio) == -1)
22
Assuming the condition is false
23
Taking false branch
160 warn("tcsetattr");
161 return(error);
24
Address of stack memory associated with local variable 'oldtio' is still referred to by the global variable 'tty' upon returning to the caller. This will be a dangling reference
162}
163
164/*
165 * Read up a header from standard input.
166 * The source string has the preliminary contents to
167 * be read.
168 *
169 */
170char *
171readtty(char *pr, char *src)
172{
173 struct sigaction act, saveint;
174 unsigned char canonb[BUFSIZ1024];
175 char *cp;
176 sigset_t oset;
177 int c, done;
178
179 memset(canonb, 0, sizeof(canonb));
180 tty.buf = canonb;
181 tty.size = sizeof(canonb) - 1;
182
183 for (cp = pr; *cp != '\0'; cp++)
184 tty_insert(&tty, *cp, 1);
185 tty_flush(&tty);
186 tty_reset(&tty);
187
188 if (src != NULL((void *)0) && strlen(src) > sizeof(canonb) - 2) {
189 puts("too long to edit");
190 return(src);
191 }
192 if (src != NULL((void *)0)) {
193 for (cp = src; *cp != '\0'; cp++)
194 tty_insert(&tty, *cp, 1);
195 tty_flush(&tty);
196 }
197
198 sigemptyset(&act.sa_mask);
199 act.sa_flags = 0; /* Note: will not restart syscalls */
200 act.sa_handler__sigaction_u.__sa_handler = ttyint;
201 (void)sigaction(SIGINT2, &act, &saveint);
202 act.sa_handler__sigaction_u.__sa_handler = ttystop;
203 (void)sigaction(SIGTSTP18, &act, NULL((void *)0));
204 (void)sigaction(SIGTTOU22, &act, NULL((void *)0));
205 (void)sigaction(SIGTTIN21, &act, NULL((void *)0));
206 (void)sigprocmask(SIG_UNBLOCK2, &intset, &oset);
207 for (;;) {
208 c = tty_getc(&tty);
209 switch (ttysignal) {
210 case SIGINT2:
211 tty_visc(&tty, '\003'); /* output ^C */
212 /* FALLTHROUGH */
213 case 0:
214 break;
215 default:
216 ttysignal = 0;
217 goto redo;
218 }
219 if (c == 0) {
220 done = 1;
221 } else if (c == '\n') {
222 tty_putc(&tty, c);
223 done = 1;
224 } else {
225 done = tty_insert(&tty, c, 0);
226 tty_flush(&tty);
227 }
228 if (done)
229 break;
230 }
231 act.sa_handler__sigaction_u.__sa_handler = SIG_DFL(void (*)(int))0;
232 sigemptyset(&act.sa_mask);
233 act.sa_flags = SA_RESTART0x0002;
234 (void)sigprocmask(SIG_SETMASK3, &oset, NULL((void *)0));
235 (void)sigaction(SIGTSTP18, &act, NULL((void *)0));
236 (void)sigaction(SIGTTOU22, &act, NULL((void *)0));
237 (void)sigaction(SIGTTIN21, &act, NULL((void *)0));
238 (void)sigaction(SIGINT2, &saveint, NULL((void *)0));
239 if (tty.flags & TTY_ERR0x2) {
240 if (ttysignal == SIGINT2) {
241 ttysignal = 0;
242 return(NULL((void *)0)); /* user hit ^C */
243 }
244
245redo:
246 cp = strlen(canonb) > 0 ? canonb : NULL((void *)0);
247 /* XXX - make iterative, not recursive */
248 return(readtty(pr, cp));
249 }
250 if (equal("", canonb)(strcmp("",canonb)==0))
251 return("");
252 return(savestr(canonb));
253}
254
255/*
256 * Receipt continuation.
257 */
258void
259ttystop(int s)
260{
261 struct sigaction act, oact;
262 sigset_t nset;
263 int save_errno;
264
265 /*
266 * Save old handler and set to default.
267 * Unblock receipt of 's' and then resend it.
268 */
269 save_errno = errno(*__errno());
270 (void)sigemptyset(&act.sa_mask);
271 act.sa_flags = SA_RESTART0x0002;
272 act.sa_handler__sigaction_u.__sa_handler = SIG_DFL(void (*)(int))0;
273 (void)sigaction(s, &act, &oact);
274 (void)sigemptyset(&nset);
275 (void)sigaddset(&nset, s);
276 (void)sigprocmask(SIG_UNBLOCK2, &nset, NULL((void *)0));
277 (void)kill(0, s);
278 (void)sigprocmask(SIG_BLOCK1, &nset, NULL((void *)0));
279 (void)sigaction(s, &oact, NULL((void *)0));
280 ttysignal = s;
281 errno(*__errno()) = save_errno;
282}
283
284/*ARGSUSED*/
285void
286ttyint(int s)
287{
288
289 ttysignal = s;
290}
291
292static void
293tty_flush(struct tty *t)
294{
295 size_t i, len;
296 int c;
297
298 if (t->cursor < t->len) {
299 for (; t->cursor < t->len; t->cursor++)
300 tty_visc(t, t->buf[t->cursor]);
301 } else if (t->cursor > t->len) {
302 len = t->cursor - t->len;
303 for (i = len; i > 0; i--) {
304 c = t->buf[--t->cursor];
305 if (c == '\t')
306 len += TABWIDTH8 - 1;
307 else if (iscntrl(c))
308 len++; /* account for leading ^ */
309 }
310 for (i = 0; i < len; i++)
311 tty_putc(t, '\b');
312 for (i = 0; i < len; i++)
313 tty_putc(t, ' ');
314 for (i = 0; i < len; i++)
315 tty_putc(t, '\b');
316 t->cursor = t->len;
317 }
318
319 t->buf[t->len] = '\0';
320}
321
322static int
323tty_getc(struct tty *t)
324{
325 ssize_t n;
326 unsigned char c;
327
328 n = read(t->fdin, &c, 1);
329 switch (n) {
330 case -1:
331 t->flags |= TTY_ERR0x2;
332 /* FALLTHROUGH */
333 case 0:
334 return 0;
335 default:
336 return c & 0x7f;
337 }
338}
339
340static int
341tty_insert(struct tty *t, int c, int nocntrl)
342{
343 const unsigned char *ws = " \t";
344
345 if (CCEQ(t->keys[VERASE], c)(c == t->keys[3] ? t->keys[3] != (0377) : 0)) {
346 if (nocntrl)
347 return 0;
348 if (t->len > 0)
349 t->len--;
350 } else if (CCEQ(t->keys[VWERASE], c)(c == t->keys[4] ? t->keys[4] != (0377) : 0)) {
351 if (nocntrl)
352 return 0;
353 for (; t->len > 0; t->len--)
354 if (strchr(ws, t->buf[t->len - 1]) == NULL((void *)0)
355 && ((t->flags & TTY_ALTWERASE0x1) == 0
356 || isalpha(t->buf[t->len - 1])))
357 break;
358 for (; t->len > 0; t->len--)
359 if (strchr(ws, t->buf[t->len - 1]) != NULL((void *)0)
360 || ((t->flags & TTY_ALTWERASE0x1)
361 && !isalpha(t->buf[t->len - 1])))
362 break;
363 } else if (CCEQ(t->keys[VKILL], c)(c == t->keys[5] ? t->keys[5] != (0377) : 0)) {
364 if (nocntrl)
365 return 0;
366 t->len = 0;
367 } else {
368 if (t->len == t->size)
369 return 1;
370 t->buf[t->len++] = c;
371 }
372
373 return 0;
374}
375
376static void
377tty_putc(struct tty *t, int c)
378{
379 unsigned char cc = c;
380
381 write(t->fdout, &cc, 1);
382}
383
384static void
385tty_reset(struct tty *t)
386{
387 memset(t->buf, 0, t->len);
388 t->len = t->cursor = 0;
389}
390
391static void
392tty_visc(struct tty *t, int c)
393{
394 int i;
395
396 if (c == '\t') {
397 for (i = 0; i < TABWIDTH8; i++)
398 tty_putc(t, ' ');
399 } else if (iscntrl(c)) {
400 tty_putc(t, '^');
401 if (c == 0x7F)
402 tty_putc(t, '?');
403 else
404 tty_putc(t, (c | 0x40));
405 } else {
406 tty_putc(t, c);
407 }
408}