Details
-
Bug
-
Status: Resolved
-
Normal
-
Resolution: Fixed
-
None
-
None
-
Night's Watch
-
5
-
NW - 2019-10-30, NW - 2019-11-13, 2019-11-27, 2019-12-11
-
Needs Assessment
-
Enhancement
-
-
Needs Assessment
Description
When executing commands, Facter will expand the first word in the command string to be a fully qualified path. I.e. ls -l will become /usr/bin/ls -l. If the command string is a compound command that contains a pipeline or conditional construct, then Facter will wrap the string in /usr/bin/sh -c.
However, the first word of the compound is still expanded to an absolute path. This breaks shell builtins like cd as they are expanded to external commands like /usr/bin/cd or fail to be found on the PATH.
Reproduction Case
- Install the latest version of puppet-agent on CentOS 7, along with strace:
yum install -y http://yum.puppetlabs.com/puppet-release-el-7.noarch.rpm |
yum install -y puppet-agent strace |
- Create a test script that loads Facter, and uses it to execute a compound command that begins with cd:
cat <<EOF > test.rb |
#!/opt/puppetlabs/puppet/bin/ruby
|
require 'facter' |
|
puts Facter::Core::Execution.execute('cd /opt/puppetlabs && ls') |
EOF
|
chmod +x test.rb |
- Execute the test script.
Outcome
The script prints the contents of the current working directory instead of /opt/puppetlabs:
# ./test.rb
|
1
|
anaconda-ks.cfg
|
linux.iso
|
test.rb
|
Running the script under strrace reveals that cd is being expanded to /usr/bin/cd before being passed to sh -c:
# strace -f -e trace=execve ./test.rb
|
execve("./test.rb", ["./test.rb"], [/* 23 vars */]) = 0
|
strace: Process 20373 attached
|
strace: Process 20374 attached
|
[pid 20374] execve("/usr/bin/sh", ["sh", "-c", "/usr/bin/cd /opt/puppetlabs && l"...], [/* 24 vars */]) = 0
|
strace: Process 20375 attached
|
[pid 20375] execve("/usr/bin/cd", ["/usr/bin/cd", "/opt/puppetlabs"], [/* 24 vars */]) = 0
|
[pid 20375] +++ exited with 0 +++
|
[pid 20374] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20375, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
|
strace: Process 20376 attached
|
[pid 20376] execve("/usr/bin/ls", ["ls"], [/* 24 vars */]) = 0
|
[pid 20376] +++ exited with 0 +++
|
[pid 20374] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20376, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
|
[pid 20374] +++ exited with 0 +++
|
[pid 20372] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20374, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
|
1
|
anaconda-ks.cfg
|
linux.iso
|
test.rb
|
[pid 20373] +++ exited with 0 +++
|
+++ exited with 0 +++
|
Expected Outcome
The script prints the content of /opt/puppetlabs:
# ./test.rb
|
bin
|
facter
|
puppet
|
pxp-agent
|
Suggested Workaround
The expansion only affects the first word in the command line, so adding an extra true && to the compound command acts as a sacrificial noop that takes the hit instead.