我读过Linux中的进程描述符(在x86上)存储在内核数据段中,但在PAGE_OFFSET(即在用户地址空间中)的地址中。 由于内核数据段和用户数据段都覆盖了全部4GB的地址空间,因此如果用户代码知道其地址,则可能通过用户数据段访问进程描述符。 这是正确的,如果是的话,这不是一个安全漏洞?
一个相关的问题:有一个断言,进程描述符的线性地址可以作为一个唯一的进程ID。 但是,由于线性地址使用页表进行翻译,并且对于PAGE_OFFSET下的地址的每个进程,页表都不相同,那么两个进程不能将它们的进程描述符存储在相同的线性地址吗?
在linux中,“进程描述符”是struct task_struct
[和其他一些]。 这些存储在内核地址空间[ PAGE_OFFSET
之上]而不是在用户空间中。
这与PAGE_OFFSET
设置为0xc0000000的32位内核更相关。
在32位内核中,用户进程虚拟地址空间被限制为PAGE_OFFSET
64位内核有些不同,限制并不重要。 PAGE_OFFSET
是0xffff880000000000
另外,内核有自己的单个地址空间映射。
每个进程/线程都有自己的虚拟地址空间,即为.so库和线程共享内存禁止共享内存是唯一的。 它不映射到内核地址空间中的任何东西。
即使有[如果有]一个公共的地址空间映射内核页面是读/写保护的用户进程。
一个相关的问题:
这真是两个问题
有一个断言,进程描述符的线性地址可以作为一个唯一的进程ID。
不可以 。这是因为几个原因而无法完成的。
只有内核有权访问(即“知道”) task_struct
地址。
其次,如果一个进程终止,它是一个僵尸,直到父进程通过wait
“收获”它。 内核必须记住哪些进程是僵尸(即它们的pids
不会被重新用于新进程),直到父节点获得它们。
但task_struct
相当大。 所以,当一个进程进入僵尸时,内核抓取task_struct
数据的一小部分(例如pid
和status
),并把它们保存在一个“zombie”结构中。 内核可以立即重用task_struct
[使用不同的 pid]。
例如,当一个有pid 37的进程在运行的时候在地址(例如)0x1000上有一个task结构,在结束之后但在reap之前,pid 37 没有任务结构地址,并且已经可以分配0x1000的任务结构到23727
但是,由于线性地址使用页表进行翻译,而对于PAGE_OFFSET下的地址,每个进程的页表都不相同,那么两个进程是否不能将它们的进程描述符存储在相同的线性地址?
再次,不。