加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux – 如何使用ptrace跳过系统调用?

发布时间:2020-12-14 01:07:09 所属栏目:Linux 来源:网络整理
导读:我正在尝试使用ptrace编写一个程序来跟踪孩子所做的所有系统调用. 现在我有一个禁止孩子的系统调用列表.我能够使用ptrace跟踪所有系统调用,但我只是不知道如何跳过特定的系统调用. 目前,我的跟踪(父)进程在每次进入或退出系统调用(PTRACE_SYSCALL)时都会收到
我正在尝试使用ptrace编写一个程序来跟踪孩子所做的所有系统调用.

现在我有一个禁止孩子的系统调用列表.我能够使用ptrace跟踪所有系统调用,但我只是不知道如何跳过特定的系统调用.

目前,我的跟踪(父)进程在每次进入或退出系统调用(PTRACE_SYSCALL)时都会收到一个信号.但如果孩子试图进入禁止的系统呼叫,那么我不想让孩子跳过该呼叫并转到下一步.此外,当我这样做时,我希望孩子知道有一个权限被拒绝错误,所以我将设置errno = 13,这还够吗?

更新:
gdb提供了跳过一行的这个功能.gdb使用什么机制?

怎么实现呢?

更新:
使用ptrace实现此目的的最佳方法是将原始系统调用重定向到其他系统调用,例如nanosleep()调用.此调用将失败,因为它将收到非法参数.然后你只需要将EAX中的返回码更改为-EACCES,以假装由于Permission denied错误而导致调用失败.

解决方法

我找到了两个大学讲座,提到无法中止已启动的系统调用,这是ptrace的一个缺点(该联机帮助页提到了一个PTRACE_SYSEMU宏看起来可以这样做,但是较新的标题没有它).从理论上讲,你可以利用ptrace入口和出口停止来抵消你不想要的调用 – 通过交换导致系统调用失败或什么也不做的虚假参数,或者通过注入代码来反击以前的系统调用,但这似乎非常hacky.

在Linux上,您应该能够通过seccomp实现目标:

#include <fcntl.h>
#include <seccomp.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

static int set_security(){
    int rc = -1;
    scmp_filter_ctx ctx;
    struct scmp_arg_cmp arg_cmp[] = { SCMP_A0(SCMP_CMP_EQ,2) };

    ctx = seccomp_init(SCMP_ACT_ERRNO(ENOSYS));
    /*ctx = seccomp_init(SCMP_ACT_ALLOW);*/
    if (ctx == NULL)
        goto out;

    rc = seccomp_rule_add(ctx,SCMP_ACT_ALLOW,SCMP_SYS(exit),0);
    if (rc < 0)
        goto out;
    rc = seccomp_rule_add(ctx,SCMP_SYS(close),0);
    if (rc < 0)
        goto out;

    rc = seccomp_rule_add(ctx,SCMP_SYS(write),1,SCMP_CMP(0,SCMP_CMP_EQ,1));
    if (rc < 0)
        goto out;

    rc = seccomp_rule_add_array(ctx,arg_cmp);
    if (rc < 0)
        goto out;

    rc = seccomp_load(ctx);
    if (rc < 0)
        goto out;

    /* ... */

out:
    seccomp_release(ctx);
    return -rc;
}
int main(int argc,char *argv[])
{
    int fd;
    const char out_msg[] = "stdout testn";
    const char err_msg[] = "stderr testn";
    if(0>set_security())
        return 1;
    if(0>write(1,out_msg,sizeof(out_msg)))
        perror("Write stdout");
    if(0>write(2,err_msg,sizeof(err_msg)))
        perror("Write stderr");

    //This should fail with ENOSYS
    if(0>(fd=open("/dev/zero",O_RDONLY)))
        perror("open");

    exit(0);

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读