首页
社区
课程
招聘
PWN入门-12-SROP拜师
发表于: 2024-10-9 20:54 4312

PWN入门-12-SROP拜师

2024-10-9 20:54
4312

信号是用户态进程与内核进行通信的一种方式,它是陷阱(软中断)的一种。如果想要查看所有的信号类型可以查询Linux手册。

信号抵达进行需要经过两个步骤,一是发送信号,而是接收信号。

在Linux中进程的待处理的信号由task_struct结构体中的signal成员和pending成员进行记录,signal成员和pending成员的区别在于,signal成员中存放的待处理信号对整个进程组都是生效的,而pending成员只对指定的线程有效。

signal成员由signal_struct结构体定义,该结构体中的shared_pending成员是管理共享信号的主要成员,它由由sigpending结构体定义,task_struct结构体中的pending成员也由sigpending结构体定义。

sigpending结构体中的list成员指向了待处理信号队列,从下面的定义中可以看到info记录了关键的信号信息。

sigpending结构体中还可以看到一个list成员的身影,既然sigpending结构体中的list成员已经可以管理待处理信号队列了,那么sigpending结构体中的list成员又有什么用呢?

要知道,在Linux中信号分成常规信号和实时信号,这里我们需要先了解一下它们的区别。

Linux中1号 - 31号是常规信号,32号+是实时信号。它们的区别在于,同进程下同类型的常规信号只能存在一个,当常规信号被响应后,下一个同类型的常规信号才可以进入队列。

对于实时信号来讲则不是这样,同进程下可以存在多个同类型的实时信号,系统会根据实时信号在队列中的数量进行多次响应。

因此sigpending结构体中的list成员管理着不同类型的信号,此链表中的信号类型是不能重复的,sigpending结构体中的list成员管理着同类型的信号,如果有需要且信号是实时信号,那么待处理信号就会被插入sigpending结构体中的list成员对应的队列中。

通过内核驱动(见附件)指定函数和进程ID,可以将进程尚未处理的信号信息打印出来,从下面可以看到,进程收到了信号SIGTERMSIGTERM信号的序号是15,该信号是对整个进程组生效的。

信号发送的原因可以分成三种,一是内核检测到错误发送(比如段错误,但并不是所有的错误都会导致信号产生)进而向进程组发送信号,二是主动发送信号(比如调用kill函数、alarm函数或者使用kill程序),三是外部事件触发的信号(如I/O设备、其他进程)。

通过Shell运行的进程,通过键盘输入CTRL + CCTRL + Z可以向进程发送SIGINTSIGTSTP信号。

进程接收到信号后,会根据信号的类型执行默认的行为(终止进程、终止进程并转储、挂起、忽略信号)。

在C语言中允许程序通过sigaction函数(更加强大,signal函数是sigaction函数的子集)设置指定信号的处理方法,而不是按照默认行为处理。

C语言提供的信号处理函数并不是所有的信号都可以处理的,比如信号SIGKILLSIGSTOP,它们就必须执行默认行为。

有时候程序接收到信号后,我们会想要知道信号发出方的信息,因此下面给出了一种自定义信号处理函数获取发出方信息的办法。

下方直接给出了自定义信号处理操作的示例代码,代码由信号处理、全局跳转、退出处理三个部分组成。

自定义的信号处理函数会打印信号信息以及发送信息方的信息,发送方的信息被存储在my_signal_handle中的siginfo变量内。

运行程序后向程序发送SIGTERM信号后,程序出现如下的打印,从打印中可以看到程序收到信号15(对应SIGTERM),si_code为0对应着SI_USER,代表信号由用户发出,si_uid给出了该用户的用户ID,si_pid给出了发出信号的进程ID。

通过echo $$可以将kill程序运行的进程ID打印出来,该进程ID是和si_pid一致的。

当然这种方法仍然是不能处理某些信号的(如SIGKILLSIGSTOP等等)。

此处以kill程序为例,我们通过strace工具追踪该程序产生的系统调用。

在打印的内容中可以看到,kill程序通过kill函数向内核发出__NR_kill系统调用。

内核会通过SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)__NR_kill系统调用进行接收,其中的kill_something_info函数是实际处理的信号的地方。

kill_something_info函数中不难看出,函数由三个部分组成,它们分别是pid > 0pid = -1pid < 0。,当pid > 0时,发送信号给指定的进程,当pid = -1时,发送信号给自身外的其余进程,当pid < 0时,发送信号给自身作者的进程组。

这里我们重点关注pid > 0的情况。

kill_proc_info函数最终会调用__send_signal_locked函数对信号进行处理。

__send_signal_locked函数的内部,首先会根据type变量判断是添加到给进程组还是线程(是PIDTYPE_PID时添加到线程队列),再通过__sigqueue_alloc分配一个sigqueue,然后sigqueue通过list_add_tail接口添加到task_strutpending成员的链表内,作为待处理信号,最后将信号信息和发送方信息添加到sigqueue内。

complete_signal函数会决定由信号由谁接收。首先判断的条件是wants_signal函数,在当前任务应该接收信号时,会将接收权限交给当前进程,之后如果发现信号是发送给指定线程或单线程进程的话,就会直接返回,最后会从多线程中找到一个可用的线程。

接下来如果发现发现信号是致命的,就会通过signal_wake_up接口给每一个线程都添加上TIF_SIGPENDING标志,反之则只给指定的线程添加TIF_SIGPENDING标志。

TIF_SIGPENDING标志代表存在待处理的信号。

不管出于哪种原因发送信号,它们第一个需要的抵达的目标地点都是相同的,这个目标地点就是内核,那么内核又是如何进一步处理信号的呢?

对于内核而言,它会通过do_signal函数(它是架构指定的,具体名字可能不同)处理信号,下面通过kprobe机制中的pre_handlerarch_do_signal_or_restart函数之前打印出栈回溯(详情可见驱动代码)。

从栈回溯中可以看到,此时用户空间触发系统调用进入内核空间,当do_syscall_64函数执行完系统调用后,会调用syscall_exit_to_user_mode函数从内核空间退回到用户空间,使用arch_do_signal_or_restart函数处理信号的操作也发生在这一阶段。

exit_to_user_mode_loop函数会接收ti_work参数,该参数调用read_thread_flags接口,该接口会从thread_info结构体内读出flags成员,接收ti_work参数后,会检查TIF_SIGPENDING标志位(上面说过,待处理信号会添加该标志位),如果发现TIF_SIGPENDING标志位存在,就说明存在待处理信号此时就会调用arch_do_signal_or_restart函数。

arch_do_signal_or_restart函数响应的操作分成两部分,一是通过get_signal函数获取信号信息,二是通过handle_signal函数处理信号。

handle_signal函数首先会通过test_thread_flag函数检查TIF_SINGLESTEP标志位,该标志位用于标记程序是否被中断下来,如果标志位存在,那就会通过user_disable_single_step函数将TIF_SINGLESTEP标志位清除掉,并通知调试器。

当调试器挂载到程序后,再触发信号时,会发现调试器会先收到通知,之后才是信号处理函数,原因就在这里。

setup_rt_frame函数是一个关键操作,第一步通过get_sigframe获取一个新的栈帧。

新的栈帧通过rt_sigframe结构体描述,其中pretcode代表着信号处理完成后下一步的返回地址,uc记录了上下文信息,info记录了信号信息。

通过user_access_end结束之前的操作,可以将原始的上下文信息保存在用户态程序的栈上。

完成栈上数据的设置操作后,会继续更新用户态程序的寄存器信息,其中当前程序指针寄存器被放置了信号处理函数的地址。

我们在my_signal_handle函数进行处理时将程序中断下来观察栈回溯。

1号栈帧被内核放置了信号处理结束后的操作__restore_rt函数,这个函数非常简单,它会将系统调用号放入rax寄存器内,然后执行系统调用,系统调用号15对应着__NR_rt_sigreturn

__restore_rt函数触发系统调用时就会再次陷入内核当中,内核根据系统调用__NR_rt_sigreturn会触发__do_sys_rt_sigreturn函数。

该函数操作并不复杂,主要就是还原之前保存在栈上的上下文信息。

此时再次回到用户态程序后,程序就会接着执行处理信号前的内容。

在整个信号处理的过程中,内核会将上下文信息保存在用户态程序的栈上,后续再通过sigreturn系统调用发出恢复信号,因为用户态栈是可读可写的,这非常方便我们进行控制,当我么规划好sigreturn所需要的栈数据并触发sigreturn系统调用时,就会让程序跳入我们的控制之内。

那么栈上的上下文信息应该如何构造呢?

被压入栈的上下文信息通过ucontext_t结构体进行描述,ucontext_t结构体中的uc_mcontext成员内的gregs记录着信号处理函数执行前的寄存器信息。

gregs中共包含23个寄存器,下面列出了元素0到元素22对应的寄存器名。

显然当我们控制rip寄存器及传递形参的rdi等寄存器中数值时,就可以借助sigreturn的返回操作跳转到我们期望中的位置,除此之外rsp寄存器也位于栈上,当通过pop rip(如ret)操作获取下一条程序指针时,我们就可以通过控制rsp组成利用链。

程序的源代码和编译命令在下方给出了。

程序并不复杂,为了基于信号返回机制完成ROP,我们这里第一步需要构造sigreturn需要的栈,在pwntool中的SigreturnFrame接口可以直接创造一个假的栈,然后再对里面的数据进行修改。

当我们想要通过execive创建进程时,首先需要考虑的就是参数问题,由于我们需要给寄存器明确指示参数的所在位置,因此我们需要知道一个栈上的地址,并利用它作为基地址填充数据。

这个程序非常简单,因此原始的栈上只包含argcargv、环境变量以及auxv,从argv开始任意的地址都是栈上的地址,程序读取0x400,如果我们可以越过首条指令,让rax为1,那么就可以泄露rsp+0x0rsp+0x400范围内的数据,并轻松的得到一个栈上的地址。

rax寄存器非常好控制,它有一个特殊用途,就是保存返回值,如果我们只读取一个字节,并让程序在结束后从mov $0x400,%edx继续运行,就可以控制rax寄存器,新发送的一个字节会覆盖rsp+0x0数据的最低位字节,当rsp+0x0处原本就存储着一个程序地址,我们再发送mov $0x400,%edx对应的最低字节数据,就可以跳过xor指令。

经过上面的分析后,构造出下面的exploit。

运行exploit后成功获取Shell。

在运行调试脚本的时候发现只有打开pwntool的调试开关后,才可以正常的完成PWN,否则就会失败。

失败之前会先进入交互模式,此时不管你输入什么都会立即失败,比如这里我们直接输入了回车键,然后直接收到了SIGSEGV的崩溃错误。

观察rsp上的数据可以发现回车键对应的ASCII码0x0a被送进了缓冲区当中。

程序仍然在读取信息,这与我们进入交互模式时是与Shell进行交互的初衷有所背离。

显然有部分的信息没有发送给程序。

要知道这是一段极其简单的汇编代码,并且直接通过syscall调用的read接口,并没有给stdout等文件处理缓冲区,由于脚本发送数据的速度过快,同时又没有缓冲区进行临时的存在,导致了数据的丢失,因为开启调试模式后,调试信息的输出需要占用一定的时间,所以send会间隔一段时间后再发送,就不会产生数据丢失的情况。

我们在send之后添加sleep函数,也可也缓解这一问题。

struct signal_struct {
    refcount_t      sigcnt;
    ......
    struct sigpending   shared_pending;
    ......
    struct rw_semaphore exec_update_lock;
} __randomize_layout;
 
struct sigpending {
    struct list_head list;
    sigset_t signal;
};
 
struct taks_struct {
    ......
    struct signal_struct            *signal;
    struct sighand_struct __rcu     *sighand;
    struct sigpending               pending;
    ......
}
struct signal_struct {
    refcount_t      sigcnt;
    ......
    struct sigpending   shared_pending;
    ......
    struct rw_semaphore exec_update_lock;
} __randomize_layout;
 
struct sigpending {
    struct list_head list;
    sigset_t signal;
};
 
struct taks_struct {
    ......
    struct signal_struct            *signal;
    struct sighand_struct __rcu     *sighand;
    struct sigpending               pending;
    ......
}
#define __SIGINFO           \
struct {                \
    int si_signo;           \
    int si_code;            \
    int si_errno;           \
    union __sifields _sifields; \
}
 
typedef struct kernel_siginfo {
    __SIGINFO;
} kernel_siginfo_t;
 
struct sigqueue {
    struct list_head list;
    int flags;
    kernel_siginfo_t info;
    struct ucounts *ucounts;
};
#define __SIGINFO           \
struct {                \
    int si_signo;           \
    int si_code;            \
    int si_errno;           \
    union __sifields _sifields; \
}
 
typedef struct kernel_siginfo {
    __SIGINFO;
} kernel_siginfo_t;
 
struct sigqueue {
    struct list_head list;
    int flags;
    kernel_siginfo_t info;
    struct ucounts *ucounts;
};
arch_do_signal_or_restart
 
[16176.561445]  pending signal ->
[16176.561447]  shared pending signal ->
[16176.561448]          00000000 - signal num = 15 ;
arch_do_signal_or_restart
 
[16176.561445]  pending signal ->
[16176.561447]  shared pending signal ->
[16176.561448]          00000000 - signal num = 15 ;
void (*signal(int sig, void (*func)(int)))(int);
 
int sigaction(int signum,
    const struct sigaction *_Nullable restrict act,
    struct sigaction *_Nullable restrict oldact);
 
特殊的处理函数 ->
    SIG_DFL:执行默认操作
    SIG_IGN:忽略信号
void (*signal(int sig, void (*func)(int)))(int);
 
int sigaction(int signum,
    const struct sigaction *_Nullable restrict act,
    struct sigaction *_Nullable restrict oldact);
 
特殊的处理函数 ->
    SIG_DFL:执行默认操作
    SIG_IGN:忽略信号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <ucontext.h>
 
typedef void (*signal_handle_func)(int, siginfo_t*, void*);
 
#define SIGNAL_REGISTER_FAILED      ((signal_handle_func)-1)
#define SETJMP_RET_VAL_1            2333
#define KRNL_UCNTXT_ELE_CNT         5
 
typedef struct my_signal_info {
    unsigned long sig_num;
    signal_handle_func handle_func;
} my_siginfo;
 
static void my_signal_handle(int, siginfo_t*, void*);
 
static my_siginfo my_si[] = {
    {
        .sig_num = SIGKILL,
        .handle_func = my_signal_handle,
    },
    {
        .sig_num = SIGTERM,
        .handle_func = my_signal_handle,
    },
};
static int ret_num = 0;
static jmp_buf test_jmp_context;
 
static void my_atexit_func(void)
{
    printf("enter %s, program will exit\n", __func__);
}
 
static void my_atexit_register(void (*func)(void))
{
    int ret;
 
    ret = atexit(func);
    if (ret != 0) {
        printf("register atexit function failed\n");
 
        exit(ret);
    }
}
 
static void siginfo_dump(siginfo_t* si)
{
    if (si) {
        printf(
            "\n[**] signinfo (signinfo_t size 0x%llx) - (_sifields size 0x%llx):\n"
            "si_signo = %08d ; si_errno = %08d ; si_code = %08d ;\n"
            "si_pid   = %08d ; si_uid   = %08d ;\n"
            "[--] _sifields will be displayed differently depending on the signal\n"
            "[--] only pid and uid will be shown here\n",
            sizeof(*si), sizeof(si->_sifields),
            si->si_signo, si->si_errno, si->si_code,
            si->_sifields._pad[0], si->_sifields._pad[1]
        );
    }
}
 
static void libc_fpstate_dump(fpregset_t fpregs)
{
    printf(
        "\tcwd = %d ; swd = %d ; ftw = %d ; fop = %d ;\n"
        "\trip = 0x%016lx ; rdp = 0x%016lx ;\n"
        "\tmxcsr = 0x%08x ; mxcr_mask = 0x%08x ;\n"
        "\tno [_st] [_xmm]\n",
        fpregs->cwd,
        fpregs->swd,
        fpregs->ftw,
        fpregs->fop,
        fpregs->rip,
        fpregs->rdp,
        fpregs->mxcsr,
        fpregs->mxcr_mask
    );
}
 
static void ucontext_dump(ucontext_t* ucontext)
{
    ssize_t arr_size, ele_size, ele_cnt;
    int i;
 
    if (ucontext) {
        printf(
            "\n[**] ucontext (ucontext_t size 0x%llx):\n"
            "uc_flags = 0x%016lx ; uc_link = 0x%016lx ;\n"
            "uc_stack (stack_t size 0x%llx) ->\n"
            "\tss_sp = 0x%016lx ; ss_flags = 0x%016lx ; ss_size = 0x%016lx\n"
            "uc_mcontext (mcontext_t size 0x%llx) ->\n"
            "\t---- gregs start ----",
            sizeof(*ucontext),
            ucontext->uc_flags, (unsigned long)ucontext->uc_link, sizeof(ucontext->uc_stack),
            ucontext->uc_stack.ss_sp, ucontext->uc_stack.ss_flags, ucontext->uc_stack.ss_size,
            sizeof(ucontext->uc_mcontext)
        );
 
        i = 0;
        while (i < __NGREG) {
            if ((i % 4) == 0) {
                printf("\n\t");
            }
 
            printf(
                "0x%016lx ; ", ucontext->uc_mcontext.gregs[i]
            );
 
            i++;
        }
 
        printf(
            "\n\t---- gregs end ----\n"
            "\t---- fpregs start -----\n"
        );
        libc_fpstate_dump(ucontext->uc_mcontext.fpregs);
        printf("\t---- fpregs end ----\n");
 
        printf(
            "no uc_sigmask (sigset_t size 0x%llx)\n"
            "__fpregs_mem (_libc_fpstate size 0x%llx) ->\n",
            sizeof(ucontext->uc_sigmask), sizeof(ucontext->__fpregs_mem)
        );
        libc_fpstate_dump(&ucontext->__fpregs_mem);
 
        i = 0;
        arr_size = sizeof(ucontext->__ssp);
        ele_size = sizeof(unsigned long long);
        ele_cnt = arr_size / ele_size;
        printf(
            "__ssp (array size 0x%llx) ->\n\t",
            arr_size
        );
        while (i < 4) {
            printf("0x%016llx ; ", ucontext->__ssp[i]);
 
            i++;
        }
        printf("\n");
    }
}
 
static void my_signal_handle(int signum, siginfo_t* si, void* ucontext)
{
    printf(
        "\n[**] receive signal, signal base info:\n"
        "signal num    = %d \n"
        "signal info   = 0x%016lx\n"
        "user context  = 0x%016lx\n",
        signum, (unsigned long)si, (unsigned long)ucontext
    );
 
    siginfo_dump(si);
    ucontext_dump(ucontext);
}
 
static signal_handle_func my_customize_signal_register_process(my_siginfo* msi)
{
    int ret;
    struct sigaction new_act, old_act;
 
    memset(&new_act, 0, sizeof(struct sigaction));
 
    sigemptyset(&new_act.sa_mask);
    new_act.sa_flags = SA_SIGINFO;
#ifdef  SA_RESTART
    new_act.sa_flags |= SA_RESTART;
#endif
    new_act.sa_sigaction = msi->handle_func;
 
    ret = sigaction(msi->sig_num, &new_act, &old_act);
    if (ret != 0) {
        return SIGNAL_REGISTER_FAILED;
    }
 
    return old_act.sa_sigaction;
}
 
static void my_signal_register(void)
{
    signal_handle_func tmp_func;
    size_t arry_size, ele_size, ele_cnt;
 
    arry_size = sizeof(my_si);
    ele_size = sizeof(my_siginfo);
    ele_cnt = arry_size / ele_size;
 
    do {
        tmp_func = my_customize_signal_register_process(&my_si[ele_cnt - 1]);
        if (tmp_func == SIGNAL_REGISTER_FAILED) {
            printf("cannot register signo %d, errno %d\n", my_si[ele_cnt - 1].sig_num, errno);
        }
        else {
            printf("register signo %d succeed\n", my_si[ele_cnt - 1].sig_num);
        }
    } while(--ele_cnt);
}
 
static void my_signal_setting(void)
{
    my_atexit_register(my_atexit_func);
 
    my_signal_register();
}
 
static void setting4globaljmp(void)
{
    printf("enter %s\n", __func__);
 
    longjmp(test_jmp_context, SETJMP_RET_VAL_1);
 
    printf("leave %s\n", __func__);
}
 
static void global_jmp_test(void)
{
    int cur_ret_val;
 
    cur_ret_val = setjmp(test_jmp_context);
    printf("num %d -> setjmp return: %d\n", ret_num, cur_ret_val);
    ret_num++;
 
    if (cur_ret_val == 0) {
        setting4globaljmp();
    }
}
 
int main(void)
{
    my_signal_setting();
    global_jmp_test();
 
    printf("pid = %d, waiting for a signal\n", getpid());
    pause();
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <ucontext.h>
 
typedef void (*signal_handle_func)(int, siginfo_t*, void*);
 
#define SIGNAL_REGISTER_FAILED      ((signal_handle_func)-1)
#define SETJMP_RET_VAL_1            2333
#define KRNL_UCNTXT_ELE_CNT         5
 
typedef struct my_signal_info {
    unsigned long sig_num;
    signal_handle_func handle_func;
} my_siginfo;
 
static void my_signal_handle(int, siginfo_t*, void*);
 
static my_siginfo my_si[] = {
    {
        .sig_num = SIGKILL,
        .handle_func = my_signal_handle,
    },
    {
        .sig_num = SIGTERM,
        .handle_func = my_signal_handle,
    },
};
static int ret_num = 0;
static jmp_buf test_jmp_context;
 
static void my_atexit_func(void)
{
    printf("enter %s, program will exit\n", __func__);
}
 
static void my_atexit_register(void (*func)(void))
{
    int ret;
 
    ret = atexit(func);
    if (ret != 0) {
        printf("register atexit function failed\n");
 
        exit(ret);
    }
}
 
static void siginfo_dump(siginfo_t* si)
{
    if (si) {
        printf(
            "\n[**] signinfo (signinfo_t size 0x%llx) - (_sifields size 0x%llx):\n"
            "si_signo = %08d ; si_errno = %08d ; si_code = %08d ;\n"
            "si_pid   = %08d ; si_uid   = %08d ;\n"
            "[--] _sifields will be displayed differently depending on the signal\n"
            "[--] only pid and uid will be shown here\n",
            sizeof(*si), sizeof(si->_sifields),
            si->si_signo, si->si_errno, si->si_code,
            si->_sifields._pad[0], si->_sifields._pad[1]
        );
    }
}
 
static void libc_fpstate_dump(fpregset_t fpregs)
{
    printf(
        "\tcwd = %d ; swd = %d ; ftw = %d ; fop = %d ;\n"
        "\trip = 0x%016lx ; rdp = 0x%016lx ;\n"
        "\tmxcsr = 0x%08x ; mxcr_mask = 0x%08x ;\n"
        "\tno [_st] [_xmm]\n",
        fpregs->cwd,
        fpregs->swd,
        fpregs->ftw,
        fpregs->fop,
        fpregs->rip,
        fpregs->rdp,
        fpregs->mxcsr,
        fpregs->mxcr_mask
    );
}
 
static void ucontext_dump(ucontext_t* ucontext)
{
    ssize_t arr_size, ele_size, ele_cnt;
    int i;
 
    if (ucontext) {
        printf(
            "\n[**] ucontext (ucontext_t size 0x%llx):\n"
            "uc_flags = 0x%016lx ; uc_link = 0x%016lx ;\n"
            "uc_stack (stack_t size 0x%llx) ->\n"
            "\tss_sp = 0x%016lx ; ss_flags = 0x%016lx ; ss_size = 0x%016lx\n"
            "uc_mcontext (mcontext_t size 0x%llx) ->\n"
            "\t---- gregs start ----",
            sizeof(*ucontext),
            ucontext->uc_flags, (unsigned long)ucontext->uc_link, sizeof(ucontext->uc_stack),
            ucontext->uc_stack.ss_sp, ucontext->uc_stack.ss_flags, ucontext->uc_stack.ss_size,
            sizeof(ucontext->uc_mcontext)
        );
 
        i = 0;
        while (i < __NGREG) {
            if ((i % 4) == 0) {
                printf("\n\t");
            }
 
            printf(
                "0x%016lx ; ", ucontext->uc_mcontext.gregs[i]
            );
 
            i++;
        }
 
        printf(
            "\n\t---- gregs end ----\n"
            "\t---- fpregs start -----\n"
        );
        libc_fpstate_dump(ucontext->uc_mcontext.fpregs);
        printf("\t---- fpregs end ----\n");
 
        printf(
            "no uc_sigmask (sigset_t size 0x%llx)\n"
            "__fpregs_mem (_libc_fpstate size 0x%llx) ->\n",
            sizeof(ucontext->uc_sigmask), sizeof(ucontext->__fpregs_mem)
        );
        libc_fpstate_dump(&ucontext->__fpregs_mem);
 
        i = 0;
        arr_size = sizeof(ucontext->__ssp);
        ele_size = sizeof(unsigned long long);
        ele_cnt = arr_size / ele_size;
        printf(
            "__ssp (array size 0x%llx) ->\n\t",
            arr_size
        );
        while (i < 4) {
            printf("0x%016llx ; ", ucontext->__ssp[i]);
 
            i++;
        }
        printf("\n");
    }
}
 
static void my_signal_handle(int signum, siginfo_t* si, void* ucontext)
{
    printf(
        "\n[**] receive signal, signal base info:\n"
        "signal num    = %d \n"
        "signal info   = 0x%016lx\n"
        "user context  = 0x%016lx\n",
        signum, (unsigned long)si, (unsigned long)ucontext
    );
 
    siginfo_dump(si);
    ucontext_dump(ucontext);
}
 
static signal_handle_func my_customize_signal_register_process(my_siginfo* msi)
{
    int ret;
    struct sigaction new_act, old_act;
 
    memset(&new_act, 0, sizeof(struct sigaction));
 
    sigemptyset(&new_act.sa_mask);
    new_act.sa_flags = SA_SIGINFO;
#ifdef  SA_RESTART
    new_act.sa_flags |= SA_RESTART;
#endif
    new_act.sa_sigaction = msi->handle_func;
 
    ret = sigaction(msi->sig_num, &new_act, &old_act);
    if (ret != 0) {
        return SIGNAL_REGISTER_FAILED;
    }
 
    return old_act.sa_sigaction;
}
 
static void my_signal_register(void)
{
    signal_handle_func tmp_func;
    size_t arry_size, ele_size, ele_cnt;
 
    arry_size = sizeof(my_si);
    ele_size = sizeof(my_siginfo);
    ele_cnt = arry_size / ele_size;
 
    do {
        tmp_func = my_customize_signal_register_process(&my_si[ele_cnt - 1]);
        if (tmp_func == SIGNAL_REGISTER_FAILED) {
            printf("cannot register signo %d, errno %d\n", my_si[ele_cnt - 1].sig_num, errno);
        }
        else {
            printf("register signo %d succeed\n", my_si[ele_cnt - 1].sig_num);
        }
    } while(--ele_cnt);
}
 
static void my_signal_setting(void)
{
    my_atexit_register(my_atexit_func);
 
    my_signal_register();
}
 
static void setting4globaljmp(void)
{
    printf("enter %s\n", __func__);
 
    longjmp(test_jmp_context, SETJMP_RET_VAL_1);
 
    printf("leave %s\n", __func__);
}
 
static void global_jmp_test(void)
{
    int cur_ret_val;
 
    cur_ret_val = setjmp(test_jmp_context);
    printf("num %d -> setjmp return: %d\n", ret_num, cur_ret_val);
    ret_num++;
 
    if (cur_ret_val == 0) {
        setting4globaljmp();
    }
}
 
int main(void)
{
    my_signal_setting();
    global_jmp_test();
 
    printf("pid = %d, waiting for a signal\n", getpid());
    pause();
}
程序运行结果:
register signo 15 succeed
cannot register signo 9, errno 22
num 0 -> setjmp return: 0
enter setting4globaljmp
num 1 -> setjmp return: 2333
pid = 10411, waiting for a signal
 
[**] receive signal, signal base info:
signal num    = 15
signal info   = 0x00007ffd67435e30
user context  = 0x00007ffd67435d00
 
[**] signinfo (signinfo_t size 0x80) - (_sifields size 0x70):
si_signo = 00000015 ; si_errno = 00000000 ; si_code = 00000000 ;
si_pid   = 00009013 ; si_uid   = 00001000 ;
[--] _sifields will be displayed differently depending on the signal
[--] only pid and uid will be shown here
 
[**] ucontext (ucontext_t size 0x3c8):
uc_flags = 0x0000000000000006 ; uc_link = 0x0000000000000000 ;
uc_stack (stack_t size 0x18) ->
        ss_sp = 0x0000000000000000 ; ss_flags = 0x0000000000000000 ; ss_size = 0x0000000000000000
uc_mcontext (mcontext_t size 0x100) ->
        ---- gregs start ----
        0x0000000000000000 ; 0x0000000000000064 ; 0x00007ffd67436053 ; 0x0000000000000202 ;
        0x0000000000000000 ; 0x00007ffd674362a8 ; 0x0000000000403d78 ; 0x00007f8de3eec020 ;
        0x00007ffd67435c20 ; 0x0000000001b612a0 ; 0x00007ffd67436180 ; 0x00007ffd67436298 ;
        0x0000000000000000 ; 0xfffffffffffffffc ; 0x00007f8de3d93d10 ; 0x00007ffd67436178 ;
        0x00007f8de3d93d10 ; 0x0000000000000202 ; 0x002b000000000033 ; 0x0000000000000000 ;
        0x0000000000000000 ; 0x0000000000000000 ; 0x0000000000000000 ;
        ---- gregs end ----
        ---- fpregs start -----
        cwd = 895 ; swd = 0 ; ftw = 0 ; fop = 0 ;
        rip = 0x0000000000000000 ; rdp = 0x0000000000000000 ;
        mxcsr = 0x00001f80 ; mxcr_mask = 0x0002ffff ;
        no [_st] [_xmm]
        ---- fpregs end ----
no uc_sigmask (sigset_t size 0x80)
__fpregs_mem (_libc_fpstate size 0x200) ->
        cwd = 0 ; swd = 0 ; ftw = 0 ; fop = 0 ;
        rip = 0x0000000000000000 ; rdp = 0x0000000000000000 ;
        mxcsr = 0x0000037f ; mxcr_mask = 0x00000000 ;
        no [_st] [_xmm]
__ssp (array size 0x20) ->
        0x0000000000000000 ; 0x0000000000000000 ; 0x0000000000000000 ; 0x00007ffd67436160 ;
enter my_atexit_func, program will exit
 
主动触发程序信息:
kill -s SIGTERM 10411
echo $$
9013
程序运行结果:
register signo 15 succeed
cannot register signo 9, errno 22
num 0 -> setjmp return: 0
enter setting4globaljmp
num 1 -> setjmp return: 2333
pid = 10411, waiting for a signal
 
[**] receive signal, signal base info:
signal num    = 15
signal info   = 0x00007ffd67435e30
user context  = 0x00007ffd67435d00
 
[**] signinfo (signinfo_t size 0x80) - (_sifields size 0x70):
si_signo = 00000015 ; si_errno = 00000000 ; si_code = 00000000 ;
si_pid   = 00009013 ; si_uid   = 00001000 ;
[--] _sifields will be displayed differently depending on the signal
[--] only pid and uid will be shown here
 
[**] ucontext (ucontext_t size 0x3c8):
uc_flags = 0x0000000000000006 ; uc_link = 0x0000000000000000 ;
uc_stack (stack_t size 0x18) ->
        ss_sp = 0x0000000000000000 ; ss_flags = 0x0000000000000000 ; ss_size = 0x0000000000000000
uc_mcontext (mcontext_t size 0x100) ->
        ---- gregs start ----
        0x0000000000000000 ; 0x0000000000000064 ; 0x00007ffd67436053 ; 0x0000000000000202 ;
        0x0000000000000000 ; 0x00007ffd674362a8 ; 0x0000000000403d78 ; 0x00007f8de3eec020 ;
        0x00007ffd67435c20 ; 0x0000000001b612a0 ; 0x00007ffd67436180 ; 0x00007ffd67436298 ;
        0x0000000000000000 ; 0xfffffffffffffffc ; 0x00007f8de3d93d10 ; 0x00007ffd67436178 ;
        0x00007f8de3d93d10 ; 0x0000000000000202 ; 0x002b000000000033 ; 0x0000000000000000 ;
        0x0000000000000000 ; 0x0000000000000000 ; 0x0000000000000000 ;
        ---- gregs end ----
        ---- fpregs start -----
        cwd = 895 ; swd = 0 ; ftw = 0 ; fop = 0 ;
        rip = 0x0000000000000000 ; rdp = 0x0000000000000000 ;
        mxcsr = 0x00001f80 ; mxcr_mask = 0x0002ffff ;
        no [_st] [_xmm]
        ---- fpregs end ----
no uc_sigmask (sigset_t size 0x80)
__fpregs_mem (_libc_fpstate size 0x200) ->
        cwd = 0 ; swd = 0 ; ftw = 0 ; fop = 0 ;
        rip = 0x0000000000000000 ; rdp = 0x0000000000000000 ;
        mxcsr = 0x0000037f ; mxcr_mask = 0x00000000 ;
        no [_st] [_xmm]
__ssp (array size 0x20) ->
        0x0000000000000000 ; 0x0000000000000000 ; 0x0000000000000000 ; 0x00007ffd67436160 ;
enter my_atexit_func, program will exit
 
主动触发程序信息:
kill -s SIGTERM 10411
echo $$
9013
strace /usr/bin/kill -s SIGTERM 2790
    execve("/usr/bin/kill", ["/usr/bin/kill", "-s", "SIGTERM", "2790"], 0x7ffc5e9561a8 /* 31 vars */) = 0
    ......
    kill(2790, SIGTERM)
    exit_group(0)                           = ?
    +++ exited with 0 +++
strace /usr/bin/kill -s SIGTERM 2790
    execve("/usr/bin/kill", ["/usr/bin/kill", "-s", "SIGTERM", "2790"], 0x7ffc5e9561a8 /* 31 vars */) = 0
    ......
    kill(2790, SIGTERM)
    exit_group(0)                           = ?
    +++ exited with 0 +++
#define __NR_kill 62
#define __NR_kill 62
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{
    struct kernel_siginfo info;
 
    prepare_kill_siginfo(sig, &info);
 
    return kill_something_info(sig, &info, pid);
}
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{
    struct kernel_siginfo info;
 
    prepare_kill_siginfo(sig, &info);
 
    return kill_something_info(sig, &info, pid);
}
static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
{
    int ret;
 
    if (pid > 0)
        return kill_proc_info(sig, info, pid);
 
    /* -INT_MIN is undefined.  Exclude this case to avoid a UBSAN warning */
    if (pid == INT_MIN)
        return -ESRCH;
 
    read_lock(&tasklist_lock);
    if (pid != -1) {
        ......
    } else {
        ......
    }
    read_unlock(&tasklist_lock);
 
    return ret;
}
static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
{
    int ret;
 
    if (pid > 0)
        return kill_proc_info(sig, info, pid);
 
    /* -INT_MIN is undefined.  Exclude this case to avoid a UBSAN warning */
    if (pid == INT_MIN)
        return -ESRCH;
 
    read_lock(&tasklist_lock);
    if (pid != -1) {
        ......
    } else {
        ......
    }
    read_unlock(&tasklist_lock);
 
    return ret;
}
kill_proc_info
    ->   kill_pid_info
        ->   group_send_sig_info
            ->   do_send_sig_info
                -> send_signal_locked
                    -> __send_signal_locked
 
enum pid_type
{
    PIDTYPE_PID,
    PIDTYPE_TGID,
    PIDTYPE_PGID,
    PIDTYPE_SID,
    PIDTYPE_MAX,
};
 
static int __send_signal_locked(int sig, struct kernel_siginfo *info,
                struct task_struct *t, enum pid_type type, bool force)
{
    ......
    pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
    ......
    q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);
    ......
    if (q) {
        list_add_tail(&q->list, &pending->list);
        switch ((unsigned long) info) {
        case (unsigned long) SEND_SIG_NOINFO:
        clear_siginfo(&q->info);
            q->info.si_signo = sig;
            q->info.si_errno = 0;
            q->info.si_code = SI_USER;
            q->info.si_pid = task_tgid_nr_ns(current,
                            task_active_pid_ns(t));
            rcu_read_lock();
            q->info.si_uid =
                from_kuid_munged(task_cred_xxx(t, user_ns),
                         current_uid());
            rcu_read_unlock();
            break;
        ......
        }
    }
    ......
    complete_signal(sig, t, type);
    ......
}
kill_proc_info
    ->   kill_pid_info
        ->   group_send_sig_info
            ->   do_send_sig_info
                -> send_signal_locked
                    -> __send_signal_locked
 
enum pid_type
{
    PIDTYPE_PID,
    PIDTYPE_TGID,
    PIDTYPE_PGID,
    PIDTYPE_SID,
    PIDTYPE_MAX,
};
 
static int __send_signal_locked(int sig, struct kernel_siginfo *info,
                struct task_struct *t, enum pid_type type, bool force)
{
    ......
    pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
    ......
    q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);
    ......
    if (q) {
        list_add_tail(&q->list, &pending->list);
        switch ((unsigned long) info) {
        case (unsigned long) SEND_SIG_NOINFO:
        clear_siginfo(&q->info);
            q->info.si_signo = sig;
            q->info.si_errno = 0;
            q->info.si_code = SI_USER;
            q->info.si_pid = task_tgid_nr_ns(current,
                            task_active_pid_ns(t));
            rcu_read_lock();
            q->info.si_uid =
                from_kuid_munged(task_cred_xxx(t, user_ns),
                         current_uid());
            rcu_read_unlock();

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-10-9 20:56 被福建炒饭乡会编辑 ,原因: 添加驱动附件
上传的附件:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//