Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: what is hackzero?



On Mar 30,  7:13am, Zefram wrote:
} Subject: Re: what is hackzero?
}
} >Does anyone know what the global variable hackzero
} >is for?  Offhand I can't figure out what bin_fg is
} >doing with it.
} 
} Looks like the shell can write into its argv[0].
} 
} Okay, "jobs -Z foo" can set the shell's argv[0].  This works (try it),
} and is undocumented.  It's a bit dangerous, as exceeding the length of
} the actual argv[0] is easy and causes undefined behaviour.  It does in
} fact cause trouble on some Unices if the length differs at all.
} 
} Does someone here know enough about modifying argv to advise how this
} could be modified to work better?

I believe this is the only way to do it that ever makes the new string
visible outside the executable, because process table readers like "ps"
use the standard kernel process data structures to extract the arguments.
(On some UNIX flavors, a copy of the arguments is maintained for use by
"ps" et. al., so there's no way to hide the original arguments on those.)

My kernel hacking is a few years' rusty, but a peek at linux sources
shows the following to be not far wrong:

Typically, all the argument strings are packed together, separated by
a single '\0' string-terminator (this may vary for systems with pointer
alignment constraints).  Elements of the argv array then point to the
beginning of each string within that block.

A typical "ps" would get the original address of argv[0] and the length
of the block from the kernel data structure, and then just spit out that
many bytes as the arguments (replacing embedded '\0' terminators with
spaces).  So if you copy a shorter string over any argument, you may
still see remnants of the longer string in the "ps" output.  I'm pretty
sure BSD 4.[23] works (worked?) this way.  So you can't reliably change
argv[0] by changing the pointer, because "ps" doesn't look at the value
of argv[0] in process space, it looks at the original value in the kernel
process table.

If the layout of the args is more complex, "ps" has to know a little more
about how to find each one, so changing the pointer argv[0] might work,
or it might just make things worse.

In the BSD 4.2-ish case, you can scribble whatever you like out as far as
the total length of all the strings (as long as nothing in your program
ever wants to access argv[n] again).

Z-Mail overwrites some if its arguments as it parses them, to convert
from GNU-ish full words into old-UNIX-ish single letters.  On Linux,
you get this:

zmail -echo -shell -folder /dev/null -exec 'sh "ps xww | grep zm"'
zmail -E    -S     -f      /dev/null -exec sh "ps xww | grep zm"

So the arguments aren't copied, but the kernel is maintaining a pointer
and length of each one somewhere outside the process, and "ps" uses that.

But on IRIX4, the original arguments are copy-preserved by the kernel:

zmail -echo -shell -folder /dev/null -exec 'sh "ps -f -u schaefer | grep zm"'
zmail -echo -shell -folder /dev/null -exec sh "ps -f -u schaefer | grep zm"

And on SunOS 4.1.3, the overwritten args are lost completely, because
changing (in this case, incrementing) argv[n] actually does change where
"ps" reads the strings from -- but note that the kernel still knows what
the original argv[0] was, so "ps" adds it in parens:

zmail -echo -shell -folder /dev/null -exec 'sh "ps xww | grep zm"'
 /dev/null -exec sh "ps xww | grep zm" (zmail)

In short, it's a useful hack in some cases, but whether (or how) it works
is hopelessly dependent on the kernel implementation.

-- 
Bart Schaefer                     Vice President, Technology, Z-Code Software
schaefer@xxxxxxxxxx                  Division of NCD Software Corporation
http://www.well.com/www/barts




Messages sorted by: Reverse Date, Date, Thread, Author