在内核态(比如应用进程执行系统调用)时,进程运行需要自己的堆栈信息(不是原用户空间中的栈),而是使用内核空间中的栈,这个栈就是进程的内核栈 2.进程的内核栈在计算机中是如何描述的?...void *stack; // 指向内核栈的指针 // ... }; task_struct数据结构中的stack成员指向thread_union结构(Linux内核通过thread_union...这个结构体保存了进程描述符中中频繁访问和需要快速访问的字段,内核依赖于该数据结构来获得当前进程的描述符(为了获取当前CPU上运行进程的task_struct结构,内核提供了current宏。..., 这就是struct task_struct, 而thread_info 就保存了特定体系结构的汇编代码段需要访问的那部分进程的数据,我们在thread_info中嵌入指向task_struct的指针..., 则我们可以很方便的通过thread_info来查找task_struct 4.内核栈的大小?
Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在include/linux/sched.h文件中。...现在,我们来看看内核如何将进程置为睡眠状态。 内核如何将进程置为睡眠状态 Linux 内核提供了两种方法将进程置为睡眠状态。...但是较新的内核代码中,进程描述符task_struct结构中没有直接指向thread_info结构的指针,而是用一个void指针类型的成员表示,然后通过类型转换来访问thread_info结构。...内核栈数据结构描述thread_info和thread_union thread_info是体系结构相关的,结构的定义在thread_info.h中 Linux内核中使用一个联合体来表示一个进程的线程描述符和内核栈...(long)]; }; 获取当前在CPU上正在运行进程的thread_info 下面来说说如何通过esp栈指针来获取当前在CPU上正在运行进程的thread_info结构。
引 在阅读perf源码的过程中,发现有诸多地方不太了解。思索再三,还是考虑先阅读一些Linux相关的资料。本文是《Linux内核设计与实现》系列阅读的第一篇文章。...在阅读的过程中,笔者尽量的在最新的源码中寻找对应,从而帮助理解。笔者基于v6.3内核进行相关的代码阅读,在引用源码的地方会通过注释标出代码位置,例如L737是指737行。...在Linux中,内核把进程列表放在一个双向循环链表中,该链表的每一项都是一个task_struct结构的数据,我们将其称之为进程描述符。...该结构定义在include/linux/sched.h文件中,而且这个结构体有非常多的属性,在《Linux内核设计与实现》一书中提到,在当时的task_struct结构体就有1.7KB大小,现在的内核只增不减...而从定义中我们会发现,这个链表并不包含具体的数据,而只有前后指针的相关信息,那内核是如何获取到整个结构体的数据的呢?我们明天在进行相关的介绍。
通过 task_struct 描述进程 内核里,通过 task_struct 结构体来描述一个进程,称为进程描述符 (process descriptor),它保存着支撑一个进程正常运行的所有信息。...task_struct 结构体内容太多,这里只列出部分成员变量,感兴趣的读者可以去源码 include/linux/sched.h头文件查看。...void *stack:指向内核栈的指针,内核通过 dup_task_struct 为每个进程都分配内核栈空间,并记录在此。...内核在启动的时候会在 head.S 里通过 __primary_switched 来做内核栈的初始化: SYM_FUNC_START_LOCAL(__primary_switched)...如何获取当前进程 内核中经常通过 current 宏来获得当前进程对应的 struct task_sturct 结构,我们借助 current,结合上面介绍的内容,看下具体的实现。
Linux内核中使用 task_struct 结构来表示一个进程,这个结构体保存了进程的所有信息,所以它非常庞大,在讲解Linux内核的进程管理,我们有必要先分析这个 task_struct 中的各项成员...task_struct *group_leader; pid:每个进程都有自己的 pid,它在内核中是唯一的,在Linux中,我们可以使用 ps -ef查看所有的进程,其中 PID 就是进程号。...Linux将进程地址空间分为内核空间和用户空间,它们之间是不能直接访问的,而一个进程某些时候可能在用户态运行,某些时候可能在内核态运行(发生系统调用时),所以一个进程既需要用户栈又需要内核栈 下面就来讲解内核给进程分配的栈结构...在 task_struct 中,有一个变量指向该进程的内核栈,如下: struct task_struct { ......中有一个变量 task_struct,指向拥有这个内核栈的进程,如下所示: 2、current宏: Linux内核中可以通过 current 宏来获取当前正在运行的进程,它的实现十分巧妙,下面我们一起来看一看
因为task_struct结构从1.0到现在5.0内核此结构一直在增大。如果将此结构放在内核栈中则很浪费内核栈的空间,则在threadinfo结构中有一个task_struct的指针就可以避免。...SP的地址通过对齐THREAD_SIZE,然后强转为thread_info结构,然后通过thread_info结构中的task就可以获取task_struct结构的值 ThreadInfo在task_struct...结构中 上面的一种方式是thread_info结构和内核栈共用一块存储区域,而另一种方式是thread_info结构存储在task_struct结构中。...这时候我们再来看下当thread_info在task_struct结构中时,用一张图描述下。 ?...当thread_info和内核栈是这种关系的时候,内核如何获取当前进程的task_struct结构呢?
Linux把跟一个进程相关的thread_info和内核栈stack放在了同一内存区域,内核通过esp寄存器获得当前CPU上运行进程的内核栈栈底地址,该地址正好是thread_info地址,由于进程描述符指针...task字段在thread_info结构体中偏移量为0,进而获得task。...然而在调试器中调了下,发现这种机制早已经被废弃掉了。thread_info结构体中只剩下一个字段flags,进程描述符字段task已经删除,无法通过thread_info获取进程描述符了。...而且进程的thread_info也不再位于进程内核栈底了,而是放在了进程描述符task_struct结构体中,见提交sched/core: Allow putting thread_info into...task_struct和x86: Move thread_info into task_struct,这样也无法通过esp寄存器获取thread_info地址了。
内核通过 task_struct 描述进程 用命令 pstree 可以让内核以树形的结构把进程之间的关系列出来,如下图: ?...这是进程在内核中的结构形式,那么内核是如何来以树形结构管理描述这些进程的呢?用来描述进程的数据结构,可以理解为进程的属性。...中 struct thread_struct thread; ...... }; 内核就是通过list_head链表把各个进程关系以树形结构管理起来的。...因此我们current查找task_struct时也是很简单了,不再用通过sp和thread_info去定位了。...Linux中的 ready 和 running 对应的都是TASK_RUNNING标志位,ready 表示进程正处在队列中,尚未被调度;running 则表示进程正在CPU上运行; ?
那么,内核是如何基于这个指针寻找相关的数据结构的呢? 今天主要基于《Linux内核设计与实现》的6.1章及内核6.3源码编写。...: task_struct与list_head 我们将这两者结合: task_struct与list_struct 可以看到,我们可以很容易在获取到task_struct指针后就通过children指针访问到...list_head结构体: 从thread_info到head_list 那么,现在的问题就演变成,我们如何在访问到list_head后回过头来访问task_struct了: 如何从head_list访问到...,从而可以遍历全部的task_struct了: list_head与task_struct 访问过程如下所示: 遍历task_struct 内核实现 在内核中,内核通过宏定义来实现从list_head...在task_struct中的成员名,例如在这里就是children。
本文在介绍过程中,会引用Linux的代码实现作为说明,同时阐述其中的一些趣闻轶事。...在Linux当中,每一个任务都是由一个c语言的struct描述,中,我们可以找到相关的信息。...对于X86而言,通过下面的方法(3.19版本实现)获取当前内核栈thread_info信息(注意thread_info在内核栈的栈底), static inline struct thread_info...current_thread_info()->task; 4.1之后的版本,对于内核栈进行了调整,4.9之后版本,不再通过thread_info获取task指针。...在介绍如何调度之前,还是有先温习一下Linux对于链表的经典实现方式(一直被模仿)。
罗军 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 基础知识 thread_union...进程在内核态运行时需要自己的堆栈信息,linux内核为每个进程都提供了一个内核栈。...对每个进程,Linux内核都把两个不同的数据结构紧凑的存放在一个单独为进程分配的内存区域中: 一个是内核态的进程堆栈stack 另一个是紧挨着进程描述符的小数据结构thread_info,叫做线程描述符...THREAD_SIZE/sizeof(long)]; }; task_struct包含了指向thread_info的字段,而thread_info通过task字段和thread_struct相互联系。...初始化亲子关系字段 将新进程pid插入散列表中 递增nr_threads变量的值 递增total_forks变量记录被创建的进程的数量 copy_thread函数 将保存在父进程的内核栈中的CPU寄存器的值来初始化子进程的内核栈
对每一个进程来说,Linux内核都会把两个不同的数据结构紧凑的存放在一个单独为进程分配的存储空间中:一个是内核态的进程堆栈,另一个是紧挨进程描述符的数据结构thread_info,叫线程描述符。...在Linux-2.6.32内核中thread_info.h文件中有对内核堆栈的定义: #define THREAD_SIZE 8192 在Linux内核中使用下面的联合结构体表示一个进程的线程描述符和内核栈...在内核中的某一个进程使用了过多的栈空间时,内核栈就会溢出到thread_info部分,这将导致严重的问题(系统重启),例如,递归调用的层次太深;在函数内定义的数据结构太大。 ?...下面的打印信息是工作中遇到的一种情况,打印了内核的堆栈信息,PC指针在dev_get_by_flags中,不能访问的内核虚地址为45685516,内核中一般可访问的地址都是以0xCXXXXXXX开头的地址...,该地址是内核空间不可访问的地址。
---- 堆栈式文件系统 Linux通过vfs虚拟文件系统来统一抽象具体的磁盘文件系统,从上到下的IO栈形成了一个堆栈式。通过对内核源码的分析,以一次读操作为例,从上到下所执行的流程如下: ?...Linux内核中已经集成了一些堆栈式文件系统,例如Ubuntu在安装时会提醒你是否需要加密home目录,其实就是一个堆栈式的加密文件系统(eCryptfs),原理如下: ?...对于第二个问题: 如何Hook?这里介绍两种方式: 第一种方式:直接进行二进制替换,将call指令的操作数替换为hook函数的地址。 ? 第二种方式:Linux内核提供的kprobes机制。...LSM在内核中做了以下工作: 在特定的内核数据结构中加入安全域。 在内核源代码中不同的关键点插入对安全钩子函数的调用。 加入一个通用的安全系统调用。 提供了函数允许内核模块注册为安全模块或者注销。...LSM,在早期的内核中,只能允许一个LSM内核模块加载,例如加载了SELinux,就不能加载其他的LSM模块,在最新的内核版本中不存在这个问题。
exp是使用shellcode,但是在3.10内核中却开启了PXN保护,无法执行用户态内存中的shellcode 提权思路 搞内核Pwn基本都是一个目的——提权。...那么在Linux在怎么把权限从普通用户变成特权用户呢?.../include/linux/sched.h ...... struct task_struct { .........,在arm32中栈的大小是0x2000,而thread_info的信息储存在栈的最底部 所以,如果我们能获取到当前进程在内核中运行时的其中一个栈地址,我们就能找到thread_info,从而顺藤摸瓜得到...-------------------------------------- 通过gdb可以获取到:$sp : 0xd415bf40 从而计算出栈底地址:0xd415a000 然后我们就能获取到thread_info
二、线程栈 从 Linux 内核的角度来说,其实它并没有线程的概念。Linux 把所有线程都当做进程来实现,它将线程和进程不加区分的统一到了 task_struct 中。...三、进程内核栈 在每一个进程的生命周期中,必然会通过到系统调用陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先进程用户空间中的栈,而是一个单独内核空间的栈,这个称作进程内核栈。...由于内核经常要访问 task_struct,高效获取当前进程的描述符是一件非常重要的事情。...,内核可以先获取到栈顶指针 esp,然后通过 esp 来获取 thread_info。...成功获取到 thread_info 后,直接取出它的 task 成员就成功得到了 task_struct。
上面讲完了用户进程/线程的创建,这里我们看下内核是如何创建线程的。...0号线程 linux 内核中为0号进程专门定义了一个静态的 task_struct 的结构,称为 init_task: /* include/linux/init_task.h */ #define INIT_TASK_COMM...,这里看几个比较重要的变量: .thread_info = INIT_THREAD_INFO(init_task), 这个结构在 “task_struct, thread_info 和内核栈...至此,我们已经知道 Linux 启动的第一个线程,0号线程是静态创建的。在0号线程启动后会接连创建两个线程,分别是1号线程和2和线程。...kthreadd 是所有内核线程的父线程,但是子线程如何把请求加入 kthread_create_list 链表,如何让子线程运行,还没有深入介绍。
领取专属 10元无门槛券
手把手带您无忧上云