整理一些杂乱的内容。以下x86架构。

Linux 内核栈大小

内核栈大小是固定的,默认为8k,曾经有选项可以设置为4k栈。由于大小固定,申请过大的栈内存,或者函数调用层次过深,都可能导致栈溢出。

关注默认4k还是8k栈,社区曾有过长时间讨论。

其中8k栈的缺点如下:

  1. 浪费内存。

  2. 由于内核4k分页,要创建一个内核栈就需要申请2块连续的4k页。当内存碎片严重,尤其内存紧张的时候,申请8k的连续内存,要比4k困难的多。

但貌似4k栈带来的麻烦更大,内核中许多bug都由4k栈太小,发生溢出导致的。

因此内核从 2.6.37 版本开始,便移除了对4k栈的支持,见 commit : dcfa726280116dd31adad37da940f542663567d0

Linux内核栈布局

栈地址是逆增长的,thread_info 结构位于栈的底部,即低地址处。

top     +----------------+
| return vals |
| & local vars |
| ... |
| |
| |
| 0's |
| thread_info |
bottom +----------------+

从内核栈布局可以的到,如果在栈上申请内存过多,则会下溢破坏 thread_info 结构。在绕过 pxn 的时候,有一个办法是修改进程的 addr_limit 值,这个值在 thread_info 中。由于内核栈固定8k的特性,要计算 thread_info 位置,只需要将 sp 指针的后13位清0,即 sp & ~(THREAD_SIZE-1) 即可。

thread_info_addr = sp & ~(THREAD_SIZE-1)

struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
#ifdef CONFIG_X86_32
unsigned long previous_esp;
__u8 supervisor_stack[0];
#endif
int uaccess_err;
};

Stack 使用安全

由申请栈内存过多、过大,或函数调用层次太深导致的溢出问题非常隐蔽,因此这是内核编码中需注意的地方。同时有许多工具来检查这类BUG:

1. CONFIG_FRAME_WARN

这是一个内核配置选项,默认为1024,在内核编译时传递给gcc的“-Wframe-larger-than=xxx”选项,当编译器检测到栈使用大于阙值时,会产生一条编译告警:

  ...
CC ipc/msg.o
CC ipc/sem.o
.../linux-3.0.y/ipc/sem.c: In function 'semctl_main.clone.7':
.../linux-3.0.y/ipc/sem.c:1021:1: warning: the frame size of 520 bytes is larger than 256 bytes
.../linux-3.0.y/ipc/sem.c: In function 'sys_semtimedop':
.../linux-3.0.y/ipc/sem.c:1514:1: warning: the frame size of 472 bytes is larger than 256 bytes
CC ipc/shm.o
CC ipc/ipcns_notifier.o

2. checkstack.pl

checkstack.pl是内核源码中的一个Perl脚本,用于执行静态的栈分析,使用方法如下:

$(CROSS_COMPILE)objdump -d vmlinux | scripts/checkstack.pl [arch]

其中arch支持arm, mips and x86等架构。注意其参数,是一个.S的汇编代码通过pipe输入checkstack.pl的

$ arm-eabi-objdummp -d vmlinux -o vmlinux-arm.S
$ cat vmlinux-arm.S | scripts/checkstack.pl arm
0x0012c858 nlmclnt_reclaim [vmlinux-arm.o]: 720
0x0025748c do_tcp_getsockopt.clone.11 [vmlinux-arm.o]: 552
0x00258d04 do_tcp_setsockopt.clone.14 [vmlinux-arm.o]: 544
...

3.CONFIG_DEBUG_STACK_USAGE

同样是一个内核选项,用于输出每个进程的栈使用情况。它的原理是在内核栈创建时使用’0’初始化,再通过计算thread_info结构到第一个非0位置的大小,获取栈使用情况。

可以通过 dmesg 查看栈使用情况:

# dmesg | grep greatest
kworker/u:0 used greatest stack depth: 10564 bytes left
busybox used greatest stack depth: 9512 bytes left
busybox used greatest stack depth: 9504 bytes left
grep used greatest stack depth: 9372 bytes left
init used greatest stack depth: 9028 bytes left

为什么dmesg中会有栈使用情况,看下CONFIG_DEBUG_STACK_USAGE的具体功能:

  • 首先在进程创建时,将进程栈填充为0(kernel/fork.c)
  • sysrq ‘t’时,显示空闲内存大小,这是通过 stack_not_used()调用实现(kernel/sched.c)
  • 定义check_stack_usage(),每次low-water时,进行printks打印
    • low-water是所有栈全局共享的
    • check_stack_usage()只有在进程退出时调用,因此只有在进程退出时才会发现栈使用的问题
  • stack_not_used()在include/linux/sched.h文件中定义,他输出从thread_info到第一个非0位置的内存大小

也可以通过 ‘t’ sysrq,得到当前运行进程栈实时的使用情况:

$ echo t >/proc/sysrq-trigger
$ dmesg | grep -v [[]
task PC stack pid father
init S 802af8b0 932 1 0 0x00000000
kthreadd S 802af8b0 2496 2 0 0x00000000
ksoftirqd/0 S 802af8b0 2840 3 2 0x00000000
kworker/0:0 S 802af8b0 2776 4 2 0x00000000
kworker/u:0 S 802af8b0 2548 5 2 0x00000000
...

Linux Kernel Stack的更多相关文章

  1. [轉]Exploit Linux Kernel Slub Overflow

    Exploit Linux Kernel Slub Overflow By wzt 一.前言 最近几年关于kernel exploit的研究比较热门,常见的内核提权漏洞大致可以分为几类: 空指针引用, ...

  2. Intel 80x86 Linux Kernel Interrupt(中断)、Interrupt Priority、Interrupt nesting、Prohibit Things Whthin CPU In The Interrupt Off State

    目录 . 引言 . Linux 中断的概念 . 中断处理流程 . Linux 中断相关的源代码分析 . Linux 硬件中断 . Linux 软中断 . 中断优先级 . CPU在关中断状态下编程要注意 ...

  3. Linux Kernel中断子系统来龙去脉浅析【转】

    转自:http://blog.csdn.net/u011461299/article/details/9772215 版权声明:本文为博主原创文章,未经博主允许不得转载. 一般来说,在一个device ...

  4. arm linux kernel 从入口到start_kernel 的代码分析

    参考资料: <ARM体系结构与编程> <嵌入式Linux应用开发完全手册> Linux_Memory_Address_Mapping http://www.chinaunix. ...

  5. andriod and linux kernel启动流程

    虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makefile,讲一下boot ...

  6. Monitoring and Tuning the Linux Networking Stack: Receiving Data

    http://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/ ...

  7. the Linux Kernel: Traffic Control, Shaping and QoS

    −Table of Contents Journey to the Center of the Linux Kernel: Traffic Control, Shaping and QoS 1 Int ...

  8. Queueing in the Linux Network Stack !!!!!!!!!!!!!!!

    https://www.coverfire.com/articles/queueing-in-the-linux-network-stack/ Queueing in the Linux Networ ...

  9. Linux kernel 4.9及以上开启TCP BBR拥塞算法

    Linux kernel 4.9及以上开启TCP BBR拥塞算法 BBR 目的是要尽量跑满带宽, 并且尽量不要有排队的情况, 效果并不比速锐差 Linux kernel 4.9+ 已支持 tcp_bb ...

随机推荐

  1. Notation, First Definitions 转 http://brnt.eu/phd/node9.html

    LaTeX command Equivalent to Output style Remarks \textnormal{...} {\normalfont...} document font fam ...

  2. mex

    edit(fullfile(prefdir, 'mexopts.bat')) http://www.mathworks.cn/support/solutions/en/data/1-8FJXQE/in ...

  3. java ArrayList 迭代器快速失败源码分析

    先来看一个例子: @Test void test2() { ArrayList<String> list = new ArrayList<String>(); list.add ...

  4. 尚学堂java 答案解析 第五章

    本答案为本人个人编辑,仅供参考,如果读者发现,请私信本人或在下方评论,提醒本人修改 一.选择题 1.AB 解析:A可以被所有类访问,B可以被当前包的所有类访问,也可以被所有子类访问 2.A 解析:所有 ...

  5. flask+apache+mod-wsgi部署遇到的坑

    首先,看到这种方式部署,我也有疑问,为什么不用nginx,gunicorn.接手的项目,就先按照前人思路run起来. 线上使用ubuntu系统,apache2,而给我玩耍的测试机是centos6.5, ...

  6. unity3D 中的C#脚本一个类调用另一类中简单方法

    案例展示 SubMenuManage类中的实例化代码如下: static SubMenuManage sub_this; public static SubMenuManage Instance() ...

  7. Android开发 ---Fragment片段布局

    前言 Fragment想必大家不陌生吧,在日常开发中,对于Fragment的使用也很频繁,现在主流的APP中,基本的架构也都是一个主页,然后每个Tab项用Fragment做布局,不同选项做切换,使用起 ...

  8. 数位DP详解

    算法使用范围 在一个区间里面求有多少个满足题目所给的约束条件的数,约束条件必须与数自身的属性有关 下面用kuangbin数位dp的题来介绍 例题  不要62 题意:在一个区间里面求出有多少个不含4和6 ...

  9. java基础学习之final关键字

    final可以修饰类.方法.变量,一旦使用了final则将不能改变被修饰的对象的引用; 被final修饰的类不可以被继承 被final修饰的方法不可以被覆盖 被final修饰的变量一般为常量,只允许对 ...

  10. Linux下Ganglia集群监控安装、配置笔记

    http://www.blogjava.net/henry14/archive/2011/12/17/ganglia.html 枪声依旧 Linux下Ganglia集群监控安装.配置笔记 Gangli ...