深入了解Linux内存检测技术

【推荐阅读】

浅谈linux 内核网络 sk_buff 之克隆与复制

深入linux内核架构--进程&线程

了解Docker 依赖的linux内核技术

Linux常见的内存访问错误有:

越界访问(out of bounds)

访问已经释放的内存(use after free)

重复释放

内存泄露(memory leak)

栈溢出(stack overflow)

不同的工具有不同的侧重点,本章主要从slub_debug、kmemleak、kasan三个工具介绍。

kmemleak侧重于内存泄露问题发现。

slub_debug和kasan有一定的重复,部分slub_debug问题需要借助slabinfo去发现;kasan更快,所有问题独立上报,缺点是需要高版本GCC支持(gcc 4.9.2 or gcc 5.0)。

测试环境准备

更新内核版本到Kernel v4.4,然后编译:

git clone https://github.com/arnoldlu/linux.git -b running_kernel_4.4 export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu- make defconfig make bzImage -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

slub_debug

关键词:Red Zone、Padding、Object Layout。

Linux内核中,小块内存大量使用slab/slub分配器,slub_debug提供了内存检测小功能。

内存中比较容易出错的地方有:

访问已经释放的内存

越界访问

重复释放内存

编译支持slub_debug内核

首先需要打开General setup -> Enable SLUB debugging support,然后再选择Kernel hacking -> Memory Debugging -> SLUB debugging on by default。

CONFIG_SLUB=y CONFIG_SLUB_DEBUG=y CONFIG_SLUB_DEBUG_ON=y CONFIG_SLUB_STATS=y

测试环境:slabinfo、slub.ko

通过slub.ko模拟内存异常访问,有些可以直接显示,有些需要通过slabinfo -v来查看。

在tools/vm目录下,执行如下命令,生成可执行文件slabinfo。放入_install目录,打包到zImage中。

make slabinfo CFLAGS=-static ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

将编译好的slabinfo放入sbin。

下面三个测试代码:https://github.com/arnoldlu/linux/tree/running_kernel_4.4/test_code/slub_debug

在test_code/slub_debug目录下执行make.sh,将slub.ko/slub2.ko/slub3.ko放入data。

进行测试

启动QEMU:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -smp 2 -m 2048 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc console=ttyAMA0 loglevel=8 slub_debug=UFPZ" -nographic

F:在free的时候会执行检查。

Z:表示Red Zone的意思。

P:是Poison的意思。

U:会记录slab的使用者信息,如果打开,会会显示分配释放对象的栈回溯。

在slub_debug打开SLAB_STORE_USER选项后,可以清晰地看到问题点的backtrace。

测试结果

内存越界访问包括Redzone overwritten和Object padding overwritten。

重复释放对应Object already free。访问已释放内存为Posion overwritten。

Redzone overwritten

执行insmod data/slub.ko,使用slabinfo -v查看结果。

static void create_slub_error(void) { buf = kmalloc(32, GFP_KERNEL); if(buf) { memset(buf, 0x55, 80);-----------------------------------虽然分配32字节,但是对应分配了64字节。所以设置为80字节访问触发异常。从buf开始的80个字节仍然被初始化成功。 } }

虽然kmalloc申请了32字节的slab缓冲区,但是内核分配的是kmalloc-64。所以memset 36字节不会报错,将36改成大于64即可。

一个slub Debug输出包括四大部分:

BUG kmalloc-64 (Tainted: G O ): Redzone overwritten-------------------------------------------------------------1. 问题描述:slab名称-kmalloc-64,什么错误-Redzone overwritten。
-----------------------------------------------------------------------------

Disabling lock debugging due to kernel taint
INFO: 0xeddb3640-0xeddb3643. First byte 0x55 instead of 0xcc------------------------------------------------1.1 问题起始和结束地址,这里一共4字节。
INFO: Allocated in 0x55555555 age=1766 cpu=0 pid=771---------------------------------------------------------1.2 slab的分配栈回溯
0x55555555
0xbf002014
do_one_initcall+0x90/0x1d8
do_init_module+0x60/0x38c
load_module+0x1bac/0x1e94
SyS_init_module+0x14c/0x15c
ret_fast_syscall+0x0/0x3c
INFO: Freed in do_one_initcall+0x78/0x1d8 age=1766 cpu=0 pid=771-----------------------------------------1.3 slab的释放栈回溯
do_one_initcall+0x78/0x1d8
do_init_module+0x60/0x38c
load_module+0x1bac/0x1e94
SyS_init_module+0x14c/0x15c
ret_fast_syscall+0x0/0x3c
INFO: Slab 0xefdb5660 objects=16 used=14 fp=0xeddb3700 flags=0x0081-----------------------------------1.4 slab的地址,以及其它信息。
INFO: Object 0xeddb3600 @offset=1536 fp=0x55555555-----------------------------------------------------------1.5 当前Object起始,及相关信息

Bytes b4 eddb35f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ------------2. 问题slab对象内容。2.1 打印问题slab对象内容之前一些字节。
Object eddb3600: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU---------2.2 slab对象内容,全部为0x55。
Object eddb3610: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
Object eddb3620: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
Object eddb3630: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
Redzone eddb3640: 55 55 55 55 UUUU----------------------------------------------------------------------------------2.3 Redzone内容,问题出在这里。
Padding eddb36e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ------------2.4 Padding内容,为了对象对齐而补充。
Padding eddb36f8: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
CPU: 2 PID: 773 Comm: slabinfo Tainted: G B O 4.4.0+ #93--------------------------------------------------------3. 检查问题点的栈打印,这里是由于slabinfo找出来的。
Hardware name: ARM-Versatile Express
[] (unwind_backtrace) from [] (show_stack+0x10/0x14)
[] (show_stack) from [] (dump_stack+0x78/0x88)
[] (dump_stack) from [] (check_bytes_and_report+0xd0/0x10c)
[] (check_bytes_and_report) from [] (check_object+0x164/0x234)
[] (check_object) from [] (validate_slab_slab+0x198/0x1bc)
[] (validate_slab_slab) from [] (validate_store+0xac/0x190)
[] (validate_store) from [] (kernfs_fop_write+0xb8/0x1b4)
[] (kernfs_fop_write) from [] (__vfs_write+0x1c/0xd8)
[] (__vfs_write) from [] (vfs_write+0x90/0x170)
[] (vfs_write) from [] (SyS_write+0x3c/0x90)
[] (SyS_write) from [] (ret_fast_syscall+0x0/0x3c)
FIX kmalloc-64: Restoring 0xeddb3640-0xeddb3643=0xcc----------------------------------------------------------4. 问题点是如何被解决的,此处恢复4个字节为0xcc。

Object padding overwritten

void create_slub_error(void)
{
  int i;

  buf = kmalloc(32, GFP_KERNEL);
  if(buf) {
    buf[-1] = 0x55;------------------------------------------------------------------------向左越界访问
    kfree(buf);
  }
}
执行insmod data/slub4.ko,结果如下。
这里的越界访问和之前有点不一样的是,这里向左越界。覆盖到了Padding区域。
al: slub error test init
=============================================================================
BUG kmalloc-128 (Tainted: G O ): Object padding overwritten------------------------------------------------------覆盖到Padding区域
-----------------------------------------------------------------------------

Disabling lock debugging due to kernel taint
INFO: 0xffff80007767e9ff-0xffff80007767e9ff. First byte 0x55 instead of 0x5a
INFO: Allocated in call_usermodehelper_setup+0x44/0xb8 age=1 cpu=1 pid=789
alloc_debug_processing+0x17c/0x188
___slab_alloc.constprop.30+0x3f8/0x440
__slab_alloc.isra.27.constprop.29+0x24/0x38
kmem_cache_alloc+0x1ec/0x260
call_usermodehelper_setup+0x44/0xb8
/ # kobject_uevent_env+0x494/0x500
kobject_uevent+0x10/0x18
load_module+0x18cc/0x1d78
SyS_init_module+0x150/0x178
el0_svc_naked+0x24/0x28
INFO: Slab 0xffff7bffc2dd9f80 objects=16 used=9 fp=0xffff80007767ea00 flags=0x4081
INFO: Object 0xffff80007767e800 @offset=2048 fp=0xffff80007767ea00

Bytes b4 ffff80007767e7f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Object ffff80007767e800: 00 01 00 00 00 00 00 00 08 e8 67 77 00 80 ff ff ..........gw....
Object ffff80007767e810: 08 e8 67 77 00 80 ff ff f8 83 0c 00 00 80 ff ff ..gw............
Object ffff80007767e820: 00 00 00 00 00 00 00 00 00 6e aa 00 00 80 ff ff .........n......
Object ffff80007767e830: 00 23 67 78 00 80 ff ff 18 23 67 78 00 80 ff ff .#gx.....#gx....
Object ffff80007767e840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff80007767e850: b8 8e 32 00 00 80 ff ff 00 23 67 78 00 80 ff ff ..2......#gx....
Object ffff80007767e860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff80007767e870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Redzone ffff80007767e880: cc cc cc cc cc cc cc cc ........
Padding ffff80007767e9c0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff80007767e9d0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff80007767e9e0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff80007767e9f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 55 ZZZZZZZZZZZZZZZU
CPU: 0 PID: 790 Comm: mdev Tainted: G B O 4.4.0+ #116
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x108
[] show_stack+0x14/0x20
[] dump_stack+0x94/0xd0
[] print_trailer+0x128/0x1b8
[] check_bytes_and_report+0xd8/0x118
[] check_object+0xa0/0x240
[] free_debug_processing+0x128/0x380
[] __slab_free+0x344/0x4a0
[] kfree+0x1ec/0x220
[] umh_complete+0x58/0x68
[] call_usermodehelper_exec_async+0x150/0x170
[] ret_from_fork+0x10/0x40
FIX kmalloc-128: Restoring 0xffff80007767e9ff-0xffff80007767e9ff=0x5a---------------------------------------------------------问题处理是将对应字节恢复为0x5a。

Object already free

void create_slub_error(void)
{
  buf = kmalloc(32, GFP_KERNEL);
  if(buf) {
    memset(buf, 0x55, 32);
    kfree(buf);
    printk("al: Object already freed");
    kfree(buf);
  }
}
内核中free执行流程如下:
kfree
  ->slab_free
    ->__slab_free
      ->kmem_cache_debug
        ->free_debug_processing
         ->on_freelist   
执行insmod data/slub2.ko,结果如下。
al: slub error test init
al: Object already freed
=============================================================================
BUG kmalloc-128 (Tainted: G B O ): Object already free------------------------------------------------------------------在64位系统,32字节的kmalloc变成了kmalloc-128,问题类型是:Object already free,也即重复释放。
-----------------------------------------------------------------------------

INFO: Allocated in create_slub_error+0x20/0x80 [slub2] age=0 cpu=1 pid=791------------------------------------内存分配点栈回溯
alloc_debug_processing+0x17c/0x188
___slab_alloc.constprop.30+0x3f8/0x440
__slab_alloc.isra.27.constprop.29+0x24/0x38
kmem_cache_alloc+0x1ec/0x260
create_slub_error+0x20/0x80 [slub2]
my_test_init+0x14/0x28 [slub2]
do_one_initcall+0x90/0x1a0
do_init_module+0x60/0x1cc
load_module+0x18dc/0x1d78
SyS_init_module+0x150/0x178
el0_svc_naked+0x24/0x28
INFO: Freed in create_slub_error+0x50/0x80 [slub2] age=0 cpu=1 pid=791------------------------------------------内存释放点栈回溯
free_debug_processing+0x17c/0x380
__slab_free+0x344/0x4a0
kfree+0x1ec/0x220
create_slub_error+0x50/0x80 [slub2]
my_test_init+0x14/0x28 [slub2]
do_one_initcall+0x90/0x1a0
do_init_module+0x60/0x1cc
load_module+0x18dc/0x1d78
SyS_init_module+0x150/0x178
el0_svc_naked+0x24/0x28
INFO: Slab 0xffff7bffc2dda800 objects=16 used=7 fp=0xffff8000776a0800 flags=0x4081
INFO: Object 0xffff8000776a0800 @offset=2048 fp=0xffff8000776a0a00

Bytes b4 ffff8000776a07f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Object ffff8000776a0800: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk-----------------内存内容打印,供128字节。
Object ffff8000776a0810: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0820: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0830: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0840: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0850: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0860: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff8000776a0870: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
Redzone ffff8000776a0880: bb bb bb bb bb bb bb bb ........
Padding ffff8000776a09c0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776a09d0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776a09e0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776a09f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
CPU: 1 PID: 791 Comm: insmod Tainted: G B O 4.4.0+ #116--------------------------------------------------------------此处问题在insmod就发现了,所以检查出问题的进程就是insmod。
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x108
[] show_stack+0x14/0x20
[] dump_stack+0x94/0xd0
[] print_trailer+0x128/0x1b8
[] free_debug_processing+0x29c/0x380
[] __slab_free+0x344/0x4a0
[] kfree+0x1ec/0x220
[] create_slub_error+0x60/0x80 [slub2]
[] my_test_init+0x14/0x28 [slub2]
[] do_one_initcall+0x90/0x1a0
[] do_init_module+0x60/0x1cc
[] load_module+0x18dc/0x1d78
[] SyS_init_module+0x150/0x178
[] el0_svc_naked+0x24/0x28
FIX kmalloc-128: Object at 0xffff8000776a0800 not freed------------------------------------------------------------------处理的结果是,此处slab 对象是没有被释放。

Poison overwritten

访问已释放内存的测试代码如下:

static void create_slub_error(void)
{
  buf = kmalloc(32, GFP_KERNEL);-----------------------此时的buf内容都是0x6B
  if(buf) {
    kfree(buf);
    printk("al: Access after free");
    memset(buf, 0x55, 32);-----------------------------虽然被释放,但是memset仍然生效了变成了0x55。
  }
}
执行insmod data/slub3.ko ,使用slabinfo -v查看结果。
=============================================================================

BUG kmalloc-128 (Tainted: G B O ): Poison overwritten----------------------------------------------slab名称为kmalloc-64,问题类型是:Poison overwritten,即访问已释放内存。
-----------------------------------------------------------------------------

 

INFO: 0xffff800077692800-0xffff80007769281f. First byte 0x55 instead of 0x6b
INFO: Allocated in create_slub_error+0x28/0xf0 [slub3] age=1089 cpu=1 pid=793----------分配点的栈回溯
alloc_debug_processing+0x17c/0x188
___slab_alloc.constprop.30+0x3f8/0x440
__slab_alloc.isra.27.constprop.29+0x24/0x38
kmem_cache_alloc+0x1ec/0x260
create_slub_error+0x28/0xf0 [slub3]
0xffff7ffffc00e014
do_one_initcall+0x90/0x1a0
do_init_module+0x60/0x1cc
load_module+0x18dc/0x1d78
SyS_init_module+0x150/0x178
el0_svc_naked+0x24/0x28
INFO: Freed in create_slub_error+0x80/0xf0 [slub3] age=1089 cpu=1 pid=793--------------释放点的栈回溯
free_debug_processing+0x17c/0x380
__slab_free+0x344/0x4a0
kfree+0x1ec/0x220
create_slub_error+0x80/0xf0 [slub3]
0xffff7ffffc00e014
do_one_initcall+0x90/0x1a0
do_init_module+0x60/0x1cc
load_module+0x18dc/0x1d78
SyS_init_module+0x150/0x178
el0_svc_naked+0x24/0x28
INFO: Slab 0xffff7bffc2dda480 objects=16 used=16 fp=0x (null) flags=0x4080
INFO: Object 0xffff800077692800 @offset=2048 fp=0xffff800077692400

 

Bytes b4 ffff8000776927f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Object ffff800077692800: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU--------前32字节仍然被修改成功。
Object ffff800077692810: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
Object ffff800077692820: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff800077692830: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff800077692840: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff800077692850: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff800077692860: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object ffff800077692870: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
Redzone ffff800077692880: bb bb bb bb bb bb bb bb ........
Padding ffff8000776929c0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776929d0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776929e0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding ffff8000776929f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
CPU: 0 PID: 795 Comm: slabinfo Tainted: G B O 4.4.0+ #116
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x108
[] show_stack+0x14/0x20
[] dump_stack+0x94/0xd0
[] print_trailer+0x128/0x1b8
[] check_bytes_and_report+0xd8/0x118
[] check_object+0x1cc/0x240
[] alloc_debug_processing+0x108/0x188
[] ___slab_alloc.constprop.30+0x3f8/0x440
[] __slab_alloc.isra.27.constprop.29+0x24/0x38
[] kmem_cache_alloc+0x1ec/0x260
[] seq_open+0x34/0x90
[] kernfs_fop_open+0x194/0x370
[] do_dentry_open+0x214/0x318
[] vfs_open+0x58/0x68
[] path_openat+0x460/0xdf0
[] do_filp_open+0x60/0xe0
[] do_sys_open+0x12c/0x218
[] compat_SyS_open+0x1c/0x28
[] el0_svc_naked+0x24/0x28
FIX kmalloc-128: Restoring 0xffff800077692800-0xffff80007769281f=0x6b

 

FIX kmalloc-128: Marking all objects used
SLUB: kmalloc-128 210 slabs counted but counter=211
slabinfo (795) used greatest stack depth: 12976 bytes left

kmemleak

kmemleak是内核提供的一种检测内存泄露工具,启动一个内核线程扫描内存,并打印发现新的未引用对象数量。

支持kmemleak内核选项

要使用kmemlieak,需要打开如下内核选项。

Kernel hacking->Memory Debugging->Kernel memory leak detector:

CONFIG_HAVE_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400 # CONFIG_DEBUG_KMEMLEAK_TEST is not set CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y---------或者关闭此选项,则不需要在命令行添加kmemleak=on。

构造测试环境

同时还需要在内核启动命令行中添加kmemleak=on。

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -smp 2 -m 2048 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc console=ttyAMA0 loglevel=8 kmemleak=on" -nographic

static char *buf; void create_kmemleak(void) { buf = kmalloc(120, GFP_KERNEL); buf = vmalloc(4096); }

进行测试

进行kmemleak测试之前,需要写入scan触发扫描操作。

然后通过读kmemlean节点读取相关信息。

打开kmemlean扫描功能:echo scan > sys/kernel/debug/kmemleak

加载问题module:insmod data/kmemleak.ko

等待问题发现:kmemleak: 2 new suspected memory leaks (see /sys/kernel/debug/kmemleak)

查看kmemleak结果:cat /sys/kernel/debug/kmemleak

分析测试结果

每处泄露,都标出泄露地址和大小;相关进程信息;内存内容dump;栈回溯。
kmemleak会提示内存泄露可疑对象的具体栈调用信息、可疑对象的大小、使用哪个函数分配、二进制打印。
unreferenced object 0xede22dc0 (size 128):-------------------------------------第一处可疑泄露128字节
  comm "insmod", pid 765, jiffies 4294941257 (age 104.920s)--------------------相关进程信息
  hex dump (first 32 bytes):---------------------------------------------------二进制打印
    6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
    6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
  backtrace:-------------------------------------------------------------------栈回溯
    [] 0xbf002014
    [] do_one_initcall+0x90/0x1d8
    [] do_init_module+0x60/0x38c
    [] load_module+0x1bac/0x1e94
    [] SyS_init_module+0x14c/0x15c
    [] ret_fast_syscall+0x0/0x3c
    [] 0xffffffff
unreferenced object 0xf12ba000 (size 4096):
  comm "insmod", pid 765, jiffies 4294941257 (age 104.920s)
  hex dump (first 32 bytes):
    d8 21 00 00 02 18 00 00 e4 21 00 00 02 18 00 00  .!.......!......
    46 22 00 00 02 18 00 00 52 22 00 00 02 18 00 00  F"......R"......
  backtrace:
    [] vmalloc+0x2c/0x34
    [] 0xbf002014
    [] do_one_initcall+0x90/0x1d8
    [] do_init_module+0x60/0x38c
    [] load_module+0x1bac/0x1e94
    [] SyS_init_module+0x14c/0x15c
    [] ret_fast_syscall+0x0/0x3c
    [] 0xffffffff

kasan

kasan暂不支持32位ARM,支持ARM64和X86。

kasan是一个动态检查内存错误的工具,可以检查内存越界访问、使用已释放内存、重复释放以及栈溢出。

使能kasan

使用kasan,必须打开CONFIG_KASAN。

Kernel hacking->Memory debugging->KASan: runtime memory debugger

CONFIG_HAVE_ARCH_KASAN=y CONFIG_KASAN=y # CONFIG_KASAN_OUTLINE is not set CONFIG_KASAN_INLINE=y CONFIG_TEST_KASAN=m

代码分析

kasan_report ->kasan_report_error ->print_error_description ->print_address_description ->print_shadow_for_address

测试用及分析

kasan提供了一个测试程序test_kacan.c,将其编译成模块,加载到内核。可以模拟很多内存错误场景。

kasan可以检测到越界访问、访问已释放内存、重复释放等类型错误,其中重复释放借助于slub_debug。

insmod data/kasan.ko

越界访问包括slab越界、栈越界、全局变量越界;访问已释放内存use-after-free;重复释放可以被slub_debug识别。

slab-out-of-bounds

static noinline void __init kmalloc_oob_right(void)
{
    char *ptr;
    size_t size = 123;

    pr_info("out-of-bounds to right\n");
    ptr = kmalloc(size, GFP_KERNEL);
    if (!ptr) {
        pr_err("Allocation failed\n");
        return;
    }

    ptr[size] = 'x';
    kfree(ptr);
}
此种错误类型是对slab的越界访问,包括左侧、右侧、扩大、缩小后越界访问。除了数组赋值,还包括memset、指针访问等等。
al: kasan error test init
kasan test: kmalloc_oob_right out-of-bounds to right
==================================================================
BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa4/0xe0 [kasan] at addr ffff800066539c7b----------------错误类型是slab-out-of-bounds,在kmalloc_oob_right中产生。
Write of size 1 by task insmod/788
=============================================================================
BUG kmalloc-128 (Tainted: G O ): kasan: bad access detected-------------------------------------------------------------------slab非法非法访问
-----------------------------------------------------------------------------

Disabling lock debugging due to kernel taint
INFO: Allocated in kmalloc_oob_right+0x54/0xe0 [kasan] age=0 cpu=1 pid=788--------------------------------------------问题点kmalloc_oob_right的栈回溯
alloc_debug_processing+0x17c/0x188
___slab_alloc.constprop.30+0x3f8/0x440
__slab_alloc.isra.27.constprop.29+0x24/0x38
kmem_cache_alloc+0x220/0x280
kmalloc_oob_right+0x54/0xe0 [kasan]
kmalloc_tests_init+0x18/0x70 [kasan]
do_one_initcall+0x11c/0x310
do_init_module+0x1cc/0x588
load_module+0x48cc/0x5dc0
SyS_init_module+0x1a8/0x1e0
el0_svc_naked+0x24/0x28
INFO: Freed in do_one_initcall+0x10c/0x310 age=0 cpu=1 pid=788
free_debug_processing+0x17c/0x368
__slab_free+0x344/0x4a0
kfree+0x21c/0x250
do_one_initcall+0x10c/0x310
do_init_module+0x1cc/0x588
load_module+0x48cc/0x5dc0
SyS_init_module+0x1a8/0x1e0
el0_svc_naked+0x24/0x28
INFO: Slab 0xffff7bffc2994e00 objects=16 used=2 fp=0xffff800066539e00 flags=0x4080
INFO: Object 0xffff800066539c00 @offset=7168 fp=0xffff800066538200

Bytes b4 ffff800066539bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................------------------------------内存dump
Object ffff800066539c00: 00 82 53 66 00 80 ff ff 74 65 73 74 73 5f 69 6e ..Sf....tests_in
Object ffff800066539c10: 69 74 20 5b 6b 61 73 61 6e 5d 00 00 00 00 00 00 it [kasan]......
Object ffff800066539c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539c40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539c70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
CPU: 1 PID: 788 Comm: insmod Tainted: G B O 4.4.0+ #108------------------------------------------------------------------打印此log消息的栈回溯
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x270
[] show_stack+0x14/0x20
[] dump_stack+0x100/0x188
[] print_trailer+0xf8/0x160
[] object_err+0x3c/0x50
[] kasan_report_error+0x240/0x558
[] __asan_report_store1_noabort+0x48/0x50
[] kmalloc_oob_right+0xa4/0xe0 [kasan]
[] kmalloc_tests_init+0x18/0x70 [kasan]
[] do_one_initcall+0x11c/0x310
[] do_init_module+0x1cc/0x588
[] load_module+0x48cc/0x5dc0
[] SyS_init_module+0x1a8/0x1e0
[] el0_svc_naked+0x24/0x28
Memory state around the buggy address:
ffff800066539b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff800066539b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff800066539c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
^
ffff800066539c80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff800066539d00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

user-after-free

user-after-free是释放后使用的意思。

static noinline void __init kmalloc_uaf(void)
{
    char *ptr;
    size_t size = 10;

    pr_info("use-after-free\n");
    ptr = kmalloc(size, GFP_KERNEL);
    if (!ptr) {
        pr_err("Allocation failed\n");
        return;
    }

    kfree(ptr);
    *(ptr + 8) = 'x';
}

测试结果如下:

kasan test: kmalloc_uaf use-after-free
==================================================================
BUG: KASAN: use-after-free in kmalloc_uaf+0xac/0xe0 [kasan] at addr ffff800066539e08
Write of size 1 by task insmod/788
=============================================================================
BUG kmalloc-128 (Tainted: G B O ): kasan: bad access detected
-----------------------------------------------------------------------------

INFO: Allocated in kmalloc_uaf+0x54/0xe0 [kasan] age=0 cpu=1 pid=788
alloc_debug_processing+0x17c/0x188
___slab_alloc.constprop.30+0x3f8/0x440
__slab_alloc.isra.27.constprop.29+0x24/0x38
kmem_cache_alloc+0x220/0x280
kmalloc_uaf+0x54/0xe0 [kasan]
kmalloc_tests_init+0x48/0x70 [kasan]
do_one_initcall+0x11c/0x310
do_init_module+0x1cc/0x588
load_module+0x48cc/0x5dc0
SyS_init_module+0x1a8/0x1e0
el0_svc_naked+0x24/0x28
INFO: Freed in kmalloc_uaf+0x84/0xe0 [kasan] age=0 cpu=1 pid=788
free_debug_processing+0x17c/0x368
__slab_free+0x344/0x4a0
kfree+0x21c/0x250
kmalloc_uaf+0x84/0xe0 [kasan]
kmalloc_tests_init+0x48/0x70 [kasan]
do_one_initcall+0x11c/0x310
do_init_module+0x1cc/0x588
load_module+0x48cc/0x5dc0
SyS_init_module+0x1a8/0x1e0
el0_svc_naked+0x24/0x28
INFO: Slab 0xffff7bffc2994e00 objects=16 used=1 fp=0xffff800066539e00 flags=0x4080
INFO: Object 0xffff800066539e00 @offset=7680 fp=0xffff800066539800

Bytes b4 ffff800066539df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539e00: 00 98 53 66 00 80 ff ff 00 00 00 00 00 00 00 00 ..Sf............
Object ffff800066539e10: 00 9e 53 66 00 80 ff ff d0 51 12 00 00 80 ff ff ..Sf.....Q......
Object ffff800066539e20: 00 00 00 00 00 00 00 00 e0 14 6d 01 00 80 ff ff ..........m.....
Object ffff800066539e30: 00 69 a3 66 00 80 ff ff 18 69 a3 66 00 80 ff ff .i.f.....i.f....
Object ffff800066539e40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539e50: 30 da 73 00 00 80 ff ff 00 69 a3 66 00 80 ff ff 0.s......i.f....
Object ffff800066539e60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff800066539e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Padding ffff800066539ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
CPU: 1 PID: 788 Comm: insmod Tainted: G B O 4.4.0+ #108
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x270
[] show_stack+0x14/0x20
[] dump_stack+0x100/0x188
[] print_trailer+0xf8/0x160
[] object_err+0x3c/0x50
[] kasan_report_error+0x240/0x558
[] __asan_report_store1_noabort+0x48/0x50
[] kmalloc_uaf+0xac/0xe0 [kasan]
[] kmalloc_tests_init+0x48/0x70 [kasan]
[] do_one_initcall+0x11c/0x310
[] do_init_module+0x1cc/0x588
[] load_module+0x48cc/0x5dc0
[] SyS_init_module+0x1a8/0x1e0
[] el0_svc_naked+0x24/0x28
Memory state around the buggy address:
ffff800066539d00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff800066539d80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff800066539e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff800066539e80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff800066539f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

stack-out-of-bounds

栈越界访问是函数中数组越界,在实际工程中经常出现,问题难以发现。

static noinline void __init kasan_stack_oob(void)
{
    char stack_array[10];
    volatile int i = 0;
    char *p = &stack_array[ARRAY_SIZE(stack_array) + i];

    pr_info("out-of-bounds on stack\n");
    *(volatile char *)p;
}
 




kasan test: kasan_stack_oob out-of-bounds on stack
==================================================================
BUG: KASAN: stack-out-of-bounds in kasan_stack_oob+0xa8/0xf0 [kasan] at addr ffff800066acb95a
Read of size 1 by task insmod/788
page:ffff7bffc29ab2c0 count:0 mapcount:0 mapping: (null) index:0x0
flags: 0x0()
page dumped because: kasan: bad access detected
CPU: 1 PID: 788 Comm: insmod Tainted: G B O 4.4.0+ #108
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x270
[] show_stack+0x14/0x20
[] dump_stack+0x100/0x188
[] kasan_report_error+0x530/0x558
[] __asan_report_load1_noabort+0x48/0x50
[] kasan_stack_oob+0xa8/0xf0 [kasan]
[] kmalloc_tests_init+0x58/0x70 [kasan]
[] do_one_initcall+0x11c/0x310
[] do_init_module+0x1cc/0x588
[] load_module+0x48cc/0x5dc0
[] SyS_init_module+0x1a8/0x1e0
[] el0_svc_naked+0x24/0x28
Memory state around the buggy address:
ffff800066acb800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ffff800066acb880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
>ffff800066acb900: f1 f1 04 f4 f4 f4 f2 f2 f2 f2 00 02 f4 f4 f3 f3
^
ffff800066acb980: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
ffff800066acba00: f1 f1 00 00 00 00 00 00 00 00 f3 f3 f3 f3 00 00
==================================================================

global-out-of-bounds

static char global_array[10];

static noinline void __init kasan_global_oob(void)
{
    volatile int i = 3;
    char *p = &global_array[ARRAY_SIZE(global_array) + i];

    pr_info("out-of-bounds global variable\n");
    *(volatile char *)p;
}

测试结果如下:

复制kasan test: kasan_global_oob out-of-bounds global variable
==================================================================
BUG: KASAN: global-out-of-bounds in kasan_global_oob+0x9c/0xe8 [kasan] at addr ffff7ffffc001c8d
Read of size 1 by task insmod/788
Address belongs to variable global_array+0xd/0xffffffffffffe3f8 [kasan]
CPU: 1 PID: 788 Comm: insmod Tainted: G B O 4.4.0+ #108
Hardware name: linux,dummy-virt (DT)
Call trace:
[] dump_backtrace+0x0/0x270
[] show_stack+0x14/0x20
[] dump_stack+0x100/0x188
[] kasan_report_error+0x530/0x558
[] __asan_report_load1_noabort+0x48/0x50
[] kasan_global_oob+0x9c/0xe8 [kasan]
[] kmalloc_tests_init+0x5c/0x70 [kasan]
[] do_one_initcall+0x11c/0x310
[] do_init_module+0x1cc/0x588
[] load_module+0x48cc/0x5dc0
[] SyS_init_module+0x1a8/0x1e0
[] el0_svc_naked+0x24/0x28
Memory state around the buggy address:
ffff7ffffc001b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ffff7ffffc001c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffff7ffffc001c80: 00 02 fa fa fa fa fa fa 00 00 00 00 00 00 00 00
^
ffff7ffffc001d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ffff7ffffc001d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================

小结

kmemleak检查内存泄露的独门绝技,让其有一定市场空间。但功能比较单一,专注于内存泄露问题。

对于非ARM64/x86平台,只能使用slub_debug进行内存问题分析;kasan更高效,但也需要更高的内核和GCC版本支持。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编辑推荐 本书介绍如何在Linux下建立,运行并维护站点的综合技术,它适合于有一定的LinuxLinux基本操作基础的网络建立者。 本书从建站的准备工作开始,写到建立功能强大的INTERNET网站,层层深入,涉及到网站建设中所遇到的种种问题。从Linux的安装和设置入手,详尽地介绍了如何建立普通站点及具有WWW、E-MAIL、FTP、BBS等功能的完整的INTERNET站点,并在最后介绍了网络的安全及网站的升级。本书还提供了笔者在实际操作中积累的一些小技巧。 内容简介 本书介绍如何在Linux下建立,运行并维护站点的综合技术,它适合于有一定的LinuxLinux基本操作基础的网络建立者。 本书从建站的准备工作开始,写到建立功能强大的INTERNET网站,层层深入,涉及到网站建设中所遇到的种种问题。从Linux的安装和设置入手,详尽地介绍了如何建立普通站点及具有WWW、E-MAIL、FTP、BBS等功能的完整的INTERNET站点,并在最后介绍了网络的安全及网站的升级。本书还提供了笔者在实际操作中积累的一些小技巧。 目录 第1章 了解Linux及其网络结构 1.1 Linux简介 1.1.1 何谓Linux 1.1.2 Linux的功能 1.1.3 Linux当前的版本 1.2 Linux的TCP/IP网络结构 1.3 IPv6简介 1.3.1 IPv6与IPv4头标的比较 1.3.2 简化的头标 1.3.3 参数的修订 1.3.4 新导入的域 1.4 站点注册 1.4.1 何谓站点注册 1.4.2 注册Linux站点 1.5 常见问题及解答 1.5.1 关于运行DOS/Windows上的程序 1.5.2 关于Linux的资料来源 1.5.3 关于获取帮助 第2章 服务器平台安装和设备管理 2.1 硬件选择 2.1.1 CPU、RAM和主板与性能的关系 2.1.2 硬盘的选择 2.1.3 显示卡与监视器的选择 2.1.4 电源与UPS的选择 2.2 Linux的安装准备 2.2.1 Linux的获取 2.2.2 了解你的计算机配置 2.2.3 Linux的安装方式 2.2.4 安装Linux的硬盘分区 2.2.5 有关LILO的基础知识 2.3 Linux的安装 2.3.1 首先应该知道的事 2.3.2 开始安装:有关安装启动程序的选择 2.3.3 安装过程 2.3.4 最后的设置工作 2.3.5 安装LILO 2.4 Linux下的硬件设备管理 2.4.1 Linux设备管理概述 2.4.2 SCSI设备 2.4.3 硬盘 2.4.4 CD-ROM驱动器 2.4.5 调制解调器 第3章 配置TCP/IP网络 3.1 开始之前需要的信息 3.1.1 IP地址 3.1.2 网络掩码 3.1.3 网络地址(Network Address) 3.1.4 广播地址(Broadcast Address) 3.1.5 网关地址(Router/Gateway Address) 3.1.6 名字服务器地址(Nameserver Address) 3.2 用netcfg配置网络 3.2.1 操纵名字 3.2.2 操纵主机 3.2.3 增加网络接口设备 3.3 安装网卡 3.3.1 设置网卡模式 3.3.2 配置网卡 3.3.3 有关Intel Etherexpress系列卡的配置 3.3.4 网卡配置中的一些疑问 3.4 路由、网关和IPChains 3.4.1 路由和网关的概念 3.4.2 使用IPChains实现数据包过滤和转发 第4章 Linux文件及系统管理 4.1 文件和目录 4.1.1 文件和目录概述 4.1.2 文件类型 4.2 文件权限 4.2.1 文件权限的概念 4.2.2 文件权限的构成 4.2.3 文件权限的依赖性 4.2.4 改变权限 4.3 文件链接 4.3.1 硬链接 4.3.2 符号链接 4.4 文件系统和标准文件系统布局 4.4.1 文件系统 4.4.2 标准文件系统布局 4.5 基本目录介绍 4.5.1 根文件系统 4.5.2 /etc文件系统 4.5.3 /dev文件系统 4.5.4 /usr文件系统 4.5.5 /var文件系统 4.5.6 /proc文件系统 4.6 启动和关机 4.6.1 启动和关机概述 4.6.2 近观启动过程 4.6.3 重新启动系统 4.6.4 紧急启动(软)盘 4.6.5 有关关机的更多信息 4.7 登录和注销 4.7.1 通过终端登录 4.7.2 通过网络登录 4.7.3 login干了些什么 4.7.4 存取控制 4.7.5 Shell启动 4.8 管理用户 4.8.1 系统管理员 4.8.2 管理职责 4.8.3 用户管理 4.8.4 用户组管理 4.8.5 使用LinuxConf管理用户 4.9 内存管理 4.9.1 什么是虚拟内存 4.9.2 产生对换空间 4.9.3 使用对换空间 4.9.4 与其他操作系统共享对换空间 4.9.5 分配对换空间 4.9.6 高速缓存 4.10 X Window 4.10.1 如果没有安装X 4.10.2 如果已经安装了X 第5章 Linux的网络设置 5.1 配置NFC服务器 5.1.1 NFS简介 5.1.2 设置NFS服务器 5.1.3 设置NFS客户机 5.1.4 NFS的工作原理 5.1.5 NFS守护程序的启动过程 5.1.6 各服务进程的作用 5.2 建立PPP连接和配置PPP服务器 5.2.1 有关PPP的基础知识 5.2.2 使用PPP拨号上网 5.2.3 配置PPP服务器 5.3 配置DNS服务器 5.3.1 DNS(Domain Name System)简介 5.3.2 域名服务系统 5.3.3 域名服务器和解析器 5.3.4 配置暂存专用名字服务器 5.3.5 建立一个简单的领域名字服务器 5.3.6 配置实例 5.3.7 维护工作 5.3.8 拨号网络连线的自动设置 第6章 建立Internet站点 6.1 E-mail服务器的建立 6.1.1 sendmail服务器的设置 6.1.2 在Linux机器上设置pop3代理 6.2 FTP服务器的建立 6.3 WWW服务器的建立 6.4 建立Samba服务器 6.4.1 Samba是什么 6.4.2 安装Samba 6.4.3 设置Samba的配置文件 6.4.4 启动Samba 6.4.5 Samba常用的重要指令 第7章 超文本标记语言(HTML) 7.1 HTML概述 7.2 HTML文件描述 7.3 段落、格式、版面分割标记 7.4 文字效果标记 7.5 超级链接标记 7.6 文字列表标记 7.7 表格标记 7.8 插入图像标记 第8章 PHP主页设计 8.1 内嵌式脚本语言PHP概述 8.1.1 PHP发展历史 8.1.2 PHP的主要技术特点 8.2 PHP语句 8.2.1 初识PHP 8.2.2 PHP语句和HTML分离 8.3 PHP中的变量 8.3.1 变量名和变量类型 8.3.2 深入了解变量类型转化 8.3.3 数组类型 8.3.4 动态变量 8.3.5 类和对象 8.3.6 变量作用域 8.4 外界变量和交互式网页 8.4.1 PHP从客户端获取信息的方法:外界变量 8.4.2 使用HTTP Form获取信息 8.4.3 HTTP Cookies与客户端信息 8.4.4 使用环境变量获取客户端信息 8.5 基本控制流程:分支和循环 8.5.1 条件语句和分支结构 8.5.2 循环语句 8.6 表达式基础 8.6.1 算术运算符 8.6.2 字符串运算符 8.6.3 赋值运算符 8.6.4 位运算符 8.6.5 逻辑运算符 8.6.6 比较运算符 8.7 PHP常用函数和MySQL数据库访问函数 8.7.1 PHP内置数学函数 8.7.2 日期时间围数 8.7.3 PHP的数据库功能及对MySQL数据库访问 第9章 建立BBS服务器 9.1 BBS服务器概述 9.2 Firebird BBS系统建站准备 9.2.1 最初的准备工作 9.2.2 BBS相关帐号的设置 9.3 Firebird BBS服务器系统安装 9.4 测试BBS并建立系统帐号 9.5 BBS相关配置 9.5.1 BBS配置文件sysconf.ini 9.5.2 sysconf.ini中定义的主要权限说明 9.5.3 版面的设置 9.5.4 Firebird BBS主要文件说明 9.6 BBS转信功能 9.6.1 主动式和被动式收信 9.6.2 BBS送信工作原理 9.6.3 安装转信程序innbbsd 第10章 服务器的安全性概述 10.1 服务器安全管理 10.1.1 安全防护的主要内容 10.1.2 Linux系统的文件安全 10.1.3 用户访问安全 10.1.4 日常安全注意事项 10.1.5 服务器被侵入后的处理 10.2 防火墙、IP伪装和代理服务器 10.2.1 什么是防火墙 10.2.2 防火墙分类 10.2.3 Linux防火墙实现策略 第11章 网站建设实例 11.1 Apache、PHP、MySQL简介 11.2 Apache、PHP、MySQL的安装 11.2.1 安装和启动MySQL 11.2.2 安装PHP+Apache 11.2.3 启动Apache并测试 11.2.4 测试MySQL数据库 11.3 网站设计和主页面制作 11.3.1 网站总体设计 11.3.2 网站风格设计 11.3.3 需要注意的问题 11.3.4 “Linux网站建设者”首页 11.4 网站设计和主页面制作 11.4.1 Web-BBS的结构分析 11.4.2 数据库的建立和测试 11.4.3 Web-BBS主页面制作 11.4.4 “发表文章”功能块制作 11.4.5 几点探讨和功能扩充
深入分析Linux内核源码 前言 第一章 走进linux 1.1 GNU与Linux的成长 1.2 Linux开发模式和运作机制 1.3走进Linux内核 1.3.1 Linux内核的特征 1.3.2 Linux内核版本的变化 1.4 分析Linux内核的意义 1.4.1 开发适合自己的操作系统 1.4.2 开发高水平软件 1.4.3 有助于计算机科学的教学和科研 1.5 Linux内核结构 1.5.1 Linux内核在整个操系统中的位置 1.5.2 Linux内核的作用 1.5.3 Linux内核的抽象结构 1.6 Linux内核源代码 1.6.1 多版本的内核源代码 1.6.2 Linux内核源代码的结构 1.6.3 从何处开始阅读源代码 1.7 Linux内核源代码分析工具 1.7.1 Linux超文本交叉代码检索工具 1.7.2 Windows平台下的源代码阅读工具Source Insight 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.1.1通用寄存器 2.1.2段寄存器 2.1.3状态和控制寄存器 2.1.4 系统地址寄存器 2.1.5 调试寄存器和测试寄存器 2.2 内存地址 2.3 段机制和描述符 2.3.1 段机制 2.3.2 描述符的概念 2.3.3系统段描述符 2.3.4 描述符表 2.3.5 选择符与描述符表寄存器 2.3.6 描述符投影寄存器 2.3.7 Linux中的段 2.4 分页机制 2.4.1 分页机构 2.4.2页面高速缓存 2.5 Linux中的分页机制 2.5.1 与页相关的数据结构及宏的定义 2.5.2 对页目录及页表的处理 2.6 Linux中的汇编语言 2.6.1 AT&T与Intel汇编语言的比较 2.6.2 AT&T汇编语言的相关知识 2.6.3 Gcc嵌入式汇编 2.6.4 Intel386汇编指令摘要 第三章中断机制 3.1 中断基本知识 3.1.1 中断向量 3.1.2 外设可屏蔽中断 3.1.3异常及非屏蔽中断 3.1.4中断描述符表 3.1.5 相关汇编指令 3.2中断描述符表的初始化 3.2. 1 外部中断向量的设置 3.2.2中断描述符表IDT的预初始化 3.2.3 中断向量表的最终初始化 3.3异常处理 3.3.1 在内核栈中保存寄存器的值 3.3.2 中断请求队列的初始化 3.3.3中断请求队列的数据结构 3.4 中断处理 3.4.1中断和异常处理的硬件处理 3.4.2 Linux对异常和中断的处理 3.4.3 与堆栈有关的常量、数据结构及宏 3.4.4 中断处理程序的执行 3.4.5 从中断返回 3.5中断的后半部分处理机制 3.5.1 为什么把中断分为两部分来处理 3.5.2 实现机制 3.5.3数据结构的定义 3.5.4 软中断、bh及tasklet的初始化 3.5.5后半部分的执行 3.5.6 把bh移植到tasklet 第四章 进程描述 4.1 进程和程序(Process and Program) 4.2 Linux中的进程概述 4.3 task_struct结构描述 4.4 task_struct结构在内存中的存放 4.4.1 进程内核栈 4.4.2 当前进程(current宏) 4.5 进程组织的方式 4.5.1哈希表 4.5.2双向循环链表 4.5.3 运行队列 4.5.4 等待队列 4.6 内核线程 4.7 进程的权能 4.8 内核同步 4.8.1信号量 4.8.2原子操作 4.8.3 自旋锁、读写自旋锁和大读者自旋锁 4.9 本章小节 第五章进程调度 5.1 Linux时间系统 5.1.1 时钟硬件 5.1.2 时钟运作机制 5.1.3 Linux时间基准 5.1.4 Linux的时间系统 5.2 时钟中断 5.2.1 时钟中断的产生 5.2.2.Linux实现时钟中断的全过程 5.3 Linux的调度程序-Schedule( ) 5.3.1 基本原理 5.3.2 Linux进程调度时机 5.3.3 进程调度的依据 5.3.4 进程可运行程度的衡量 5.3.5 进程调度的实现 5.4 进程切换 5.4.1 硬件支持 5.4.2 进程切换 第六章 Linux内存管理 6.1 Linux内存管理概述 6.1.1 Linux虚拟内存的实现结构 6.1.2 内核空间和用户空间 6.1.3 虚拟内存实现机制间的关系 6.2 Linux内存管理的初始化 6.2.1 启用分页机制 6.2.2 物理内存的探测 6.2.3 物理内存的描述 6.2.4 页面管理机制的初步建立 6.2.5页表的建立 6.2.6内存管理区 6.3 内存的分配和回收 6.3.1 伙伴算法 6.3.2 物理页面的分配和释放 6.3.3 Slab分配机制 6.4 地址映射机制 6.4.1 描述虚拟空间的数据结构 6.4.2 进程的虚拟空间 6.4.3 内存映射 6.5 请页机制 6.5.1 页故障的产生 6.5.2 页错误的定位 6.5.3 进程地址空间中的缺页异常处理 6.5.4 请求调页 6.5.5 写时复制 6.6 交换机制 6.6.1 交换的基本原理 6.6.2 页面交换守护进程kswapd 6.6.3 交换空间的数据结构 6.6.4 交换空间的应用 6.7 缓存和刷新机制 6.7.1 Linux使用的缓存 6.7.2 缓冲区高速缓存 6.7.3 翻译后援存储器(TLB) 6.7.4 刷新机制 6.8 进程的创建和执行 6.8.1 进程的创建 6.8.2 程序执行 6.8.3 执行函数 第七章 进程间通信 7.1 管道 7.1.1 Linux管道的实现机制 7.1.2 管道的应用 7.1.3 命名管道(FIFO) 7.2 信号(signal) 7.2.1 信号种类 7.2.2 信号掩码 7.2.3 系统调用 7.2.4 典型系统调用的实现 7.2.5 进程与信号的关系 7.2.6 信号举例 7.3 System V 的IPC机制 7.3.1 信号量 7.3.2 消息队列 7.3.3 共享内存 第八章 虚拟文件系统 8.1 概述 8.2 VFS中的数据结构 8.2.1 超级块 8.2.2 VFS的索引节点 8.2.3 目录项对象 8.2.4 与进程相关的文件结构 8.2.5 主要数据结构间的关系 8.2.6 有关操作的数据结构 8.3 高速缓存 8.3.1 块高速缓存 8.3.2 索引节点高速缓存 8.3.3 目录高速缓存 8.4 文件系统的注册、安装与拆卸 8.4.1 文件系统的注册 8.4.2 文件系统的安装 8.4.3 文件系统的卸载 8.5 限额机制 8.6 具体文件系统举例 8.6.1 管道文件系统pipefs 8.6.2 磁盘文件系统BFS 8.7 文件系统的系统调用 8.7.1 open 系统调用 8.7.2 read 系统调用 8.7.3 fcntl 系统调用 8 .8 Linux2.4文件系统的移植问题 第九章 Ext2文件系统 9.1 基本概念 9.2 Ext2的磁盘布局和数据结构 9.2.1 Ext2的磁盘布局 9.2.2 Ext2的超级块 9.2.3 Ext2的索引节点 9.2.4 组描述符 9.2.5 位图 9.2.6 索引节点表及实例分析 9.2.7 Ext2的目录项及文件的定位 9.3 文件的访问权限和安全 9.4 链接文件 9.5 分配策略 9.5.1 数据块寻址 9.5.2 文件的洞 9.5.3 分配一个数据块 第十章 模块机制 10.1 概述 10.1.1 什么是模块 10.1.2 为什么要使用模块? 10.2 实现机制 10.2.1 数据结构 10.2.2 实现机制的分析 10.3 模块的装入和卸载 10.3.1 实现机制 10.3.2 如何插入和卸载模块 10.4 内核版本 10.4.1 内核版本与模块版本的兼容性 10.4.2 从版本2.0到2.2内核API的变化 10.4.3 把内核2.2移植到内核2.4 10.5 编写内核模块 10.5.1 简单内核模块的编写 10.5.2 内核模块的Makefiles文件 10.5.3 内核模块的多个文件 第十一章 设备驱动程序 11.1 概述 11.1.1 I/O软件 11.1.2 设备驱动程序 11.2 设备驱动基础 11.2.1 I/O端口 11.2.2 I/O接口及设备控制器 11.2.3 设备文件 11.2.4 VFS对设备文件的处理 11.2.5 中断处理 11.2.6 驱动DMA工作 11.2.7 I/O 空间的映射 11.2.8 设备驱动程序框架 11.3 块设备驱动程序 11.3.1 块设备驱动程序的注册 11.3.2 块设备基于缓冲区的数据交换 11.3.3 块设备驱动程序的几个函数 11.3.4 RAM 盘驱动程序的实现 11.3.5 硬盘驱动程序的实现 11.4 字符设备驱动程序 11.4.1 简单字符设备驱动程序 11.4.2 字符设备驱动程序的注册 11.4.3 一个字符设备驱动程序的实例 11.4.4 驱动程序的编译与装载 第十二章 网络 12.1 概述 12.2 网络协议 12.2.1 网络参考模型 12.2.2 TCP/IP 协议工作原理及数据流 12.2.3 Internet 协议 12.2.4 TCP协议 12.3 套接字(socket) 12.3.1 套接字在网络中的地位和作用 12.3.2 套接字接口的种类 12.3.3 套接字的工作原理 12.3.4 socket 的通信过程 12.3.5 socket为用户提供的系统调用 12.4 套接字缓冲区(sk_buff) 12.4.1 套接字缓冲区的特点 12.4.2 套接字缓冲区操作基本原理 12.4.3 sk_buff数据结构的核心内容 12.4.4 套接字缓冲区提供的函数 12.4.5 套接字缓冲区的上层支持例程 12.5 网络设备接口 12.5.1 基本结构 12.5.2 命名规则 12.5.3 设备注册 12.5.4 网络设备数据结构 12.5.5 支持函数 第十三章 启动系统 13.1 初始化流程 13.1.1 系统加电或复位 13.1.2 BIOS启动 13.1.3 Boot Loader 13.1.4 操作系统的初始化 13.2 初始化的任务 13.2.1 处理器对初始化的影响 13.2.2 其他硬件设备对处理器的影响 13.3 Linux 的Boot Loarder 13.3.1 软盘的结构 13.3.2 硬盘的结构 13.3.3 Boot Loader 13.3.4 LILO 13.3.5 LILO的运行分析 13.4 进入操作系统 13.4.1 Setup.S 13.4.2 Head.S 13.5 main.c中的初始化 13.6 建立init进程 13.6.1 init进程的建立 13.6.2 启动所需的Shell脚本文件 附录: 1 Linux 2.4内核API 2.1 驱动程序的基本函数 2.2 双向循环链表的操作 2.3 基本C库函数 2.4 Linux内存管理中Slab缓冲区 2.5 Linux中的VFS 2.6 Linux的连网 2.7 网络设备支持 2.8 模块支持 2.9 硬件接口 2.10 块设备 2.11 USB 设备 2 参考文献
### 回答1: 《深入理解Linux内核》是一本经典的计算机科学书籍,它是由Daniel P. Bovet和Marco Cesati共同撰写的。该书深入介绍了Linux内核的各个方面,包括进程管理、内存管理、文件系统、设备驱动程序等等。 在《深入理解Linux内核》中,作者系统地介绍了Linux内核的设计和实现原理。他们从整体架构开始,逐步深入讲解各个子系统的功能和实现细节,全面展示了Linux内核的工作原理。通过学习这本书,读者可以学习到Linux内核的基本概念、关键数据结构和算法,以及与其他操作系统的对比。 这本书针对的读者主要是计算机专业的学生和从业人员。它不仅能帮助读者更深入地理解Linux操作系统,还能培养读者分析和解决操作系统相关问题的能力。同时,书中丰富的实例和代码也对学习者进行了良好的指导,帮助他们更好地理解和掌握内核编程技巧。 总而言之,《深入理解Linux内核》是一本值得深入研读的经典教材。它不仅详细介绍了Linux内核的各个方面,还为读者提供了丰富的实例和代码,帮助他们更好地理解和掌握内核编程技巧。读完这本书,读者可以更深入地理解Linux内核的工作原理,为深入研究和开发操作系统打好坚实的基础。 ### 回答2: 《深入理解 Linux 内核》是一本介绍 Linux 操作系统内核设计和实现原理的经典著作。这本书的目的是帮助读者深入了解 Linux 内核的核心概念、运行机制和关键模块,从而更好地理解 Linux 操作系统的工作原理。 首先,这本书涵盖了 Linux 内核的各个方面,包括进程管理、内存管理、进程间通信、文件系统、设备驱动程序等。通过深入了解这些模块的设计和实现原理,读者可以全面掌握 Linux 内核的工作方式,并能够更好地进行系统调优和应用开发。 此外,本书还介绍了 Linux 内核的主要数据结构和算法,包括链表、红黑树、哈希表等。对这些数据结构的深入理解,对于理解 Linux 内核代码和实现原理非常重要。通过详细讲解这些数据结构的设计和实现,读者可以更好地理解它们在 Linux 内核中的使用场景和性能特性。 另外,本书还详细介绍了 Linux 内核的调试和性能优化技术。作者详细介绍了使用 GNU 调试器来调试内核代码、使用运行时检测工具来检测内核错误、使用静态分析工具来分析内核代码等技术。这些技术对于诊断和解决内核问题非常有帮助,并能够提高系统性能。 总的来说,深入理解 Linux 内核这本书是一本系统而深入的介绍 Linux 内核设计和实现原理的优秀著作。通过学习这本书,读者可以全面掌握 Linux 内核的运行机制和关键模块,提高对 Linux 操作系统的理解和应用开发的能力。 ### 回答3: 《深入理解Linux内核》 PDF是一本经典的Linux内核学习资料,它以深入和全面的方式探索了Linux内核的工作原理和设计思想。 首先,这本书介绍了Linux内核的基本概念和组成结构。它从进程管理、内存管理、文件系统等方面详细解析了内核的各个功能模块,让读者了解内核的整体架构和运行机制。 其次,这本书深入剖析了Linux内核的调度器和进程管理。它详细介绍了调度器的工作原理,包括进程调度策略、调度队列的管理等内容。此外,它还讨论了进程的创建、销毁以及进程状态转换等方面,帮助读者理解进程管理的核心概念和实现原理。 此外,这本书还介绍了Linux内核的内存管理机制。它涵盖了虚拟内存、分页机制、内存分配和回收等关键话题。通过解析内存管理的细节,读者可以更好地理解Linux内核如何管理系统资源,并优化内存使用效率。 此外,《深入理解Linux内核》 PDF还深入讲解了Linux的文件系统。它涵盖了文件系统的组织结构、文件系统缓存、文件的读写操作等关键知识点。通过学习文件系统的实现原理,读者可以了解文件系统如何存储和管理文件数据,并对文件I/O操作有更深入的理解。 最后,这本书还涵盖了设备驱动程序和网络协议栈等内容。它讲解了设备驱动程序的框架和实现原理,以及Linux内核对网络通信的支持。通过学习这些内容,读者可以了解Linux内核如何与外设和网络进行交互。 总之,这本书通过详细而全面的介绍,帮助读者深入理解Linux内核的工作原理和设计思想。它不仅适合想要深入研究Linux内核的专业人士,也适合对Linux系统有兴趣的读者参考学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值