Bug Summary

File:reptyr.c
Location:line 132, column 9
Description:The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage

Annotated Source Code

1/*
2 * Copyright (C) 2011 by Nelson Elhage
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#include <fcntl.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/select.h>
26#include <sys/ioctl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <errno(*__errno_location ()).h>
30#include <string.h>
31#include <stdarg.h>
32#include <termios.h>
33#include <signal.h>
34
35#include "reptyr.h"
36
37#ifndef __linux__1
38#error reptyr is currently Linux-only.
39#endif
40
41static int verbose = 0;
42
43void _debug(const char *pfx, const char *msg, va_list ap) {
44
45 if (pfx)
46 fprintf(stderrstderr, "%s", pfx);
47 vfprintf(stderrstderr, msg, ap);
48 fprintf(stderrstderr, "\n");
49}
50
51void die(const char *msg, ...) {
52 va_list ap;
53 va_start(ap, msg)__builtin_va_start(ap, msg);
54 _debug("[!] ", msg, ap);
55 va_end(ap)__builtin_va_end(ap);
56
57 exit(1);
58}
59
60void debug(const char *msg, ...) {
61
62 va_list ap;
63
64 if (!verbose)
65 return;
66
67 va_start(ap, msg)__builtin_va_start(ap, msg);
68 _debug("[+] ", msg, ap);
69 va_end(ap)__builtin_va_end(ap);
70}
71
72void error(const char *msg, ...) {
73 va_list ap;
74 va_start(ap, msg)__builtin_va_start(ap, msg);
75 _debug("[-] ", msg, ap);
76 va_end(ap)__builtin_va_end(ap);
77}
78
79void setup_raw(struct termios *save) {
80 struct termios set;
81 if (tcgetattr(0, save) < 0)
82 die("Unable to read terminal attributes: %m");
83 set = *save;
84 cfmakeraw(&set);
85 if (tcsetattr(0, TCSANOW0, &set) < 0)
86 die("Unable to set terminal attributes: %m");
87}
88
89void resize_pty(int pty) {
90 struct winsize sz;
91 if (ioctl(0, TIOCGWINSZ0x5413, &sz) < 0)
92 return;
93 ioctl(pty, TIOCSWINSZ0x5414, &sz);
94}
95
96int writeall(int fd, const void *buf, ssize_t count) {
97 ssize_t rv;
98 while (count > 0) {
99 rv = write(fd, buf, count);
100 if (rv < 0) {
101 if (errno(*__errno_location ()) == EINTR4)
102 continue;
103 return rv;
104 }
105 count -= rv;
106 buf += rv;
107 }
108 return 0;
109}
110
111volatile sig_atomic_t winch_happened = 0;
112
113void do_winch(int signal) {
114 winch_happened = 1;
115}
116
117void do_proxy(int pty) {
118 char buf[4096];
119 ssize_t count;
120 fd_set set;
121 while (1) {
13
Loop condition is true. Entering loop body
122 if (winch_happened) {
14
Assuming 'winch_happened' is 0
15
Taking false branch
123 winch_happened = 0;
124 /*
125 * FIXME: If a signal comes in after this point but before
126 * select(), the resize will be delayed until we get more
127 * input. signalfd() is probably the cleanest solution.
128 */
129 resize_pty(pty);
130 }
131 FD_ZERO(&set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&set)->fds_bits)[0])
: "memory"); } while (0)
;
132 FD_SET(0, &set)((void) (((&set)->fds_bits)[((0) / (8 * (int) sizeof (
__fd_mask)))] |= ((__fd_mask) 1 << ((0) % (8 * (int) sizeof
(__fd_mask))))))
;
16
Within the expansion of the macro 'FD_SET':
a
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
133 FD_SET(pty, &set)((void) (((&set)->fds_bits)[((pty) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) 1 << ((pty) % (8 * (int
) sizeof (__fd_mask))))))
;
134 if (select(pty+1, &set, NULL((void*)0), NULL((void*)0), NULL((void*)0)) < 0) {
135 if (errno(*__errno_location ()) == EINTR4)
136 continue;
137 fprintf(stderrstderr, "select: %m");
138 return;
139 }
140 if (FD_ISSET(0, &set)((((&set)->fds_bits)[((0) / (8 * (int) sizeof (__fd_mask
)))] & ((__fd_mask) 1 << ((0) % (8 * (int) sizeof (
__fd_mask))))) != 0)
) {
141 count = read(0, buf, sizeof buf);
142 if (count < 0)
143 return;
144 writeall(pty, buf, count);
145 }
146 if (FD_ISSET(pty, &set)((((&set)->fds_bits)[((pty) / (8 * (int) sizeof (__fd_mask
)))] & ((__fd_mask) 1 << ((pty) % (8 * (int) sizeof
(__fd_mask))))) != 0)
) {
147 count = read(pty, buf, sizeof buf);
148 if (count < 0)
149 return;
150 writeall(1, buf, count);
151 }
152 }
153}
154
155void usage(char *me) {
156 fprintf(stderrstderr, "Usage: %s [-s] PID\n", me);
157 fprintf(stderrstderr, " %s -l|-L [COMMAND [ARGS]]\n", me);
158 fprintf(stderrstderr, " -l Create a new pty pair and print the name of the slave.\n");
159 fprintf(stderrstderr, " if there are command-line arguments after -l\n");
160 fprintf(stderrstderr, " they are executed with REPTYR_PTY set to path of pty.\n");
161 fprintf(stderrstderr, " -L Like '-l', but also redirect the child's stdio to the slave.\n");
162 fprintf(stderrstderr, " -s Attach fds 0-2 on the target, even if it is not attached to a tty.\n");
163 fprintf(stderrstderr, " -h Print this help message and exit.\n");
164 fprintf(stderrstderr, " -v Print the version number and exit.\n");
165 fprintf(stderrstderr, " -V Print verbose debug output.\n");
166}
167
168void check_yama_ptrace_scope(void) {
169 int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY00);
170 if (fd >= 0) {
171 char buf[256];
172 int n;
173 n = read(fd, buf, sizeof buf);
174 close(fd);
175 if (n > 0) {
176 if (!atoi(buf)) {
177 return;
178 }
179 }
180 } else if (errno(*__errno_location ()) == ENOENT2)
181 return;
182 fprintf(stderrstderr, "The kernel denied permission while attaching. If your uid matches\n");
183 fprintf(stderrstderr, "the target's, check the value of /proc/sys/kernel/yama/ptrace_scope.\n");
184 fprintf(stderrstderr, "For more information, see /etc/sysctl.d/10-ptrace.conf\n");
185}
186
187int main(int argc, char **argv) {
188 struct termios saved_termios;
189 struct sigaction act;
190 int pty;
191 int arg = 1;
192 int do_attach = 1;
193 int force_stdio = 0;
194 int unattached_script_redirection = 0;
195
196 if (argc < 2) {
1
Assuming 'argc' is >= 2
2
Taking false branch
197 usage(argv[0]);
198 return 2;
199 }
200 if (argv[arg][0] == '-') {
3
Taking true branch
201 switch(argv[arg][1]) {
4
Control jumps to 'case 76:' at line 208
202 case 'h':
203 usage(argv[0]);
204 return 0;
205 case 'l':
206 do_attach = 0;
207 break;
208 case 'L':
209 do_attach = 0;
210 unattached_script_redirection = 1;
211 break;
5
Execution continues on line 231
212 case 's':
213 arg++;
214 force_stdio = 1;
215 break;
216 case 'v':
217 printf("This is reptyr version %s.\n", REPTYR_VERSION"0.5dev");
218 printf(" by Nelson Elhage <nelhage@nelhage.com>\n");
219 printf("http://github.com/nelhage/reptyr/\n");
220 return 0;
221 case 'V':
222 arg++;
223 verbose = 1;
224 break;
225 default:
226 usage(argv[0]);
227 return 1;
228 }
229 }
230
231 if (do_attach && arg >= argc) {
232 fprintf(stderrstderr, "%s: No pid specified to attach\n", argv[0]);
233 usage(argv[0]);
234 return 1;
235 }
236
237 if ((pty = open("/dev/ptmx", O_RDWR02|O_NOCTTY0400)) < 0)
6
Taking false branch
238 die("Unable to open /dev/ptmx: %m");
239 if (unlockpt(pty) < 0)
7
Taking false branch
240 die("Unable to unlockpt: %m");
241 if (grantpt(pty) < 0)
8
Taking false branch
242 die("Unable to grantpt: %m");
243
244 if (do_attach) {
9
Taking false branch
245 pid_t child = atoi(argv[arg]);
246 int err;
247 if ((err = attach_child(child, ptsname(pty), force_stdio))) {
248 fprintf(stderrstderr, "Unable to attach to pid %d: %s\n", child, strerror(err));
249 if (err == EPERM1) {
250 check_yama_ptrace_scope();
251 }
252 return 1;
253 }
254 } else {
255 printf("Opened a new pty: %s\n", ptsname(pty));
256 fflush(stdoutstdout);
257 if (argc > 2) {
10
Assuming 'argc' is <= 2
11
Taking false branch
258 if(!fork()) {
259 setenv("REPTYR_PTY", ptsname(pty), 1);
260 if (unattached_script_redirection) {
261 int f;
262 setpgid(0, getppid());
263 setsid();
264 f = open(ptsname(pty), O_RDONLY00, 0); dup2(f, 0); close(f);
265 f = open(ptsname(pty), O_WRONLY01, 0); dup2(f, 1); dup2(f,2); close(f);
266 }
267 close(pty);
268 execvp(argv[2], argv+2);
269 exit(1);
270 }
271 }
272 }
273
274 setup_raw(&saved_termios);
275 memset(&act, 0, sizeof act);
276 act.sa_handler__sigaction_handler.sa_handler = do_winch;
277 act.sa_flags = 0;
278 sigaction(SIGWINCH28, &act, NULL((void*)0));
279 resize_pty(pty);
280 do_proxy(pty);
12
Calling 'do_proxy'
281 tcsetattr(0, TCSANOW0, &saved_termios);
282
283 return 0;
284}