| 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 | } |