Day 14 VMA来袭

前言

昨天介绍完了damand page与 copy on write这两个在现今系统常常能够看见的机制之後,要更深入的走入 Linux中,看看理论中用到的虚拟记忆体在实际的程序码中会以怎麽样的形式出现,本章主要简单的介绍VMA的结构与主要成员。

mm_struct

在Linux中需要管理每个行程的所有记忆体区域以及他们对应的分页映射,所以必须抽象出一个资料结构负责完成这方面的事情,这就是 mm_struct ,在行程控制快(PCB)的资料结构 task_sturct 中有个指针 mm 就是指向 mm_struct 的。

以下列出几个 task_struct 内常见的类别

<include/linux/sched.h>
task_struct{
	struct thread_info thread_info;  // 基本资讯
	struct mm_struct mm;  // 虚拟记忆体描述符
	struct fs_struct *fs; // 指向档案系统资讯
	struct files_struct *files; // 行程打开的档案
    struct signal_struct *signal; // 所接受的信号
    ....
}

mm_struct 也包含在其中,以下列出 mm_struct 比较会用到的项目。

<include/linux/mm_types.h>
struct mm_struct {
    struct vm_area_struct *mmap;		/* list of VMAs */
    struct rb_root mm_rb;
    u64 vmacache_seqnum;                   /* per-thread vmacache */
    unsigned long (*get_unmapped_area) (struct file *filp,
            unsigned long addr, unsigned long len,
            unsigned long pgoff, unsigned long flags);

    unsigned long mmap_base;	/* base of mmap area */
    pgd_t * pgd;

    /**
     * @mm_users: The number of users including userspace.
     *
     * Use mmget()/mmget_not_zero()/mmput() to modify. When this
     * drops to 0 (i.e. when the task exits and there are no other
     * temporary reference holders), we also release a reference on
     * @mm_count (which may then free the &struct mm_struct if
     * @mm_count also drops to 0).
     */
    atomic_t mm_users;

    /**
     * @mm_count: The number of references to &struct mm_struct
     * (@mm_users count as 1).
     *
     * Use mmgrab()/mmdrop() to modify. When this drops to 0, the
     * &struct mm_struct is freed.
     */
    atomic_t mm_count;
    spinlock_t page_table_lock;
    /* Protects page tables and some counters */
    struct rw_semaphore mmap_sem;

    struct list_head mmlist; 
            /* List of maybe swapped mm's.These
          * are globally strung together off
          * init_mm.mmlist, and are protected
          * by mmlist_lock
          */
    unsigned long start_code, end_code, start_data, end_data;
    unsigned long start_brk, brk, start_stack;
            ....
};

mmap : 行程里面所有的VMA会形成一个单向的链表,mmap是这个链表的 head。
mm_rb : VMA红黑树的根节点。
get_unmapped_area :判断虚拟记忆体是否还有足够的空间,这个函数会返回一段未使用过的空间的起始位址。
mmap_base : 指向mmap区域的起始地址。
pge :指向行程的第一层页表。
mm_users :纪录正在使用该行程地址空间的行程数目若有两个执行绪共享行程的地址空间,那麽 mm_users 便会是2。
mm_count : mm_struct 有多少个行程正在使用,像是 fork()後,子行程会与父行程共用位址。
mmap_sem :用来保护行程地址空间VMA的一个锁。
mmlist : 所有 mm_struct会连结的一个双向链表,该链表的头是 init_mm
start_codeend_code : 程序段的起始地址与结束地址。
start_data``end_data: 资料段的起始地址与结束地址。
start_brk:目前heap的起始位址。
brk:目前heap中 VMA的结束位址。
total_vm : 已经使用的行程空间的总和。

VMA

VMA 是虚拟记忆体的重要资料结构,他的主要成员如下,

struct vm_area_struct {
	/* The first cache line has the info for VMA tree walking. */

	unsigned long vm_start;		/* Our start address within vm_mm. */
	unsigned long vm_end;		/* The first byte after our end address
					   within vm_mm. */

	/* linked list of VM areas per task, sorted by address */
	struct vm_area_struct *vm_next, *vm_prev;

	struct rb_node vm_rb;

	/*
	 * Largest free memory gap in bytes to the left of this VMA.
	 * Either between this VMA and vma->vm_prev, or between one of the
	 * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
	 * get_unmapped_area find a free area of the right size.
	 */
	unsigned long rb_subtree_gap;

	/* Second cache line starts here. */

	struct mm_struct *vm_mm;	/* The address space we belong to. */
	pgprot_t vm_page_prot;		/* Access permissions of this VMA. */
	unsigned long vm_flags;		/* Flags, see mm.h. */

	/*
	 * For areas with an address space and backing store,
	 * linkage into the address_space->i_mmap interval tree.
	 */
	struct {
		struct rb_node rb;
		unsigned long rb_subtree_last;
	} shared;

	/*
	 * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
	 * list, after a COW of one of the file pages.	A MAP_SHARED vma
	 * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
	 * or brk vma (with NULL file) can only be in an anon_vma list.
	 */
	struct list_head anon_vma_chain; /* Serialized by mmap_sem &
					  * page_table_lock */
	struct anon_vma *anon_vma;	/* Serialized by page_table_lock */

	/* Function pointers to deal with this struct. */
	const struct vm_operations_struct *vm_ops;

	/* Information about our backing store: */
	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
					   units */
	struct file * vm_file;		/* File we map to (can be NULL). */
	void * vm_private_data;		/* was vm_pte (shared mem) */

	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
...
} __randomize_layout;

vm_startvm_end :指定VMA在行程位址空间中的起始地址跟结束地址。
vm_nextvm_prev :行程的VMA被链接成一个链表。
vm_rb : VMA 作为一个节点加入红黑数,每个行程的mm_struct资料结构中都有一颗红黑数mm->mm_rb
vm_mm :指向VMA所属进程的 mm_struct资料结构。
vm_page_prot : VMA的存取权。
vm_flags:描述VMA的一组标志。
anon_vma_chainanon_vma : 用於管理RMAP, RMAP的部分後面会讲到。
vm_ops: 指向VMA能做的行为,这些方法用在VMA执行各种操作。
vm_pgoff : 指定文件映射的偏移量,这个变量的单位不是字节,而是分页的大小。
vm_file: 指向 file,描述一个被映射的文件。

这里要特别注意一个特别的地方 __randomize_layout ,详细解说来自 stackoverflow

As a side note, the Linux kernel implements a gcc plugin to introduce an attribute named randomize_layout. The goal is to use it in the definition of the structures to make the compiler randomize the order of the fields. Linux kernel uses it for the sake of security to counter attacks that need to know the layout of structures.

简单来说,这个插件是为了把结构内的顺序打散,藉以对抗外部的攻击。
原始的定义出现在 include/linux/compiler-gcc.h 内,

#define __randomize_layout __attribute__((randomize_layout))

为何同时有 linklist 与 rbtree

rb-tree -> 查找快速

randomized mem layout
ref: 奔跑吧!Linux内核


<<:  Day 14: Draft

>>:  第 14 天 我不是要压榨你我是给你个成长的机会|Reactive Form

Day12 - 解析图片中的 QR Code 资料

前言 前篇讲解如何产二维条码 QR Code,这篇则是示范如何解析(解码) QR Code,类似工具...

Day 17手势识别GestureDectector

手势识别GestureDectector (一)介绍 支援一些较复杂的互动,例如缩放、双击、垂直、水...

[ Day 2 ] 一步一步学 Web Exploitation

好的,我们开始从 Web 领域开始罗 Web 顾名思义就是网路相关的题型 复习一下昨天讲的 分析网页...

Html表单元素(DAY6)

我们在上一篇文章中介绍了input的text,Password,button,radio,check...

Day20 ( 中级 ) 拉不走的弹力球

拉不走的弹力球 教学原文参考:拉不走的弹力球 这篇文章会介绍,如何在 Scratch 3 里使用扩充...