Re: Tracing with utrace, some questions
On Sun, 10 Oct 2010 11:35:02 -0700 (PDT), Roland McGrath rol...@redhat.com wrote: 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. Neat. Although returning just UTRACE_SYSCALL_ABORT doesn't work. It just makes the process hang for me. I had to do: return (no == SYS_socket) ? UTRACE_SYSCALL_ABORT | UTRACE_RESUME : UTRACE_SYSCALL_RUN | UTRACE_RESUME; to make it work. You probably didn't mention that because it was obvious but honestly it wasn't that clear for me and didn't see it was mentioned in the documentation. 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'. Neat^2. I think documenting this is a good idea as well. Maybe I should start writing a patch for the documentation to make it easier for new-comers like me :) 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. Thanks, appreciated. 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. One question about report_syscall_exit, I'm trying to change the errno to EPERM for aborted system calls but I think I'm doing it wrong: static u32 ubox_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { enum utrace_syscall_action decision; decision = utrace_syscall_action(action); switch (decision) { case UTRACE_SYSCALL_ABORT: syscall_set_return_value(current, regs, -EPERM, -1); /* fall through */ default: return UTRACE_RESUME; } } The decision argument is never set to UTRACE_SYSCALL_ABORT for me. It's always 0 aka UTRACE_SYSCALL_RUN. 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). I'll check out is_compat_task(), thanks. 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. Not perfect but WFM. 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. Looks like really nice example for me! I'm reading it now :) Thanks, Roland Thanks for answering, I really
Tracing with utrace, some questions
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
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