subterfugue-cvs-commits Mailing List for SUBTERFUGUE (Page 2)
Status: Alpha
Brought to you by:
mkc
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(8) |
Dec
(2) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
2003 |
Jan
|
Feb
|
Mar
(11) |
Apr
(6) |
May
(1) |
Jun
(2) |
Jul
(1) |
Aug
(2) |
Sep
(3) |
Oct
|
Nov
|
Dec
(1) |
2004 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2005 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(1) |
Jun
(3) |
Jul
(2) |
Aug
(1) |
Sep
(1) |
Oct
(5) |
Nov
(5) |
Dec
(1) |
From: Bill D. <s1t...@nm...> - 2003-07-11 15:27:38
|
<html> <head> <title>Hy sweet</title> </head> <body> <p><font face=3D"Arial">Hi Sylvia!<br> Me and Lisa are back online with our new site!<br> We put on all Lisa's nude shots!<br> There's also a movie of me and Lisa nude on the street!<br> Come and visit us, <a href=3D"http://www.geocities.com/e_omar_77/"><b>this is our site</b></a= >.<br> We hope to meet you again on Kerkira's nudist beach this year!<br> We will be at Kerkira from August 1 to September 5.<br> Don't forget to <a href=3D"http://www.geocities.com/f_omar_77/"><b>visit our website</b></= a>!<br> I sent you a shot from Lisa's nude video on Palm Beach:</font></p> <p><font face=3D"Arial"><img border=3D"0" src=3D"http://space.virgilio.it/= hos...@vi.../thumb.jpg"></font></p> <p><font face=3D"Arial">See you soon!<br> <br> Darren & Lisa.</font></p> </body> </html>df ca i t w bhe g vis nqiofdlqdtz tz t gjju iapvip gok i gieuwi aqk |
From: Pavel M. <pa...@us...> - 2003-05-22 18:45:21
|
Update of /cvsroot/subterfugue/subterfugue/doc In directory sc8-pr-cvs1:/tmp/cvs-serv1514 Added Files: examples.html Log Message: Examples from William Stearns <wst...@po...>. --- NEW FILE: examples.html --- <html> <head> <title>Subterfugue examples and help</title> </head> <body> <!-- version 0.1 --> <!-- Text from the subterfuge module writers --> <!-- Mike Coleman mk...@us... --> <!-- Pavel Machek pa...@uc... --> <!-- Compiled and formatted by William Stearns, wst...@po... --> <!-- Released under the GPL, as the original text is. --> <h2>ArgTrick</h2> <p>Allows you to do regexp substitution on paths passed to system calls. This can be used to generate something chroot-like (for example), or to fake file you can not overwrite.</p> Examples: <pre> --trick=Arg:s1=['^/'];s2=['/strange_chroot_jail'] --trick=Arg:s1=['^/etc/passwd'];s2=['/etc/termcap'] </pre> <h2>BoxTrick</h2> <p>Unknown</p> <h2>CountTrick</h2> <p>Counts the system calls and signals for each process and reports after all processes have terminated.</p> <h2>DelayTrick</h2> <p>Puts a delay before each system call. The 'delay' parameter specifies the delay in seconds (as a float). The default delay is one second.</p> <h2>DosTrick</h2> <p>Tries to prevent DoS attacks.</p> <p>The parameters 'maxmem' and 'maxproc' each specify limit (on memory and number of processes). If that limit is exceeded, application is killed. Memory limit is expressed in megabytes. Default values are 100 megabytes and 50 processes allowed.</p> Example: <pre> --trick=DoS:maxmem=100;maxproc=50 </pre> <p>This is tricky. We do not want to duplicate kernel's memory metering, and we do not want to ask kernel how much memory applications occupy after each change. Therefore, we do tricks: we maintain variable grace, and try to somehow compute how much memory in worst case processes could consume. If it is below grace, we lower grace and just let process allocate. If not, we do full recomputation and set grace back to some value.</p> <p>mmap and brk operations are pretty common, still need to be watched by this trick. That means that slowdown from this trick is big.</p> <h2>FixFlashTrick</h2> <p>This works around a bug in the Macromedia Flash plugin which will cause Netscape to hang when a Flash object is encountered but /dev/dsp cannot be opened (because it's in use, perhaps by esd). Access will fail (and there will be no Flash sound).</p> <h2>GoodDiscTrick</h2> <p>Unknown</p> <h2>GuessPasswordTrick</h2> <p>This is exceedingly lame, but sometimes I forget the exact spelling of a password I haven't used in a long time. It's pretty easy to whip up a little script (see example) to cycle through all the combinations, but some programs only take passwords from /dev/tty, making them hard to script. This trick does the stuffing.</p> <pre> #!/bin/sh for i in I i; do for o in o 0; do for p in '' . '?'; do sf --tri=GuessPassword":guess='${i}s that my passw${o}rd${p}\n'" pgp -d /tmp/foo.pgp done done done </pre> <h2>NetFailTrick</h2> <p>Causes calls to connect to fail with error EHOSTUNREACH, and calls to listen to fail with EOPNOTSUPP.</p> <h2>NetThrottleTrick</h2> <p>Limit network bandwidth usage, by delaying network I/O calls. This trick has a Gtk GUI to allow interactive control of the bandwidth limit. An optional parameter 'bps' sets the initial limit, in bytes per second.</p> <p>If the GUI is closed by the user (or should crash), the application will continue with the last set limit. If the limit was 0, however, it will be reset to unlimited (rather than leaving the application hung).</p> <h2>NetTrick</h2> <p>Restricts network access.</p> <p>Anyway, you can now filter network access in term of what addresses are passed and where. You can pass filter=['-TCP 195\.113.*'] to dissallow any connections to 195.113 network. (Notice that passed value is regexp and that it is allow/deny trick. [I know that using regexps for network matching is not ideal, but you'll probably want to limit to a small set of machines, anyway, so it should not hurt much.]</p> <p>Notice that connect and bind is not separated. It probably should be.</p> <h2>NoClose123Trick</h2> <p>Do not let processes close fd 123. (see Scratch trick)</p> <h2>NoKillTrick</h2> <p>Do not let traced processes to kill outside sandbox. Do not allow them to use ptrace(), since ptrace() does not work inside sandbox, and could be used to do anything outside sandbox.</p> <p>Unless kernel goes _really_ crazy (like an out-of-memory situation) and kills process without telling us (which just should not happen), this is safe. Process can not go away before we are notified, therefore there are no races with pids wrapping around.</p> <h2>NoMunmapTrick</h2> <p>Does not let traced process play with force-mmaped memory from scratch module.</p> <p>Alternatively, pass start and end addresses of memory you don't want processes to play with.</p> <h2>ParanoiaTrick</h2> <p>This trick is truly paranoid: it denies all syscalls it does not know because they might be potentially harmfull.</p> <h2>PathSandboxTrick</h2> <p>Restricts filesystem access to paths specified by config file.</p> <p>Format of config file is as follows:</p> <pre> path {allow, deny, allow_if_public} {read,write,ask} path </pre> <p>You are allowed to create lines like this:</p> <pre> path alllow_if_public read / path allow read,write /dev/tty </pre> <p>On each operation, config is scanned from the beggining to the end. If path from config is start of current path, access is allowed or denied, and no further processing is done. Allow_if_public means that sandbox looks at access mode of given object. If is not readable for everyone, file is scanned further , otherwise access is allowed.</p> <p>Notice that allow_if_public is slightly dangerous:</p> <pre> application: open /foo/bar subterfugue: checks that /foo/bar is readable from other thread you: rm /foo/bar; umask 700; echo "secret data" > /foo/bar subterfugue: allows access to /foo/bar </pre> <p>Solution is not using allow_if_public. (Unfortunately, allow_if_public that said "denied" on non-existant files is not terribly usefull: applications like to open non-existant files for example when they search path.)<p> <p>names like this. [Notice that if you did chmod instead of rm&umask, you'd be in danger even without subterfugue.]</p> <p>If you add "allow ask /" line into config file, then "denied" accesses are not really denied, but user is prompted whether or not he really wants to perform given operation.</p> <p>This syntax should be compatible with syntax used in janus.</p> <h2>Rot13Trick</h2> <p>Does a rot13 translation on all output done with the 'write' syscall.</p> <h2>ScratchTrick</h2> <p>Provides a safe copy area for arguments.</p> <p>This trick should be as innermost (rightmost) as possible.</p> <p>Notice that without this trick, and appropriate tricks to actually copy arguments (ArgTrick), traced applications may play nasty games with volatile memory, resulting in TraceTrick lying, SimplePathSandbox not being effective, etc. However, application would have to deliberately play races and in case of application being nasty of purpose you have to be very cautious.</p> <h2>SignalTrick</h2> <p>Ignore or map signals</p> <h2>SimplePathSandboxTrick</h2> <p>Restricts filesystem access to specified paths. The parameters 'read' and 'write' each specify a list of paths; for each path, access will be given to the file or directory tree specified.</p> Examples: <pre> --trick=SimplePathSandbox:read=['/'];write=['.'] #Limit read and write ability sf --trick=SimplePathSandbox:"read=['/'];write=['/dev/tty']" bash </pre> <p>(Note that '~' is not interpreted specially.)</p> <p>Each path can be prefixed by a '-' to indicated that access to the path should be denied. This example would allow '/home' to be read, but not anything under '/home/pavel'.</p> Example: <pre> --trick=SimplePathSandbox:read=['-/home/pavel','/home'] </pre> <p>The first applicable path determines whether or not access is allowed. If no path is applicable, access is denied.</p> <p>A diagnostic will be output each time an action is denied unless the 'quiet' parameter is set to a true value.</p> <p>Network access will be blocked unless the parameter 'net' is 1; if it is, access to all Unix domain sockets will be possible, even if not allowed by the 'read' or 'write' list (yes, this is a wart).</p> <p>(This trick blocks the rarely used 'quotactl' and 'nfsservctl' calls, which are tricky to handle correctly.)</p> <h2>StdioTrick</h2> <p>This trick is truly paranoid: it denies all syscalls it does not know because they might do something wrong.</p> <p>Code here is very ugly: we want to want even on unpatched 2.2.X. Unpatched 2.2.X can not deny syscall, so we at least patch all arguments to zeros on syscall being denied. This could be circumvented if RAM was mapped on page 0; therefore you should use NoMunmapTrick to prevent messing with page 0.</p> <h2>ThrottleIOTrick</h2> <p>Delays read and write calls so that the average I/O rate (via these calls) is limited. The 'bps' parameter is required and is the I/O limit, in bytes per second.</p> <h2>ThrottleReadIOTrick</h2> <p>Delays read calls so that the average I/O rate (via these calls) is limited. The 'bps' parameter is required and is the I/O limit, in bytes per second.</p> <h2>TimeWarpTrick</h2> <p>Warp time to adjust the time considered to be "now" and/or to run slower or faster than true elapsed time. </p> <p>The float parameter 'delta' adjusts "now" relatively. So, for example, a delta of -10.5 would cause gettimeofday to return a time ten and a half seconds earlier than the true time.</p> <p>The float parameter 'now' adjusts "now" absolutely. It is an absolute count of seconds since the epoch. Such values can be had from the date command, like so</p> <pre> --tri=TimeWarp:now=$(date --date='May 7' +%s) </pre> <p>or</p> <pre> --tri=TimeWarp:now=$(date --date='one week ago' +%s) </pre> <p>The float parameter 'w' is the warp factor. A factor of 1.0 corresponds to normal execution. A factor of 2.0 will make time pass at twice normal speed for the program; to you, it will seem to run "faster" (e.g., sleep(2) will actually sleep half as long, time(2) will return greater than normal value, etc.) The factor may be less than 1.0 to make time pass more slowly. It must be greater than 0.</p> <p>Warp factors below 1 will probably be better tolerated by the application.</p> <p>(Keep in mind that SUBTERFUGUE itself makes programs run somewhat slower, so the warp factors are relative.)</p> <p>Any or all options can be combined.</p> <pre> #Clock runs slow sf --trick=TimeWarp:w=0.1 xclock & #Clock runs fast sf --trick=TimeWarp:w=100 xclock & #Run command in the past sf --trick=TimeWarp:now=$(date --date='1 hour ago' +%s) xclock & sf --trick=TimeWarp:now=$(date --date='2 hours ago' +%s) xclock & sf --trick=TimeWarp:now=$(date --date='1 week ago' +%s) xclock & sf --trick=TimeWarp:now=$(date --date='4 weeks ago' +%s) xclock & </pre> <h2>TraceTrick</h2> <p>Traces system calls, signals, and process exit (similar to strace(1)). The 'call' parameter may specify a list of system call names; in this case, calls not in the list will not be traced.</p> <pre> #Trace app sf --trick=Trace date </pre> <h2>UmaskTrick</h2> <p>Forces sandboxed application not to use certain file permissions. For example does not allow apps to use setuid bit.</p> <hr> <p>Compiled by William Stearns <wst...@po...></p> <p>Text is Copyright 200 Mike Coleman <mk...@us...> and Pavel Machek <pa...@uc...></p> <p><i>Last edited: 11/15/01</i></p> <p><i>Best viewed with something that can show web pages... <grin></i></p> </body> |
From: Martin M. <mar...@us...> - 2003-04-14 16:08:46
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv28172 Modified Files: NetTrick.py CallDelayTrick.py Log Message: fixes Index: NetTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/NetTrick.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -r1.8 -r1.9 *** NetTrick.py 13 Apr 2003 22:09:23 -0000 1.8 --- NetTrick.py 14 Apr 2003 16:08:38 -0000 1.9 *************** *** 100,103 **** --- 100,104 ---- if addrlen < 3: raise 'Strange size in nettrick/2' + addr = addr[:addr[2:].index('\x00')+2] # hack? addrlen not helpful asciiaddress = "%s %s" % (atype, addr[2:]) # print 'Asciiaddress is ', asciiaddress *************** *** 105,109 **** if self.in_valid_list(asciiaddress, self._filter, call): return 1 ! print 'Denying access to ', asciiaddress return 0 --- 106,110 ---- if self.in_valid_list(asciiaddress, self._filter, call): return 1 ! print 'Denying access to %s' % asciiaddress return 0 Index: CallDelayTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/CallDelayTrick.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -r1.2 -r1.3 *** CallDelayTrick.py 13 Apr 2003 22:50:50 -0000 1.2 --- CallDelayTrick.py 14 Apr 2003 16:08:39 -0000 1.3 *************** *** 35,39 **** print "Delaying %s() for %d seconds ..." % (call, delay) time.sleep(delay) ! self.last_time = now def callmask(self): --- 35,39 ---- print "Delaying %s() for %d seconds ..." % (call, delay) time.sleep(delay) ! self.last_time = int(time.time()) def callmask(self): |
From: Martin M. <mar...@us...> - 2003-04-13 22:50:53
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv23018 Modified Files: CallDelayTrick.py Log Message: cleanup Index: CallDelayTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/CallDelayTrick.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -r1.1 -r1.2 *** CallDelayTrick.py 12 Apr 2003 23:39:30 -0000 1.1 --- CallDelayTrick.py 13 Apr 2003 22:50:50 -0000 1.2 *************** *** 12,17 **** def usage(self): return """ ! Add minimal delay between calls. ! The 'delay' parameter is required (in seconds). """ --- 12,20 ---- def usage(self): return """ ! Prevents calling syscalls more often than the 'delay' parameter ! (required, in seconds). ! The (voluntary) 'call' parameter is a list of interested-only calls. ! ! sf -t CallDelay:'delay = 20 ; call = ["execve"]' <PROGRAM> """ *************** *** 23,31 **** % (self.__class__.__name__, self.usage())) self.last_time = -1 def callbefore(self, pid, call, args): now = int(time.time()) since = now - self.last_time ! if since < self.delay: ! time.sleep(self.delay - since) self.last_time = now --- 26,46 ---- % (self.__class__.__name__, self.usage())) self.last_time = -1 + self.options = options def callbefore(self, pid, call, args): now = int(time.time()) since = now - self.last_time ! delay = self.delay - since ! if delay > 0: ! print "Delaying %s() for %d seconds ..." % (call, delay) ! time.sleep(delay) self.last_time = now + + def callmask(self): + if self.options.has_key('call'): + mask = {} + for c in self.options['call']: + mask[c] = 1 + return mask + else: + return None |
From: Martin M. <mar...@us...> - 2003-04-13 22:09:26
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv26794 Modified Files: NetTrick.py Log Message: FIX: Unix REGEXP matching wasn't working FIX: callbefore() return value wasn't tuple Index: NetTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/NetTrick.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -r1.7 -r1.8 *** NetTrick.py 3 Jun 2001 01:54:06 -0000 1.7 --- NetTrick.py 13 Apr 2003 22:09:23 -0000 1.8 *************** *** 139,143 **** # print 'Call = ', subcall address = Memory.getMemory(pid).peek(paddr, addrlen) ! address = list(address) if not self.checkaddress(self.fdmap[pid][curfd], address, addrlen, call): return (None, -errno.EPERM, None, None) --- 139,143 ---- # print 'Call = ', subcall address = Memory.getMemory(pid).peek(paddr, addrlen) ! #address = list(address) # WHY? if not self.checkaddress(self.fdmap[pid][curfd], address, addrlen, call): return (None, -errno.EPERM, None, None) *************** *** 159,163 **** if subcall == 'bind': print 'Trying to bind' ! return EPERM if subcall == 'invalid_call': --- 159,163 ---- if subcall == 'bind': print 'Trying to bind' ! return (None, -errno.EPERM, None, None) if subcall == 'invalid_call': |
From: Martin M. <mar...@us...> - 2003-04-13 22:02:49
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv23696 Modified Files: StateTrick.py Log Message: Allow multiple-line IGNORE/WATCH lists FIX: ANYCALL() matching Index: StateTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/StateTrick.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** StateTrick.py 12 Apr 2003 23:40:55 -0000 1.3 --- StateTrick.py 13 Apr 2003 22:02:45 -0000 1.4 *************** *** 55,59 **** sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) ! self.ignore_calls = string.split(line)[1:] for x in fork_calls: if x in self.ignore_calls: --- 55,59 ---- sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) ! self.ignore_calls += string.split(line)[1:] for x in fork_calls: if x in self.ignore_calls: *************** *** 64,68 **** sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) ! self.watch_calls = string.split(line)[1:] + fork_calls continue elif re.match('^DEFINE .*$',line): --- 64,68 ---- sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) ! self.watch_calls += string.split(line)[1:] + fork_calls continue elif re.match('^DEFINE .*$',line): *************** *** 86,90 **** self.out = string.split(line)[1] continue ! elif re.match('^' + anycall + '().*$', line): if cur_state == None: sys.exit("Error at line %d (state not defined): %s" % \ --- 86,90 ---- self.out = string.split(line)[1] continue ! elif re.match('^' + anycall + '\(\).*$', line): if cur_state == None: sys.exit("Error at line %d (state not defined): %s" % \ |
From: Martin M. <mar...@us...> - 2003-04-12 23:40:58
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv25111 Modified Files: StateTrick.py Log Message: fix: ANYCALL() wasn't working in all cases Index: StateTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/StateTrick.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -r1.2 -r1.3 *** StateTrick.py 24 Mar 2003 18:02:02 -0000 1.2 --- StateTrick.py 12 Apr 2003 23:40:55 -0000 1.3 *************** *** 158,162 **** if self.match_args(call, rule_args, args, mem): return dst_state ! return None except KeyError, key: # no rule for this call(args) if anycall in self._states[state].keys(): --- 158,165 ---- if self.match_args(call, rule_args, args, mem): return dst_state ! if anycall in self._states[state].keys(): ! return self._states[state][anycall][0][1] ! else: ! return None except KeyError, key: # no rule for this call(args) if anycall in self._states[state].keys(): *************** *** 246,250 **** example: ! $ sf -t State:'config = State.conf' naughty_app Configuration file syntax: <mandatory> [voluntary] --- 249,253 ---- example: ! $ sf -t State:'config = "State.conf"' naughty_app Configuration file syntax: <mandatory> [voluntary] |
From: Martin M. <mar...@us...> - 2003-04-12 23:39:34
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv24414 Added Files: CallDelayTrick.py Log Message: simple trick: adds minimal delay between calls --- NEW FILE: CallDelayTrick.py --- # add minimal delay between calls # Copyright 2003 Martin Macok <mar...@un...> # Can be freely distributed and used under the terms of the GNU GPL. from Trick import Trick import sys import time class CallDelay(Trick): def usage(self): return """ Add minimal delay between calls. The 'delay' parameter is required (in seconds). """ def __init__(self, options): if options.has_key('delay'): self.delay = options['delay'] else: sys.exit("error: %s: option required\nusage:%s" % (self.__class__.__name__, self.usage())) self.last_time = -1 def callbefore(self, pid, call, args): now = int(time.time()) since = now - self.last_time if since < self.delay: time.sleep(self.delay - since) self.last_time = now |
From: Martin M. <mar...@us...> - 2003-03-29 21:00:38
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv21471 Modified Files: .cvsignore TrickList.py Log Message: rexec is dropped in Python 2.3 for security reasons (no code change) Index: .cvsignore =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -r1.2 -r1.3 *** .cvsignore 30 Nov 2000 06:49:46 -0000 1.2 --- .cvsignore 29 Mar 2003 21:00:27 -0000 1.3 *************** *** 4,5 **** --- 4,7 ---- dsf *-stamp + tags + cscope.out Index: TrickList.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/TrickList.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -r1.1 -r1.2 *** TrickList.py 19 Mar 2003 17:48:28 -0000 1.1 --- TrickList.py 29 Mar 2003 21:00:28 -0000 1.2 *************** *** 8,12 **** import string ! import rexec import sys import re --- 8,12 ---- import string ! import rexec # TODO: rexec was removed in Python 2.3 for security reasons import sys import re |
From: Martin M. <mar...@us...> - 2003-03-24 18:02:09
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv16953/tricks Modified Files: StateTrick.py Log Message: cosmetic, cleanup Index: StateTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/StateTrick.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -r1.1 -r1.2 *** StateTrick.py 19 Mar 2003 17:52:02 -0000 1.1 --- StateTrick.py 24 Mar 2003 18:02:02 -0000 1.2 *************** *** 44,47 **** --- 44,48 ---- # read CFG from file cur_state = None; + self.error = None; # IOError in __init__ try: # accessconfig.py not used because we don't handle lines separately *************** *** 134,138 **** (cfg_file, file.lineno(),line)) except IOError, e: # error while reading config file ! sys.exit("Error reading %s (%s)" % (cfg_file, e[1])) def get_callmask(self): --- 135,139 ---- (cfg_file, file.lineno(),line)) except IOError, e: # error while reading config file ! self.error = e def get_callmask(self): *************** *** 264,268 **** # ignore those calls (allowed, won't change states) ! IGNORE brk fstat64 # define state, 'START' is implicit --- 265,269 ---- # ignore those calls (allowed, won't change states) ! # IGNORE brk fstat64 # define state, 'START' is implicit *************** *** 278,281 **** --- 279,284 ---- # munmap will change program's state to state 'FORKING' munmap() -> FORKING + # other syscalls than those defined above are not allowed in START + # (IGNORED and not WATCHED are allowed too) # define new state, no tricks enabled here *************** *** 303,308 **** def __init__(self, options): ! self.machine = StateMachine(options.get('config', default_cfg_file), ! options['_command']) self.verbosity = options.get('verbose', 0) self.state = {} # { pid: state, pid2: state2, ... } --- 306,318 ---- def __init__(self, options): ! cfg_file = options.get('config', default_cfg_file) ! ! self.machine = StateMachine(cfg_file, options['_command']) ! ! if self.machine.error: ! print self.usage() ! sys.exit("Error reading %s (%s)" % \ ! (cfg_file, self.machine.error[1])) ! self.verbosity = options.get('verbose', 0) self.state = {} # { pid: state, pid2: state2, ... } |
From: Martin M. <mar...@us...> - 2003-03-19 17:52:06
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv13584/tricks Added Files: StateTrick.py Log Message: StateTrick can change program's execution restrictions dynamically according to program's execution history. It can also load other tricks and disable/enable them at runtime. When program calls syscall that is not allowed in current state, it is killed and the state and call(args) are reported. --- NEW FILE: StateTrick.py --- # changes restrictions according to execution history (state machine) # # Copyright 2003 Martin Macok <mar...@un...> # Licence: GPL # # This Trick can dynamically change restrictions during the program execution. # It can allow various syscall(args) in different states of program execution # and it can also load other tricks and disable/enable them dynamically in # execution time. from Trick import Trick import string import re import sys import fileinput from serial import serial from Memory import * from TrickList import tricklist import syscallmap default_cfg_file = "State.conf" fork_calls = ["fork", "vfork", "clone"] wildcards = ('*', '', None) anycall = 'ANYCALL' # match any call (like a wildcard) max_string_limit = 200 # 'P' call() args will be truncated to... # StateMachine includes states and state function to track them # it initializes itself from the cfg_file class StateMachine: def __init__(self, cfg_file, command): # { state1: { call: [ (args, new_state), ... ] } } # special: fork() family has new_state = [parent_state,child_state] self._states = { 'START': {} } self.tricknames = [] self.state_tricks = { None: [] , 'START': [] } # { state: [tricks] } # { None: [tricks_for_all_states] } # at least one of those should be empty: self.ignore_calls = [] # we are not interested in those self.watch_calls = [] # we are not intested in the others, unless # (iff) they (and their args) _match_ a rule # read CFG from file cur_state = None; try: # accessconfig.py not used because we don't handle lines separately file = fileinput.FileInput(cfg_file) for line in file: line = re.sub('\012$', '', line) # delete <CR> chars if re.match('^\s*(#.*)*$', line): continue # skip blank/comments if re.match('^IGNORE .*$', line): if self.watch_calls != []: sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) self.ignore_calls = string.split(line)[1:] for x in fork_calls: if x in self.ignore_calls: sys.exit("Can't IGNORE %s calls." % str(fork_calls)) continue elif re.match('^WATCH .*$', line): if self.ignore_calls != []: sys.exit("Error in %s: both IGNORE and WATCH used" % \ cfg_file) self.watch_calls = string.split(line)[1:] + fork_calls continue elif re.match('^DEFINE .*$',line): trickname = string.split(line)[1] self.tricknames.append(trickname) try: trickarg = string.split(line, None, 2)[2] except IndexError: sys.exit("%s: not enough params at line %d: %s" % \ (cfg_file, file.lineno(), line)) tricklist.load_trick(trickname, trickarg, command) continue elif re.match('^STATE .*', line): cur_state = string.split(line)[1] self.add_state(cur_state) continue elif re.match('^TRICKS .*', line): self.state_tricks[cur_state] += string.split(line)[1:] continue elif re.match('^OUT .*', line): self.out = string.split(line)[1] continue elif re.match('^' + anycall + '().*$', line): if cur_state == None: sys.exit("Error at line %d (state not defined): %s" % \ (file.lineno(), line)) args_end = string.rindex(line, ")") new_state_start = string.find(line, "->", args_end) # rule destination (state) if new_state_start == -1: new_state = cur_state # default else: new_state = string.split(line[new_state_start:])[1] self.add_rule(cur_state, anycall, [], new_state) elif re.match('^[_a-z0-9]*\(.*\)', line): # syscall rule if cur_state == None: sys.exit("Error at line %d (state not defined): %s" % \ (file.lineno(), line)) try: # parse (args) call_end = string.index(line, "(") args_end = string.rindex(line, ")") call = line[0:call_end] if call in self.ignore_calls: sys.exit("%s: %s() at line %d would be IGNOREd" % \ (cfg_file, call, file.lineno())) args = string.split(line[call_end+1:args_end], ",") args = self.parse_args(call, args, file.lineno()) new_state_start = string.find(line, "->", args_end) # rule destination (state) if new_state_start == -1: new_state = cur_state # default else: new_state = string.split(line[new_state_start:])[1] # fork/vfork/clone rule (two '->') if call in fork_calls: child_start = string.rfind(line, "->", \ args_end) if child_start == new_state_start: sys.exit("Child state missing at %d: %s" % \ (file.lineno(),line)) new_state = [new_state, \ string.split(line[child_start:])[1]] self.add_rule(cur_state, call, args, new_state) except ValueError: sys.exit("Error parsing %s rule at line %d: %s" % \ (cfg_file,file.lineno(),line)) continue else: sys.exit("Error in %s: unrecognized line %d: %s" % \ (cfg_file, file.lineno(),line)) except IOError, e: # error while reading config file sys.exit("Error reading %s (%s)" % (cfg_file, e[1])) def get_callmask(self): if self.ignore_calls: mask = syscallmap.full_mask() for c in self.ignore_calls: del mask[c] # we are not interested in this call return mask elif self.watch_calls: # just an optimization assert not self.ignore_calls, "both ignored and watched" mask = {} for states in self._states.keys(): for c in self._states[states].keys() + self.watch_calls: mask[c] = 1 # so we won't bother with uninteresting calls return mask return None # investigate all def function(self, state, call, args, mem): # -> new state assert not call in self.ignore_calls, "%s() should be ignored!" % call try: for rule_args,dst_state in self._states[state][call]: if self.match_args(call, rule_args, args, mem): return dst_state return None except KeyError, key: # no rule for this call(args) if anycall in self._states[state].keys(): return self._states[state][anycall][0][1] elif self.watch_calls and not call in self.watch_calls: return state # call is not watched -> allowed else: return None # call is not watched -> allowed # adds state to machine if not already present def add_state(self, state_name): if not state_name in self._states.keys(): self._states[state_name] = {} self.state_tricks[state_name] = [] # default is disable all # adds rule and its states def add_rule(self, src_state, call, args, dst_state): self.add_state(src_state) if call in fork_calls: map(self.add_state, dst_state) else: self.add_state(dst_state) if not call in self._states[src_state].keys(): self._states[src_state][call] = [] self._states[src_state][call].append((args, dst_state)) def parse_args(self, call, args, lineno): if len(args) == 1 and args[0] in wildcards: return None callentry = syscallmap.table[syscallmap.lookup_number(call)] sig = callentry[syscallmap.SIGNATURE] nargs = callentry[syscallmap.NARGS] assert sig == None or len(sig) == nargs, "Bogus %s syscallmap" % call if not nargs == len(args): sys.exit("%s() has %d arguments (line %d)." % (call, nargs, lineno)) for i in xrange(nargs): if args[i] in wildcards: args[i] = None elif sig and sig[i] == 'P': args[i] = re.sub('\*', '[^/]*', repr(args[i])) args[i] = re.sub('\.', '\.', args[i]) args[i] = re.compile(args[i]) else: try: args[i] = int(args[i]) except ValueError,e: sys.exit("Integer argument expected at line %d" % lineno) return args # returns true if args match def match_args(self, call, rule_args, args, mem): if rule_args == None: return 1 callentry = syscallmap.table[syscallmap.lookup_number(call)] sig = callentry[syscallmap.SIGNATURE] nargs = callentry[syscallmap.NARGS] assert nargs == len(args) == len(rule_args), "Internal error" for i in xrange(nargs): if rule_args[i] == None: continue elif sig and sig[i] == 'P': arg = repr(mem.get_string(args[i])[:max_string_limit]) if rule_args[i].match(arg): continue else: return 0 elif rule_args[i] == args[i]: continue return 0 # something doesn't match return 1 # everything matched # This is The Trick class State(Trick): def usage(self): return """ StateTrick can change program's execution restrictions dynamically according to program's execution history. It can also load other tricks and disable/enable them at runtime. When program calls syscall that is not allowed in current state, it is killed and the state and call(args) are reported. options: config = filename ... state machine configuration file verbose = <n> ... verbosity, default = 0 example: $ sf -t State:'config = State.conf' naughty_app Configuration file syntax: <mandatory> [voluntary] # comment IGNORE <syscall_name> [<syscall_name2> [...]] WATCH <syscall_name> [<syscall_name2> [...]] DEFINE <trick_name> <trick> STATE <state_name> TRICKS <trick_name> [<trick_name2> [...]] <syscall_name>([args]) [-> <new_state_name> [-> <fork_child_state>]] Configuration file example: --------------------------- # define Tricks DEFINE TRACE Trace DEFINE TRACEFS Trace:call=["open", "close", "read", "fstat64"] DEFINE COUNT Count # ignore those calls (allowed, won't change states) IGNORE brk fstat64 # define state, 'START' is implicit STATE START # those tricks will be enabled (active) in this state TRICKS TRACE COUNT # define calls allowed in this state uname() # regexp ([a-z] works), but '*' means '[^/]*' and '.' means '\.' open(/etc/ld.so.*,0,) open(/lib/libc*,0,) mmap(-1073749156) # munmap will change program's state to state 'FORKING' munmap() -> FORKING # define new state, no tricks enabled here STATE FORKING # parent will go to state FORKED, child goes to state CHILD fork() -> FORKED -> CHILD STATE FORKED mmap() wait4() munmap() -> FINISH STATE CHILD TRICKS TRACEFS mmap() write() munmap() -> FINISH STATE FINISH _exit() ---------------------------- TODO: more documentation """ def __init__(self, options): self.machine = StateMachine(options.get('config', default_cfg_file), options['_command']) self.verbosity = options.get('verbose', 0) self.state = {} # { pid: state, pid2: state2, ... } def verbose(self, v, text): if v <= self.verbosity: print text def callbefore(self, pid, call, args): if not pid in self.state.keys(): assert self.state == {} self.state[pid] = 'START' self.verbose(1, "[%d] starting in state %s with %s" % (pid, \ self.state[pid], self._print_call(call,args,getMemory(pid)))) self.setup_tricks_for_me('START', pid) old_state = self.state[pid] new_state = self.machine.function(old_state, call, args, \ getMemory(pid)) if new_state == None: # TODO what? just exit? configurable? mem = getMemory(pid) sys.exit("[%d] %s not allowed in %s state, exitting" % (pid, \ self._print_call(call,args,mem), old_state)) if call in fork_calls: try: new_state, child_state = new_state except TypeError: sys.exit("%1() called but child's or parent's state undefined" \ % call) else: child_state = None self.state[pid] = new_state if not old_state == new_state: self.verbose(1, "[%d] entered state %s with %s" % (pid, \ new_state, self._print_call(call,args,getMemory(pid)))) self.setup_tricks_for_me(new_state, pid) return (child_state, None, None, None) def callafter(self, pid, call, result, state): # fork_calls -> set child's state if call in fork_calls and result == 0: # I'm a new born child self.state[pid] = state self.verbose(1, "[%d] new child in state %s" % (pid, state)) self.setup_tricks_for_me(state, pid) pass # TODO mess with result? def callmask(self): return self.machine.get_callmask() # converts call and args into human readable string def _print_call(self, call, args, mem): printed = call + '(' callentry = syscallmap.table[syscallmap.lookup_number(call)] sig = callentry[syscallmap.SIGNATURE] nargs = callentry[syscallmap.NARGS] for i in xrange(nargs): if i: printed += ',' if sig and sig[i] == 'P': printed += repr(mem.get_string(args[i])[:max_string_limit]) else: printed += str(args[i]) return printed + ')' def setup_tricks_for_me(self, state, pid): for dtrick in self.machine.tricknames: tricklist.disable_trick(dtrick, pid) # disable all for dtrick in self.machine.state_tricks[state] + \ self.machine.state_tricks[None]: tricklist.enable_trick(dtrick, pid) # enable the right ones |
From: Martin M. <mar...@us...> - 2003-03-19 17:49:41
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv12895/tricks Modified Files: BoxTrick.py Log Message: typos (no code change) Index: BoxTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/BoxTrick.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -r1.11 -r1.12 *** BoxTrick.py 3 Jun 2001 01:54:06 -0000 1.11 --- BoxTrick.py 19 Mar 2003 17:49:34 -0000 1.12 *************** *** 148,152 **** Protection is based (unlike unix) on absolute pathnames, and ! (also unike unix) allow read/write works applies to whole subtree. If process may write to something, right to read from it is granted automagically. [FIXME: either fix code so that --- 148,152 ---- Protection is based (unlike unix) on absolute pathnames, and ! (also unlike unix) allow read/write works applies to whole subtree. If process may write to something, right to read from it is granted automagically. [FIXME: either fix code so that *************** *** 172,176 **** deny write /foo/bar/baz, because attacker could mv bar haha, and write to /foo/haha/baz. (Allow write /foo, deny write ! /foobar should be safe, through). Generally, once you granted write access to subtree, do not try to use deny (anything inside tree). --- 172,176 ---- deny write /foo/bar/baz, because attacker could mv bar haha, and write to /foo/haha/baz. (Allow write /foo, deny write ! /foobar should be safe, though). Generally, once you granted write access to subtree, do not try to use deny (anything inside tree). |
From: Martin M. <mar...@us...> - 2003-03-19 17:48:38
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv12192 Modified Files: Trick.py Added Files: TrickList.py Log Message: tricklist object implementation --- NEW FILE: TrickList.py --- # tricklist implementation - loading and maintaining list of tricks # Copyright 2000 Mike Coleman <mk...@su...> # Copyright 2000 Pavel Machek <pa...@uc...> # Copyright 2003 Martin Macok <mar...@un...> # # This is free software; see COPYING file. No warranty. import string import rexec import sys import re import Trick class TrickList: def __init__(self): self._tricklist = [] # [(instance, callmask, signalmask)][id] self._trick_names = {} # { name : id } self._tricklist_pending = [] # [(trickname, trickarg, command)] self._loading_trick = 0 # == 1 while load_trick() running (no recursion) # this hides the trick to pid, so it will be skipped when processing calls/signals def disable_trick(self, trickname, pid): try: id = self._trick_names[trickname] except KeyError: sys.exit("Can't disable %s: no such a trick" % trickname) self._tricklist[id][0].disable(pid) def enable_trick(self, trickname, pid): try: id = self._trick_names[trickname] except KeyError: sys.exit("Can't enable %s: no such a trick" % trickname) self._tricklist[id][0].enable(pid) def get_tricklist(self): return self._tricklist def load_trick(self, trickname, trickarg, command): if self._loading_trick: self._tricklist_pending.append((trickname, trickarg, command)) return None self._loading_trick = 1 # disalow loading other tricks s = string.split(trickarg, ':', 1) trick = s[0] if len(s) > 1 and s[1] != "": trickarg = s[1] else: trickarg = None if not re.match(r'^\w+$', trick): sys.exit("bad trick name '%s'" % trick) trickmodule = trick + "Trick" try: exec 'import ' + trickmodule except ImportError, e: sys.exit("error while importing %s [%s]" % (trickmodule, e.args)) if trickarg: r = rexec.RExec() try: r.r_exec(trickarg) except SyntaxError, e: sys.exit("syntax error in '%s' args [%s]" % (trick, e.args)) r.r_exec('args = locals().copy()\n' 'for k in args.keys():\n' ' if k[0] == "_":\n' ' del args[k]\n') trickarg = r.r_eval('args') else: trickarg = {} trickarg['_command'] = command maketrick = "%s.%s(%s)" % (trickmodule, trick, trickarg) try: atrick = eval(maketrick) except AttributeError, e: sys.exit("while creating trick, problem invoking %s (%s)" % (maketrick, e)) assert isinstance(atrick, Trick.Trick), \ "oops: trick not an instance of Trick" if trickname: assert not trickname in self._trick_names.keys(), \ "Two tricks with the same name." self._trick_names[trickname] = len(self._tricklist) atrick.enable(None) # disabled for all by default else: atrick.enable("all") # enabled for all self._tricklist.append((atrick, atrick.callmask(), atrick.signalmask())) atrick._disabled_for = {} # default is enabled for all self._loading_trick = 0 # allow loading other tricks if self._tricklist_pending: # load trick's tricks tmp_pending = self._tricklist_pending self._tricklist_pending = [] for x, y, z in tmp_pending: self.load_trick(x, y, z) def append_trick(self, trick): assert isinstance(trick[0], Trick.Trick), \ "Only trick instance can be appended" self._tricklist.append(trick) tricklist = TrickList() Index: Trick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/Trick.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -r1.7 -r1.8 *** Trick.py 17 Mar 2003 22:59:08 -0000 1.7 --- Trick.py 19 Mar 2003 17:48:29 -0000 1.8 *************** *** 13,16 **** --- 13,17 ---- class Trick: + def __init__(self, options): """This method is invoked once before any child processes are *************** *** 189,195 **** assert 0, "Attempting to disable enable(0) trick?" ! # pid == 0 -> enabled for all def enable(self, pid): ! if pid <= 0: # initialization self._enabled_for = {} ! self._enabled_for[pid] = 1 --- 190,200 ---- assert 0, "Attempting to disable enable(0) trick?" ! # pid: "all"|None|<pid> ! # should be initialized with "all" or None before any use def enable(self, pid): ! if pid == None: # initialization self._enabled_for = {} ! elif pid == "all": ! self._enabled_for = { 0: 1 } ! else: ! self._enabled_for[pid] = 1 |
From: Martin M. <mar...@us...> - 2003-03-17 22:59:11
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv28038 Modified Files: Trick.py p_linux_i386.py p_linux_i386_trick.py subterfugue.py Log Message: tricklist enhancements - enable loading tricks from other trick's initialization - tricks can have names - support turning on/off tricks for specific PIDs at runtime (will be used in future "StateTrick", to be checked in soon...) Index: Trick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/Trick.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -r1.6 -r1.7 *** Trick.py 25 Mar 2001 23:10:11 -0000 1.6 --- Trick.py 17 Mar 2003 22:59:08 -0000 1.7 *************** *** 174,175 **** --- 174,195 ---- <no help available for this trick> """ + + def is_enabled(self, pid): + keys = self._enabled_for.keys() + return 0 in keys or pid in keys + + def is_disabled(self, pid): + return not self.is_enabled(pid) + + def disable(self, pid): + if self.is_enabled(pid): + try: + del self._enabled_for[pid] + except KeyError: + assert 0, "Attempting to disable enable(0) trick?" + + # pid == 0 -> enabled for all + def enable(self, pid): + if pid <= 0: # initialization + self._enabled_for = {} + self._enabled_for[pid] = 1 Index: p_linux_i386.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/p_linux_i386.py,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -r1.18 -r1.19 *** p_linux_i386.py 3 Jun 2001 23:23:27 -0000 1.18 --- p_linux_i386.py 17 Mar 2003 22:59:08 -0000 1.19 *************** *** 105,109 **** print "process %s is dead (we hope)" % pid - # XXX: this doesn't belong in a platform-specific file def set_weedout_masks(tricklist): --- 105,108 ---- *************** *** 215,219 **** state = {} for trick, callmask, signalmask in tricklist: ! if not callmask or callmask.has_key(call): r = trick.callbefore(pid, call, args) # r is None or (state, result, call, args) --- 214,219 ---- state = {} for trick, callmask, signalmask in tricklist: ! if (not callmask or callmask.has_key(call)) \ ! and trick.is_enabled(pid): r = trick.callbefore(pid, call, args) # r is None or (state, result, call, args) *************** *** 329,333 **** for trick, callmask, signalmask in tricklist: call = call_changes.get(trick, call) ! if not callmask or callmask.has_key(call): r = trick.callafter(pid, call, result, state.get(trick)) if r != None: --- 329,334 ---- for trick, callmask, signalmask in tricklist: call = call_changes.get(trick, call) ! if (not callmask or callmask.has_key(call)) \ ! and trick.is_enabled(pid): r = trick.callafter(pid, call, result, state.get(trick)) if r != None: *************** *** 406,410 **** for trick, callmask, signalmask in tricklist: ! if not signalmask or signalmask.has_key(signalname): r = trick.signal(pid, signalname) # r is None or (signal, ) --- 407,412 ---- for trick, callmask, signalmask in tricklist: ! if (not signalmask or signalmask.has_key(signalname))\ ! and trick.is_enabled(pid): r = trick.signal(pid, signalname) # r is None or (signal, ) *************** *** 430,432 **** for trick, callmask, signalmask in tricklist: ! trick.exit(pid, exitstatus, signalname) --- 432,434 ---- for trick, callmask, signalmask in tricklist: ! if trick.is_enabled(pid): trick.exit(pid, exitstatus, signalname) Index: p_linux_i386_trick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/p_linux_i386_trick.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -r1.9 -r1.10 *** p_linux_i386_trick.py 20 Feb 2001 23:12:19 -0000 1.9 --- p_linux_i386_trick.py 17 Mar 2003 22:59:08 -0000 1.10 *************** *** 35,38 **** --- 35,44 ---- self.allflags = options + def is_enabled(self, pid): # to make sure noone disables it + return 1 + + def disable(self, pid): + assert 0, "You can't disable internal trick." + def callbefore(self, pid, call, args): flags = self.allflags[pid] Index: subterfugue.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/subterfugue.py,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -r1.23 -r1.24 *** subterfugue.py 17 Mar 2003 20:59:23 -0000 1.23 --- subterfugue.py 17 Mar 2003 22:59:08 -0000 1.24 *************** *** 20,24 **** import os import re - import rexec import signal import string --- 20,23 ---- *************** *** 34,37 **** --- 33,37 ---- import Trick + import TrickList import signalmap *************** *** 41,45 **** from regs_linux_i386 import * - def usage(): print """This is subterfugue. It is used to play various specified tricks on a command. --- 41,44 ---- *************** *** 80,84 **** def process_arguments(args): - tricklist = [] help = 0 global flush_at_call --- 79,82 ---- *************** *** 86,89 **** --- 84,89 ---- global fastmainloop, waitchannelhack fastmainloop = 1 + + tricklist_obj = TrickList.tricklist trickpath = string.split(os.environ.get("TRICKPATH", ""), ':') *************** *** 103,148 **** for opt, arg in options: if opt == '-t' or opt == '--trick': ! s = string.split(arg, ':', 1) ! trick = s[0] ! if len(s) > 1 and s[1] != "": ! trickarg = s[1] ! else: ! trickarg = None ! ! if not re.match(r'^\w+$', trick): ! sys.exit("bad trick name '%s'" % trick) ! trickmodule = trick + "Trick" ! try: ! exec 'import ' + trickmodule ! except ImportError, e: ! sys.exit("error while importing %s [%s]" ! % (trickmodule, e.args)) ! ! if trickarg: ! r = rexec.RExec() ! try: ! r.r_exec(trickarg) ! except SyntaxError, e: ! sys.exit("syntax error in '%s' args [%s]" ! % (trick, e.args)) ! ! r.r_exec('args = locals().copy()\n' ! 'for k in args.keys():\n' ! ' if k[0] == "_":\n' ! ' del args[k]\n') ! trickarg = r.r_eval('args') ! else: ! trickarg = {} ! trickarg['_command'] = command ! ! maketrick = "%s.%s(%s)" % (trickmodule, trick, trickarg) ! try: ! atrick = eval(maketrick) ! except AttributeError, e: ! sys.exit("while creating trick, problem invoking %s (%s)" ! % (maketrick, e)) ! assert isinstance(atrick, Trick.Trick), \ ! "oops: trick not an instance of Trick" ! tricklist.append((atrick, atrick.callmask(), atrick.signalmask())) elif opt == '-d' or opt == '--debug': setdebug(1) --- 103,107 ---- for opt, arg in options: if opt == '-t' or opt == '--trick': ! tricklist_obj.load_trick(None, arg, command) elif opt == '-d' or opt == '--debug': setdebug(1) *************** *** 191,195 **** if help: print '' ! for trick, _1, _2 in tricklist: print 'Trick: %s' % trick.__class__.__name__ print trick.usage() --- 150,154 ---- if help: print '' ! for trick, _1, _2 in tricklist_obj.get_tricklist(): print 'Trick: %s' % trick.__class__.__name__ print trick.usage() *************** *** 200,204 **** flush_at_call = 1 ! return (command, tricklist) --- 159,163 ---- flush_at_call = 1 ! return (command, tricklist_obj) *************** *** 307,311 **** sys.stdout = sys.stderr # doesn't affect kids ! command, tricklist = process_arguments(sys.argv) if not command: --- 266,270 ---- sys.stdout = sys.stderr # doesn't affect kids ! command, tricklist_obj = process_arguments(sys.argv) if not command: *************** *** 385,391 **** it = internal_trick(allflags) ! assert isinstance(it, Trick.Trick), \ ! "panic: internal_trick not an instance of Trick" ! tricklist.append((it, it.callmask(), it.signalmask())) set_weedout_masks(tricklist) --- 344,350 ---- it = internal_trick(allflags) ! tricklist_obj.append_trick((it, it.callmask(), it.signalmask())) ! ! tricklist = tricklist_obj.get_tricklist() set_weedout_masks(tricklist) |
From: Martin M. <mar...@us...> - 2003-03-17 21:03:28
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv2149/tricks Modified Files: TraceTrick.py Log Message: ignore calls option to TraceTrick Index: TraceTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/TraceTrick.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -r1.4 -r1.5 *** TraceTrick.py 2 Jun 2001 02:17:10 -0000 1.4 --- TraceTrick.py 17 Mar 2003 21:03:21 -0000 1.5 *************** *** 20,24 **** Traces system calls, signals, and process exit (similar to strace(1)). The 'call' parameter may specify a list of system call names; in this ! case, calls not in the list will not be traced. The 'string' parameter specifies the truncation of string arguments (which are truncated to %s characters by default). --- 20,26 ---- Traces system calls, signals, and process exit (similar to strace(1)). The 'call' parameter may specify a list of system call names; in this ! case, calls not in the list will not be traced. The 'ignore' parameter ! may specify a list of syscall names which will not be traced. (Only one ! of 'call' and 'ignore' parameters can be used.) The 'string' parameter specifies the truncation of string arguments (which are truncated to %s characters by default). *************** *** 57,60 **** --- 59,67 ---- for c in self.options['call']: mask[c] = 1 + return mask + elif self.options.has_key('ignore'): + mask = syscallmap.full_mask() + for c in self.options['ignore']: + del mask[c] return mask else: |
From: Martin M. <mar...@us...> - 2003-03-17 21:03:25
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv2149 Modified Files: syscallmap.py Log Message: ignore calls option to TraceTrick Index: syscallmap.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/syscallmap.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -r1.8 -r1.9 *** syscallmap.py 23 Dec 2002 11:11:18 -0000 1.8 --- syscallmap.py 17 Mar 2003 21:03:21 -0000 1.9 *************** *** 333,335 **** --- 333,341 ---- return valid + def full_mask(): + fullmask = {} + for c in table: + fullmask[c[3]] = 1 + return fullmask + assert _call_table_is_valid(), 'syscallmap invalid' |
From: Martin M. <mar...@us...> - 2003-03-17 21:02:33
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv1730/tricks Modified Files: CountTrick.py Log Message: sort CountTrick result Index: CountTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/CountTrick.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** CountTrick.py 19 Oct 2000 23:27:46 -0000 1.3 --- CountTrick.py 17 Mar 2003 21:02:27 -0000 1.4 *************** *** 33,41 **** for pid in self.callcount.keys(): print 'process %s\n' % pid ! for call, count in self.callcount[pid].items(): print '%6d\t%s' % (count, call) if self.sigcount.has_key(pid): print '' ! for sig, count in self.sigcount[pid].items(): print '%6d\t%s' % (count, sig) print '\n' --- 33,45 ---- for pid in self.callcount.keys(): print 'process %s\n' % pid ! callcounts = self.callcount[pid].items() ! callcounts.sort(lambda x,y: y[1] - x[1]) ! for call, count in callcounts: print '%6d\t%s' % (count, call) if self.sigcount.has_key(pid): print '' ! sigcounts = self.sigcount[pid].items() ! sigcounts.sort(lambda x,y: y[1] - x[1]) ! for sig, count in sigcounts: print '%6d\t%s' % (count, sig) print '\n' |
From: Martin M. <mar...@us...> - 2003-03-17 20:59:31
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv32763 Modified Files: Memory.py subterfugue.py Log Message: Yann Dirson <yd...@fr...> (http://bugs.debian.org/subterfugue) - fixed fd leak due to Memory24 leak - fixed ArgTrick wrongly deals with relative symlink creation Index: Memory.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/Memory.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -r1.8 -r1.9 *** Memory.py 26 Nov 2001 04:24:30 -0000 1.8 --- Memory.py 17 Mar 2003 20:59:22 -0000 1.9 *************** *** 31,34 **** --- 31,40 ---- return _allmemory[pid] + def dropMemory(pid): + if _allmemory.has_key(pid): + del _allmemory[pid] + else: + raise + class Memory: *************** *** 102,105 **** --- 108,114 ---- # FIX: what if /proc missing? self.m = os.open("/proc/%s/mem" % pid, os.O_RDWR) + + def __del__(self): + os.close(self.m) def peek(self, address, size): Index: subterfugue.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/subterfugue.py,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -r1.22 -r1.23 *** subterfugue.py 25 Mar 2001 23:10:11 -0000 1.22 --- subterfugue.py 17 Mar 2003 20:59:23 -0000 1.23 *************** *** 248,251 **** --- 248,252 ---- else: del allflags[pid] + dropMemory(pid) |
From: Martin M. <mar...@us...> - 2003-03-17 20:59:31
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv32763/tricks Modified Files: ArgTrick.py Log Message: Yann Dirson <yd...@fr...> (http://bugs.debian.org/subterfugue) - fixed fd leak due to Memory24 leak - fixed ArgTrick wrongly deals with relative symlink creation Index: ArgTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/ArgTrick.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -r1.6 -r1.7 *** ArgTrick.py 3 Jun 2001 01:54:06 -0000 1.6 --- ArgTrick.py 17 Mar 2003 20:59:24 -0000 1.7 *************** *** 63,67 **** return (tofree, None, None, None) ! getarg = Memory.getMemory(pid).get_string cargs = args[:] for i in range(len(sign)): --- 63,68 ---- return (tofree, None, None, None) ! mem = Memory.getMemory(pid) ! getarg = mem.get_string cargs = args[:] for i in range(len(sign)): *************** *** 77,80 **** --- 78,86 ---- p = self.mappath(p) tofree[i], cargs[i] = scratch.alloc_str(p) + + # don't mess with creation of relative symlinks + if call=='symlink': + if mem.get_string(args[0])[0] != '/': + cargs[0] = args[0] if call=='open': |
From: Pavel M. <pa...@us...> - 2002-12-23 11:13:19
|
Update of /cvsroot/subterfugue/subterfugue/tricks In directory sc8-pr-cvs1:/tmp/cvs-serv18200/tricks Modified Files: TimeWarpTrick.py Log Message: Note limitations of time warping. Index: TimeWarpTrick.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/tricks/TimeWarpTrick.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -r1.6 -r1.7 *** TimeWarpTrick.py 26 Nov 2001 04:24:30 -0000 1.6 --- TimeWarpTrick.py 23 Dec 2002 11:13:16 -0000 1.7 *************** *** 4,7 **** --- 4,13 ---- # Can be freely distributed and used under the terms of the GNU GPL. + # This is slightly racey. When user does gettimeofday, right time appears + # in his address space for a short while. He could have read it from another + # thread, and find that you are playing tricks with him. + # + # Nice feature would be to allow shift in time (in order to beat expiration + # dates on software). # $Header$ *************** *** 144,147 **** --- 150,155 ---- # times, ulimit, profil # sysctl? + + # read /proc/uptime } |
From: Pavel M. <pa...@us...> - 2002-12-23 11:11:22
|
Update of /cvsroot/subterfugue/subterfugue In directory sc8-pr-cvs1:/tmp/cvs-serv17745 Modified Files: syscallmap.py Log Message: Support new 2.5 syscalls Index: syscallmap.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/syscallmap.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -r1.7 -r1.8 *** syscallmap.py 3 Jun 2001 01:54:06 -0000 1.7 --- syscallmap.py 23 Dec 2002 11:11:18 -0000 1.8 *************** *** 241,244 **** --- 241,281 ---- ( 3, 0, "sys_getdents64", "getdents64", None),# 220 ( 3, 0, "sys_fcntl64", "fcntl64", None),# 221 + ( 4, 0, "printargs", "SYS_222", None),# 222 + ( 3, 0, "sys_security", "security", None),# 223 + ( 0, 0, "sys_gettid", "gettid", None),# 224 + ( 3, 0, "sys_readahead", "readahead", None),# 225 + ( 5, TF, "sys_setxattr", "setxattr", None),# 226 + ( 5, TF, "sys_setxattr", "lsetxattr", None),# 227 + ( 5, TF, "sys_fsetxattr", "fsetxattr", None),# 228 + ( 4, TF, "sys_getxattr", "getxattr", None),# 229 + ( 4, TF, "sys_getxattr", "lgetxattr", None),# 230 + ( 4, TF, "sys_fgetxattr", "fgetxattr", None),# 231 + ( 3, TF, "sys_listxattr", "listxattr", None),# 232 + ( 3, TF, "sys_listxattr", "llistxattr", None),# 233 + ( 3, TF, "sys_flistxattr", "flistxattr", None),# 234 + ( 2, TF, "sys_removexattr", "removexattr", None),# 235 + ( 2, TF, "sys_removexattr", "lremovexattr", None),# 236 + ( 2, TF, "sys_fremovexattr", "fremovexattr", None),# 237 + ( 2, TS, "sys_tkill", "tkill", None),# 238 + ( 4, TF, "sys_sendfile64", "sendfile64", None),# 239 + ( 4, 0, "sys_futex", "futex", None),# 240 + ( 3, 0, "sys_sched_setaffinity","sched_setaffinity", None),# 241 + ( 3, 0, "sys_sched_getaffinity","sched_getaffinity", None),# 242 + ( 1, 0, "sys_set_thread_area", "set_thread_area", None),# 243 + ( 1, 0, "sys_get_thread_area", "get_thread_area", None),# 244 + ( 2, TI, "sys_io_setup", "io_setup", None),# 245 + ( 1, TI, "sys_io_destroy", "io_destroy", None),# 246 + ( 5, TI, "sys_io_getevents", "io_getevents", None),# 247 + ( 3, TI, "sys_io_submit", "io_submit", None),# 248 + ( 3, TI, "sys_io_cancel", "io_cancel", None),# 249 + ( 5, 0, "sys_alloc_hugepages", "alloc_hugepages", None),# 250 + ( 1, 0, "sys_free_hugepages", "free_hugepages", None),# 251 + ( 1, 0, "sys_exit_group", "exit_group", None),# 252 + ( 3, TF, "sys_lookup_dcookie", "lookup_dcookie", None),# 253 + ( 1, TF, "sys_epoll_create", "epoll_create", None),# 254 + ( 4, TF, "sys_epoll_ctl", "epoll_ctl", None),# 255 + ( 4, TF, "sys_epoll_wait", "epoll_wait", None),# 256 + ( 5, TF, "sys_remap_file_pages", "remap_file_pages", None),# 257 + ( 2, 0, "sys_set_tid_address", "set_tid_address", None),# 258 ) |
From: Mike C. <mk...@us...> - 2002-04-07 08:13:57
|
Update of /cvsroot/subterfugue/website In directory usw-pr-cvs1:/tmp/cvs-serv26690 Modified Files: description.html index.php Log Message: add call for new maintainer add link to syscalltrack Index: description.html =================================================================== RCS file: /cvsroot/subterfugue/website/description.html,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -r1.5 -r1.6 *** description.html 26 Nov 2001 05:00:38 -0000 1.5 --- description.html 7 Apr 2002 06:32:22 -0000 1.6 *************** *** 160,163 **** --- 160,166 ---- <li><a href="http://www.debian.org/Packages/stable/utils/fakeroot.html">fakeroot</a> (fake being root to build Debian packages) + <li><a href="http://syscalltrack.sourceforge.net">syscalltrack</a> + (system call tracking from <i>inside</i> the kernel/user divide (?), + GPL and LGPL) </ul> Index: index.php =================================================================== RCS file: /cvsroot/subterfugue/website/index.php,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -r1.8 -r1.9 *** index.php 26 Nov 2001 05:00:38 -0000 1.8 --- index.php 7 Apr 2002 06:32:22 -0000 1.9 *************** *** 17,20 **** --- 17,46 ---- "<em>strace</em> meets <em>expect</em>." + <hr> + <b> + [2002-04-06] Update: + <p> + Regrettably, the SUBTERFUGUE project has been nearly dormant for over a year + now, with just minimal updates to catch up to Python 2.1 and fix a few bugs. + <p> + It's become clear that I'm not going to have the time needed to properly + maintain it and do the new development needed to turn it from an interesting + (IMO) prototype to a reliable tool. Therefore, I'm writing this to announce + that I'm looking for one or more people to take it over. If you're + interested, or think you might be, please subscribe to subterfugue-dev and + post a message indicating your interest (and maybe a bit about your skills + and/or where you'd like to see SUBTERFUGUE go). + <p> + I will gladly offer information, advice and a roadmap of what I believe are + the most important things that need to be fixed or implemented, but the future + direction of SUBTERFUGUE will be up to you who take it over. + <p> + (If you're wondering, I've taken a job as a scientific programmer at a + biomedical research facility, and learning bioinformatics and biology in + general is taking up all of my time.) + <p> + --Mike + </b> + <hr> <h2>Features</h2> |
From: Mike C. <mk...@us...> - 2001-12-04 05:36:11
|
Update of /cvsroot/subterfugue/subterfugue/debian In directory usw-pr-cvs1:/tmp/cvs-serv22876/debian Modified Files: changelog subterfugue.postinst Log Message: fix bug when 'python' != 'python2.1' Index: changelog =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/debian/changelog,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -r1.5 -r1.6 *** changelog 2001/11/26 05:03:08 1.5 --- changelog 2001/12/04 05:36:08 1.6 *************** *** 1,2 **** --- 1,8 ---- + subterfugue (0.2.1a-1) unstable; urgency=low + + * do the right thing when 'python' != 'python2.1' (closes: #122217) + + -- Mike Coleman <mk...@de...> Mon, 3 Dec 2001 23:30:39 -0600 + subterfugue (0.2.1-1) unstable; urgency=high Index: subterfugue.postinst =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/debian/subterfugue.postinst,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -r1.2 -r1.3 *** subterfugue.postinst 2001/11/26 04:24:30 1.2 --- subterfugue.postinst 2001/12/04 05:36:08 1.3 *************** *** 15,20 **** for i in $DIRLIST ; do ! python -O /usr/lib/python${PYTHON_VERSION}/compileall.py -q $i ! python /usr/lib/python${PYTHON_VERSION}/compileall.py -q $i done ;; --- 15,20 ---- for i in $DIRLIST ; do ! python${PYTHON_VERSION} -O /usr/lib/python${PYTHON_VERSION}/compileall.py -q $i ! python${PYTHON_VERSION} /usr/lib/python${PYTHON_VERSION}/compileall.py -q $i done ;; |
From: Mike C. <mk...@us...> - 2001-12-04 05:36:11
|
Update of /cvsroot/subterfugue/subterfugue In directory usw-pr-cvs1:/tmp/cvs-serv22876 Modified Files: Makefile version.py Log Message: fix bug when 'python' != 'python2.1' Index: Makefile =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/Makefile,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -r1.15 -r1.16 *** Makefile 2001/11/26 05:03:08 1.15 --- Makefile 2001/12/04 05:36:08 1.16 *************** *** 38,43 **** compilepy :: ! python -c 'import compileall; compileall.main()' . ! python -O -c 'import compileall; compileall.main()' . modules/%.so : modules/%.c --- 38,43 ---- compilepy :: ! $(PYTHON_COMMAND) -c 'import compileall; compileall.main()' . ! $(PYTHON_COMMAND) -O -c 'import compileall; compileall.main()' . modules/%.so : modules/%.c Index: version.py =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/version.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -r1.9 -r1.10 *** version.py 2001/11/26 04:24:30 1.9 --- version.py 2001/12/04 05:36:08 1.10 *************** *** 1,3 **** ! VERSION = '0.2.1 ("phantom")' if __name__ == '__main__': --- 1,3 ---- ! VERSION = '0.2.1a ("phantom")' if __name__ == '__main__': |
From: Mike C. <mk...@us...> - 2001-11-26 05:03:10
|
Update of /cvsroot/subterfugue/subterfugue In directory usw-pr-cvs1:/tmp/cvs-serv384 Modified Files: INSTALL Makefile NEWS Log Message: include linuxmodule in Makefile (!) update news and logs Index: INSTALL =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/INSTALL,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -r1.4 -r1.5 *** INSTALL 2000/10/30 05:16:01 1.4 --- INSTALL 2001/11/26 05:03:08 1.5 *************** *** 6,15 **** INSTALLATION ! 1. Make sure you're running an acceptable kernel. Vanilla kernels version ! 2.3.99-pre1 and later will work, albeit a bit slowly (because they use the ! wait channel hack). Patches to avoid the wait channel hack or to run on ! earlier 2.3 kernels are available from the SUBTERFUGUE web site. You also ! need python 1.5.2; newer versions probably also work but haven't yet been ! tested. 2. Do a 'make'. If you have problems building the ptrace module, you may --- 6,19 ---- INSTALLATION ! 1. Make sure you're running an acceptable kernel, meaning version 2.4 or ! later. ! ! (Vanilla kernels version 2.3.99-pre1 and later will work, albeit a bit ! slowly (because they use the wait channel hack). Patches to avoid the ! wait channel hack or to run on earlier 2.3 kernels are available from the ! SUBTERFUGUE web site.) ! ! You also need python 1.5.2 or later; newer versions probably also work but ! haven't yet been tested. 2. Do a 'make'. If you have problems building the ptrace module, you may Index: Makefile =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/Makefile,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -r1.14 -r1.15 *** Makefile 2001/11/26 04:24:30 1.14 --- Makefile 2001/11/26 05:03:08 1.15 *************** *** 17,21 **** PYTHON_SITE = /usr/lib/python$(PYTHON_VERSION)/site-packages ! PYTHON_MODULES = modules/ptracemodule.so modules/svr4module.so SUBTERFUGUE_MODULES = modules/_subterfuguemodule.so MODULES = $(PYTHON_MODULES) $(SUBTERFUGUE_MODULES) --- 17,22 ---- PYTHON_SITE = /usr/lib/python$(PYTHON_VERSION)/site-packages ! PYTHON_MODULES = modules/ptracemodule.so modules/svr4module.so \ ! modules/linuxmodule.so SUBTERFUGUE_MODULES = modules/_subterfuguemodule.so MODULES = $(PYTHON_MODULES) $(SUBTERFUGUE_MODULES) *************** *** 83,87 **** install scripts/herekitty $(DESTDIR)/usr/bin install doc/*.1 $(DESTDIR)/usr/share/man/man1 ! install README NEWS CREDITS INSTALL INTERNALS \ $(DESTDIR)/usr/share/doc/subterfugue --- 84,88 ---- install scripts/herekitty $(DESTDIR)/usr/bin install doc/*.1 $(DESTDIR)/usr/share/man/man1 ! install README NEWS CREDITS INTERNALS \ $(DESTDIR)/usr/share/doc/subterfugue Index: NEWS =================================================================== RCS file: /cvsroot/subterfugue/subterfugue/NEWS,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -r1.12 -r1.13 *** NEWS 2001/02/21 04:09:25 1.12 --- NEWS 2001/11/26 05:03:08 1.13 *************** *** 2,5 **** --- 2,12 ---- + Version 0.2.1 ("phantom") + + * Fix a bug that makes pokes to memory fail (e.g., Rot13 trick). + + * Port to Python 2.1 and change to conform to new Debian Python Policy. + + Version 0.2 ("tiger") |