2017-07-17 58 views
2

我正在嘗試使用原始克隆系統調用來避免必須將pid 0代碼重構爲函數。 Linux需要16個字節的堆棧,另外,libc預留了16位存儲ptid和ctid。下面的代碼創建一個對齊的堆棧,然後退出該孩子。在等待由libc的包裝器克隆的孩子之後,我每次在使用原始系統調用時程序段錯誤時都使用具有相同緩衝區的原始系統調用。附加是strace的輸出,除非我忽略任何東西顯示系統調用參數兩次都是一樣的。 在SO上至少有一個其他問題Raw Clone system call,其中OP似乎有類似的困難,不幸的是,接受的答案使用libc克隆包裝器而不是系統調用。原始克隆系統調用不能正常工作

#define _GNU_SOURCE 

#include <sched.h> 
#include <stdalign.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <syscall.h> 
#include <signal.h> 
#include <stdint.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/wait.h> 

int test(void*c) 
{ 
    quick_exit(0); 
} 

int main(void) 
{ 
    alignas (16) unsigned char stack[4096] = {0}; 
    printf("Top of stack %p\n", stack+sizeof(stack)); 
    printf("Top of stack minus 16 %p\n", stack+sizeof(stack)-16); 
    pid_t pid = clone(test, stack+sizeof(stack), CLONE_VM|SIGCHLD, 0, 0, 0, 0); 

    wait(NULL); 

    memset(stack, 0, sizeof stack); 

    pid = syscall(SYS_clone, CLONE_VM|SIGCHLD, stack+sizeof(stack)-16); 
    if (pid == 0) 
     quick_exit(0); 
wait(NULL); 
    quick_exit(0); 
} 

strace的輸出:

[email protected]:~$ strace ./a.out 
execve("./a.out", ["./a.out"], [/* 57 vars */]) = 0 
brk(NULL)        = 0x55b1e58ee000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70303a0000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/tls/x86_64", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/tls", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/x86_64", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 
open("/opt/google/chrome/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/lib/tls/x86_64", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/lib/tls", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/lib/x86_64", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/opt/google/chrome/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
stat("/opt/google/chrome/lib", 0x7ffcc0e2e400) = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=171231, ...}) = 0 
mmap(NULL, 171231, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7030376000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\5\2\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0755, st_size=1856752, ...}) = 0 
mmap(NULL, 3959200, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f702fdb7000 
mprotect(0x7f702ff74000, 2097152, PROT_NONE) = 0 
mmap(0x7f7030174000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f7030174000 
mmap(0x7f703017a000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f703017a000 
close(3)        = 0 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7030374000 
arch_prctl(ARCH_SET_FS, 0x7f7030374700) = 0 
mprotect(0x7f7030174000, 16384, PROT_READ) = 0 
mprotect(0x55b1e46da000, 4096, PROT_READ) = 0 
mprotect(0x7f70303a3000, 4096, PROT_READ) = 0 
munmap(0x7f7030376000, 171231)   = 0 
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 8), ...}) = 0 
brk(NULL)        = 0x55b1e58ee000 
brk(0x55b1e590f000)      = 0x55b1e590f000 
write(1, "Top of stack 0x7ffcc0e2ecd0\n", 28Top of stack 0x7ffcc0e2ecd0 
) = 28 
write(1, "Top of stack minus 16 0x7ffcc0e2"..., 37Top of stack minus 16 0x7ffcc0e2ecc0 
) = 37 
clone(child_stack=0x7ffcc0e2ecc0, flags=CLONE_VM|SIGCHLD) = 122458 
wait4(-1, NULL, 0, NULL)    = 122458 
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=122458, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- 
clone(child_stack=0x7ffcc0e2ecc0, flags=CLONE_VM|SIGCHLD) = 122459 
exit_group(0 <unfinished ...> 
+++ killed by SIGSEGV +++ 
Segmentation fault (core dumped) 

回答

5

syscallclone沒有專門的知識。這意味着當函數試圖在新創建的線程中返回時,它會從交換堆棧讀取返回地址,該地址爲零。如果您向堆棧寫入非零位模式並放棄CLONE_VM,這樣會更加明顯,因此孩子不會打破父級。

+0

有沒有辦法告訴編譯器不要存儲返回值?我試圖失敗,但沒有奏效。 – clockley1

+0

這不是關於返回值*,而是關於'syscall'函數本身存儲返回地址*的位置。如果不修改'syscall'函數實現,就沒有辦法改變它,並且不完全清楚這個改變應該是什麼樣子的(可能類似'vfork'中使用的東西)。改進更高層次的克隆接口可能會更好。 –

+0

好的,謝謝+1 .. – clockley1