内核调试环境搭建

内核调试环境搭建

目录

  • 经过测试好用的内核调试环境搭建过程
  • ubuntu和linux版本
    • 查看commit所属的内核版本
    • 查看Ubuntu版本号等信息
  • 下载与安装内核
    • 下载内核
    • ubuntu更换内核
    • 手动下载并切换到指定源码
    • 用apt下载源码
    • 使用git下载对应版本
  • 编译并安装linux内核(使用linux-5.15.10版本)
    • 得到Ubuntu内核需要的编译选项
    • 常用的内核编译选项
    • 查看已有操作系统的编译选项
    • 源码编译Ubuntu内核
    • 得到有调试信息的源码编译结果
    • 查看编译结果
  • qemu的安装和使用
    • 安装qemu
    • 使用
  • 创建文件系统
    • 文件系统的操作
    • 编译文件系统
    • 用busybox创建文件系统
    • 用别人创建的initrd(文件系统)
  • 用文件系统启动内核
    • 启动内核
    • 启动调试
    • 文件共享
  • 调试技巧
    • 关于符号信息的坑
    • 关于源代码
    • 安装vmlinux调试信息
  • 调试qemu的Ubuntu虚拟机
    • 创建qemu虚拟机
    • qemu虚拟机和主机互通
    • 关闭kaslr(添加内核启动选项)(否则断点断不下来)
  • 调试vmware虚拟机
    • 启用调试
    • 问题
    • vmware双机调试(用串口)
  • 编译内核模块
  • 其他

参考

利用qemu+gdb在ubuntu下搭建调试kernel的环境 - EwanHai - 博客园 (cnblogs.com)

经过测试好用的内核调试环境搭建过程

  • 1、使用qemu创建Ubuntu虚拟机
  • 2、使用git下载对应版本 获取源码
  • 3、源码编译Ubuntu内核 得到deb包
  • 4、qemu虚拟机和主机互通 传输文件
  • 5、Ubuntu更换内核 安装deb包
  • 6、关闭kaslr
  • 7、调试技巧

在很多情况下,只使用linux内核加文件系统不能得到漏洞依赖的环境

VMware虚拟机调试方便,但是在进行测试时虚拟机会崩溃关机。

用make方式编译安装Ubuntu内核可能会有一些内核选项没有开启,导致Ubuntu黑屏,用官方提供的方式编译成deb包是很稳定的。

用apt安装内核调试信息的方法,调试信息和源码很可能对应不上,自己编译安装是最稳妥的方式。

ubuntu和linux版本

https://blog.csdn.net/Breeze_CAT/article/details/123787636

举例:linux版本5.15.5

  • 目前发布的主版本,增长很缓慢,通常后面的数字比较大了的时候该数字会增长。
  • 次版本号,表示稳定的版本号。
  • 修订版本号,代表改版本补丁次数,在下一个稳定版本发布之前出现补丁和修复会更新该版本号。非长期维护版本一般20多个。

很久之前内核通过版本号中的第二个数字即B的奇偶来表示稳定版和预发布版。但现在已经取消这个规则,现在预发布版用-rcX来表示如5.17-rc3,X为数字,一般不超过rc8

长期维护版本:5.15、5.10、5.4、4.19、4.14、4.9

查看commit所属的内核版本

kernel/git/torvalds/linux.git - Linux kernel source tree

内核调试环境搭建_第1张图片

查看tree中根目录下的Makefile文件可以看到对应的版本号

查看Ubuntu版本号等信息

cat /etc/issue
Ubuntu 20.04.2 LTS \n \l
或
lsb_release -a  命令
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.2 LTS
Release:        20.04   版本
Codename:       focal   别名

查看Ubuntu信息
➜  uname -a
Linux tower-virtual-machine 5.15.0-71-generic #78~20.04.1-Ubuntu SMP Wed Apr 19 11:26:48 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
➜  uname -r
5.15.0-71-generic    内核版本    5.15表示内核稳定版本号,一般ubuntu中最后小修订号都是0,因为ubuntu会自己合入补丁。
                      71表示由ubuntu进行的第35次修订(合入补丁)。
                      generic:通用版本,除此之外还可能有服务器版server或老式处理器的i386版等。
                      

Ubuntu对应的别名

内核调试环境搭建_第2张图片

Ubuntu使用的内核
内核调试环境搭建_第3张图片

经过测试,其他版本的内核是可以安装的(如 focal系列的Ubuntu内核代码编译之后可以安装到Ubuntu18主机上)(没有经过更多测试)

下载与安装内核

下载内核

下载ubuntu

https://mirrors.aliyun.com/oldubuntu-releases/releases/20.04.0/?spm=a2c6h.25603864.0.0.10467ff3XF6iMS 阿里云镜像

https://old-releases.ubuntu.com/releases/ Ubuntu官方镜像

下载Ubuntu内核

https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.15.10/ 较粗的deb包

下载linux内核源码

https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/ 版本比较粗

kernel/git/torvalds/linux.git - Linux kernel source tree Linux源码

Kernel/Dev/KernelGitGuide - Ubuntu Wiki Ubuntu内核源码

找到对应的源码:

git tag | grep 4.10.0-19

git checkout ubuntu-4.10.0-19........

ubuntu更换内核

  • 下载对应image和modules
  • sudo dpkg -i *.deb
  • 重启

或使用apt更换内核

sudo apt search 'linux-image-5.4.0-81-generic'
sudo apt install 'linux-image-5.4.0-81-generic'
更新并重启
sudo update-initramfs -u -k all
sudo update-grub
reboot
安装新版本内核头文件,用于开发编译
sudo apt install linux-headers-$(uname -r)

开机按esc选择选高级,找到对应版本内核启动

如果进不去需要修改引导启动信息:

  • 修改文件/etc/default/grub

    注释掉GRUB_TIMEOUT_STYLE=hidden

    修改GRUB_TIMEOUT=0为GRUB_TIMEOUT=10

  • 执行sudo update-grub启用修改

  • reboot 重启时会进入引导界面等待选择内核

手动下载并切换到指定源码

https://bbs.kanxue.com/thread-249192.htm

在https://wiki.ubuntu.com/Kernel/Dev/KernelGitGuide选择对应的Ubuntu系列

查看主机的Ubuntu系列(这里需要下载被调试主机的源码)

➜  CVE-2021-3493 git:(main) ✗ cat /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse

如Ubuntu20可以下载

git clone https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal

git tag | grep 4.10.0-19
git checkout ubuntu-4.10.0-19........

gdb中指定源代码路径,或把source文件直接拷贝到gdb检测源码的目录(如/build/linux-kcrkKx/linux-5.4.0)

set substitute-path PATH1 PATH2,PATH1是vmlinux中的路径信息,PATH2是source code存放的真实路径。

用apt下载源码

apt source linux-image-unsigned-5.11.0-44-generic # 版本号根据需求更改,可以用apt search搜索

ubuntu 内核git:https://kernel.ubuntu.com/git/ubuntu/

使用git下载对应版本

可以查看分支名https://kernel.ubuntu.com/git/ubuntu/ubuntu-focal.git/refs/tags

git clone git://kernel.ubuntu.com/ubuntu/ubuntu-focal.git -b Ubuntu-hwe-5.13-5.13.0-35.40_20.04.1 --depth 1

编译并安装linux内核(使用linux-5.15.10版本)

make ARCH=x86_64 x86_64_defconfig 
make ARCH=x86_64 menuconfig
配置 Kernel-hacking -> Compile-time checks and compiler options
Compile the kernel with debug info —> Provide GDB scripts for kernel debugging
关闭 Reduce debugging information


make -j8

sudo make modules_install   安装模块
sudo make install      安装
sudo update-initramfs -c -k 5.3.10 启用(数字为版本号)
sudo update-grub   更新grub
reboot

也可以使用docker编译https://registry.hub.docker.com/r/chenaotian/kernelcompile(编译5.x)

docker run -ti --rm -h kc --name kc -v D:/share:/work chenaotian/kernelcompile:latest /bin/bash
docker exec -it kc /bin/bash

得到Ubuntu内核需要的编译选项

常用的内核编译选项

# 设置调试符号
CONFIG_DEBUG_INFO=y
# fuse 开启,一些漏洞利用会用到
CONFIG_FUSE_FS=y
# VIPC 开启,可以使用msg系列
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_CHECKPOINT_RESTORE=y # 设置这个才能正确调用msg 里的copy 系列函数

查看已有操作系统的编译选项

cat /usr/src/linux-headers-`uname -r`/.config 
或
cat /boot/config-`uname -r`

源码编译Ubuntu内核

Kernel/BuildYourOwnKernel - Ubuntu Wiki

安装依赖

sudo apt-get build-dep linux
sudo apt-get install libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf llvm

编译

LANG=C fakeroot debian/rules clean
LANG=C fakeroot debian/rules binary-headers binary-generic binary-perarch  快速编译
# if you need linux-tools or lowlatency kernel, run instead: 会多出来更多东西
LANG=C fakeroot debian/rules binary  

得到有调试信息的源码编译结果

sudo apt-get install pkg-config-dbgsym
LANG=C fakeroot debian/rules clean
LANG=C fakeroot debian/rules binary-headers binary-generic binary-perarch skipdbg=false

查看编译结果

System.map 文件可以查看一些关键函数有没有

cat System.map |grep function_name

查看字符串

strings vmlinux |grep function_name

qemu的安装和使用

安装qemu

sudo apt-get install qemu qemu-system  

使用

常用的启动脚本

#! /bin/sh

cd ./rootfs
find . | cpio -o --format=newc > ../rootfs.img 
cd ../

qemu-system-x86_64 \
-m 512M \
-kernel ./bzImage \
-initrd  ./rootfs.img \
-nographic \
-append "console=ttyS0 root=/dev/sda rw nokaslr quiet" \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-cpu kvm64,+smep,+smap \
-gdb tcp::10086

创建文件系统

文件系统的操作

解包和打包

cpio -idmv < ../rootfs.img #解包cpio
find . | cpio -o --format=newc > ../rootfs.img #打包cpio

有可能在外层更进行了一次gzip压缩,使用binwalk可以可以解包

binwalk -Me ./rootfs.img

如果一定需要动态链接的exp,偷懒方法就是,ldd 查看exp 需要的动态库,然后将ld-linux-x86-64.so.2 和其他依赖的so全部拷贝到文件系统中,qemu 启动后,用LD_LIBRARY_PATH 来运行

将其依赖的so全部拷贝到一个文件夹内然后放入rootfs中制作成initrd.img,然后启动qemu,按照如下方法运行

cp ...so ./rootfs/exp #将so 拷贝到制作initrd.img的目录中
cd ./rootfs
find . | cpio -o --format=newc > ../rootfs.img #制作initrd.img
cd ../
./boot.sh #启动qemu
# qemu 启动后
cd /expdir
export LD_LIBRARY_PATH=`pwd`
./ld-linux-x86-64.so.2 ./exploit

编译文件系统

使用busybox构建文件系统比较复杂,用buildroot相对简单

git clone git://git.buildroot.net/buildroot
cd buildroot
make menuconfig
  • 在跳出的UI界面依次选择

Target options

Target Architecture (x86_64)

x86_64上按空格键,以选择该选项

  • 再返回与Target options同一级的界面

选择Filesystem images

ext2/3/4 root filesystem按Y,并进入ext2/3/4 variant (ext4)选择ext4

make -j4

用busybox创建文件系统

wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
tar -jxvf busybox-1.35.0.tar.bz2

cd busybox-1.35.0
make defconfig
make menuconfig

选择settings中选择静态链接

内核调试环境搭建_第4张图片

make -j4
sudo make install

make install会把文件拷贝到当前目录下的 _install目录

拷贝文件,创建init

mkdir ramdisk
cd ramdisk
cp -r ../busy-1.25.0/_install/* .

cd ramdisk
ln -s bin/busybox init

设置启动程序,init程序首先会访问etc/inittab文件,以获取开机要启动的程序列表,因此我们得编写一个inittab

cd etc
vim inittab  

  ::sysinit:/etc/init.d/rcS   
  ::askfirst:-/bin/sh    
  ::restart:/sbin/init
  ::ctrlaltdel:/sbin/reboot
  ::shutdown:/bin/umount -a -r
  ::shutdown:/sbin/swapoff -a

chmod +x etc/inittab

系统初始化寻找etc/init.d/rcS,需要创建,内容添加

#!/bin/sh

mount proc
mount -o remount,rw /
mount -a    
clear                               
echo "My Tiny Linux Start :D ......"

并加权限

chmod +x  rcS

rcS中,mount -a 是自动挂载 /etc/fstab 中的内容,因此我们需要一个fstab文件,以设置需要挂载的系统, 创建文件并添加内容

proc            /proc        proc    defaults          0       0
sysfs           /sys         sysfs   defaults          0       0
devtmpfs        /dev         devtmpfs  defaults        0       0

最后把文件压缩成镜像

cd ramdisk
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.img

cpio --null或-0接受新增列控制字符,通常配合find指令的"-print0"参数使用。
-o或--create  执行copy-out模式,建立备份档。
-v或--verbose  详细显示指令的执行过程。
newc 新型 (SVR4) 跨平台格式, 支持大于 65536 i节点的文件系统,一般 制作 ramdisk 就用 这个 格式
-9 表示压缩率

用别人创建的initrd(文件系统)

用文件系统启动内核

启动内核

使用buildroot编译的镜像

qemu-system-x86_64 -kernel bzImage -boot c -m 1024 -hda rootfs.ext2 -append "root=/dev/sda rw console=ttyS0, 115200 acpi=off nokaslr" -serial stdio -display none -s -S

使用busybox构建的镜像启动命令

# 在A Terminal中运行以下命令
qemu-system-x86_64 -kernel bzImage -boot c -m 1024 -initrd initramfs.img -append "root=/dev/sda rw console=ttyS0, 115200 acpi=off nokaslr" -serial stdio -display none -s -S

如果需要调试内核的kvm模块,则向上述命令添加 -enable-kvm

启动调试

gdb vmlinux
target remote localhost:1234

文件共享

把自己的文件放入文件系统

  • 如果使用busybox创建文件系统,直接把文件拷贝到对应目录,执行命令把文件打包成镜像
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.img
  • 如果使用buildroot构建镜像,添加自定义文件到文件系统System configuration菜单下选择 Custom scripts to run before creating filesystem images写入命令,把文件拷贝到对应目录output/target目录下 ,在测试的时候报错命令出错。
  • 编译过之后,直接用手动拷贝文件到output/target然后再执行一次make -j4 得到的镜像内部有需要的文件

调试技巧

关于符号信息的坑

vmlinux文件可能不包含一些符号,如图

在这里插入图片描述

原因是ovlerlay文件系统被编译成了内核模块文件,需要手动添加

gef➤  add-symbol-file ./fs/overlayfs/overlay.ko  0xffffffffc04ee000

查看内核模块加载地址(内核模块被加载了之后才能看到,可能需要先执行一次相关的命令或执行相关的poc)

cat /proc/modules

关于源代码

用docker编译的内核会从docker中的路径寻找二进制源码,在调试时会出现找不到源码的情况

gef➤  list
46      in /work/ubuntu-focal/arch/x86/include/asm/irqflags.h

用set命令重定位源码目录即可

set substitute-path /work/ubuntu-focal /home/tower/aiwencode/vul/CVE-2023-0386/ubuntu-focal

安装vmlinux调试信息

Ubuntu内核默认不包含调试信息

安装内核调试信息

https://developer.aliyun.com/article/899339

获取Ubuntu内核调试信息

https://bbs.kanxue.com/thread-249192.htm

cat /boot/config-uname -r| grep -i "GDB"查看当前内核是否支持KGDB
增加符号对应的源文件
codename=$(lsb_release -c | awk '{print $2}')
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
EOF
# 添加访问符号服务器的秘钥文件
wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add -
# 更新源文件
sudo apt-get update

或sudo apt-get install aptitude

获取被调试内核信息,并安装对应内核符号

被调试主机:unamr -r

调试主机:sudo apt-get install linux-image-<被调试主机执行uname -r结果>-dbgsym

在调试主机上进行调试

gdb -s /usr/lib/debug/boot/vmlinux-5.15.0-71-generic   直接加载之前下载的包含符号信息的vmlinux
set architecture i386:x86-64:intel

target remote localhost:8864

调试qemu的Ubuntu虚拟机

创建qemu虚拟机

创建虚拟磁盘

qemu-img create -f qcow2 qemu_disk.img 10G
查看磁盘信息
qemu-img info qemu_disk.img

可以创建的格式如下


Supported formats: blkdebug blklogwrites blkreplay blkverify bochs cloop compress copy-on-read dmg file host_cdrom host_device luks nbd null-aio null-co nvme parallels qcow
qcow2 qed quorum raw replication sheepdog throttle vdi vhdx vmdk vpc vvfat

启动虚拟机

qemu-system-x86_64 -m 4G -smp 4  -boot d  -hda ubuntu20.qcow2 -cdrom ubuntu-18.04.5-desktop-amd64.iso

boot order 的选项如下,代表系统的启动顺序,每种方式都有一个对应的字母缩写
-boot [order=drives][,once=drives][,menu=on|off]
  'drives': floppy (a), hard disk (c), CD-ROM (d), network (n) 

安装好之后再次启动

qemu-system-x86_64 -m 8G -smp 4  -hda ubuntu20.qcow2 

https://www.cnblogs.com/sun-ye/p/15750205.html

qemu虚拟机和主机互通

https://www.cnblogs.com/haiyonghao/p/14440163.html

网桥模式

用ip addr命令查看自己的网络中可以使用的网卡名

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP group default qlen 1000
    link/ether 00:0c:29:9e:f6:c2 brd ff:ff:ff:ff:ff:ff
    altname enp3s0

主机创建网桥,把主机网卡添加到网桥上(网络会断开重启),启用stp ,

apt-get install bridge-utils  安装依赖
brctl addbr br0    创建
brctl addif br0 ens160绑定
brctl stp br0 on
ifconfig ens160 0
dhclient br0
route   查看创建网桥的信息(br0的信息),对应填到qemu虚拟机里

启动qemu虚拟机,在启动命令后加

-net nic -net tap,ifname=tap1

修改qemu虚拟机内的网络配置编辑/etc/netplan/ *-cloud-init.yaml文件

ip设置为和br0 同一网段,gateway设置为route查到的(我这里是0.0.0.0),dns 8.8.8.8

配置网络 https://blog.csdn.net/allway2/article/details/121949816 (Ubuntu18 以上)

关闭kaslr(添加内核启动选项)(否则断点断不下来)

断点断不下来原因为地址不对,如果不关闭kaslr,需要查看/proc/kallsys中对应的符号地址下断点

sudo vim /etc/default/grub

添加
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nokaslr"   添加内核启动选项

更新,重启

sudo update-grub
reboot

调试vmware虚拟机

启用调试

在文件xxx.vmx中最后添加(在gdb执行c之后虚拟机崩溃问题没有解决)

debugStub.listen.guest64="TRUE"

debugStub.port.guest64 = "8864"

用gdb连接127.0.0.1:8864

用其他主机进行调试可以加一个端口转发

netsh interface portproxy add v4tov4 listenaddress=192.168.1.68 listenport=8864 connectaddress=127.0.0.1 connectport=8864
使用ipv4 to ipv4模式将源地址是127.0.0.18864端口代理到192.168.1.68(本机当前ip)8864端口上,源地址处也可以改为可以内网互通的服务器的内网地址。

netsh interface portproxy show all
关闭转发,这种方式转发可能会失败(不报错)需要删除之后重新设置
netsh interface  portproxy delete v4tov4 listenaddress=192.168.1.68 listenport=8864

安装vmwaretools

sudo apt upgrade
sudo apt install open-vm-tools-desktop -y
sudo reboot

问题

下断点continue之后崩溃退出

内核调试环境搭建_第5张图片

没有找到解决方案

vmware双机调试(用串口)

https://blog.csdn.net/Breeze_CAT/article/details/123787636

https://bbs.kanxue.com/thread-249192.htm

http://blog.nsfocus.net/gdb-kgdb-debug-application/

编译内核模块

Makefile替换babydriver为文件名,KERNELDIR 为内核源码的目录

#!/bin/bash

obj-m += babydriver.o 

#CROSS_COMPILE  ?= /opt/linaro/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-  # Compiler path settings

KERNELDIR :=/home/tower/aiwencode/sourcecode/linux-5.15/  # Kernel code directory

PWD ?= $(shell pwd)

all:
  make -C $(KERNELDIR) M=$(PWD) modules  # Compile the instructions of the kernel module

clean:                                              
  rm -rf *.ko *.mod.c *.o modules.* Module.symvers  # delete all generated files


源码举例

/*
* arttnba3_module.ko
* developed by arttnba3
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEVICE_NAME "babydev"
#define CLASS_NAME "a3module"

static int major_num;
static struct class * module_class = NULL;
static struct device * module_device = NULL;
static spinlock_t spin;

static int __init kernel_module_init(void);
static void __exit kernel_module_exit(void);
static int a3_module_open(struct inode *, struct file *);
static ssize_t a3_module_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t a3_module_write(struct file *, const char __user *, size_t, loff_t *);
static int a3_module_release(struct inode *, struct file *);
static long a3_module_ioctl(struct file *, unsigned int cmd, long unsigned int param);

static struct file_operations a3_module_fo = 
{
    .owner = THIS_MODULE,
    .unlocked_ioctl = a3_module_ioctl,
    .open = a3_module_open,
    .read = a3_module_read,
    .write = a3_module_write,
    .release = a3_module_release,
};

static struct
{
    void        *device_buf;
    size_t      device_buf_len;
}babydev_struct;

module_init(kernel_module_init);
module_exit(kernel_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("arttnba3");

static int __init kernel_module_init(void)
{
    spin_lock_init(&spin);
    printk(KERN_INFO "[arttnba3_TestModule:] Module loaded. Start to register device...\n");
    major_num = register_chrdev(0, DEVICE_NAME, &a3_module_fo);
    if(major_num < 0)
    {
        printk(KERN_INFO "[arttnba3_TestModule:] Failed to register a major number.\n");
        return major_num;
    }    
    printk(KERN_INFO "[arttnba3_TestModule:] Register complete, major number: %d\n", major_num);

    module_class = class_create(THIS_MODULE, CLASS_NAME);
    if(IS_ERR(module_class))
    {
        unregister_chrdev(major_num, DEVICE_NAME);
        printk(KERN_INFO "[arttnba3_TestModule:] Failed to register class device!\n");
        return PTR_ERR(module_class);
    }
    printk(KERN_INFO "[arttnba3_TestModule:] Class device register complete.\n");

    module_device = device_create(module_class, NULL, MKDEV(major_num, 0), NULL, DEVICE_NAME);
    if(IS_ERR(module_device))
    {
        class_destroy(module_class);
        unregister_chrdev(major_num, DEVICE_NAME);
        printk(KERN_INFO "[arttnba3_TestModule:] Failed to create the device!\n");
        return PTR_ERR(module_device);
    }
    printk(KERN_INFO "[arttnba3_TestModule:] Module register complete.\n");
    return 0;
}

static void __exit kernel_module_exit(void)
{
    printk(KERN_INFO "[arttnba3_TestModule:] Start to clean up the module.\n");
    device_destroy(module_class, MKDEV(major_num, 0));
    class_destroy(module_class);
    unregister_chrdev(major_num, DEVICE_NAME);
    printk(KERN_INFO "[arttnba3_TestModule:] Module clean up complete. See you next time.\n");
}

static long a3_module_ioctl(struct file * __file, unsigned int cmd, long unsigned int param)
{
    if (cmd == 65537)
    {
        kfree(babydev_struct.device_buf);
        babydev_struct.device_buf = kmalloc(param, GFP_ATOMIC);
        babydev_struct.device_buf_len = param;
        printk(KERN_INFO "alloc done\n");
        return 0;
    }
    else
    {
        printk(KERN_INFO "default arg is %ld\n", param);
        return -22;
    }
}

static int a3_module_open(struct inode * __inode, struct file * __file)
{
    babydev_struct.device_buf = kmalloc(0x40, GFP_ATOMIC);
    babydev_struct.device_buf_len = 0x40;
    printk(KERN_INFO "device open\n");
    return 0;
}

static int a3_module_release(struct inode * __inode, struct file * __file)
{
    kfree(babydev_struct.device_buf);
    printk(KERN_INFO "device release\n");
    return 0;
}

static ssize_t a3_module_read(struct file * __file, char __user * user_buf, size_t size, loff_t * __loff)
{
    size_t result;

    if (!babydev_struct.device_buf)
        return -1LL;
    result = -2LL;

    if (babydev_struct.device_buf_len > size)
    {
        copy_to_user(user_buf, babydev_struct.device_buf, size);
        result = size;
    }
    return result;
}

static ssize_t a3_module_write(struct file * __file, const char __user * user_buf, size_t size, loff_t * __loff)
{
    size_t result;

    if (!babydev_struct.device_buf )
        return -1LL;
    result = -2LL;
    if ( babydev_struct.device_buf_len > size)
    {
        copy_from_user(babydev_struct.device_buf, user_buf, size);
        result = size;
    }
    return result;
}

其他

查看内核支持的选项

grep CONFIG_PID_NS /boot/config-$(uname -r)

查看内核崩溃日志

/proc/last_kmsg
/sys/fs/pstore/console-ramoops

你可能感兴趣的:(linux,ubuntu,运维,网络安全)