龙空技术网

理解xv6——2.8 代码:exec

chenleiyfk 93

前言:

当前我们对“phpexec返回”大体比较讲究,同学们都想要剖析一些“phpexec返回”的相关知识。那么小编也在网摘上搜集了一些有关“phpexec返回””的相关资讯,希望各位老铁们能喜欢,兄弟们一起来学习一下吧!

Exec is the system call that creates the user part of an address space. It initializes the user part of an address space from a file stored in the file system. Exec (6610) opens the named binary path using namei (6623) , which is explained in Chapter 6. Then, it reads the ELF header. Xv6 applications are described in the widely-used ELF format, defined in elf.h. An ELF binary consists of an ELF header, struct elfhdr (0905) , followed by a sequence of program section headers, struct proghdr (0924) . Each proghdr describes a section of the application that must be loaded into memory; xv6 programs have only one program section header, but other systems might have separate sections for instructions and data.

exec

Exec是创建地址空间的用户部分的系统调用。它从存储在文件系统中的文件初始化地址空间的用户部分。Exec(6610)使用namei(6623)打开命名的二进制路径,这将在第6章中解释。然后,它读取ELF头。Xv6应用程序是以广泛使用的ELF格式描述的,在elf. h中定义。ELF二进制文件由ELF头struct elfhdr(0905)和一系列程序段struct proghdr(0924)组成。每个程序段描述了应用程序中必须加载到内存中的一个部分; xv6程序只有一个程序段,但其它系统可能有用于指令和数据的单独段。

The first step is a quick check that the file probably contains an ELF binary. An ELF binary starts with the four-byte ‘‘magic number’’ 0x7F, ’E’, ’L’, ’F’, or ELF_MAGIC (0902) . If the ELF header has the right magic number, exec assumes that the binary is well-formed.

header

第一步是快速检查文件可能包含ELF二进制的文件。ELF二进制文件以四个字节的“幻数”0x7F、“E”、“L”、“F”或ELF_MAGIC开始(0902)。如果ELF头有正确的幻数,exec假设二进制文件格式良好。

Exec allocates a new page table with no user mappings with setupkvm (6637) , allocates memory for each ELF segment with allocuvm (6651) , and loads each segment into memory with loaduvm (6655) . allocuvm checks that the virtual addresses requested is below KERNBASE. loaduvm (1903) uses walkpgdir to find the physical address of the allocated memory at which to write each page of the ELF segment, and readi to read from the file.

×vm

loaduvm

Exec使用setupkvm(6637)分配一个没有用户映射的新页表,使用alocuvm(6651)为每个ELF段分配内存,并使用loaduvm(6655)将每个段加载到内存中。allocuvm检查所请求的虚拟地址是否低于KERNBASE。loaduvm(1903)使用walkpgdir来找到所分配的存储器的物理地址,在该物理地址处写入ELF段的每个页面,并且readi从文件读取。

The program section header for /init, the first user program created with exec,looks like this:第一个使用exec创建的用户程序/init的程序段看起来像这样:

header

The program section header’s filesz may be less than the memsz, indicating that the gap between them should be filled with zeroes (for C global variables) rather than read from the file. For /init, filesz is 2240 bytes and memsz is 2252 bytes, and thus allocuvm allocates enough physical memory to hold 2252 bytes, but reads only 2240 bytes from the file /init.

程序段头的filesz可能小于memsz,这表明它们之间差距应该用零填充(对于C全局变量),而不是从文件中读取。对于/init,filesz是2240(0x8c0)字节,memsz是2252字节,因此allocuvm分配了足够的物理内存来容纳2252字节,但只从文件/init中读取2240字节。

Now exec allocates and initializes the user stack. It allocates just one stack page. Exec copies the argument strings to the top of the stack one at a time, recording the pointers to them in ustack. It places a null pointer at the end of what will be the argv list passed to main. The first three entries in ustack are the fake return PC, argc, and argv pointer.

现在exec分配并初始化用户堆栈。它只分配一个堆栈页。Exec将参数字符串一次一个地复制到堆栈顶部,并在ustack中记录指向它们的指针。它在传递给main的argv列表的末尾放置一个空指针。ustack中的前三个条目是伪返回PC、argc和argv指针。

Exec places an inaccessible page just below the stack page, so that programs that try to use more than one page will fault. This inaccessible page also allows exec to deal with arguments that are too large; in that situation, the copyout (2118) function that exec uses to copy arguments to the stack will notice that the destination page is not accessible, and will return –1.

copyout

Exec将一个不可访问的页放在堆栈页的正下方,这样试图使用超过一个页面的程序就会出错。这个不可访问的页面还允许exec处理太大的参数;在这种情况下,exec用于将参数复制到堆栈的copyout(2118)函数将注意到目标页不可访问,并将返回-1。

During the preparation of the new memory image, if exec detects an error like an invalid program segment, it jumps to the label bad, frees the new image, and returns –1. Exec must wait to free the old image until it is sure that the system call will succeed: if the old image is gone, the system call cannot return –1 to it. The only error cases in exec happen during the creation of the image. Once the image is complete, exec can install the new image (6701) and free the old one (6702) . Finally, exec returns 0.

free

在准备新内存映像的过程中,如果exec检测到一个错误,比如一个无效的程序段,它会跳转到标签bad,释放新映像,并返回-1。Exec必须等待释放旧映像,直到确定系统调用将成功:如果旧的映像已经消失,系统调用不能返回-1。exec中唯一的错误情况发生在创建映像的过程中。一旦映像完成,执行可以安装新映像(6701)并释放旧映像(6702)。最后,exec返回0。

Exec loads bytes from the ELF file into memory at addresses specified by the ELF file. Users or processes can place whatever addresses they want into an ELF file. Thus exec is risky, because the addresses in the ELF file may refer to the kernel, accidentally or on purpose. The consequences for an unwary kernel could range from a crash to a malicious subversion of the kernel’s isolation mechanisms (i.e., a security exploit).

Exec将字节从ELF文件加载到内存中ELF文件指定的地址。用户或进程可以将他们想要的任何地址放入ELF文件中。因此exec是有风险的,因为ELF文件中的地址可能会意外地或故意地引用内核。对一个设计拙劣的内核来说,后果可能从崩溃到内核隔离机制的恶意颠覆(即安全漏洞)。

xv6 performs a number of checks to avoid these risks. To understand the importance of these checks, consider what could happen if xv6 didn’t check if(ph.vaddr + ph.memsz < ph.vaddr). This is a check for whether the sum overflows a 32-bit integer. The danger is that a user could construct an ELF binary with a ph.vaddr that points into the kernel, and ph.memsz large enough that the sum overflows to 0x1000. Since the sum is small, it would pass the check if(newsz >= KERNBASE) in allocuvm.

xv6执行许多检查以避免这些风险。要理解这些检查的重要性,请考虑一下如果xv6不检查if(ph.vaddr + ph.memsz <ph.vaddr)会发生什么。这是一个检查总和是否溢出一个32位整数。危险在于,用户可以构造一个ELF二进制文件,其中ph.vaddr指向内核,而ph.memsz足够大,以至于总和溢出到0x1000。由于总和很小,它将通过alocuvm中的if(newsz >= KERNBASE)检查。

The subsequent call to loaduvm passes ph.vaddr by itself, without adding ph.memsz and without checking ph.vaddr against KERNBASE, and would thus copy data from the ELF binary into the kernel. This could be exploited by a user program to run arbitrary user code with kernel privileges. As this example illustrates, argument checking must be done with great care. It is easy for a kernel developer to omit a crucial check, and real-world kernels have a long history of missing checks whose absence can be exploited by user programs to obtain kernel privileges. It is likely that xv6 doesn’t do a complete job of validating user-level data supplied to the kernel, which a malicious user program might be able to exploit to circumvent xv6’s isolation.

随后对loaduvm的调用只传递ph.vaddr本身,而不添加ph.memsz,也不检查ph.vaddr是否与KERNBASE一致,因此会将数据从ELF二进制文件复制到内核中。用户程序可利用此漏洞以内核权限运行任意用户代码。正如这个例子所说明的,参数检查必须非常小心。内核开发人员很容易忽略一个关键的检查,并且现实世界的内核有很长一段缺少检查的历史,用户程序可以利用这些检查来获得内核权限。xv6可能没有完成对提供给内核的用户级数据的完整验证工作,恶意用户程序可能会利用这些数据来绕过xv6的隔离。

标签: #phpexec返回 #apachephpexec权限