【问题标题】:execute git hooks in non executable environment/ edit how git calls hooks在非可执行环境中执行 git hooks/编辑 git 如何调用 hooks
【发布时间】:2018-03-22 14:19:36
【问题描述】:

问题:如何编辑 git 调用钩子的方式?

TL;DR - 我的托管平台的安全性很奇怪,我需要弄清楚如何编辑 git 如何调用 post-receive 挂钩。

我正在尝试通过 GIT 设置自动部署,但人们建议您这样做的主要方式是使用接收后脚本。如果我 cd 进入钩子并执行

$ sh post-receive

,它工作得很好,但如果我

$ ./post-receive

,虽然它有权限,但它会抱怨权限

$ chmod 777 post-receive

(您可以使用 $ ls -l 查看)。

这是我从支持人员那里得到的消息: “原因是出于安全原因,SSH 环境被挂载为不可执行的环境。这意味着您不能仅通过路径运行脚本。

例如,running: /www/repos/webprosjekt18.git/hooks/post-receive 将不起作用,它会给出权限错误。

正在运行:bash /www/repos/webprosjekt18.git/hooks/post-receive 可以正常工作(取决于该脚本的 ofc 功能,但它至少会运行该文件)。

我们认为 git 默认通过调用 /www/repos/webprosjekt18.git/hooks/post-receive 来运行钩子,这将失败。 "

远程脚本:

mkdir repos
cd repos
git init --bare
cat > hooks/post-receive <<END
#!/bin/sh
echo "executing post-receive hook"
END
chmod 777 hooks/post-receive
cd hooks
sh post-receive

【问题讨论】:

  • 他们是怎么做到的?如果您从使用 ssh 登录获得的 shell 执行 bash 会发生什么。仍然无法执行脚本? (这是否只影响脚本?)如果您执行PATH=$PATH:. 将当前目录添加到PATH 会怎样?
  • 你是什么意思他们是怎么做到的?如文中所述,该脚本可以通过在调用它时说明它是什么脚本语言来执行,但我猜 git 不会那样做。如果我 cd 进入钩子并在接收后执行 $ sh,它工作正常。也不知道你建议我在哪里做 PATH 的东西。
  • 对不起。我认为他们必须使用一些奇怪的诡计来做到这一点。所以我想知道他们是否会给你一些特殊的外壳? 1)通过ssh登录后,尝试执行例如/usr/bin/bash(或任何其他外壳,例如 /bin/shtcsh 等)。生成的 shell 会有相同的限制吗? 2)通过ssh登录后,尝试执行PATH=$PATH:.。如果你这样做,你应该能够通过script.sh 而不是./script.sh 在当前路径中执行脚本。这行得通吗? 3) which bash 的输出是什么 4) .bashrc/.bash_profile 是在登录时执行的吗?
  • 顺便说一句,git 只是 execves 钩子脚本。我很确定有办法绕过您的托管平台的安全性。例如,二进制可执行文件是否有效?如果是,你可以例如使用像 int main() { system("bash script.sh"); } 这样的小型 C 程序作为钩子。

标签: git ssh sh githooks


【解决方案1】:

作为sneep noted in a comment,一旦决定运行某个钩子,Git 本质上只是做一个fork 后跟execve 的钩子路径。 (有关“决定运行某个钩子”的更多信息,请参见下文。)这意味着由 内核 决定是否允许执行操作。

The specific source code involved is here. 注意ENOEXEC 的测试,但不是EACCES

如果您查看the Linux mount documentation,您会看到noexec 选项禁止在该挂载文件系统上执行(执行操作)任何文件。 (BSD 的mount 有一个类似的选项,以防宿主系统是基于 BSD 的。)这种情况下返回的错误是EACCES,而不是ENOEXEC。这意味着您的托管系统的分析是正确的,您根本无法做到这一点。


有趣的是,如果 Git 会运行一个没有设置 x 位的钩子,那么上面调用的代码部分在某些情况下可能会得到 ENOEXEC(不是这些——你会想弄乱“魔法number" 来触发这个) 并且在钩子上运行 shell 的第二个代码路径实际上可以工作。但是,the find_hook code 特别要求access(path, X_OK) 成功。这需要both the x bits set and the file system mounted without noexec

您可以尝试构建一个 Git 的变体版本来更改这些测试,并让您的托管公司将其安装为他们的 Git 版本,但如果他们愿意这样做,他们可能愿意将您的存储库放在一个文件中允许执行的系统。

【讨论】:

    【解决方案2】:

    这并不是一个真正的答案,因为它在很大程度上建立在@torek 的建议之上,它​​可能正在使用NOEXEC 挂载选项。那么这个解决方法怎么样:你可以添加一个钩子,它是指向/usr/bin/script 的符号链接(即使使用NOEXEC,指向其他文件系统的符号链接也是可执行的)。 script 会执行bashbash 会认为它在终端中。 (如果你只是符号链接到hooks 目录中的/bin/bashbash 将放弃看到它不能open /dev/tty,但script 会为我们处理这个问题。)如果我们放一些代码在~/.bashrc 中确定这是否被称为 git 钩子,我们执行真正的脚本。所以我们可以把它放在/.bashrc的顶部:

    pppid=$(ps -o ppid= $PPID) # determine grandparent PID
    ppproc=$(ps -o comm= $pppid) # determine grandparent process name
    if [ "$ppproc" == "git" ]; then # is it 'git'?
        echo running from git @ `date` # call script here
        exit
    else
        echo not running from git # you might want to remove this
    fi
    

    例子:

    $ touch test15
    $ git add test15
    $ git commit -m "Test15"
    Script started, file is typescript
    running from git @ Fri Mar 23 13:19:54 JST 2018
    Script done, file is typescript
    [master 608083b] Test15
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test15
    

    (这会在您的 Git 目录中创建一个名为 typescript 的文件。)

    【讨论】:

    • 这是一个相当令人印象深刻的技巧。我不清楚是否有人会考虑在挂载点之外遵循符号链接导致“允许执行”成为错误。它似乎并没有打开很多蠕虫罐,所以毕竟它可能没问题,但是使用你的技巧,它确实可以实现一些人可能认为不可能的事情(我确实认为这是不可能的!)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 2020-08-09
    • 2013-06-26
    • 1970-01-01
    • 2018-11-18
    • 2015-06-13
    • 2014-11-04
    相关资源
    最近更新 更多