内核调试环境搭建

news2024/11/24 0:36:40

内核调试环境搭建

目录

  • 经过测试好用的内核调试环境搭建过程
  • 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

在这里插入图片描述

查看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对应的别名

在这里插入图片描述

Ubuntu使用的内核
在这里插入图片描述

经过测试,其他版本的内核是可以安装的(如 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中选择静态链接

在这里插入图片描述

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之后崩溃退出

在这里插入图片描述

没有找到解决方案

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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis自学之路—分布式锁(四)

目录 分布式锁定义 靠谱的分布式锁具备的特征 【互斥性】 【锁超时释放】 【可重入性】 【高性能和高可用】 【安全性】 Redis分布式锁方案 一、SETNX EXPIRE 二、SETNX value值是&#xff08;系统时间过期时间&#xff09; 三、使用Lua脚本&#xff08;包含SETNXE…

【Web服务器集群】Apache网页优化

文章目录 一、Apache网页优化概述1.优化内容2.网页压缩2.1gzip概述2.2作用2.3Apache的压缩模块概述mod_gzip模块与mod_deflate模块 3.配置网页压缩功能3.1启用网页压缩功能步骤3.2具体操作步骤 4.配置网页缓存功能4.1启用网页压缩功能步骤4.2具体操作步骤 二、Apache安全优化1.…

Unity嵌入AndroidStudio(二) IL2CPP打包

首先建立Unity工程&#xff0c;话不多说直接上图&#xff1a; 导出Android工程&#xff1a; 得到如下文件&#xff0c;备用&#xff1a; 接下来创建安卓项目&#xff1a; 注意包名要和unity里面的一致&#xff0c;sdk版本也要一致 等待编译完成&#xff1a; 打开setting.grade…

2-网络初识——IP地址和端口号

目录 1.IP地址&#xff08;分为IPV4&#xff08;默认情况下&#xff09;和IPV6&#xff09; 1.1.概念 1.2.格式 1.3.特殊IP 2.端口号 2.1.概念 2.2.格式 2.3.注意事项 网络互连的目的是进行网络通信&#xff0c;也即是网络数据传输&#xff0c;更具体一点&#xff0c;是…

SpringMVC源码分析:SpringMVC初始化(一)

一、概述 SpringMVC的初始化大概分为Spring的初始化和SpringMVC的初始化两个部分&#xff0c;他们之间的关系如下图。下面我将按照这个顺序进行详细介绍。 二、Spring初始化 ContextLoaderListener.contextInitialized进行容器的初始化。 继续点进去ContextLoader.initWebApp…

Redis五大数据结构的底层实现(未完成)

一)String类型:可以使用object encoding name就可以查看字符串的编码 SDS&#xff0c;flags的值不同&#xff0c;那么len和alloc所表示的值的数据范围也不同&#xff0c;所以flags的只是为了标识SDS头的总大小&#xff1b; alloc和len刚开始进行申请内存空间的时候都是相同的 S…

简谈你对synchronized关键字的使用

&#x1f468;‍&#x1f393;作者&#xff1a;bug菌 ✏️博客&#xff1a;CSDN、掘金、infoQ、51CTO等 &#x1f389;简介&#xff1a;CSDN|阿里云|华为云|51CTO等社区博客专家&#xff0c;历届博客之星Top30&#xff0c;掘金年度人气作者Top40&#xff0c;51CTO年度博主Top12…

Word控件Spire.Doc 【其他】教程(4):在 Word 中插入上标和下标

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

5.2.1 分类的IP地址

5.2.1 分类的IP地址 通过前面的学习我们知道IPv4协议中包含的内容非常的多&#xff0c;我们学习IPv4又分为几个方面 介绍分类的IP地址IP地址的分配与使用IP分组的格式因特网地址到物理地址的映射&#xff08;ARP协议&#xff09;&#xff0c;用以动态完成IP地址到物理地址映射…

时间序列预测 | Matlab基于灰狼算法优化支持向量机(GWO-SVM)的时间序列预测

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于灰狼算法优化支持向量机(GWO-SVM)的时间序列预测 评价指标包括:MAPE、MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %----------------

别再纠结页面设计!挑选小程序页面设计模板就对了

小程序页面设计模板可以是一个非常棒的选择&#xff0c;特别是如果你想要快速创建一个优秀的小程序。 以下是一些关于如何选择小程序页面设计模板的建议&#xff1a; 确定你的需求&#xff1a;在开始挑选小程序页面设计模板之前&#xff0c;你需要明确你的需求。确定你的小程…

下载安装LabVIEW

下载安装LabVIEW 介绍下载安装流程下载安装 后续 介绍 LabVIEW 是 工程 师 用来 开发 自动 化 研究、 验证 和 生产 测试 系统 的 图形 化 编 程 环境。Labview作为图形化编程语言&#xff0c;图形控件拖拽式编程&#xff0c;显得更加直观形象&#xff0c;也很容易上手学习。 …

pytorch 绘制一维热力图

热力图 热力图&#xff08;Heat Map&#xff09;是指用 X 轴 和 Y 轴 表示的两个分类字段确定数值点的位置&#xff0c;通过相应位置的矩形颜色去表现数值的大小&#xff0c;颜色深代表的数值大。 热力图是非常特殊的一种图&#xff0c;可以显示不可点击区域发生的事情。热力…

3.5. 异常处理

在Java中&#xff0c;异常是一种用于表示程序在运行过程中遇到的错误或异常情况的对象。Java提供了一套异常处理机制&#xff0c;可以帮助我们更好地处理运行时可能出现的错误和异常。异常处理的主要概念包括&#xff1a; 异常类&#xff1a;Java中的异常类是继承自Throwable类…

L1频段卫星导航射频前端低噪声放大器芯片 AT2659/AT2659S

AT2659 是一款具有高增益、低噪声系数的低噪声放大器&#xff08;LNA&#xff09;芯片&#xff0c;支持L1频段多模式全球卫星定位&#xff0c;可以应用于GPS、北斗二代、伽利略、Glonass等GNSS导航接收机中。芯片采用先进的SiGe工艺制造&#xff0c;采用1.5 mm X 1 mm 0.78 mm的…

招标采购评标专家管理数智化解决方案

评标专家作为评标活动的重要一环&#xff0c;对保证评标活动的公平公正和评标质量&#xff0c;乃至提升营商环境都意义重大。 为了加强招采过程中评标专家的监督管理、健全评标专家库制度&#xff0c;保证评标活动的公平公正&#xff0c;提高评标质量&#xff0c;国家出台了相…

Pytest 高级进阶用法Hook使用pdm打包成插件

系列文章目录 提示&#xff1a;阅读本章之前&#xff0c;请先阅读目录 文章目录 系列文章目录前言一、创建项目二、安装pdm三、使用pdm创建项目四、创建src五、src下面&#xff0c;再创建包名六、编写plugin七、编写配置pyproject.toml八、使用pdm&#xff0c;添加pytest到该插…

如何看待人工智能?——比尔盖茨谈智能时代的机遇与挑战

原创 | 文 BFT机器人 01 比尔盖茨称AI将颠覆搜索、购物网站 “你永远不会去搜索网站了&#xff0c;也不会再去亚马逊了。” 当地时间5月22日&#xff0c;盖茨在出席一场关于AI的活动时表示&#xff0c;未来的顶级AI助理将颠覆现有互联网使用方式&#xff0c;替代人们执行某些任…

PHPMySQL基础(三):处理查询SQL返回的结果集

PHP&MySQL基础&#xff08;一&#xff09;:创建数据库并通过PHP进行连接_长风沛雨的博客-CSDN博客 PHP&MySQL基础&#xff08;二&#xff09;:通过PHP对MySQL进行增、删、改、查_长风沛雨的博客-CSDN博客 目录 一、连接MySQL&#xff0c;处理错误&#xff0c;统一字…

面了个4年经验的测试,自动化都不会,真是醉了····

最近面试了一个 4 年测试经验的测试工程师&#xff0c;简历和个人介绍都提到了会自动化&#xff0c;于是我就问了几个自动化方面的问题&#xff1a; 在自动化测试中&#xff0c;你是如何选择和设计测试用例的&#xff1f;你使用过哪些自动化测试工具&#xff0c;如何选择自动化…