我这样问是因为字符串比较很慢,但索引很快,而且我编写的很多脚本都是在 bash 中,据我所知,bash 会对每个可执行调用执行完整的字符串查找。所有这些ls
's 和grep
's 都会快一点,而无需在每个步骤中执行字符串查找。当然,现在深入研究编译器优化。
无论如何,有没有一种方法可以仅使用其 inode 号直接调用 Linux 中的程序(假设您只需在所有调用中查找一次)?
答案1
最简洁的答案是不。
更长的答案是 Linux 用户 API 不支持使用 inode 号通过任何方法访问文件。对 inode 号的唯一访问通常是通过 stat() 系统调用,该系统调用公开 inode 号,这对于识别两个文件名是否是同一个文件很有用,但不用于其他任何用途。
通过 inode 访问文件会违反安全性,因为它会绕过包含链接到该 inode 的文件的目录的权限。
最接近的方法是通过打开文件句柄访问文件。但是您也无法从中运行程序,这仍然需要通过路径打开文件。 (正如评论中所指出的,出于安全原因,此功能与其余的 *at 系统调用一起添加到 Linux 中,但不可移植。(标准还在发展。))
还有很多方法可以使用 inode 编号来查找文件(基本上是抓取文件系统并使用 stat),然后正常运行它,但这与您想要的相反,因为它比仅仅访问文件要昂贵得多通过路径名,也不会消除该成本。
话虽如此,担心这种类型的优化可能没有什么意义,因为 Linux 已经对内部 inode 查找进行了很多优化。此外,传统上,shell 会散列可执行文件的路径位置,因此它们不必$PATH
每次都从所有目录中寻找它们。
答案2
是的可能的通过文件的 inode 执行文件:
find / -inum 242 -exec {} \; -quit
不过,性能引发了这个问题,而上面的内容并不是性能。不仅会遍历目录结构来查找具有该索引节点(并且可能有多个)的文件,而且在幕后,索引节点号会解析为路径,并将该路径提供给内核来执行。但为什么?
内核公开了 exec 系列函数(execl
、execvp
等),它们都包装了内核函数execve
。该函数用一个新的过程映像替换当前的过程映像,该映像是通过读取内容来引导的从给定的文件路径。所以每一个内核提供的执行程序的方式需要通过路径给出。通过使用文件路径作为入口点,我们可以获得与文件路径相关的所有访问控制优势,因此,“按路径”API 是 Linux 中唯一用于执行程序的 API。
然而,存在一种繁琐且不能保证在所有环境中工作的机制,允许您调用程序从记忆中。由于内存中的任何内容都必然比磁盘上的任何内容都要快,因此这就触及了问题的核心:如何尽可能快地运行程序。
2002 年初,一位(著名)黑客 grugq 引入了 userland exec 的概念。这不是 shell 的exec
函数:它是内核execve
函数执行的每一步的模拟,只是在用户态中编写。这对于想要隐藏其活动的黑客来说是理想的选择,因为它允许在通常的访问控制机制之外执行程序execve
。
此方法的实现需要大量帮助程序,这些帮助程序可以清理地址空间、加载动态链接器(如果需要)、初始化堆栈等。该机制还要求将所需的代码加载到某些类型的内存中。
还有一些对策可以使这种事情变得困难,但请注意,并非不可能。所需要的只是目标系统具有页面对齐的内存、将内存标记为可执行的能力以及跳转到内存中任意点的能力。这些要求通常转化为:您必须用 C 语言编写它并在没有 SELinux 或没有完全启用 SELinux 的系统上使用它。我不会在这里讨论实现细节,但会提供链接供您自行探索。
因此,如果您的 Linux 系统满足上述要求,那么您可以通过以下方式从内存中执行代码:
- 将代码加载到内存中的某个位置。作为初始删除的一部分,恶意行为者已经将所需的代码侧加载到内存中,但如果您想按照 inode 的方式进行操作,您可以这样做
find / -inum 242 -exec cat {} \;
- 调用 userland exec 机制,将其入口点设置为您在步骤 1 中存储程序的内存地址
- 利润
内核、文件系统和 shell 都经过了调整,使得程序的查找和执行只占工作所需总开销的一小部分。在内存中加载程序并从那里执行它并不真正属于平均用例的范围,所以除非这样做是为了好玩,否则我会说您需要在投入时间尝试之前对性能进行基准测试。
参考:
答案3
这不是对 i-node 问题的直接回答,而是避免在 shell 脚本中查找标准实用程序路径的可能方法。
忙碌盒是一个程序,它将许多标准 Unix 实用程序组合成一个可执行文件,该可执行文件比它所取代的所有工具的总大小要小得多。它在嵌入式世界中非常流行,磁盘大小通常非常重要。在典型的基于 BusyBox 的系统中,sh
、
ls
和grep
都是到 的符号链接busybox
。因此,调用ls
和的 shell 脚本grep
只会busybox
调用自身两次。
BusyBox 有一个实验性功能,称为“独立 shell”。启用此功能后,充当 shell 的 BusyBox 不会对其实现的实用程序执行路径查找。相反,它只是/proc/self/exe
通过正确的参数执行自身 。例如,如果它运行一个调用 的 shell 脚本,那么它将执行 ,而不是在 中grep
查找。内核中仍然有一个路径查找,但无论调用什么实用程序,它总是相同的,并且可执行映像已经在内存中,因此不需要加载它。grep
$PATH
/proc/self/exe grep <arguments>
/proc/self/exe
但请注意,BusyBox 进行了大量优化对于尺寸而不是速度,因此如果您关心节省几微秒,它可能不是您的最佳选择。此外,如前所述,“独立 shell”功能被标记为实验性的。
答案4
有没有一种方法可以仅使用节点号直接调用 Linux 中的程序
不,不是,原因很简单:您使用的是单数形式“A计划”和“它是inode number”,但 inode 不是唯一的:系统中可以有多个文件具有相同的 inode 号。
因此,根据简单的常识,您能做的最好的事情就是“仅使用其索引节点号直接调用一组程序中的一个或多个”,但是您不能调用一个具体的节目,无需关于所述节目的附加识别信息,以便从一组节目中挑选出一个节目。
当然,其中一个识别信息可能是它的路径......此时你又回到了原点。