Date: Tue, 11 May 1999 21:51:40 -0400
Reply-To: "David F. Skoll" <dfs@DOE.CARLETON.CA>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: "David F. Skoll" <dfs@DOE.CARLETON.CA>
Subject: LD_PRELOAD potential problems
To: BUGTRAQ@netspace.org
Many UNIX systems allow you to "pre-load" shared libraries by setting
an environment variable LD_PRELOAD. This allows you to do interesting
things like replace standard C library functions or even the C
interfaces to system calls with your own functions.
I recently ran across a piece of software which depended upon knowing
the time reasonably accurately. By replacing the time(2) UNIX system
call with my own function, I was able to fool the program and get it
to misbehave, without the inconvenience of actually changing the system
time or even requiring root privileges.
If you are writing programs which depend on C library functions or
UNIX system calls for secure operation, please distribute only
statically-linked versions, as the effort to fool statically-linked
binaries is a lot higher than a simple LD_PRELOAD spoof.
--
David F. Skoll
http://www.roaringpenguin.com
Date: Thu, 13 May 1999 18:52:12 -0400
Reply-To: Kragen Sitaker <kragen@POBOX.COM>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Kragen Sitaker <kragen@POBOX.COM>
Subject: Re: LD_PRELOAD potential problems
To: BUGTRAQ@netspace.org
David Skoll wrote:
> If you are writing programs which depend on C library functions or
> UNIX system calls for secure operation, please distribute only
> statically-linked versions, as the effort to fool statically-linked
> binaries is a lot higher than a simple LD_PRELOAD spoof.
First: the set of binaries you can set LD_PRELOAD for is the set of
binaries you can run from the command line. Network servers that you
connect to on a box you don't have access to are not vulnerable to
LD_PRELOAD spoofing.
Second: the binaries you can run from the command line are of two
kinds, the kind that can do something you wouldn't be able to do
yourself, because they're setuid or setgid, and the kind that can't,
because they aren't.
Binaries of the first kind are not vulnerable to LD_PRELOAD on any
secure Unix system, because the kernel or dynamic linker makes sure
they aren't. On the few poorly-thought-out Unix systems where this is
not the case, you can violate security in a much more direct way; you
can LD_PRELOAD libraries that directly do malicious things when they
are loaded, and they will be able to do them with the effective uid or
gid of the binary they are running in. In short, on these systems,
nothing you can do short of removing LD_PRELOAD support from the
dynamic loader can give you *any* security.
Binaries of the second kind can be fooled into doing anything you want
them to, whether they are statically or dynamically linked, but that's
OK, because they can't do anything you yourself aren't permitted to
do. (People who distribute copy-protected software may be concerned
about this statement. People who remove copy protection for a hobby
will recognize it as obvious.)
In short: this is not a problem.
--
<kragen@pobox.com>
Kragen Sitaker <http://www.pobox.com/~kragen/>
TurboLinux is outselling NT in Japan's retail software market 10 to 1,
so I hear.
-- http://www.performancecomputing.com/opinions/unixriot/981218.shtml
Date: Fri, 14 May 1999 09:17:25 -0400
Reply-To: "David F. Skoll" <dfs@DOE.CARLETON.CA>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: "David F. Skoll" <dfs@DOE.CARLETON.CA>
Subject: Clarification: LD_PRELOAD issue
To: BUGTRAQ@netspace.org
Hi,
I feel I need to provide more context for the LD_PRELOAD issue. Yes,
I'm well aware that set[ug]id programs ignore LD_PRELOAD and the other
LD_* environment variables.
The context is a software license manager. A commercial software
organization wants to protect its software with a license manager
which relies on accurate time information. Any user of the system,
including root, must be viewed as a potential cracker. This is not your
usual security issue.
Now, any license manager can be spoofed, from as blunt an attack as
changing the system time to sophisticated reverse-engineering attacks
on the license manager binary. The issue is to prevent "cheap"
attacks -- if attacking the license manager is expensive enough,
people won't bother (or they'll find other avenues of attack. :-))
Changing the system time introduces all kinds of problems, so most
potential license abusers won't do it. A two-line shell script with a
6-line C program is a very cheap attack on a dynamically-linked
license manager daemon. Attacking a statically-linked license manager
binary is quite a bit more expensive, and should greatly reduce the
incentive for an attack.
--
David F. Skoll
Date: Fri, 14 May 1999 17:55:53 +0200
Reply-To: Casper Dik <casper@HOLLAND.SUN.COM>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Casper Dik <casper@HOLLAND.SUN.COM>
Subject: Re: Clarification: LD_PRELOAD issue
X-To: "David F. Skoll" <dfs@DOE.CARLETON.CA>
To: BUGTRAQ@netspace.org
>Changing the system time introduces all kinds of problems, so most
>potential license abusers won't do it. A two-line shell script with a
>6-line C program is a very cheap attack on a dynamically-linked
>license manager daemon. Attacking a statically-linked license manager
>binary is quite a bit more expensive, and should greatly reduce the
>incentive for an attack.
License managers really only protect you again honest customers
using more (cconcurrent copies of) software than they paid for.
In that context, tamper proofing is perhaps ill advised because of both
the drawbacks and the ease of circumventing them:
- statically linked binaries require you to release a new
version of your product each OS release, if you're unlucky.
I've seen statically linked license daemons break going
from Solaris 2.5.1 to 2.6 (-lsocket)
Solaris 2.3 or 2.4 changed the way gettimeofday() worked, so
statically linking that also broke.
- in some cases (flexlm), you need to statically link both the
licensemanager and all products using it.
And the 3rd point:
it's really not much more difficult to write an LD_PRELOAD than
it is to write a program that uses /proc or ptrace() on
system calls and substitutes return values of its liking.
(I've done that for hostids on SunOS 4.x)
Statically linking raises the bar only a little; the maintenance costs,
however, may soar and customer satisfaction may very well decline.
(What do you mean, I need a different version of your product for
each of the four Solaris releases I'm currently using? Can I have
a version with libc bug X fixed?)
Casper
Date: Thu, 13 May 1999 15:47:31 -0700
Reply-To: James Lockwood <james@VANEYCK.GII.GETTY.EDU>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: James Lockwood <james@VANEYCK.GII.GETTY.EDU>
Subject: Re: LD_PRELOAD potential problems
To: BUGTRAQ@netspace.org
On Tue, 11 May 1999, David F. Skoll wrote:
> I recently ran across a piece of software which depended upon knowing
> the time reasonably accurately. By replacing the time(2) UNIX system
> call with my own function, I was able to fool the program and get it
> to misbehave, without the inconvenience of actually changing the system
> time or even requiring root privileges.
>
> If you are writing programs which depend on C library functions or
> UNIX system calls for secure operation, please distribute only
> statically-linked versions, as the effort to fool statically-linked
> binaries is a lot higher than a simple LD_PRELOAD spoof.
I would hardly call 30 seconds with adb or gdb "a lot higher". Static
linking is bad for many reasons, one of the chief being that if bugs are
found in the libraries you are using there is no way to fix the
executable. Static linking also wastes memory, and many Unices are
starting to deprecate static linking of system libraries (Solaris is a
good example).
If you must have your program run in an unaltered state, then ask that it
be installed setuid nobody (for example) and have it drop uid/gid privs in
the first two lines of code. LD_PRELOAD (and LD_LIBRARY_PATH, for that
matter) are not honored on setuid executables.
If you are distributing time-limited crippleware, then nothing will help
you. Those who want to bypass it will, but most will not. There is no
way around this, as long as the user is downloading and executing your
code under her control she will be able to modify it.
Normally I wouldn't consider this a worthwhile discussion for BUGTRAQ, but
I think that the point must be made that static linking prevents library
fixes from being propagated to compiled applications. When a library bug
exists that can endanger system security, statically linked applications
become a significant problem. Systems with many statically linked
applications are more difficult to keep up to date security and
stability-wise than other systems.
--
James D. Lockwood
The
(former) Getty Information Institute
System Administrator
1200
Getty Center Drive, Suite 300
james@gii.getty.edu
Los
Angeles, CA 90049-1680
Date: Fri, 14 May 1999 11:58:34 -0400
Reply-To: Phillip Vandry <vandry@MLINK.NET>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Phillip Vandry <vandry@MLINK.NET>
Subject: Re: LD_PRELOAD potential problems
X-To: "David F. Skoll" <dfs@DOE.CARLETON.CA>
To: BUGTRAQ@netspace.org
You should note of course that LD_PRELOAD will not work for any setuid
or setgid binary. Users thus cannot do anything they wouldn't have been
able to do otherwise by modifying code or compiling their own using this
trick.
I agree that LD_PRELOAD is very easy to use, but vendors shipping
statically linked binaries is a big inconvenience, and I don't believe
they should do it on account of the LD_PRELOAD hack. It's just not
worth it.
Here are some of the disadvantages of a statically linked binary:
- It's big on disk. Not only that but if there are multiple binaries that
share code (and what two binaries don't share at least code from libc?),
the size of this code is multiplied by the number of binaries.
- It's big in memory. Same argument, but this time regarding code that it
duplicated in memory (shared libraries are mapped only once)
- It's compatible with only one version of the operating system. (libc's
kernel interfaces are always free to change)
- The binary won't benefit from bugfixes in the vendor's system libraries.
- In many cases, it may not even be possible. For example, in Solaris,
using the name service switch REQUIRES a dynamically linked binary, and
keep in mind that you need the name service switch for all getXXXbyYYY()
functions.
In fact, it's not hard using gdb and breakpoints to override any desired
function in statically linked binaries too. (Harder if it's stripped,
admitedly).
If you must, extract those functions which you consider critical from
libc.a, and link those into the main binary (or even use syscall()
directly, but please link your stuff dynamically!
I assume that in your original message you are referring to an example of
using time() for a task such as forcing a demo copy of software to
expire (and overriding time() to fool the scheme). Similar situations
occur with binaries that check a machine's hostid or IP address to
verify license to use it.
In all these cases, if you are writing software that does this, and you
want to protect yourself from people bypassing your tests, you definately
need to contort your code a bit. If there's a function called
check_license() and a user can overwrite the beginning of this function
with code for "return 0" and that totally bypasses all your checks, then
you got fooled pretty easily. I suggest the following:
- Check this inside main() or some other big long function to discourage
disassembly/decompilation.
- Arrange that it is not possible to bypass your checks by nopping out a
single function/function call
- Don't print a message immediately after you do the checks. The user will
be able to set a breakpoint at the place where you print your message
(since you ultimately have to make a system call to print text) and know
pretty much what section of your code is making the checks.
Tangeant: On Solaris, you can override the system call of your choice
by making a kernel module that goes in the kernel/sys subdirectory. I
do not have documentation as to how that's done, but this method of
overriding a system call is virtually undetectable by user level
software. On OSes where you have source, of course, you're free to
modify system calls with even more ease!
-Phil
Date: Fri, 14 May 1999 11:51:09 -0400
Reply-To: "John R. LoVerso" <john@LOVERSO.SOUTHBOROUGH.MA.US>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: "John R. LoVerso" <john@LOVERSO.SOUTHBOROUGH.MA.US>
Subject: Re: Clarification: LD_PRELOAD issue
To: BUGTRAQ@netspace.org
Here's an example I cooked up a few years ago that
accomplishes
exactly this. Works on FreeBSD. ("make tryit")
John
Date: Fri, 14 May 1999 09:45:44 +0100
Reply-To: Darren J Moffat - Enterprise Services OS Product Support Group
<darren.moffat@uk.sun.com>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Darren J Moffat - Enterprise Services OS Product Support Group
<darren.moffat@uk.sun.com>
Subject: Re: LD_PRELOAD potential problems
X-To: dfs@DOE.CARLETON.CA
To: BUGTRAQ@netspace.org
>Many UNIX systems allow you to "pre-load" shared libraries by setting
>an environment variable LD_PRELOAD. This allows you to do interesting
>things like replace standard C library functions or even the C
>interfaces to system calls with your own functions.
Correct, but so does setting of some of the other LD_* variables.
Solaris has at least the following other variables that could be
used to achieve similar results:
LD_LOADFLTR
LD_AUDIT
>I recently ran across a piece of software which depended upon knowing
>the time reasonably accurately. By replacing the time(2) UNIX system
>call with my own function, I was able to fool the program and get it
>to misbehave, without the inconvenience of actually changing the system
>time or even requiring root privileges.
Correct, but given that the process wasn't running as root all you can
do is screw up yourself. This isn't a compromise of the system.
>From the new man page for ld.so.1:
If an LD_LIBRARY_PATH environment variable is in effect for
a secure process, then only the trusted directories
speci-
fied by this variable will be used to augment the
runtime
linker's search rules. Presently, the only trusted directory
known to the runtime linker
is /usr/lib/secure, or
/usr/lib/secure/sparcv9 for 64-bit SPARCV9 objects.
In a secure process, any runpath specifications provided by
the application or any of its
dependencies will be used,
provided they are full pathnames, that is,
the pathname
starts with a '/'.
Additional objects may be loaded with a secure process using
the LD_PRELOAD environment variable, provided
the objects
are specified as simple file names, with no '/' in the name.
These objects will be located subject to
the search path
restrictions previously described.
What this is saying is that in Solaris (from 5.7 with the Kernel Update
106541-05 - which is not yet released) LD_PRELOAD for setuid programs
will not work unless the file is in /usr/lib/secure which is by default
empty.
>If you are writing programs which depend on C library functions or
>UNIX system calls for secure operation, please distribute only
>statically-linked versions, as the effort to fool statically-linked
>binaries is a lot higher than a simple LD_PRELOAD spoof.
A lot of people go with this as good practice. However there are a
number of caveats as to why static linking is not a good idea.
Issues with static linking
--------------------------
Static linking reduces the overhead when the program is started up, mainly
because relocations and other start-up activities are done at compile time.
However, static linking is generally discouraged. Here are some reasons :
* Static linking prevents libc_psr.so.1 from working for platform
specifics. This library automatically enables dynamically linked
programs from linking in platform specific versions of various
library routines which are optimized for a particular platform.
* Static linking greatly increases working set size and disk footprint.
* Statically linked executables are NOT necessarily binary compatible
between releases.
eg. statically linked programs that use
libsocket will
failed if compiled on
2.5.1 or less and run on 2.6
* Patches to system libaries for bug fixes and performance enhancements
are not automatically picked up by the application.
* Some debugging libraries/tools will fail to work properly.
eg. malloc debugging.
* And most importantly you will not benifit from security or other
fixes in the vendor provided libaries when patches are released.
When to use static linking
--------------------------
* The binary is critical to system operation when in single user-mode
either for the startup of the OS or for disaster recovery.
* Statically linking a private (internal) libarary is okay.
Don'ts
------
* Statically link against libc
* Statically link against libdl
And finally there are no 64bit static libaries in Solaris 7 and we
will NOT be providing them in the future for 64bit.
--
Darren J Moffat
Date: Fri, 14 May 1999 17:35:31 +0200
Reply-To: Roger Espel Llima <espel@LLAIC.U-CLERMONT1.FR>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Roger Espel Llima <espel@LLAIC.U-CLERMONT1.FR>
Subject: Re: LD_PRELOAD potential problems
X-To: "David F. Skoll" <dfs@DOE.CARLETON.CA>
To: BUGTRAQ@netspace.org
On Tue, May 11, 1999 at 09:51:40PM -0400, David F. Skoll wrote:
> I recently ran across a piece of software which depended upon knowing
> the time reasonably accurately. By replacing the time(2) UNIX system
> call with my own function, I was able to fool the program and get it
> to misbehave, without the inconvenience of actually changing the system
> time or even requiring root privileges.
Getting a program to misbehave, when it's running under your uid, is no
trouble at all. Just ptrace() the thing, put breakpoints, change its
variables, etc.
(read-only programs are supposedly protected against this, but this is a
rather iffy kind of protection, and I woulnd't base a program's security
on it)
> If you are writing programs which depend on C library functions or
> UNIX system calls for secure operation, please distribute only
> statically-linked versions, as the effort to fool statically-linked
> binaries is a lot higher than a simple LD_PRELOAD spoof.
If you are writing programs whose security model counts the uid they run
as as a potential attacker, your security is broken by design.
If the ordinary user has something to gain by making the program
misbehave, then the binary should be suid to some other uid, and
explicitly make the appropriate security checks. In that case, any
non-braindead dynamic loader will ignore LD_PRELOAD.
If the program counts even the *admin* as a potential attacker, then
good luck -- it's security by obscurity, just hope that no-one takes the
time to break it.
--
Roger Espel Llima, espel@llaic.u-clermont1.fr
http://www.eleves.ens.fr:8080/home/espel/index.html
Date: Sat, 15 May 1999 18:52:53 -0400
Reply-To: John Daniele <JDaniele@KPMG.CA>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: John Daniele <JDaniele@KPMG.CA>
Subject: Re: Clarification: LD_PRELOAD issue
To: BUGTRAQ@netspace.org
/*
* rollover.c
*
* using ptrace() to intercept and modify the return value of a system call
*
* John Daniele
* jdaniele@kpmg.ca
* VOX: (416) 777-3759
*
*/
#include <unistd.h>
#include <sys/ptrace.h>
int main(void)
{
int ret, x, y;
pid_t procid;
if(procid = fork()) {
for(;;) {
x = ptrace(PTRACE_PEEKUSR, procid, 44, 0);
if(x == 13) {
y = ptrace(PTRACE_PEEKUSR, procid, EBX,
0);
ptrace(PTRACE_POKEDATA, procid, y,
2175984000);
}
ptrace(PTRACE_SYSCALL, procid, 1, 0);
}
}
ptrace(PTRACE_TRACEME, 0, 1, 0);
execl("/bin/date", "/bin/date", NULL, (char *)0);
}
Date: Fri, 14 May 1999 17:28:42 -0400
Reply-To: Kragen Sitaker <kragen@POBOX.COM>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Kragen Sitaker <kragen@POBOX.COM>
Subject: Re: Clarification: LD_PRELOAD issue
To: BUGTRAQ@netspace.org
A Mr. Skoll writes:
> Now, any license manager can be spoofed, from as blunt an attack as
> changing the system time to sophisticated reverse-engineering attacks
> on the license manager binary. The issue is to prevent "cheap"
> attacks -- if attacking the license manager is expensive enough,
> people won't bother (or they'll find other avenues of attack. :-))
>
> Changing the system time introduces all kinds of problems, so most
> potential license abusers won't do it. A two-line shell script with a
> 6-line C program is a very cheap attack on a dynamically-linked
> license manager daemon. Attacking a statically-linked license manager
> binary is quite a bit more expensive, and should greatly reduce the
> incentive for an attack.
This logic is utter nonsense when applied to programs.
It makes sense when applied to safes or encrypted messages. If a
single safe takes 20 hours to break into, a thousand of them will take
20,000 hours to break into.
It does not make sense when applied to software. If a single program
takes 20 hours to break into (quite a liberal estimate for most
copy-protection), then it will take perhaps another half hour to post
the exploit, and then ten minutes each to apply the fix to the other
thousand copies of the program, for a total of about 187 hours.
And static linking doesn't take care of it, either; root still can load
kernel modules to put each application in a different 'time zone', for
example, and running the license manager under a debugger that traps
calls to the time() function is also no big deal, and works fine even
if the program is statically linked.
In short: your battle is in vain, and the futile measures you employ in
it hurt the rest of us. They hurt our system security, reliability,
and performance. Your needs (treat the kernel and root as potential
crackers) are in direct opposition to those of us who wish to run
secure systems.
--
<kragen@pobox.com>
Kragen Sitaker <http://www.pobox.com/~kragen/>
TurboLinux is outselling NT in Japan's retail software market 10 to 1,
so I hear.
-- http://www.performancecomputing.com/opinions/unixriot/981218.shtml
Date: Tue, 18 May 1999 12:06:47 -0400
Reply-To: John Daniele <JDaniele@KPMG.CA>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: John Daniele <JDaniele@KPMG.CA>
Subject: Re: LD_PRELOAD: Clarification
To: BUGTRAQ@netspace.org
Barnett wrote:
> cc -o rollover rollover.c
> "rollover.c", line 75: undefined symbol: PTRACE_PEEKUSR
> "rollover.c", line 77: undefined symbol: EBX
> cc: acomp failed for rollover.c
> *** Error code 2
> Solaris 2.6
> What OS is your program for?
In response to similar emails rev'd, I was sitting in front of a linux box at
the
time of the LD_PRELOAD posting, thus my code reflects this. However, Solaris
2.6 should support PTRACE_PEEKUSR as this was favoured over PTRACE_READDATA
in 2.5 I believe (correct me if I'm wrong). In any case, look at <sys/ptrace.h>
for valid request types. The value of EBX is defined in <asm/ptrace.h> and is 0.
If all else fails, you can always issue ioctl routines on a process within the
/proc filesystem ;)
John
Daniele
jdaniele@kpmg.ca
VOX:
(416) 777-3759
Date: Tue, 18 May 1999 15:40:38 +0100
Reply-To: dbrown@CCDC.CAM.AC.UK
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Daniel Brown <dbrown@CCDC.CAM.AC.UK>
Subject: Re: Clarification: LD_PRELOAD issue
To: BUGTRAQ@netspace.org
Here's a similar snippet for Solaris using the procfs interface...
Dan.
--
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <procfs.h>
#include <stdio.h>
#include <unistd.h>
/* Faking of the time() system call via procfs.
*
* Daniel Brown, dbrown@ccdc.cam.ac.uk
*
* Compiled and tested under Solaris 2.6/sparc and 2.6/x86
*/
int
read_status(pid_t pid, pstatus_t *status)
{
char buf[MAXPATHLEN];
int fd;
sprintf(buf, "/proc/%d/status", (int) pid);
if ((fd = open(buf, O_RDONLY)) == -1) {
perror("read_status(open)");
return 1;
}
if (read(fd, (void *) status, sizeof(pstatus_t)) != sizeof(pstatus_t))
{
perror("read_status(read)");
return 1;
}
close(fd);
return 0;
}
int
write_ctl(pid_t pid, long syscall, void *arg, size_t arglen)
{
int fd;
char buf[MAXPATHLEN];
struct iovec vec[2];
sprintf(buf, "/proc/%d/ctl", (int) pid);
if ((fd = open(buf, O_WRONLY)) == -1) {
perror("write_ctl(open)");
return 1;
}
vec[0].iov_base = (void *) &syscall;
vec[0].iov_len = sizeof(long);
if (arg != NULL) {
vec[1].iov_base = arg;
vec[1].iov_len = arglen;
if (writev(fd, vec, 2) != (vec[0].iov_len + vec[1].iov_len)) {
perror("write_ctl(write2)");
close(fd);
return 1;
}
} else {
if (writev(fd, vec, 1) != vec[0].iov_len) {
perror("write_ctl(write1)");
return 1;
}
}
close(fd);
return 0;
}
int
main(int argc, char **argv)
{
pid_t pid, ppid;
pstatus_t pstatus;
sysset_t sysset;
long val;
setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0);
ppid = getpid();
if (read_status(ppid, &pstatus))
exit(1);
printf("Parent PID is %d\n", (int) ppid);
printf("Setting PCSEXIT for time() : stop on exit from time().\n");
premptyset(&sysset);
praddset(&sysset, SYS_time);
if (write_ctl(ppid, PCSEXIT, (void *) &sysset, sizeof(sysset_t)))
exit(1);
printf("Setting PR_FORK, so that the child inherits these traps.\n");
val = PR_FORK;
if (write_ctl(ppid, PCSET, (void *) &val, sizeof(long)))
exit(1);
printf("Finally, setting PCSENTRY for exit() "
": stop on entry to exit().\n");
premptyset(&sysset);
praddset(&sysset, SYS_exit);
if (write_ctl(ppid, PCSENTRY, (void *) &sysset, sizeof(sysset_t)))
exit(1);
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
} else if (pid > 0) { /* Parent */
printf("Clearing exit() trap for the parent...\n");
premptyset(&sysset);
if (write_ctl(ppid, PCSENTRY, (void *) &sysset,
sizeof(sysset_t)))
exit(1); /* Good luck! */
if (read_status(pid, &pstatus))
exit(1);
printf("Child PID is %d and %s have a trap set on time().\n",
(int) pstatus.pr_pid,
(prismember(&pstatus.pr_sysexit,
SYS_time)) ? "does" : "doesn't");
while (1) {
printf("Waiting for child to call time() or exit().\n");
if (write_ctl(pid, PCWSTOP, (void *) 0, 0))
exit(1);
printf("Write PCWSTOP returned. Reading status.\n");
if (read_status(pid, &pstatus))
exit(1);
if (pstatus.pr_lwp.pr_syscall == SYS_exit) {
printf("Child has called exit(). Bye!\n");
exit(0);
} else if (pstatus.pr_lwp.pr_syscall != SYS_time) {
printf("We've caught syscall %d! Eeeek!\n",
(int) pstatus.pr_lwp.pr_syscall);
exit(1);
}
printf("Child has called time().\n");
printf("LWP register R_R0 is %d.\n",
(int) pstatus.pr_lwp.pr_reg[R_R0]);
printf("Setting LWP register R_R0 to 123.\n");
pstatus.pr_lwp.pr_reg[R_R0] = 123;
if (write_ctl(pid, PCSREG, (void *) &pstatus.pr_lwp.pr_reg,
sizeof(prgregset_t)))
exit(1);
printf("Restarting the child.\n");
val = 0L;
if (write_ctl(pid, PCRUN, (void *) &val, sizeof(long)))
exit(1);
printf("Restarted.\n");
} /* while (1) */
/* NOT REACHED */
}
/* Child */
sleep(5);
execl("/usr/bin/date", "/usr/bin/date", (char *) NULL);
perror("execl failed");
return 99;
}