Go+eBPF kprobe 禁止运行指定程序

Go+eBPF kprobe 禁止运行指定程序

1. 说明

本文属于专栏 Go语言+libbpfgo实战eBPF开发,示例代码目录为 001

如何下载并运行代码,请参考 专栏介绍。

注: 老学员可以直接 git pull 拉取最新代码。


2. 引言

上节课,我们学习了如何通过 tracepoint 监控进程的执行。今天,我们更进一步,学习如何使用 eBPF + kprobe 来禁止运行指定程序。

在某些场景下,我们希望限制某些程序的运行,比如:

  • 禁止 reboot,防止服务器被重启
  • 禁止 wget,防止未经授权的文件下载
  • 禁止 insmod,防止恶意模块加载

那么,如何用 eBPF 实现这一需求呢?🤔


3. 原理

在 Linux 中,execve 是用户态程序创建进程、执行新程序的关键系统调用。它的作用是用新的可执行文件替换当前进程的地址空间。我们可以利用 eBPF 挂载到 execve,拦截其执行并进行控制。

3.1 kprobe 介绍

什么是 kprobe

kprobe(Kernel Probe)是一种非常强大的 Linux 机制,它允许我们动态插入探针(Probe),以监控内核中的任意函数

当被探测的内核函数执行时,kprobe 会触发回调函数,我们可以在回调函数中收集信息、修改参数,甚至影响内核行为。

kprobe 的工作方式

kprobe 主要包含以下几种类型:

  1. kprobe:在目标函数的入口处插入探针
  2. kretprobe:在目标函数返回时插入探针
  3. jprobe(已废弃):可以捕获函数的所有参数

本项目使用 kprobe,即在 execve 被调用时立刻触发,并决定是否拦截该系统调用。


3.2 实现思路

我们的核心思路如下:

  1. 使用 kprobe 挂载到 __x64_sys_execve,监听所有进程的 execve 调用
  2. 读取要执行的文件路径,获取 filename
  3. 检查规则列表(rule_list),判断该路径是否在禁止名单中
  4. 拦截 execve 调用:如果匹配,则调用 bpf_override_return(),直接让 execve 返回 -1,进程执行失败

📌 bpf_override_return()eBPF 提供的 API,它允许我们修改被 Hook 函数的返回值。在本例中,我们让 execve 返回 -1,程序就无法运行了。


3.3 kprobe 挂载点选择

在 Linux 内核中,execve 主要有两种:

  1. sys_execve(老版本4.17之前的内核)
  2. __x64_sys_execve(4.17及之后的 x86_64 内核)

大多数现代 x86_64 内核都使用 __x64_sys_execve,因此我们挂载 kprobe 到该函数:

SEC("kprobe/__x64_sys_execve")
int BPF_KPROBE(probe_execve, struct pt_regs *regs)

📌 为什么不使用 tracepoint

  • tracepoint 设计的目的主要是用来监控(trace), 而不是拦截。它虽然也能监控到 execve的执行, 但是拦截起来比较麻烦。
  • kprobe 更灵活,可以在 execve 真正执行前 进行拦截,适合阻止程序运行。
    • 注: 需要开启CONFIG_BPF_KPROBE_OVERRIDE=y, Ubuntu 24.04 默认开启。

4. 代码详解

4.1 eBPF 代码

4.1.1 代码整体逻辑

BPF 代码主要完成以下几件事:

  • 监听 execve
  • 读取要执行的文件路径
  • 遍历 rule_list,判断是否在禁止列表中
  • 如果匹配,则拦截 execve,并向用户空间发送事件
4.1.2 代码解析
struct event_t {
    pid_t ppid;
    pid_t pid;
    int ret;
    char comm[16];
    char filename[FILE_NAME_MAX];
};

SEC("kprobe/__x64_sys_execve")
int BPF_KPROBE(probe_execve, struct pt_regs *regs)
{
    struct event_t event = { 0, };
    fill_event_base_info(&event);

    // 获取进程要执行的文件路径
    const char *filename_str = (char *)PT_REGS_PARM1_CORE(regs);
    bpf_probe_read_str(&event.filename, FILE_NAME_MAX, filename_str);

    // 遍历 rule_list,判断是否禁止执行
    bpf_for_each_map_elem(&rule_list, &rule_list_cb, &event, 0);

    if (event.ret == -1) {
        // 拦截 execve,返回 -1,阻止进程执行
        bpf_override_return(ctx, event.ret);
        // 只上报被禁止的执行事件
        bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
    }

    return 0;
}

📌 关键点解析

  • BPF_KPROBE 宏, 方便我们定义 kprobe 探针, 他会自动帮我们转换函数参数, 宏展开后大概是这个样子:

    • int probe_execve(struct pt_regs *ctx){
          regs = (struct pt_regs *)PT_REGS_PARM1_CORE(ctx);
          return ___probe_execve(ctx, regs)
      }
      int ____probe_execve(struct pt_regs *ctx, struct pt_regs *regs)
      
    • 这里出现2次struct pt_regs可能有些难理解, 我尝试解释一下:
    • struct pt_regs *ctx 这个ctx参数是kprobe机制提供的, 里面包括了被hook函数的参数信息
    • struct pt_regs *regs 这个regs参数是__x64_sys_execve系统调用的参数, 4.17内核之后所有的系统调用参数都统一是struct pt_regs *regs, 而实际要用到的参数(例如文件路径)需要额外再使用PT_REGS_PARMx_CORE获取.
  • PT_REGS_PARM1_CORE(regs) 获取 execve 系统调用的第一个参数,即要执行的程序路径

  • bpf_probe_read_str() 读取该路径

  • bpf_for_each_map_elem() 遍历 rule_list,检查是否禁止

  • 如果匹配,bpf_override_return(ctx, event.ret) 直接让 execve 失败


4.2 Go 代码

4.2.1 代码整体逻辑

用户态 Go 代码的职责:

  1. 加载 BPF:加载 bpf 代码,并挂载到 kprobe
  2. 管理规则:向 rule_list 添加要禁止的程序
  3. 监听事件:通过 perf buffer 监听 bpf 发送的事件
4.2.2 代码解析
func main() {
    ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
    defer stop()

    log.SetLevel(log.DebugLevel)

    // 加载 BPF
    bpfModule, err := util.BpfLoadAndAttach("bpf.o")
    if err != nil {
        log.Fatalf("%+v", err)
    }
    defer bpfModule.Close()

    // 获取规则 map
    facMap, err := bpfModule.GetMap("rule_list")
    if err != nil {
        log.Fatalf("get rule_list map error: %v", err)
    }

    // 添加规则:禁止 /usr/bin/ping
    r := NewRule("/usr/bin/ping", 1)
    err = r.UpdateMap(facMap, 0)
    if err != nil {
        log.Fatalf("add rule error: %v", err)
    }

    // 监听 perf buffer 事件
    eventsChannel := make(chan []byte)
    lostChannel := make(chan uint64)
    pb, err := bpfModule.InitPerfBuf("events", eventsChannel, lostChannel, 1024)
    if err != nil {
        log.Fatalf("%+v", err)
    }
    pb.Start()
    defer pb.Close()

    processEvents(eventsChannel, lostChannel, ctx)
}

📌 关键点解析

  • util.BpfLoadAndAttach("bpf.o") 加载 bpf 代码
  • facMap, err := bpfModule.GetMap("rule_list") 获取 eBPF map
  • r := NewRule("/usr/bin/ping", 1) 添加规则,禁止 ping
  • processEvents(eventsChannel, lostChannel, ctx) 监听 bpf 发送的事件

这里应该没有太多难点, 如果大家有问题欢迎留言交流.


5. 总结

在本篇文章中,我们学习了如何:

  • 使用 kprobe 监听 execve
  • 通过 bpf_override_return 阻止程序执行
  • Go 代码中管理 eBPF map
  • 监听 perf buffer,查看哪些进程被阻止

✅ 你现在可以用 eBPF 禁止特定程序的运行了!


6. 练习题

  1. 修改代码,使其可以通过 命令行参数 传入要禁止的程序路径
  2. rule_list 支持 同时禁止多个程序

👉 你能实现吗?试试看! 🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/983828.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用Deepseek写一个五子棋微信小程序

在当今快节奏的生活中,休闲小游戏成为了许多人放松心情的好选择。五子棋作为一款经典的策略游戏,不仅规则简单,还能锻炼思维。最近,我借助 DeepSeek 的帮助,开发了一款五子棋微信小程序。在这篇文章中,我将…

【Raspberry Pi 5 测评】无显示器上手指南

【Raspberry Pi 5 测评】无显示器上手指南 一、硬件开箱二、系统安装2.1 安装 Raspberry Pi Imager2.2 安装 Rasberry Pi OS 三、系统登录3.1 ping测试3.2 SSH登录 四、远程桌面4.1 启用VNC服务4.2 使用VNC客户端 五、软件安装5.1 替换软件源5.2 安装常用软件 六、参考链接 摘要…

图像标注与OCR工具分析

图像标注和OCR(光学字符识别)工具的代码进行详细分析。该工具允许用户在图像上进行矩形标注,使用 OCR 对标注区域进行文本识别,并将结果保存为 Excel 文件。同时,用户可以保存和加载标注,清除标注&#xff…

使用Node.js从零搭建DeepSeek本地部署(Express框架、Ollama)

目录 1.安装Node.js和npm2.初始化项目3.安装Ollama4.下载DeepSeek模型5.创建Node.js服务器6.运行服务器7.Web UI对话-Chrome插件-Page Assist 1.安装Node.js和npm 首先确保我们机器上已经安装了Node.js和npm。如果未安装,可以通过以下链接下载并安装适合我们操作系…

基于粒子群算法的配电网重构

一、配电网重构原理 定义: 配电网重构是指在满足运行约束的前提下,通过改变开关状态优化配电网性能,提高系统的经济效益和运行效率。 拓扑约束: 配电网必须保持径向拓扑,避免环网或孤岛。采用算法控制开关状态的选择&…

下载Hugging Face模型的几种方式

1.网页下载 直接访问Hugging Face模型页面,点击“File and versions”选项卡,选择所需的文件进行下载。 2.使用huggingface-cli 首先,安装huggingface_hub: pip install huggingface_hub 然后,使用以下命令下载模型&#xff1…

【Dubbo+Zookeeper】——SpringBoot+Dubbo+Zookeeper知识整合

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL&#xff0…

DeepSeek R1 学习笔记

DeepSeek为了方便大众的使用,同时提供了6个蒸馏版本 DeekSeek使用方式 1.大众方式: 网页版:DeepSeek App版:手机各大应用商店下载安装DeepSeek-AI智能对话助手 2.专业用户 开发者:调用API DeepSeek服务器 网址&a…

《从零构建企业级容器镜像生态:Harbor与Registry双星架构实战手记》

目录 一、企业级镜像中枢:Harbor架构深度解析 1.Harbor介绍 环境准备 2. Harbor战略部署 下载安装Harbor 关键配置文件 报错一 添加本地解析 登录测试Harbor 报错二 登录成功 测试 成功显示 二、轻量化镜像驿站:Registry闪电战部署 简单介…

FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解

FPGA之Usb数据传输 Usb 通信 你也许会有疑问,明明有这么多通信方式和数据传输(SPI、I2C、UART、以太网)为什么偏偏使用USB呢? 原因有很多,如下: 1. 高速数据传输能力 高带宽:USB接口提供了较高的数据传…

mysql中in和exists的区别?

大家好,我是锋哥。今天分享关于【mysql中in和exists的区别?】面试题。希望对大家有帮助; mysql中in和exists的区别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中,IN 和 EXISTS 都用于进行子查询,但它…

Unity摄像机跟随物体

功能描述 实现摄像机跟随物体,并使物体始终保持在画面中心位置。 实现步骤 创建脚本:在Unity中创建一个新的C#脚本,命名为CameraFollow。 代码如下: using UnityEngine;public class CameraFollow : MonoBehaviour {public Tran…

springcloud sentinel教程

‌QPS(Queries Per Second)即每秒查询率 TPS,每秒处理的事务数目 PV(page view)即页面浏览量 UV 访问数(Unique Visitor)指独立访客访问数 一、初识Sentinel 什么是雪崩问题? 微服务之间相…

【Tools】Windows下Git 2.48安装教程详解

00. 目录 文章目录 00. 目录01. Git简介02. Git参考资料03. Git安装04. Git测试05. 附录 01. Git简介 Git(读音为/gɪt/。)是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理。 [1] Git 是 Linus Torvalds 为了帮助管理 Linux 内核…

【Linux系统编程】初识系统编程

目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理(Process Management)2. 内存管理(Memory Management)3. 文…

神经网络|(十四)|霍普菲尔德神经网络-Hebbian训练

【1】引言 前序学习进程中,除了对基本的神经网络知识进行了学习,还掌握了SOM神经网络原理,文章链接包括且不限于: 神经网络|(十一)|神经元和神经网络-CSDN博客 神经网络|(十二)|常见激活函数-CSDN博客 神经网络|(十三)|SOM神经…

Hive八股

Hive八股 说一下GC模型遇到过gc调优吗yarn有哪些了解讲讲hqI转化为MR源码hbase读写流程hive数据倾斜page cache和buffer的区别和相同近来你关注了大数据生态哪些领域的发展,比如新的feature,新的领域等 Hive1Hive1hive简介2hive架构3hive与Hadoop的关系4…

Docker 部署 Graylog 日志管理系统

Docker 部署 Graylog 日志管理系统 前言一、准备工作二、Docker Compose 配置三、启动 Graylog 服务四、访问 Graylog Web 界面总结 前言 Graylog 是一个开源的日志管理平台,专为实时日志收集、分析和可视化设计。它支持强大的搜索功能,并且与 Elastics…

im即时聊天客服系统SaaS还是私有化部署:成本、安全与定制化的权衡策略

随着即时通讯技术的不断发展,IM即时聊天客服系统已经成为企业与客户沟通、解决问题、提升用户体验的重要工具。在选择IM即时聊天客服系统时,企业面临一个重要决策:选择SaaS(软件即服务)解决方案,还是进行私…

MySQL(单表)知识点

文章目录 1.数据库的概念2.下载并配置MySQL2.1初始化MySQL的数据2.2注册MYSQL服务2.3启动MYSQL服务2.4修改账户默认密码2.5登录MYSQL2.6卸载MYSQL 3.MYSQL数据模型3.1连接数据库 4.SQL简介4.1SQL的通用语法4.2SQL语句的分类4.3DDL语句4.3.1数据库4.3.2表(创建,查询,修改,删除)4…