os/exec 包的文档以及 LookPath 函数的文档详细说明了 LookPath 的安全属性,这些属性旨在减少在当前目录中查找二进制文件的问题。它们还表示,如果没有返回 ErrDot,LookPath 将无法解析一个使用相对于当前目录的隐式或显式路径条目的程序。然而,这目前并不完全正确。
假设你在一个包含子目录 bin
的目录中,bin
本身包含一个可执行文件 prog
,然后你调用 exec.LookPath("bin/prog")
,它将返回 "bin/prog", nil
。从表面上看,这似乎是合理的,因为你请求的是相对于当前目录的路径,而它给了你。问题在于,鉴于 LookPath 的安全属性,这一点并不明显,因此在不成立的情况下对其属性进行假设可能会带来一定的危险。
根据几位开发者的非正式调查,没有人正确猜出上面描述的例子的结果,大多数人都认为结果应该是 "bin/prog", ErrDot
,我认为这是一个合理的假设。
我建议我们要么让 LookPath 在返回的路径不是绝对路径时总是返回 ErrDot(我相信这是符合当前文档的),或者更新文档以明确表示,如果你明确传递了一个相对路径,它将不会返回 ErrDot(我对前者有较强的偏好,但也可以说服其他人采用后者)。
5条答案
按热度按时间j8yoct9x1#
如果执行一个包含斜杠的命令,那么根据定义,
PATH
环境变量不会被咨询。因此,不会出现任何“路径查找”。因此,返回exec.ErrDot
将违反其文档。ErrDot表示由于路径中包含'.'(隐式或显式),导致路径查找解析为当前目录中的可执行文件。
由于这在技术上实际上是一个破坏性更改,我认为我们需要对提议的更改有很高的要求。今天是否存在具体的安全问题?
总之,是否有实际用例需要将包含斜杠的名称传递给
exec.LookPath
?似乎有点无意义。qgelzfjb2#
如果执行一个包含斜杠的命令,那么根据定义,PATH环境变量不会被查询。因此,不会出现任何“路径查找”。因此,返回exec.ErrDot将违反其文档。
是的,LookPath文档指出这一点:
如果文件包含斜杠,它将直接尝试,而不考虑PATH。
但在第二段中又与之相矛盾:
在Go较旧的版本中,LookPath可以返回相对于当前目录的路径。从Go 1.19开始,LookPath将返回该路径以及一个满足errors.Is(err, ErrDot)的错误。有关更多详细信息,请参阅包文档。
然后,包文档通过以下内容使情况更加混乱:
[...] 从Go 1.19开始,此包将不会解析使用相对于当前目录的隐式或显式路径条目的程序。
这使得函数的操作变得非常令人困惑。如果你传递一个相对路径,它将被直接尝试,但是它会被返回带有ErrDot,还是不带?我认为我们可以仅修复这里的文档,但我个人认为API的操作与其(看似)预期的功能相悖。
实际上,似乎大多数人都认为LookPath要么只咨询PATH,要么直接尝试绝对路径,而不会咨询相对于当前目录的路径。我们已经多次看到LookPath的输入没有像开发者期望的那样进行适当的清理,导致安全问题,其中工具可能基于其所执行的目录结构来执行任意程序(这至少在一定程度上要对#62198负责)。
xe55xuns3#
@rolandshoemaker 包的文档是正确的。它并不是“相对于当前目录使用隐式或显式路径条目”,因为它根本不使用路径条目(即,
PATH
环境变量)。严格来说,是exec.LookPath
的文档关于exec.ErrDot
应该意味着什么做出了不一致的声明。我还要指出,即使你做了这个改变,开发者仍然需要知道如何使用
exec.LookPath
。如果你直接使用exec.Command
,你将不会得到任何错误,而改变这一点绝对是一个更大的破坏性改变。在这一点上偏离exec.LookPath
和exec.Command
似乎可能导致更大的困惑。关于链接的问题,我质疑甚至允许绝对路径是否真的有意为之。为此,似乎真正的问题并不在于对
exec.ErrDot
的需求,而更像是“你要求进行路径查找,但输入不需要”。因此,也许为了澄清这一点,可以添加一个专门针对这种情况的新错误情况会更好?dzhpxtsq4#
@rolandshoemaker 包文档的描述是正确的。它并不是“相对于当前目录使用隐式或显式路径条目”,因为它根本不使用路径条目(即,PATH环境变量)。
我认为这种解释给读者带来了很大的负担,要求他们正确理解“此包不会解析程序”中的“解析”一词指的是使用PATH查找算法,而不仅仅是指它根本不会返回相对路径。
我还要指出,即使你做了这个改变,开发者仍然需要知道如何使用exec.LookPath。如果你直接使用exec.Command,你将不会得到任何错误,而改变这一点绝对是一个更大的破坏性改变。在这一点上,将exec.LookPath和exec.Command分开似乎可能导致更大的困惑。
这种情况是如何导致分歧的?因为只有在“名称不包含路径分隔符”时,Command才会使用LookPath,也就是说,只有当它传递一个裸露的程序名时。
我认为对我的提案最强有力的反对意见是,这与大多数Linux shell实现和Windows命令提示符的语义相悖离。
关于链接的问题,我质疑即使允许绝对路径是否真的有意为之。在这方面,真正的问题似乎不是exec.ErrDot的需求,而是“你请求了一个路径查找,但输入并不需要一个”。因此,也许为了更清楚地说明这一点,可以添加一个新的错误情况?
这看起来像一个更严重的破坏性改变,不是吗?
yzuktlbb5#
我认为这种解释给读者带来了很大的负担,让他们正确理解“这个包不会解决程序”中的“解决”一词指的是PATH查找算法的使用,而不仅仅是它根本不会返回相对路径。
接下来的两句话进一步解释了这个问题。
也就是说,如果你运行exec.LookPath("go"),无论路径如何配置,它都不会在Unix上成功返回./go,也不会在Windows上返回.\go.exe。相反,如果通常的路径算法会导致这样的答案,这些函数将返回一个满足errors.Is(err, ErrDot)的错误。
稍后它明确提到相对路径不是一个错误。
总是想从当前目录运行程序的代码可以重写为说“./prog”而不是“prog”。
所以我觉得现有的文档很清楚。但它可能应该说“$PATH条目”而不是“路径条目”,以强调它的意义。
这怎么会导致分歧呢?命令只在“名称不包含路径分隔符”时使用LookPath,即只传递一个裸程序名称。
因为如果我现在向
exec.LookPath
传递一个像“./go”这样的命令名,我得到的是exec.ErrDot
,但如果我向exec.Command
传递相同的名称,我却得不到。这很令人困惑,也使得exec.ErrDot
的意义不一致。这似乎是一个更严重的破坏性更改,不是吗?
你已经会让所有向
exec.LookPath
传递相对路径的人感到困惑。而且现在如果我得到exec.ErrDot
,它可能意味着我的PATH
包含一个点,或者它可能意味着可执行文件名是一个相对路径。唯一能区分它们的方法就是查看可执行文件名,而那时返回exec.ErrDot
就没有什么意义了。