mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix argv rewrite on invoking hashbangless script (rhbz#1047506)
The fixargs() function is invoked when ksh needs to run a script
without a #!/hashbang/path. Instead of letting the kernel invoke a
shell, ksh exfile()s the script itself from sh_main(). In the
forked child, it calls fixargs() to set the argument list in the
environment to the args of the new script, so that 'ps' and
/proc/PID/cmdline show the expected output.
But fixargs() is broken because, on systems other than HP-UX (on
which ksh uses pstat(2)), ksh simply inserts a terminating zero.
The arguments list is not a zero-terminated C string. Unix systems
expect the entire arguments buffer to be zeroed out, otherwise 'ps'
and /proc/*/cmdline will have fragments of previous command lines
in the output.
The Red Hat patch for this bug is:
642af4d6/f/ksh-20120801-argvfix.patch
However, that fix is incomplete because 'command_len' was also
hardcoded to be limited to 64 characters (!), which still gave
invalid 'ps' output if the erased command line was longer.
src/cmd/ksh93/sh/main.c: fixargs():
- Remove CMD_LENGTH macro which was defined as 64.
- Remove code that limited the erasure of the arguments buffer to
CMD_LENGTH characters. That code also had quite a dodgy strdup()
call -- it copies arguments to the heap, but they are never freed
(or even used), so it's a memory leak. Also, none of this is
ever done if the length is calculated using pstat(2) on HP-UX,
which is a clear indication that it's unnecessary.
(I think this code block must have been some experiment they
forgot to remove. One reason why I think so is that a 64 byte
arguments limit never made sense, even in the 1980s when they
wrote ksh on 80-column CRT displays. Another indication of this
is that fixing it didn't require adding anything; the code to do
the right thing was already there, it was just being overridden.)
- Zero out the full arguments length as in the Red Hat patch.
src/cmd/ksh93/tests/basic.sh:
- Add test. It's sort of involved because 'ps' is one of the least
portable commands in practice, in spite of standardisation.
This commit is contained in:
parent
651bbd563e
commit
cefe087d23
4 changed files with 42 additions and 17 deletions
|
@ -692,5 +692,29 @@ actual=$(exptest foo)
|
|||
[[ $actual == "$expect" ]] || err_exit 'Corruption of multibyte char following expansion of single-char name' \
|
||||
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
||||
|
||||
# ======
|
||||
# ksh didn't rewrite argv correctly (rhbz#1047506)
|
||||
# When running a script without a #! hashbang path, ksh attempts to replace argv with the arguments
|
||||
# of the script. However, fixargs() didn't wipe out the rest of previous arguments after the last
|
||||
# \0. This caused an erroneous record in /proc/<PID>/cmdline and the output of the ps command.
|
||||
if actual=$(UNIX95=1 ps -o args= -p "$$" 2>&1) # UNIX95=1 makes this work on HP-UX
|
||||
# Some 'ps' implementations add leading and/or trailing whitespace. Remove.
|
||||
while [[ $actual == [[:space:]]* ]]; do actual=${actual#?}; done
|
||||
while [[ $actual == *[[:space:]] ]]; do actual=${actual%?}; done
|
||||
[[ $actual == "$SHELL $0" ]] # this is how shtests invokes this script
|
||||
then expect='./atest 1 2'
|
||||
echo 'sleep 10; exit 0' >atest
|
||||
chmod 755 atest
|
||||
./atest 1 2 &
|
||||
actual=$(UNIX95=1 ps -o args= -p "$!")
|
||||
kill "$!"
|
||||
while [[ $actual == [[:space:]]* ]]; do actual=${actual#?}; done
|
||||
while [[ $actual == *[[:space:]] ]]; do actual=${actual%?}; done
|
||||
[[ $actual == "$expect" ]] || err_exit "ksh didn't rewrite argv correctly" \
|
||||
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
||||
else err_exit "warning: skipping argv rewrite test due to noncompliant 'ps' utility (got $(printf %q "$actual"))"
|
||||
let Errors--
|
||||
fi
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue