Tracing with utrace, some questions

2010-10-10 Thread Ali Polatel
Hi,

I'm trying to write a simple module that will abort socket() calls for
the attached process. It's nothing serious, just for learning purposes.
What I have so far is largely based on crash-suspend.c so I didn't feel
the need to share any source code. I can, however, if need be. I have a
few questions:

1. From what I've read in the DocBook pages I've figured out that I have
to have two report entries. One for syscall_entry and one for
syscall_exit. On syscall_entry I should use syscall_get_nr() and check
if this number is equal to __NR_socket and return UTRACE_SYSCALL_ABORT
in that case and on syscall_exit, I need to call syscall_rollback() to
rollback the registers if utrace_syscall_action(action) returns
UTRACE_SYSCALL_ABORT. Is this correct?

2. First I've read the documentation from Roland's page and figured out
it's out of date. report_syscall_entry callback used to have a struct
task_struct argument but now it doesn't. How should I get a struct
task_struct to pass to syscall_get_nr? Am I supposed to keep a
reference to the struct pid I used in init_module() and use
pid_task(pid, PIDTYPE_PID) or should I use find_get_pid() just as I used
in the init_module()?

3. In the report_syscall_exit callback, is the struct pt_regs argument
there so that the user can directly pass it to syscall_rollback() or do
I have to save the registers I had in report_syscall_entry() callback
and use them instead?

4. __NR_socket is available on some architectures and it's implemented
on top of __NR_socketcall on others. I'm running this example on x86_64.
How should my module figure out which mode the target process is running
in? I suppose this is related to the CS register. Having figured that
how am I supposed to include system call numbers from both architectures
and use __NR_socketcall for 32bit mode and __NR_socket for 64bit?

5. Is there any project in the outer-space that does something like
this, sandboxing or monitoring system calls, from which I can learn
more?

Thanks for reading.

-- 
Regards,
Ali Polatel


pgpWr4WBTUM0p.pgp
Description: PGP signature


Re: Tracing with utrace, some questions

2010-10-10 Thread Roland McGrath
 1. From what I've read in the DocBook pages I've figured out that I have
 to have two report entries. One for syscall_entry and one for
 syscall_exit. On syscall_entry I should use syscall_get_nr() and check
 if this number is equal to __NR_socket and return UTRACE_SYSCALL_ABORT
 in that case and on syscall_exit, I need to call syscall_rollback() to
 rollback the registers if utrace_syscall_action(action) returns
 UTRACE_SYSCALL_ABORT. Is this correct?

The report_syscall_entry hook is the only one you need to prevent the
system call from running.  If it returns UTRACE_SYSCALL_ABORT, then the
system call will fail with the ENOSYS error code.  You only need to use a
report_syscall_exit hook if you want the registers the user process sees
after attempting the system call to be different from that.

 2. First I've read the documentation from Roland's page and figured out
 it's out of date. report_syscall_entry callback used to have a struct
 task_struct argument but now it doesn't. How should I get a struct
 task_struct to pass to syscall_get_nr? Am I supposed to keep a
 reference to the struct pid I used in init_module() and use
 pid_task(pid, PIDTYPE_PID) or should I use find_get_pid() just as I used
 in the init_module()?

Those callbacks are made in the affected thread itself.  
So you can just use the magic variable 'current'.

I've updated the web copy of the documentation.  If you install the
kernel-doc rpm on a Fedora system, that contains the version of this same
documentation that goes with the kernel you have.

 3. In the report_syscall_exit callback, is the struct pt_regs argument
 there so that the user can directly pass it to syscall_rollback() or do
 I have to save the registers I had in report_syscall_entry() callback
 and use them instead?

You can just pass that pointer directly.  In fact, the same pointer to
'struct pt_regs' will be passed to both callbacks.  This is always the same
pointer that 'task_pt_regs(current)' would return, just made quicker to
access by having the argument to the callbacks.

 4. __NR_socket is available on some architectures and it's implemented
 on top of __NR_socketcall on others. I'm running this example on x86_64.
 How should my module figure out which mode the target process is running
 in? I suppose this is related to the CS register. 

There are several ways to go about this, depending on how arch-specific you
want to make it.  On x86-64 it's possible for 32-bit processes to make
64-bit system calls and vice versa, though normal user programs will never
actually do this.  Perhaps the easiest and cleanest way, that both covers
this arcane possibility and also works on other architectures, is to call
is_compat_task() (under #ifdef CONFIG_COMPAT).

 Having figured that how am I supposed to include system call numbers from
 both architectures and use __NR_socketcall for 32bit mode and __NR_socket
 for 64bit?

Unfortunately, there is no clean way to refer to the 32-bit syscall numbers
in code inside the 64-bit kernel.  socketcall is not one of the few listed
in asm/ia32_unistd.h, so off hand I think you'd just have to hard-code the
i386 __NR_socketcall value in your module.

 5. Is there any project in the outer-space that does something like
 this, sandboxing or monitoring system calls, from which I can learn
 more?

Renzo Davoli's umview/kmview is just such an animal.
See http://wiki.virtualsquare.org for details.


Thanks,
Roland