Code Comments
Programming Forum and web based access to our favorite programming groups.My program needs to keep track of processes, so it has a little code to wrap the fork() system call. The wrapper simply makes an entry in a little embedded database, then calls through to the real fork() using dlsym(RTLD_NEXT, ...) et al. This works fine. But I've realized there's still substantial use of vfork() out there - in fact it seems to be less deprecated than it used to be - so I figured I'd better catch vfork() uses as well. Unfortunately it turns out to be impossible to put a wrapper function around vfork because of the following restriction: > The procedure that called vfork(), however, should not return > while running in the child's context, since the eventual return > from vfork() would be to a stack frame that no longer exists. This is from the Solaris man page but SUS has similar text. Obviously, once the wrapper function returns the stack frame is hosed, and there's no way to get to the exec without the wrapper returning first. The current workaround is to replace vfork() with fork(); i.e. my vfork wrapper calls fork under the covers. This is at least technically legal since SUSv3 says "On some implementations, vfork() is equivalent to fork()." But I'm still looking for some brilliant hack that would allow trapping of calls to vfork. Anyone? BTW, I should note that in some cases I have to inject this tracking code into programs we don't control via LD_PRELOAD, so simply avoiding the use of vfork is not a complete solution. -- Thanks, M.Biswas
Post Follow-up to this messageMohun Biswas <m.biswas@invalid.addr> writes: > But I'm still looking for some brilliant > hack that would allow trapping of calls to vfork. Anyone? The *only* possible solution (I think) is to write your wrapper in assembly and in such a way that it keeps all its state in registers and doesn't touch any memory. Cheers, -- In order to understand recursion you must first understand recursion. Remove /-nsp/ for email.
Post Follow-up to this messageIn article <xYD2d.65442$D%.32367@attbi_s51>, Mohun Biswas wrote: >BTW, I should note that in some cases I have to inject this tracking >code into programs we don't control via LD_PRELOAD, so simply avoiding >the use of vfork is not a complete solution. Have you looked at Dave Wagner's "Janus" involving a loadable kernel module for hints at code interception ? I haven't looked at it in detail. http://http.cs.berkeley.edu/~daw/janus/ -- Elvis Notargiacomo master AT barefaced DOT chhttp://www.notatla.org.uk/goen/ My energy-saving light bulb caught fire. Now I know the NSA are beaming microwaves at my flat.
Post Follow-up to this messagePaul Pluzhnikov wrote: > Mohun Biswas <m.biswas@invalid.addr> writes: > > > The *only* possible solution (I think) is to write your wrapper in > assembly and in such a way that it keeps all its state in registers > and doesn't touch any memory. I think I see ... you mean the wrapper wouldn't have the usual preamble code to push a stack frame, so I'd be responsible for not scribbling on registers and memory. And when vfork() returned in the parent it would find the stack frame where it expected. Is that right? And if so, if I called another (regular) function from within this magic half-function that should be ok, since it would save and restore registers and so on, right? Just to make sure the situation is clear, I don't want to mess with anything at all *after* the split. I just need a hook to make an entry in a database *before* the split, while everything's still running in one simple unitary process. The problem is that I have to push a stack frame in order to get that hook but I'm not allowed to pop a stack frame afterwards. Catch-22. -- Thanks, M.Biswas
Post Follow-up to this messageMohun Biswas <m.biswas@invalid.addr> wrote: > Paul Pluzhnikov wrote: > > I think I see ... you mean the wrapper wouldn't have the usual preamble > code to push a stack frame, so I'd be responsible for not scribbling on > registers and memory. And when vfork() returned in the parent it would > find the stack frame where it expected. Is that right? And if so, if I > called another (regular) function from within this magic half-function > that should be ok, since it would save and restore registers and so on, > right? > > Just to make sure the situation is clear, I don't want to mess with > anything at all *after* the split. I just need a hook to make an entry > in a database *before* the split, while everything's still running in > one simple unitary process. The problem is that I have to push a stack > frame in order to get that hook but I'm not allowed to pop a stack frame > afterwards. Catch-22. Not sure I understand exactly, but it seems that making a tail call to vfork() inside your wrapper function will work. This will make vfork() to return directly to the caller of the wrapper instead of returning to your wrapper function. This way, the stack is popped before the vfork call. Or do you want something else ? -- #pragma ident "Seongbae Park, compiler, http://blogs.sun.com/seongbae/"
Post Follow-up to this messageIn article <HtI2d.66182$D%.65464@attbi_s51>, Mohun Biswas <m.biswas@invalid.addr> wrote: > Paul Pluzhnikov wrote: > > I think I see ... you mean the wrapper wouldn't have the usual preamble > code to push a stack frame, so I'd be responsible for not scribbling on > registers and memory. And when vfork() returned in the parent it would > find the stack frame where it expected. Is that right? And if so, if I > called another (regular) function from within this magic half-function > that should be ok, since it would save and restore registers and so on, > right? > > Just to make sure the situation is clear, I don't want to mess with > anything at all *after* the split. I just need a hook to make an entry > in a database *before* the split, while everything's still running in > one simple unitary process. The problem is that I have to push a stack > frame in order to get that hook but I'm not allowed to pop a stack frame > afterwards. Catch-22. As long as you don't need to do anything *after* vfork() returns, this is not impossible. Basically, all you need to do is write a small assembly routine which: sets up a stack frame calls your C routine, which: does a bunch of work returns (dlsym(RTLD_NEXT, "vfork")) tears down the stack frame jumps through the returned function pointer On sparc, this would look something like: (call this vfork.S) --- cut here --- #define _ASM #include <sys/asm_linkage.h> ENTRY(vfork) save %sp, -SA(MINFRAME), %sp call vfork_wrapper ! returns &vfork in %o0 nop jmp %o0 restore ! delay slot SET_SIZE(vfork) --- cut here --- The x86 routine would be about the same complexity. The vfork syscall will return directly to the caller. - jonathan
Post Follow-up to this messageIn article <jwadams-A8DAAD.15055217092004@news1nwk.sfbay.sun.com>, Jonathan Adams <jwadams@gmail.com> wrote: > > On sparc, this would look something like: (call this vfork.S) > > --- cut here --- > #define _ASM > #include <sys/asm_linkage.h> > > ENTRY(vfork) > save %sp, -SA(MINFRAME), %sp > call vfork_wrapper ! returns &vfork in %o0 > nop > jmp %o0 > restore ! delay slot > SET_SIZE(vfork) > --- cut here --- > > The x86 routine would be about the same complexity. The vfork syscall > will return directly to the caller. x86: --- cut here --- #define _ASM #include <sys/asm_linkage.h> ENTRY(vfork) pushl %ebp movl %esp, %ebp call vfork_wrapper movl %ebp, %esp popl %ebp jmp *%eax SET_SIZE(vfork) --- cut here --- (the advantage of this over the "convince the compiler to make it a tail-call" approach is that sometimes the compiler is hard to convince) - jonathan
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread
Powered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.