[Toybox] Shell corner cases.

Rob Landley rob at landley.net
Wed Apr 30 15:23:54 PDT 2025


On 4/29/25 08:53, Chet Ramey wrote:
> On 4/28/25 6:03 PM, Rob Landley wrote:
>> FYI, I'd prefer not to implement either of these in toybox:
>>
>> 1) function names with / in them
>>
>>    $ which sudo
>>    /usr/bin/sudo
>>    $ /usr/bin/sudo() { echo owned; }
>>    $ /usr/bin/sudo
>>    owned
>>    $ ./sudo() { echo still owned; }
>>    $ ./sudo
>>    still owned
> 
> Sure, probably a good idea. POSIX execution rules say they'd never be
> called anyway.

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.

>> 2) deferred alias definitions
>>
>>    $ alias potato='echo hello'; potato
>>    bash: potato: command not found
>>    $ potato
>>    hello
> 
> I'm not sure what `deferred' means here. The shell reads a line of input,
> parses it into a command (a list with two elements in this case), then
> executes the command.

$ x() { echo hello; }; D=x; $D
hello

> 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...

> 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:

$ bash -c $'echo $LINENO;alias a=b\necho $LINENO;a'
1
2
bash: line 2: a: command not found

It's the second line according to $LINENO but the same one according to 
alias tokenization. That really seems like an implementation detail 
bubbling through. I was just treating aliases as early functions sniped 
before variable expansion, so:

$ alias one=ls ;B=one
$ $B
bash: one: command not found

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

And, of course:

$ alias one=two
$ on\e
bash: one: command not found

So many corner cases to test...

Rob


More information about the Toybox mailing list