Re: Announce: ndiswrapper

From: Maciej Zenczykowski
Date: Tue Nov 18 2003 - 10:33:14 EST


> > Speaking of io-trace has anyone actually done this? I'm working on a
>
> It's actually not all that simple. Some CPUs do have direct inb/outb
> instructions that are not syscalls. So you either have to single-step
> all the program and look at it's execution path, or you'd run it as a
> notmal user and handle the privilege penetration then luser starts
> inb'ing:) A coworker of me has done that with a DOS driver, doing such
> IO tracing for the dosemu it was running it.
>
> Maybe he cares to explain it in detail...
>
> MfG, JBG

Well I have a working patch for linux x86 strace 4.5 (mostly needs
cleanup) which implements IO-trace for non-mmaped IO by causing protection
violations on IO instructions. Normally you'd call ioperm/iopl to get at
the hardware this is intercepted, noted on the side and _not_ passed to
the kernel. All IO accesses from now on cause SIGSEGV's - which I procede
to printf and emulate.

I'm still not decided on whether this should be done entirely in
user-space (there are issues...) or partially or even mostly in kernel.

I'm attaching a patch for strace 4.5 (from sourceforge), you'll need to
patch and then likely run aclocal and automake before configure and make.
It currently only works for x86 linux non-string IO instructions for plain
non-segmented 32bit code (which is probably 99% of x86 IO not covered by
dosemu). Attach/detach don't work (fully), so you'll want to strace -I a
program from the very beginning :) I've run SVGATextMode through it and
it works, haven't tried it but the Xserver would likely work as well
(although that would probably require far more disk space in tmp then I
have :)). If you're strace'ing IO which access the video card it is
probably smart to redirect stderr to a file to keep the kernel from
accessing the video card at the same time (locking during strace is
impossible).

Any comments? Feedback and ideas are welcome...

Cheers,

MaZe.
diff -urN strace-4.5/defs.h strace-4.5mz/defs.h
--- strace-4.5/defs.h 2003-08-21 11:58:00.000000000 +0200
+++ strace-4.5mz/defs.h 2003-11-15 16:08:25.000000000 +0100
@@ -284,6 +284,14 @@
int nclone_threads; /* # of nchildren with CLONE_THREAD */
int nclone_detached; /* # of nchildren with CLONE_DETACHED */
int nclone_waiting; /* clone threads in wait4 (TCB_SUSPENDED) */
+#ifdef I386
+ int ioscno;
+ int ioretval;
+ int iopl;
+ char cap_rawio;
+#define MAX_IOPERM 1024
+ unsigned char io_bitmap[MAX_IOPERM / 8 + 1];
+#endif
#endif
/* (1st arg of wait4()) */
long baddr; /* `Breakpoint' address */
@@ -395,7 +403,7 @@
extern struct tcb **tcbtab;
extern int qual_flags[];
extern int debug, followfork, followvfork;
-extern int rflag, tflag, dtime, cflag, xflag, qflag;
+extern int rflag, tflag, dtime, cflag, ioflag, xflag, qflag;
extern int acolumn;
extern char *outfname;
extern unsigned int nprocs, tcbtabsize;
@@ -456,6 +464,9 @@
extern void tprint_iov P((struct tcb *, int, long));

#ifdef LINUX
+#ifdef I386
+extern int internal_ioemu P((struct tcb *));
+#endif
extern int internal_clone P((struct tcb *));
#endif
extern int internal_fork P((struct tcb *));
diff -urN strace-4.5/io_emu.c strace-4.5mz/io_emu.c
--- strace-4.5/io_emu.c 1970-01-01 01:00:00.000000000 +0100
+++ strace-4.5mz/io_emu.c 2003-11-15 19:07:08.000000000 +0100
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2003 Maciej Zenczykowski <maze@xxxxxxx>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: io_emu.c,v 1.00 2003/10/15 17:36:37 maze Exp $
+ */
+
+#include "defs.h"
+
+#if defined(LINUX) && defined(I386)
+
+/*
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+#include <sys/ptrace.h>
+*/
+#include <linux/ptrace.h>
+/*
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/io.h>
+*/
+
+typedef int bool;
+#define false ((bool)0)
+#define true ((bool)1)
+
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+struct user_regs {
+ union {
+ struct { uint32 ebx, ecx, edx; };
+ struct { uint16 bx, xbx, cx, xcx, dx, xdx; };
+ struct { uint8 bl, bh, xbl, xbh, cl, ch, xcl, xch, dl, dh, xdl, xdh; };
+ };
+ union {
+ struct { uint32 esi, edi, ebp; };
+ struct { uint16 si, xsi, di, xdi, bp, xbp; };
+ };
+ union {
+ struct { uint32 eax; };
+ struct { uint16 ax, xax; };
+ struct { uint8 al, ah, xal, xah; };
+ };
+ uint16 ds, xds, es, xes, fs, xfs, gs, xgs;
+ union {
+ struct { uint32 _eax, eip; };
+ struct { uint16 _ax, _xax, ip, xip; };
+ struct { uint8 _al, _ah, _xal, _xah; };
+ };
+ uint16 cs, xcs;
+ union {
+ struct { uint32 eflags, esp; };
+ struct { uint16 flags, xflags, sp, xsp; };
+ };
+ uint16 ss, xss;
+};
+
+static inline void out_b (uint16 port, uint8 * v) { asm volatile ("outb\t%b0, %w1" : : "a" (*v), "Nd" (port)); };
+static inline void out_w (uint16 port, uint16 * v) { asm volatile ("outw\t%w0, %w1" : : "a" (*v), "Nd" (port)); };
+static inline void out_l (uint16 port, uint32 * v) { asm volatile ("outl\t%0, %w1" : : "a" (*v), "Nd" (port)); };
+
+static inline void in_b (uint16 port, uint8 * v) { asm volatile ("inb\t%w1, %b0" : "=a" (*v) : "Nd" (port)); };
+static inline void in_w (uint16 port, uint16 * v) { asm volatile ("inw\t%w1, %w0" : "=a" (*v) : "Nd" (port)); };
+static inline void in_l (uint16 port, uint32 * v) { asm volatile ("inl\t%w1, %0" : "=a" (*v) : "Nd" (port)); };
+
+bool valid_port (struct tcb *tcp, uint16 port, int mask) {
+ if (tcp->iopl == 3) return true;
+ if ( ((*(uint16*)&tcp->io_bitmap[port >> 3]) >> (port & 7)) & mask ) return false;
+ return true;
+};
+#define valid8(P) valid_port((P), 1)
+#define valid16(P) valid_port((P), 3)
+#define valid32(P) valid_port((P), 7)
+
+uint32 mask[] = { 0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF };
+
+static int emulate_io (struct tcb *tcp) {
+ struct user_regs regs;
+ ptrace(PTRACE_GETREGS, tcp->pid, 0, (int)&regs);
+ int seg = 0;
+ bool gr1 = 0, gr2 = 0, gr3 = 0, gr4 = 0;
+ bool op32 = 1, ad32 = 1; /* !!! ASSUMES 32BIT CODE !!! */
+ bool lock = 0, repne = 0, repe = 0;
+ int pp = 0;
+ uint8 insn, param;
+
+loop:
+#define CODE8(P) ((uint8)(ptrace(PTRACE_PEEKTEXT, tcp->pid, (char*)(P), 0)))
+ insn = CODE8(regs.eip + pp); ++pp;
+ param = CODE8(regs.eip + pp);
+
+ switch (insn) {
+#define dprintf(...)
+ case 0x26: dprintf("ES: "); if (gr1++) goto error; seg = ES; goto loop;
+ case 0x2E: dprintf("CS: "); if (gr1++) goto error; seg = CS; goto loop;
+ case 0x36: dprintf("SS: "); if (gr1++) goto error; seg = SS; goto loop;
+ case 0x3E: dprintf("DS: "); if (gr1++) goto error; seg = DS; goto loop;
+ case 0x64: dprintf("FS: "); if (gr1++) goto error; seg = FS; goto loop;
+ case 0x65: dprintf("GS: "); if (gr1++) goto error; seg = GS; goto loop;
+ case 0x66: dprintf("(op32) "); if (gr2++) goto error; op32 ^= 1; goto loop;
+ case 0x67: dprintf("(ad32) "); if (gr3++) goto error; ad32 ^= 1; goto loop;
+ case 0xF0: dprintf("lock " ); if (gr4++) goto error; lock = 1; goto loop;
+ case 0xF2: dprintf("repne " ); if (gr4++) goto error; repne = 1; goto loop;
+ case 0xF3: dprintf("rep(e) "); if (gr4++) goto error; repe = 1; goto loop;
+#undef dprintf
+
+ /* DISABLE/ENABLE INTERRUPTS - IGNORE! */
+ case 0xFA: if (gr1 || gr2 || gr3 || gr4) goto error; tprintf("cli"); goto ok;
+ case 0xFB: if (gr1 || gr2 || gr3 || gr4) goto error; tprintf("sti"); goto ok;
+
+ /* STRING I/O - UNIMPLEMENTED */
+ case 0x6C: if (gr1 || lock || repne) goto error; tprintf("insb"); goto error;
+ case 0x6D: if (gr1 || lock || repne) goto error; tprintf("insw/l"); goto error;
+ case 0x6E: if ( lock || repne) goto error; tprintf("outsb"); goto error;
+ case 0x6F: if ( lock || repne) goto error; tprintf("outsw/l"); goto error;
+
+#define simulate_in(szo, sza, port) \
+tprintf("in%c(0x%0*X) = ", "0bw3l"[szo], sza+sza, port); \
+if (!valid_port(tcp, port, (1 << szo) - 1 )) { tprintf("ERROR"); goto error; }; \
+if (szo == 1) in_b(port, &regs.al); \
+if (szo == 2) in_w(port, &regs.ax); \
+if (szo == 4) in_l(port, &regs.eax); \
+tprintf("0x%0*X", szo+szo, regs.eax & mask[szo]); \
+goto ok;
+
+#define simulate_out(szo, sza, port) \
+tprintf("out%c(0x%0*X, 0x%0*X)", "0bw3l"[szo], sza+sza, port, szo+szo, regs.eax & mask[szo]); \
+if (!valid_port(tcp, port, (1 << szo) - 1 )) { tprintf(" => ERROR"); goto error; }; \
+if (szo == 1) out_b(port, &regs.al); \
+if (szo == 2) out_w(port, &regs.ax); \
+if (szo == 4) out_l(port, &regs.eax); \
+goto ok;
+
+ /* NORMAL I/O */
+ case 0xE4: if (gr1 || gr3 || gr4) goto error; pp++; simulate_in ( 1, 1, param);
+ case 0xE5: if (gr1 || gr3 || gr4) goto error; pp++; simulate_in (op32 ? 4 : 2, 1, param);
+ case 0xE6: if (gr1 || gr3 || gr4) goto error; pp++; simulate_out( 1, 1, param);
+ case 0xE7: if (gr1 || gr3 || gr4) goto error; pp++; simulate_out(op32 ? 4 : 2, 1, param);
+ case 0xEC: if (gr1 || gr3 || gr4) goto error; simulate_in ( 1, 2, regs.dx);
+ case 0xED: if (gr1 || gr3 || gr4) goto error; simulate_in (op32 ? 4 : 2, 2, regs.dx);
+ case 0xEE: if (gr1 || gr3 || gr4) goto error; simulate_out( 1, 2, regs.dx);
+ case 0xEF: if (gr1 || gr3 || gr4) goto error; simulate_out(op32 ? 4 : 2, 2, regs.dx);
+
+#undef simulate_out
+#undef simulate_in
+
+ /* ANYTHING ELSE IS BAD */
+ default: goto error;
+ };
+ok:
+ regs.eip += pp;
+ ptrace(PTRACE_SETREGS, tcp->pid, 0, (int)&regs);
+ return pp;
+error:
+ return 0;
+};
+
+int internal_ioemu (struct tcb *tcp) {
+ int res;
+ printleader(tcp);
+ res = emulate_io(tcp);
+ printtrailer(tcp);
+ return res;
+};
+
+#endif
diff -urN strace-4.5/linux/dummy.h strace-4.5mz/linux/dummy.h
--- strace-4.5/linux/dummy.h 2003-06-27 23:20:10.000000000 +0200
+++ strace-4.5mz/linux/dummy.h 2003-11-15 13:28:01.000000000 +0100
@@ -28,10 +28,13 @@
* $Id: dummy.h,v 1.12 2003/06/27 21:20:10 roland Exp $
*/

-/* still unfinished */
+/* possibly simulated for IO-trace on x86 */
+#ifndef I386
#define sys_ioperm printargs
-#define sys_syslog printargs
#define sys_iopl printargs
+#endif
+/* still unfinished */
+#define sys_syslog printargs
#define sys_vm86old printargs
#define sys_get_kernel_syms printargs
#define sys_bdflush printargs
diff -urN strace-4.5/Makefile.am strace-4.5mz/Makefile.am
--- strace-4.5/Makefile.am 2003-03-31 02:59:18.000000000 +0200
+++ strace-4.5mz/Makefile.am 2003-11-15 17:38:06.000000000 +0100
@@ -15,7 +15,7 @@
strace_SOURCES = strace.c syscall.c util.c desc.c file.c ipc.c \
io.c ioctl.c mem.c net.c process.c bjm.c \
resource.c signal.c sock.c system.c term.c time.c \
- proc.c stream.c
+ proc.c stream.c io_emu.c
noinst_HEADERS = defs.h

EXTRA_DIST = $(man_MANS) errnoent.sh signalent.sh syscallent.sh ioctlsort.c \
diff -urN strace-4.5/strace.c strace-4.5mz/strace.c
--- strace-4.5/strace.c 2003-06-10 05:05:53.000000000 +0200
+++ strace-4.5mz/strace.c 2003-11-15 18:54:55.000000000 +0100
@@ -3,6 +3,7 @@
* Copyright (c) 1993 Branko Lankester <branko@xxxxxxxxxx>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@xxxxxxxxxxxxx>
* Copyright (c) 1996-1999 Wichert Akkerman <wichert@xxxxxxxxxx>
+ * Copyright (c) 2003 Maciej Zenczykowski <maze@xxxxxxx> Linux x86 IO trace
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +50,10 @@
# include <asm/ptrace_offsets.h>
#endif

+#if defined(linux) && defined(I386)
+# include <sys/io.h>
+#endif
+
#ifdef USE_PROCFS
#include <poll.h>
#endif
@@ -64,7 +69,7 @@

int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
-int iflag = 0, xflag = 0, qflag = 0;
+int iflag = 0, ioflag = 0, xflag = 0, qflag = 0;
int pflag_seen = 0;

/* Sometimes we want to print only succeeding syscalls. */
@@ -133,33 +138,36 @@
FILE *ofp;
int exitval;
{
- fprintf(ofp, "\
-usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
- [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
- [command [arg ...]]\n\
- or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
- [command [arg ...]]\n\
--c -- count time, calls, and errors for each syscall and report summary\n\
--f -- follow forks, -ff -- with output into separate files\n\
--F -- attempt to follow vforks, -h -- print help message\n\
--i -- print instruction pointer at time of syscall\n\
--q -- suppress messages about attaching, detaching, etc.\n\
--r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
--T -- print time spent in each syscall, -V -- print version\n\
--v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
--x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
--a column -- alignment COLUMN for printing syscall results (default %d)\n\
--e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
- options: trace, abbrev, verbose, raw, signal, read, or write\n\
--o file -- send trace output to FILE instead of stderr\n\
--O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
--p pid -- trace process with process id PID, may be repeated\n\
--s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
--S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
--u username -- run command as username handling setuid and/or setgid\n\
--E var=val -- put var=val in the environment for command\n\
--E var -- remove var from the environment for command\n\
-" /* this is broken, so don't document it
+ fprintf(ofp,
+"usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n"
+" [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n"
+" [command [arg ...]]\n"
+" or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n"
+" [command [arg ...]]\n"
+"-c -- count time, calls, and errors for each syscall and report summary\n"
+"-f -- follow forks, -ff -- with output into separate files\n"
+"-F -- attempt to follow vforks, -h -- print help message\n"
+"-i -- print instruction pointer at time of syscall\n"
+#if defined(LINUX) && defined(I386)
+"-I -- perform IO instruction traceing (experimental, doesn't work with attach/detach)\n"
+#endif
+"-q -- suppress messages about attaching, detaching, etc.\n"
+"-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n"
+"-T -- print time spent in each syscall, -V -- print version\n"
+"-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n"
+"-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n"
+"-a column -- alignment COLUMN for printing syscall results (default %d)\n"
+"-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n"
+" options: trace, abbrev, verbose, raw, signal, read, or write\n"
+"-o file -- send trace output to FILE instead of stderr\n"
+"-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n"
+"-p pid -- trace process with process id PID, may be repeated\n"
+"-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n"
+"-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n"
+"-u username -- run command as username handling setuid and/or setgid\n"
+"-E var=val -- put var=val in the environment for command\n"
+"-E var -- remove var from the environment for command\n"
+ /* this is broken, so don't document it
-z -- print only succeeding syscalls\n\
*/
, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
@@ -205,7 +213,7 @@
set_sortby(DEFAULT_SORTBY);
set_personality(DEFAULT_PERSONALITY);
while ((c = getopt(argc, argv,
- "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
+ "+cdfFhiIqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
switch (c) {
case 'c':
cflag++;
@@ -226,6 +234,9 @@
case 'i':
iflag++;
break;
+ case 'I':
+ ioflag++; /* only actually works on I386 */
+ break;
case 'q':
qflag++;
break;
@@ -581,6 +592,14 @@
sigaction(SIGCHLD, &sa, NULL);
#endif /* USE_PROCFS */

+#if defined(LINUX) && defined(I386)
+ if (ioflag && iopl(3) < 0) {
+ perror("strace: iopl");
+ cleanup();
+ exit(1);
+ }
+#endif
+
if (trace() < 0)
exit(1);
cleanup();
@@ -630,6 +649,13 @@
tcp->nclone_threads = tcp->nclone_detached = 0;
tcp->nclone_waiting = 0;
#endif
+#if defined(LINUX) && defined(I386)
+ tcp->cap_rawio = 1; /*FIXME*/
+ tcp->ioscno = 0;
+ tcp->ioretval = 0;
+ tcp->iopl = 3; /*FIXME_MAZE on fork should inherit*/
+ memset(tcp->io_bitmap, -1, sizeof(tcp->io_bitmap)); /*AS ABOVE*/
+#endif
tcp->flags = TCB_INUSE | TCB_STARTUP;
tcp->outf = outf; /* Initialise to current out file */
tcp->stime.tv_sec = 0;
@@ -2108,6 +2134,19 @@
}
continue;
}
+#if defined (LINUX) && defined (I386)
+ if (ioflag && WSTOPSIG(status) == SIGSEGV) {
+ if (internal_ioemu(tcp)) {
+ if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
+ perror("trace: ptrace(PTRACE_SYSCALL, ...)");
+ cleanup();
+ return -1;
+ }
+ tcp->flags &= ~TCB_SUSPENDED;
+ continue;
+ }
+ }
+#endif
if (!cflag
&& (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
unsigned long addr = 0, pc = 0;
diff -urN strace-4.5/syscall.c strace-4.5mz/syscall.c
--- strace-4.5/syscall.c 2003-09-25 00:22:41.000000000 +0200
+++ strace-4.5mz/syscall.c 2003-11-15 17:39:09.000000000 +0100
@@ -6,6 +6,7 @@
* Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Linux for s390 port by D.J. Barrow
* <barrow_dj@xxxxxxxxxxxxxx,djbarrow@xxxxxxxxxx>
+ * Copyright (c) 2003 Maciej Zenczykowski <maze@xxxxxxx> Linux x86 IO trace
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -2111,6 +2112,14 @@
if (res != 1)
return res;

+#if defined(LINUX) && defined(I386)
+ if (tcp->ioscno) {
+ tcp->scno = tcp->ioscno;
+ tcp->ioscno = 0;
+ force_result(tcp, 0, tcp->ioretval);
+ }
+#endif
+
if (tcp->flags & TCB_INSYSCALL) {
long u_error;
res = get_error(tcp);
@@ -2161,7 +2170,7 @@
tcp->flags &= ~TCB_INSYSCALL;
return 0;
}
-
+
if (tcp->scno >= nsyscalls || tcp->scno < 0
|| (qual_flags[tcp->scno] & QUAL_RAW))
sys_res = printargs(tcp);
@@ -2413,6 +2422,61 @@
return 0;
}

+#if defined(LINUX) && defined(I386)
+int
+sys_iopl(tcp)
+struct tcb *tcp;
+{
+ printargs(tcp);
+ if (ioflag && !(tcp->flags & TCB_INSYSCALL) ) {
+ int res; unsigned level = tcp->u_arg[0];
+
+ res = -EINVAL;
+ if (level > 3) goto out;
+ /* Trying to gain more privileges? */
+ res = -EPERM;
+ if (level > tcp->iopl) if (!tcp->cap_rawio) goto out;
+ res = 0;
+ tcp->iopl = level;
+ out:
+ tcp->ioretval = res;
+ tcp->ioscno = tcp->scno;
+ /* ignore the syscall */
+ tcp->scno = 0;
+ ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*ORIG_EAX), 0);
+ }
+ return 0;
+}
+
+int
+sys_ioperm(tcp)
+struct tcb *tcp;
+{
+ printargs(tcp);
+ if (ioflag && !(tcp->flags & TCB_INSYSCALL) ) {
+ int res, i;
+ unsigned from = tcp->u_arg[0], num = tcp->u_arg[1], turn_on = tcp->u_arg[2];
+ res = -EINVAL;
+ if ((from + num <= from) || (from + num > MAX_IOPERM)) goto out;
+ res = -EPERM;
+ if (turn_on && !tcp->cap_rawio) goto out;
+
+ res = 0; /* doesn't have to be fast */
+ for (i = from; i < from + num; i++) {
+ if (turn_on) tcp->io_bitmap[i >> 3] &= ~( 1 << (i & 7) );
+ else tcp->io_bitmap[i >> 3] |= ( 1 << (i & 7) );
+ };
+ out:
+ tcp->ioretval = res;
+ tcp->ioscno = tcp->scno;
+ /* ignore the syscall */
+ tcp->scno = 0;
+ ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*ORIG_EAX), 0);
+ }
+ return 0;
+}
+#endif
+
long
getrval2(tcp)
struct tcb *tcp;