ParcelFileDescritor.createPipe(),又名管道 (2) 和安全性

ParcelFileDescritor.createPipe(), aka pipe(2), and security

请注意,虽然我是在 Android 的上下文中问这个问题,但它更像是一个关于 pipe(2) ...

的一般 unix 问题

要将大量数据从一个进程传输到另一个进程,可以使用ParcelFileDescritor.createPipe(),然后通过绑定器将管道的读取端发送到另一个进程。 ParcelFileDescritor.createPipe() 直接映射到 unix pipe(2) 系统调用。

虽然 FD 通过 binder 安全地传输到另一个进程,但由于最终 FD 只是一个 int,它是否有可能被发现,甚至被恶意进程猜测、打开和读取?

根据我的阅读,这似乎归结为通过默默无闻的安全性。只要你不知道,也猜不出 FD 的 int 值,就可以了。匿名管道不会公开以其他方式发现 FD 的方法。但从理论上讲,有人可能会编写一个具有大量线程的应用程序,这些线程会不断尝试根据随机 int 值打开 int,可能会利用某种选择数字的模式并最终利用 pipe(2).

Linux 内核跟踪一个文件描述符 table (struct fdtable) for each process (more or less). The entries in this table are indexed by small integers —starting with 0, 1, 2, etc., new entries are given the smallest available integer— and each points to one open file (struct file)。

Linux 内核中的文件是 inode (struct inode) 和一些状态(例如搜索位置)的句柄。

如果多次打开同一个文件,文件描述符中会有多个条目table,每个条目指向不同的文件结构,每个条目都指向相同的inode结构。

如果您打开一个文件,然后 dup 文件描述符,您将在文件描述符 table 中有多个条目,每个条目都指向相同的文件结构。

创建 pipe 会产生两个文件描述符:读端和写端。它们有些神奇:从第一个文件描述符读取的数据将 return 写入第二个文件描述符的数据。创建时,管道两端只能被本进程访问。

将文件描述符传递给另一个进程(通常由 sendmsg over an AF_UNIX domain socket with auxiliary SCM_RIGHTS attached, but on Android is done by Binder.transact with a Parcel.writeFileDescriptor 完成)会导致一个新条目被添加到接收进程的文件描述符 table,指向相同的文件结构发送进程的文件描述符中的原始条目 table。注意:两个进程中同一文件的整数索引不相关;事实上,它很可能会有所不同。

通常在 C 语言中,您会使用 fopen to obtain a FILE * structure that you can fread/fwrite/etc. on. The C runtime library does this by opening a file descriptor and wrapping it a structure (that holds additional buffering, etc.). fdopen 获取已在本地进程中打开的文件描述符,以及围绕它的 FILE * 结构。

拼凑:

没有其他进程可以通过猜测 FD 编号来打开文件,因为这些数字仅在单个进程中有意义。*在进程之间传递文件描述符是安全的,由内核调解,内核正在操纵对象,只有内核可以访问。

*给予适当的权限,您可以通过 /proc/$PID/fd/$FD pseudo-filesystem 找到其他进程的文件描述符,并 re-open 自己找到它们。然而,"appropriate privileges" 是 "same user or root"。在 Android 上,所有应用程序 运行 作为不同的用户,并且 none 运行 作为 root – 这是不可能的。此外,Android 的 SELinux 策略无论如何都会阻止应用程序与 /proc 接口进行交互。