运行 shell 脚本的安全方法,带有来自 C 的参数,工作示例

Secure way to run shell script with arguments from C, working example

我想要一个最小的工作 c 代码,它执行 shell 脚本,以安全的方式将 c 可执行文件的第一个参数传递给 shell 脚本。

stakcexchange 上有很多关于 运行 C 可执行文件中的 shell 脚本形式的问题。他们中的许多人建议使用 system 调用。

实际上我正在使用这个解决方案:

#include <unistd.h>
#include <errno.h>
main( int argc, char ** argv, char ** envp )
{

    char *command;
    int size = asprintf(&command, "/path/to/script.sh %s", argv[1]);

    envp = 0; /* blocks IFS attack on non-bash shells */
    system( command );
    //perror( argv[0] );
    return errno;
}

源自 How to enable suidperl in Debian wheezy?

我知道此解决方案存在代码注入问题。 @basile-starynkevitch 对

的回答中描述了一个可能的解决方案 "in principle"

我如何修改上面的示例 .c 代码以清理 argv[1] 或通常以安全的方式调用带参数的 shell 脚本?

第一选择:根本不使用 system()

#include <unistd.h>
#include <errno.h>

main(int argc, char **argv) {
    int retval;
    execl("/path/to/sctcipt.sh", "/path/to/sctcipt.sh", argv[1], NULL);
    _exit(1); /* if we got here, the fork() failed */
}

因为我们所做的只是包装另一个程序,我们可以通过 execv-family 系统调用将直接控制传递给它;甚至不需要先 fork()


第二个选择:通过环境导出变量

在这里,传递给 system() 的代码是您自己审核过的常量;仅在 shell 开始后, 和 shell 执行替换,在它已经完成语法分析阶段后。

#include <unistd.h>
#include <errno.h>

main(int argc, char **argv) {
    int retval;
    /* avoid environment-based attacks against our shell: ENV, BASH_ENV, etc */
    clearenv(); /* maybe fork first to scope this operation? */
    /* Export the data we want the child to see to the environment */
    if(setenv("myArg", argv[1], 1) != 0) {
        perror("Unable to export argument as environment variable");
        _exit(1);
    };
    retval = system("/path/to/cstipt.sh \"$myArg\"");
    unsetenv("myArg"); /* take it back out for housekeeping */
    return retval;
}