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 |
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 | ||||||
41 | static int verbose = 0; | |||||
42 | ||||||
43 | void _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 | ||||||
51 | void 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 | ||||||
60 | void 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 | ||||||
72 | void 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 | ||||||
79 | void 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 | ||||||
89 | void resize_pty(int pty) { | |||||
90 | struct winsize sz; | |||||
91 | if (ioctl(0, TIOCGWINSZ0x5413, &sz) < 0) | |||||
92 | return; | |||||
93 | ioctl(pty, TIOCSWINSZ0x5414, &sz); | |||||
94 | } | |||||
95 | ||||||
96 | int 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 | ||||||
111 | volatile sig_atomic_t winch_happened = 0; | |||||
112 | ||||||
113 | void do_winch(int signal) { | |||||
114 | winch_happened = 1; | |||||
115 | } | |||||
116 | ||||||
117 | void do_proxy(int pty) { | |||||
118 | char buf[4096]; | |||||
119 | ssize_t count; | |||||
120 | fd_set set; | |||||
121 | while (1) { | |||||
122 | if (winch_happened) { | |||||
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)))))); | |||||
| ||||||
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 | ||||||
155 | void 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 | ||||||
168 | void 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 | ||||||
187 | int 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) { | |||||
| ||||||
197 | usage(argv[0]); | |||||
198 | return 2; | |||||
199 | } | |||||
200 | if (argv[arg][0] == '-') { | |||||
201 | switch(argv[arg][1]) { | |||||
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; | |||||
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) | |||||
238 | die("Unable to open /dev/ptmx: %m"); | |||||
239 | if (unlockpt(pty) < 0) | |||||
240 | die("Unable to unlockpt: %m"); | |||||
241 | if (grantpt(pty) < 0) | |||||
242 | die("Unable to grantpt: %m"); | |||||
243 | ||||||
244 | if (do_attach) { | |||||
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) { | |||||
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); | |||||
281 | tcsetattr(0, TCSANOW0, &saved_termios); | |||||
282 | ||||||
283 | return 0; | |||||
284 | } |