[Toybox] Shell corner cases.

Chet Ramey chet.ramey at case.edu
Thu May 1 08:29:11 PDT 2025


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.


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

OK? Commands are parsed, then executed.

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

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

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


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

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

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet at case.edu    http://tiswww.cwru.edu/~chet/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 203 bytes
Desc: OpenPGP digital signature
URL: <http://lists.landley.net/pipermail/toybox-landley.net/attachments/20250501/7d733fbd/attachment.sig>


More information about the Toybox mailing list