目录
参考
利用qemu+gdb在ubuntu下搭建调试kernel的环境 - EwanHai - 博客园 (cnblogs.com)
经过测试好用的内核调试环境搭建过程
在很多情况下,只使用 linux 内核加文件系统不能得到漏洞依赖的环境
VMware 虚拟机调试方便,但是在进行测试时虚拟机会崩溃关机。
用 make 方式编译安装 Ubuntu 内核可能会有一些内核选项没有开启,导致 Ubuntu 黑屏,用官方提供的方式编译成 deb 包是很稳定的。
用 apt 安装内核调试信息的方法,调试信息和源码很可能对应不上,自己编译安装是最稳妥的方式。
ubuntu 和 linux 版本
https://blog.csdn.net/Breeze_CAT/article/details/123787636
举例:linux 版本 5.15.5
很久之前内核通过版本号中的第二个数字即 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 选择选高级,找到对应版本内核启动
如果进不去需要修改引导启动信息:
手动下载并切换到指定源码
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 可以可以解包
如果一定需要动态链接的 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
复制代码
Target options
Target Architecture (x86_64)
在x86_64
上按空格键,以选择该选项
选择Filesystem images
在ext2/3/4 root filesystem
按 Y,并进入ext2/3/4 variant (ext4)
选择ext4
用 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 ......"
复制代码
并加权限
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
复制代码
文件共享
把自己的文件放入文件系统
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)
关于源代码
用 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" 添加内核启动选项
复制代码
更新,重启
调试 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.1的8864端口代理到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
复制代码
评论