[Toybox] Shell corner cases.
Rob Landley
rob at landley.net
Thu May 1 12:44:36 PDT 2025
On 5/1/25 10:29, Chet Ramey wrote:
> On 4/30/25 6:23 PM, Rob Landley wrote:
>
>> Somebody forwarded that to me from an exploit how-to site. It's
>> apparently a trick used to subvert scripts that call things via
>> absolute path to avoid malicious $PATH.
>
> I suppose if you can get a script to source an arbitrary file, you can do
> pretty much anything.
$ command /usr/bin/whoami
landley
$ command() { echo nope; }
$ command /usr/bin/whoami
nope
What was the _benefit_ of allowing / in command names?
>> $ x() { echo hello; }; D=x; $D
>> hello
>
> OK? Commands are parsed, then executed.
To me, that seemed like analogous behavior working on the same line.
Mostly the use of alias I've encountered seems to be things like alias
ls='ls -l' allowing additional arguments, although ls() { ls -l "$@"; }
seems like it could do it too. The _unique_ feature is stuff like:
$ alias ls='ls >'
$ ls
bash: syntax error near unexpected token `newline'
Which I've never seen the utility of, other than people who do variants
of the old "define begin {" stuff pascal programmers used to do when
forced to use C...
>>> Since alias expansion happens when the command is
>>> read and tokenized,
>>
>> Yeah, that was the weird part. My code breaks argv[] into separate
>> chunks but doesn't try to figure out what they _mean_ until it needs
>> to run them, because:
>>
>> $ alias one='$X'
>> $ X='$A'; A=$X one
>> bash: $A: command not found
>>
>> Is still figuring out that it has to move past the prefix assignment
>> to expand the alias, so you're saying your "tokenization" recognizes
>> prefix assignments...
>
> Alias expansion happens on the first word of a simple command (for our
> purposes here). The first word of a simple command that's going to be
> eligible for alias expansion is a WORD, not an ASSIGNMENT_WORD.
>
> The parser knows when it's going to read a command, so it knows when to
> expect a simple command, and if it reads an assignment statement in that
> position, it knows it's an ASSIGNMENT_WORD. Only WORDs in the right
> position are eligible for alias expansion -- it's context-dependent.
It works for prefix assignments but not:
$ alias blah='echo hello'
$ >file blah
$ cat blah
cat: blah: No such file or directory
(Don't ask me why the error message went to stdout instead of stderr,
but the $ prompt goes to stderr. I think I need to walk away from the
keyboard for a bit...)
> As POSIX puts it:
>
> "Further distinction on TOKEN is context-dependent. It may be that the same
> TOKEN yields WORD, a NAME, an ASSIGNMENT_WORD, or one of the reserved words
> below, dependent upon the context."
>
>>
>>> the list will be parsed before any of the commands
>>> are executed. This is how Bourne-style shells work.
>>
>> The logic of what counts as a "line" in this context is unclear to me:
>
> Oh, we had a rocking discussion about that topic, and the comments here
> aren't half of it.
>
> https://www.austingroupbugs.net/view.php?id=953
Oh joy.
>> $ bash -c $'echo $LINENO;alias a=b\necho $LINENO;a'
>> 1
>> 2
>> bash: line 2: a: command not found
>
> Anywhere the shell executes a string (the command_string argument to
> `sh -c', `eval', command substitution bodies), it parses the entire string
> as a compound_list and then executes that list.
I just did fmemopen(buf, strlen(buf), "r") and fed it to the same line
reading loop as everything else. You're saying I should write extra code
to behave differently for the special case.
>> Wouldn't trigger (like it does for functions).
>>
>> Then again busybox ash, mksh, zsh, and even dash are all doing this
>> too, so I guess "compatible" beats "sane". Maybe it's so you can do:
>>
>> alias potato=fruitbat
>> source filename
>> unalias potato
>
> See above about compound_list parsing.
Sigh.
>> And, of course:
>>
>> $ alias one=two
>> $ on\e
>> bash: one: command not found
>
> When that is tokenized, the backslash is still part of the word, so it
> can't match an alias name.
Only because:
$ alias on\\e=two
bash: alias: `on\e': invalid alias name
Which function definition _doesn't_ do...
My first pass at implementing this just recycled the "is this a valid
variable name" logic:
$ abc/def=ghi
bash: abc/def=ghi: No such file or directory
But functions can have / in them for reasons.
Possibly I should just get this wrong and wait to see who complains...
> Chet
Rob
More information about the Toybox
mailing list