bash shellshock更新导致脚本的行为不同

时间:2014-10-05 10:35:29

标签: python linux bash perl perforce

这是我们更新了bash后发生的事情之一(由于Shellshock的事情)

这是我正在测试的代码:

#!/usr/bin/python2.4
import subprocess, os
    p = subprocess.Popen(
            cmd,        
            shell = True,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE
        )
        out, err = p.communicate()

        print "out:", out
        print "err:", er

首先运行命令:

cmd = "cd /home/me/; pwd; p4 client -o"
out: /home/me/
err:
perforce client that is NOT mine ( some kind of a default template is trying to be used here )

第二个测试,我添加了以下Python args:

env = os.environ.copy()
# and add "env" variable to the Popen command after "cmd, like:
env = env,

输出:

cmd = "cd /home/me/; pwd; p4 client -o"
out: /home/me/
err:
my perforce client information - as it should.

我的问题是, 我似乎无法理解为什么" env = env,"在这里很重要 我试过运行几个命令,如#34; export"等了解有/无之间的差异 - 但结果是一样的,还检查了" shell"两者都使用" sh"。所以我不确定环境的哪个部分导致它不能作为例子#1。

我确定它与Perforce本身并不相关,Perforce可能只需要一些环境变量,这些变量因为这个bash Shellshock事件而受到某种影响。

编辑 - 澄清@ 5gon12eder建议

我尝试在不使用" env = env," (这是一个os.environ.copy()),

# 1
# The outouput is wrong ( generic Perforce views )
cd /home/me/; pwd; p4 client -o

# 2 - manually adding P4CONFIG
# The outouput is *correct*
cd /home/me/; pwd; P4CONFIG='.perforce'; p4 client -o


# But the environment variable looks like is there with the correct information ( can't paste it here )
subprocess.call("env") | grepping the script's output P4
> P4CONFIG=...
> P4PORT=...
> P4USER ...

注意,P4变量配置了两次:

/etc/profile
/home/me/.bash_profile

编辑2 - 用Perl再现:

环境忽略%ENV中的P4CONFIG条目。

#!/usr/bin/perl -w

use strict;
use Data::Dumper;

my $dir = "/home/me/";
my $cmd1 = "cd $dir; p4 client -o";
my $cmd2 = "cd $dir; P4CONFIG='.perforce'; p4 client -o";

# Scenario 1 - does NOT work ! $ENV does have P4CONFIG with a correct value.  
`$cmd1`;
# ** still wrong result - generic Perforce views

# Scenario 2 - adding P4CONFIG= to the command:
`$cmd2`;
# Correct result - my .perforce client's views.

# Scenario 3 - Adding to the ENV P4CLIENT ( which does not exists in %ENV )
$ENV{'P4CLIENT'} = "my_client_name";
`$cmd1`;    # The one without the P4CONFIG enforcement. - WORK.

编辑3 - 如果我使用/不使用>>会有区别和|

实际上,在考虑它的时候,当我的一个libs有一个">时,引入了整个问题。的/ dev / null的"在子进程中重定向(Python)" cmd"上面的示例导致脚本挂起并在超时时退出,我将其替换为" -o file-output"问题已经消失,但后来我陷入了这个问题所以我打开了这个帖子。

# I already found that adding this row - solving the ENV thing ( not really solving ... but )
$ENV{'P4CONFIG'} = ".perforce";

# Work, I see the excepted output
my $bla = `p4 client -o`;

# Doesn't work, script hangs and Perforce exit with a timeout ( like a P4PORT missing error )
# (I was just trying to remove all the comments-junk )
my $bla = `p4 client -o | grep -v '^#'`;

# Script doesn't hang for example if I just "echo"
my $bla = `echo 'p4 client bla bla' | grep -v '^#'`;

只是想再说一遍,它是在shellshock之前的所有工作(可能是一个真实的或者可能是巧合)但是在exec()调用的环境中有些不同...... 有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您的代码是否在修改环境?事情是那个

os.putenv('VAR', 'VAL')

(可能)直接修改环境但不更新os.environ

os.environ['VAR'] = 'VAL'

一样。来自Python documentation

  

直接致电putenv()不会更改os.environ,因此最好修改os.environ

     

如果未提供putenv(),则可以将此映射的修改副本传递给相应的流程创建函数,以使子进程使用已修改的环境。

本文档中的内容不是很清楚,但在阅读了os Python模块和附带的posixmodule C模块的有些模糊的源代码之后,如果底层平台的C库没有拥有putenv(3) C函数,然后在os.environ中设置密钥只影响Python字典,os.putenv是无操作。来自Lib/os.py

try:
    _putenv = putenv
except NameError:
    _putenv = lambda key, value: None
else:
    if "putenv" not in __all__:
        __all__.append("putenv")

来自Modules/posixmodule.c

static PyMethodDef posix_methods[] = {
  /* Lots and lots of code skipped... */
#ifdef HAVE_PUTENV
  {"putenv", posix_putenv, METH_VARARGS, posix_putenv__doc__},
#endif
  /* Even more code skipped... */
};

因此,您可以在您显示的两种情况下观察到不同的行为 - 令我惊讶的是 - 如果将env=None传递给subprocess.Popen构造函数,那么不会os.environ替换为默认值,但使用C标准库中的值。

为子进程设置环境的代码(在Lib/subprocess.py中)是

if env is not None:
    env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
                for k, v in env.items()]
    else:
        env_list = None  # Use execv instead of execve.

并且最近没有变化。从exec(3)的手册页(强调我的):

  

execle()execvpe()函数允许调用者通过参数envp指定执行程序的环境。 envp参数是指向以null结尾的字符串的指针数组,必须以空指针终止。 其他函数从调用过程中的外部变量environ获取新过程映像的环境。

我进入了Modules/_posixsubprocess.cexecv / execve}和Modules/posixmodule.cputenv)的源代码,检查他们是否真的称之为系统功能如上所述,从我所知道的,它们似乎是这样做的。这两个C模块中没有一个收到最近似乎与此功能相关的更改。

在阅读完问题后,我的第一个想法是,最终,Python开发人员已经对传递给子进程的环境进行了一次完整性检查,但似乎没有。很抱歉,如果这是一个非答案,但我认为它可能仍然有助于他们避免潜入CPython源代码。

作为进一步调试的建议,请尝试运行

$ python -c "import os; import subprocess; os.putenv('VAR', 'VAL'); subprocess.call('env');" | grep VAR=

以及各种变化来追踪正在发生的事情。

脚注:我认为subprocess.Popen的行为更多是一个错误,而不是一个功能,因为它使Python代码在提供或不提供{{1}的平台上表现不同C函数没有充分的理由。

答案 1 :(得分:0)

因此,我希望与所有人分享调查结果,以防其他人在此问题上坚持一段时间。 问题是,我们在以下方面有一些导出功能:

/etc/profile

在实施bash补丁后,导致环境行为不同。 删除这些功能解决了我们所有脚本中的问题......并且环境变量不再需要进行任何更改..

感谢大家的帮助!