1 /* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com> 5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert (at) cistron.nl> 6 * Copyright (c) 1999-2018 The strace developers. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "defs.h" 33 #include "xstring.h" 34 35 SYS_FUNC(close) 36 { 37 printfd(tcp, tcp->u_arg[0]); 38 39 return RVAL_DECODED; 40 } 41 42 SYS_FUNC(dup) 43 { 44 printfd(tcp, tcp->u_arg[0]); 45 46 return RVAL_DECODED | RVAL_FD; 47 } 48 49 static int 50 do_dup2(struct tcb *tcp, int flags_arg) 51 { 52 printfd(tcp, tcp->u_arg[0]); 53 tprints(", "); 54 printfd(tcp, tcp->u_arg[1]); 55 if (flags_arg >= 0) { 56 tprints(", "); 57 printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???"); 58 } 59 60 return RVAL_DECODED | RVAL_FD; 61 } 62 63 SYS_FUNC(dup2) 64 { 65 return do_dup2(tcp, -1); 66 } 67 68 SYS_FUNC(dup3) 69 { 70 return do_dup2(tcp, 2); 71 } 72 73 static int 74 decode_select(struct tcb *const tcp, const kernel_ulong_t *const args, 75 void (*const print_tv_ts) (struct tcb *, kernel_ulong_t), 76 const char * (*const sprint_tv_ts) (struct tcb *, kernel_ulong_t)) 77 { 78 int i, j; 79 int nfds, fdsize; 80 fd_set *fds = NULL; 81 const char *sep; 82 kernel_ulong_t addr; 83 84 /* Kernel truncates args[0] to int, we do the same. */ 85 nfds = (int) args[0]; 86 87 /* Kernel rejects negative nfds, so we don't parse it either. */ 88 if (nfds < 0) 89 nfds = 0; 90 91 /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ 92 if (nfds > 1024*1024) 93 nfds = 1024*1024; 94 95 /* 96 * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below. 97 * Instead of args[0], use nfds for fd count, fdsize for array lengths. 98 */ 99 fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize; 100 101 if (entering(tcp)) { 102 tprintf("%d", (int) args[0]); 103 104 if (verbose(tcp) && fdsize > 0) 105 fds = malloc(fdsize); 106 for (i = 0; i < 3; i++) { 107 addr = args[i+1]; 108 tprints(", "); 109 if (!fds) { 110 printaddr(addr); 111 continue; 112 } 113 if (umoven_or_printaddr(tcp, addr, fdsize, fds)) 114 continue; 115 tprints("["); 116 for (j = 0, sep = "";; j++) { 117 j = next_set_bit(fds, j, nfds); 118 if (j < 0) 119 break; 120 tprints(sep); 121 printfd(tcp, j); 122 sep = " "; 123 } 124 tprints("]"); 125 } 126 free(fds); 127 tprints(", "); 128 print_tv_ts(tcp, args[4]); 129 } else { 130 static char outstr[1024]; 131 char *outptr; 132 #define end_outstr (outstr + sizeof(outstr)) 133 int ready_fds; 134 135 if (syserror(tcp)) 136 return 0; 137 138 ready_fds = tcp->u_rval; 139 if (ready_fds == 0) { 140 tcp->auxstr = "Timeout"; 141 return RVAL_STR; 142 } 143 144 fds = malloc(fdsize); 145 146 outptr = outstr; 147 sep = ""; 148 for (i = 0; i < 3 && ready_fds > 0; i++) { 149 int first = 1; 150 151 addr = args[i+1]; 152 if (!addr || !fds || umoven(tcp, addr, fdsize, fds) < 0) 153 continue; 154 for (j = 0;; j++) { 155 j = next_set_bit(fds, j, nfds); 156 if (j < 0) 157 break; 158 /* +2 chars needed at the end: ']',NUL */ 159 if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) { 160 if (first) { 161 outptr = xappendstr(outstr, 162 outptr, 163 "%s%s [%u", 164 sep, 165 i == 0 ? "in" : i == 1 ? "out" : "except", 166 j 167 ); 168 first = 0; 169 sep = ", "; 170 } else { 171 outptr = xappendstr(outstr, 172 outptr, 173 " %u", j); 174 } 175 } 176 if (--ready_fds == 0) 177 break; 178 } 179 if (outptr != outstr) 180 *outptr++ = ']'; 181 } 182 free(fds); 183 /* This contains no useful information on SunOS. */ 184 if (args[4]) { 185 const char *str = sprint_tv_ts(tcp, args[4]); 186 if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) { 187 outptr = xappendstr(outstr, outptr, 188 "%sleft %s", sep, str); 189 } 190 } 191 *outptr = '\0'; 192 tcp->auxstr = outstr; 193 return RVAL_STR; 194 #undef end_outstr 195 } 196 return 0; 197 } 198 199 #if HAVE_ARCH_OLD_SELECT 200 SYS_FUNC(oldselect) 201 { 202 kernel_ulong_t *args = 203 fetch_indirect_syscall_args(tcp, tcp->u_arg[0], 5); 204 205 if (args) { 206 return decode_select(tcp, args, print_timeval, sprint_timeval); 207 } else { 208 if (entering(tcp)) 209 printaddr(tcp->u_arg[0]); 210 return RVAL_DECODED; 211 } 212 } 213 #endif /* HAVE_ARCH_OLD_SELECT */ 214 215 #ifdef ALPHA 216 SYS_FUNC(osf_select) 217 { 218 return decode_select(tcp, tcp->u_arg, print_timeval32, sprint_timeval32); 219 } 220 #endif 221 222 SYS_FUNC(select) 223 { 224 return decode_select(tcp, tcp->u_arg, print_timeval, sprint_timeval); 225 } 226 227 static int 228 umove_kulong_array_or_printaddr(struct tcb *const tcp, const kernel_ulong_t addr, 229 kernel_ulong_t *const ptr, const size_t n) 230 { 231 #ifndef current_klongsize 232 if (current_klongsize < sizeof(*ptr)) { 233 uint32_t ptr32[n]; 234 int r = umove_or_printaddr(tcp, addr, &ptr32); 235 if (!r) { 236 size_t i; 237 238 for (i = 0; i < n; ++i) 239 ptr[i] = ptr32[i]; 240 } 241 return r; 242 } 243 #endif /* !current_klongsize */ 244 return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr); 245 } 246 247 SYS_FUNC(pselect6) 248 { 249 int rc = decode_select(tcp, tcp->u_arg, print_timespec, sprint_timespec); 250 if (entering(tcp)) { 251 kernel_ulong_t data[2]; 252 253 tprints(", "); 254 if (!umove_kulong_array_or_printaddr(tcp, tcp->u_arg[5], 255 data, ARRAY_SIZE(data))) { 256 tprints("{"); 257 /* NB: kernel requires data[1] == NSIG_BYTES */ 258 print_sigset_addr_len(tcp, data[0], data[1]); 259 tprintf(", %" PRI_klu "}", data[1]); 260 } 261 } 262 263 return rc; 264 } 265