Changing argv[0] under Linux.
Hi all :))
I'm not sure whether this issue belongs to the kernel or to the
libc, but I think that is more on the kernel side, that's why I ask here.
Let's go to the matter: I want to change the argv[0] a program
shows, in order to be pretty-printed when issuing 'ps', 'top' or other commands. What I'm doing now is just writing over the existing argv[0] string, but then I must use a *shorter-or-equal* string in order to fit it on the existing space. What if I need to put a *larger* string on argv[0]? Is this possible at all?
Thanks in advance :)
Raúl
Quoted 6 lines · DervishD
Hi all :))
I'm not sure whether this issue belongs to the kernel or to the
libc, but I think that is more on the kernel side, that's why I ask here.
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
PID TTY STAT TIME COMMAND
126 4 S 0:00 /sbin/agetty 38400 tty4 127 5 S 0:00 /sbin/agetty 38400 tty5 128 6 S 0:00 /sbin/agetty 38400 tty6 5241 2 S 0:00 -bash 13476 1 S 0:00 How-long-do-you-want-this-string-to-be?--is-this-long-enoug 13489 3 R 0:00 ps 27498 3 S 0:00 -bash 31011 1 S 0:00 -bash
#include <stdio.h>
#include <string.h>
int main(int cnt, char *argv[]) {
strcpy(argv[0], "How-long-do-you-want-this-string-to-be?--is-this-long-enough?");
pause();
return 0;
}Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Hi Richard :)
Quoted 3 lines
Quoted 1 line
libc, but I think that is more on the kernel side, that's why I ask
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
Any header where I can see the length for argv[0] or is this some
kind of unoficial standard? Just doing strcpy seems dangerous to me (you can read 'paranoid'...).
Thanks a lot for your answer, Richard :)
Raúl
Quoted 6 lines · DervishD
Hi Richard :)
Quoted 3 lines
Quoted 1 line
libc, but I think that is more on the kernel side, that's why I ask
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
Quoted 7 lines
Any header where I can see the length for argv[0] or is this some
kind of unoficial standard? Just doing strcpy seems dangerous to me (you can read 'paranoid'...).Thanks a lot for your answer, Richard :)
Raúl
They need to have space for _POSIX_PATH_MAX (512 bytes), to claim POSIX compatibility so any POSIX system will have at least 512 bytes available because the pathname of the executable normally goes there.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Hi Richard :)
Quoted 7 lines
Quoted 3 lines
Any header where I can see the length for argv[0] or is this some
kind of unoficial standard? Just doing strcpy seems dangerous to me (you can read 'paranoid'...).They need to have space for
_POSIX_PATH_MAX(512 bytes), to claim POSIX compatibility so any POSIX system will have at least 512 bytes available because the pathname of the executable normally goes there.
Enough for me, then. Thanks a lot :)) Just one more thing: in my
Single Unix Spec v3 says that the minimum value of _POSIX_PATH_MAX is 256, not 512, and the libc manual says just the same :??
Anyway, 256 bytes is a fair large amount ;))))
Thanks again, Richard.
Raúl
Quoted 14 lines · DervishD
Hi Richard :)
Quoted 7 lines
Quoted 3 lines
Any header where I can see the length for argv[0] or is this some
kind of unoficial standard? Just doing strcpy seems dangerous to me (you can read 'paranoid'...).They need to have space for
_POSIX_PATH_MAX(512 bytes), to claim POSIX compatibility so any POSIX system will have at least 512 bytes available because the pathname of the executable normally goes there.Enough for me, then. Thanks a lot :)) Just one more thing: in my
Single Unix Spec v3 says that the minimum value of_POSIX_PATH_MAXis 256, not 512, and the libc manual says just the same :??
Quoted 6 lines
Anyway, 256 bytes is a fair large amount ;))))
Thanks again, Richard.
Raúl
Well I just grepped through usr/include/bits/posix1_lim.h and it shows 255 (with this 'C' library) so you are probably right.
In any event, a "whole line of text" isn't going to overrun it.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Quoted 3 lines · Richard B. Johnson
Well I just grepped through
usr/include/bits/posix1_lim.hand it shows 255 (with this 'C' library) so you are probably right. In any event, a "whole line of text" isn't going to overrun it.
Looking at the code, it looks to me as if argv[0] can be any size up to _SC_ARG_MAX, with the restraining factor being that the environment variables and the other arguments must fit in the same space.
Is this not correct?
mark
Signature · 9 lines
[email protected]/[email protected]/[email protected] __________________________ . . _ ._ . . .__ . . ._. .__ . . . .__ | Neighbourhood Coder |\/| |_| |_| |/ |_ |\/| | |_ | |/ |_ | | | | | | \ | \ |__ . | | .|. |__ |__ | \ |__ | Ottawa, Ontario, Canada One ring to rule them all, one ring to find them, one ring to bring them all and in the darkness bind them... http://mark.mielke.cc/
Quoted 11 lines · Richard B. Johnson
Quoted 6 lines · DervishD
Hi all :))
I'm not sure whether this issue belongs to the kernel or to the
libc, but I think that is more on the kernel side, that's why I ask here.Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
Last time must have been in an alternate reality.
You just overwrote all your arguments (argv[0] and others) and part of the environment.
Try this for a change:
#include <stdio.h>
#include <string.h>
extern char ** _environ;
int main(int cnt, char *argv[]) {
char **eptr;
for ( eptr = _environ; *eptr; ++eptr )
printf("ENV before: %s\n", *eptr);
strcpy(argv[0], "How-long-do-you-want-this-string-to-be?--is-this-long-enough?");
for ( eptr = _environ; *eptr; ++eptr )
printf("ENV after: %s\n", *eptr);
pause();
return 0;
}Phil.
Quoted 5 lines · Mark Mielke
Quoted 3 lines · Richard B. Johnson
Well I just grepped through
usr/include/bits/posix1_lim.hand it shows 255 (with this 'C' library) so you are probably right. In any event, a "whole line of text" isn't going to overrun it.
Quoted 7 lines
Looking at the code, it looks to me as if argv[0] can be any size up to
_SC_ARG_MAX, with the restraining factor being that the environment variables and the other arguments must fit in the same space.Is this not correct?
mark
Don't think so. In my headers _SC_ARG_MAX is an enumerated type that is numerically equal to 0. It's in confname.h, the first element in the enumerated list.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Quoted 11 lines · Philippe Troin
Quoted 9 lines · Richard B. Johnson
Quoted 6 lines · DervishD
Hi all :))
I'm not sure whether this issue belongs to the kernel or to the
libc, but I think that is more on the kernel side, that's why I ask here.
Quoted 8 lines
Quoted 2 lines
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
Last time must have been in an alternate reality.
You just overwrote all your arguments (argv[0] and others) and part of the environment.
It seems to depend upon the machine, maybe the 'C' runtime library.
uname -a
Linux chaos 2.4.18 #15 SMP Mon Jul 15 14:19:43 EDT 2002 i686 This machine is a composite, made from stuff dating back over 5 years, but with two 'C' runtime library updates and many of the programs/utilities re-compiled.
Script started on Tue Jan 14 15:45:11 2003
[9;0]# xxx
ENV before: LOGNAME=root
ENV before: NLSPATH=/usr/man:/usr/X11/man:/usr/openwin/man:/opt/schily/man
ENV before: MINICOM=-c on
ENV before: VISUAL=/bin/vi
ENV before: MAIL=/var/spool/mail/root
ENV before: LD_LIBRARY_PATH=/lib:/usr/lib/:/opt/intel/compiler50/ia32/lib:/usr/X11R6/lib:/opt/Office50/lib:/usr/java/lib/i686
ENV before: TERMCAP=vt100|vt100-am|dec vt100 (w/advanced video):am:mi:ms:xn:xo:co#80:it#8:li#25:vt#3:@8=\EOM:DO=\E[%dB:K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:ac=\140\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:ae=^O:
as=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:eA=\E(B\E)0:ho=\E[H:k0=\EOy:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:kr=\EOC:ks=\
E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:me=\E[m\017:mr=\E[7m:nd=\E[C:is=\E<\E)0:r2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:rc=\E8:sc=\E7:se=\E[m:sf=^J:so=\E[1;7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:us=\E[4m:
ENV before: TERM=vt100-am
ENV before: HOSTTYPE=i386
ENV before: PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/opt/schily/bin:/usr/bin/X11:/sbin/:/usr/TeX/bin:/usr/openwin/bin:/opt/intel/compiler50/ia32/bin:/usr/games:.:/usr/local/Office50/bin:/usr/java/bin:/home/users/root/tools:/home/users/root/tools
ENV before: PRINTER=mcd
ENV before: HOME=/root
ENV before: PS_SYSTEM_MAP=/System.map
ENV before: SHELL=/bin/bash
ENV before: LINES=25
ENV before: PS1=#
ENV before: PS2=>
ENV before: MANPATH=/usr/man:/usr/X11/man:/usr/openwin/man:/opt/schily/man
ENV before: LESS=-MM
ENV before: COLUMNS=80
ENV before: LIB=/usr/X11R6/lib:/usr/X11/lib:/usr/X11/lib
ENV before: GNUHELP=/usr/local/lib/gnuplot/gnuplot.gih
ENV before: JAVA_HOME=/usr/java
ENV before: DISPLAY=:0
ENV before: LANG=en_US.88591
ENV before: OSTYPE=Linux
ENV before: OPENWINHOME=/usr/openwin
ENV before: SHLVL=2
ENV before: EDITOR=/bin/vi
ENV before: LS_COLORS=no=00:fi=40;32:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;33:*.cmd=01;32:*.o=40;32:*.c=01;26:*.S=01;26:*.h=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=0 1;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:
ENV before: TZ=US/Eastern
ENV before: _=./xxx
ENV after: LOGNAME=root
ENV after: NLSPATH=/usr/man:/usr/X11/man:/usr/openwin/man:/opt/schily/man
ENV after: MINICOM=-c on
ENV after: VISUAL=/bin/vi
ENV after: MAIL=/var/spool/mail/root
ENV after: LD_LIBRARY_PATH=/lib:/usr/lib/:/opt/intel/compiler50/ia32/lib:/usr/X11R6/lib:/opt/Office50/lib:/usr/java/lib/i686
ENV after: TERMCAP=vt100|vt100-am|dec vt100 (w/advanced video):am:mi:ms:xn:xo:co#80:it#8:li#25:vt#3:@8=\EOM:DO=\E[%dB:K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:ac=\140\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:ae=^O:a s=^N:bl=^G:cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:do=^J:eA=\E(B\E)0:ho=\E[H:k0=\EOy:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\EOt:k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:kr=\EOC:ks=\E [?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:me=\E[m\017:mr=\E[7m:nd=\E[C:is=\E<\E)0:r2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:rc=\E8:sc=\E7:se=\E[m:sf=^J:so=\E[1;7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:up=\E[A:us=\E[4m:
ENV after: TERM=vt100-am
ENV after: HOSTTYPE=i386
ENV after: PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/opt/schily/bin:/usr/bin/X11:/sbin/:/usr/TeX/bin:/usr/openwin/bin:/opt/intel/compiler50/ia32/bin:/usr/games:.:/usr/local/Office50/bin:/usr/java/bin:/home/users/root/tools:/home/users/root/tools ENV after: PRINTER=mcd
ENV after: HOME=/root
ENV after: PS_SYSTEM_MAP=/System.map
ENV after: SHELL=/bin/bash
ENV after: LINES=25
ENV after: PS1=#
ENV after: PS2=>
ENV after: MANPATH=/usr/man:/usr/X11/man:/usr/openwin/man:/opt/schily/man
ENV after: LESS=-MM
ENV after: COLUMNS=80
ENV after: LIB=/usr/X11R6/lib:/usr/X11/lib:/usr/X11/lib
ENV after: GNUHELP=/usr/local/lib/gnuplot/gnuplot.gih
ENV after: JAVA_HOME=/usr/java
ENV after: DISPLAY=:0
ENV after: LANG=en_US.88591
ENV after: OSTYPE=Linux
ENV after: OPENWINHOME=/usr/openwin
ENV after: SHLVL=2
ENV after: EDITOR=/bin/vi
ENV after: LS_COLORS=no=00:fi=40;32:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;33:*.cmd=01;32:*.o=40;32:*.c=01;26:*.S=01;26:*.h=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01 ;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:
ENV after: TZ=US/Eastern
ENV after: _=./xxx
# exit Script done on Tue Jan 14 15:45:48 2003
My Sun.......
Script started on Tue Jan 14 15:47:18 2003
# uname -a SunOS hal 5.5.1 Generic sun4m sparc SUNW,SPARCstation-5 # ./xxx ENV before: HOME=/ ENV before: HZ=100 ENV before: LD_LIBRARY_PATH=/usr/ucblib:/usr/lib:/usr/local/lib:/usr/local/lib/gcc-lib:/lib ENV before: LOGNAME=root ENV before: MAIL=/var/mail/root ENV before: PATH=/usr/bin:/usr/local/bin:/usr/sbin:/usr/ccs/bin:/usr/openwin/bin:/sbin/:. ENV before: SHELL=/sbin/sh ENV before: TERM=vt100-am ENV before: TZ=US/Eastern ENV after: ng-do-you-want-this-string-to-be?--is-this-long-enough? ENV after: ou-want-this-string-to-be?--is-this-long-enough? ENV after: -this-string-to-be?--is-this-long-enough? ENV after: LOGNAME=root ENV after: MAIL=/var/mail/root ENV after: PATH=/usr/bin:/usr/local/bin:/usr/sbin:/usr/ccs/bin:/usr/openwin/bin:/sbin/:. ENV after: SHELL=/sbin/sh ENV after: TERM=vt100-am ENV after: TZ=US/Eastern ^C# exit script done on Tue Jan 14 15:47:34 2003
My red-hat 7.0 machine shows the environment overwrite also.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Quoted 5 lines · Richard B. Johnson
Quoted 4 lines · Mark Mielke
Quoted 3 lines · Richard B. Johnson
Well I just grepped through
usr/include/bits/posix1_lim.hand it shows 255 (with this 'C' library) so you are probably right. In any event, a "whole line of text" isn't going to overrun it.
Quoted 7 lines
Quoted 4 lines
Looking at the code, it looks to me as if argv[0] can be any size up to
_SC_ARG_MAX, with the restraining factor being that the environment variables and the other arguments must fit in the same space. Is this not correct?Don't think so. In my headers
_SC_ARG_MAXis an enumerated type that is numerically equal to 0. It's inconfname.h, the first element in the enumerated list.
_SC_ARG_MAX is one of the identifiers that are used with sysconf() to lookup a system-wide configuration value:
$ perl -MPOSIX -e 'print sysconf(_SC_ARG_MAX), "\n"'
131072The environment size for a program invoked using exec() can be up to 131072 bytes long (my configuration). This environment holds the command arguments as well as the environment.
On my system, _SC_ARG_MAX is telling me that it is possible to have argv[0] be just under 131072 bytes long.
mark
Signature · 9 lines
[email protected]/[email protected]/[email protected] __________________________ . . _ ._ . . .__ . . ._. .__ . . . .__ | Neighbourhood Coder |\/| |_| |_| |/ |_ |\/| | |_ | |/ |_ | | | | | | \ | \ |__ . | | .|. |__ |__ | \ |__ | Ottawa, Ontario, Canada One ring to rule them all, one ring to find them, one ring to bring them all and in the darkness bind them... http://mark.mielke.cc/
In article <[email protected]>,
Quoted 8 lines · Richard B. Johnson
Quoted 3 lines · DervishD
I'm not sure whether this issue belongs to the kernel or to the
libc, but I think that is more on the kernel side, that's why I ask here.Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
No cigar. This stuff is all set up by the kernel on the stack; in order you have
Top of stack at 0xbfffffff environ[0]\0environ[1]\0\0 From high .. argv[0]\0argv[1]\0\0 *environ[]; *argv[]; .. to low.
The kernel only reserves space as needed. If you have an empty environment, and you copy 512 bytes over argv[0], you'll end up with a SEGV.
If you want to modify argv[0] etc, loop over argv[], count howmuch space there is (strlen(argv[0] + 1 + strlen(argv[1] + 1 ... etc) and make sure you do NOT write a string longer than that. Also make sure that you end the string with a double \0
Mike.
Signature · 2 lines
They all laughed when I said I wanted to build a joke-telling machine. Well, I showed them! Nobody's laughing *now*! -- [email protected]
Quoted 4 lines · Miquel van Smoorenburg
If you want to modify argv[0] etc, loop over argv[], count howmuch space there is (strlen(argv[0] + 1 + strlen(argv[1] + 1 ... etc) and make sure you do NOT write a string longer than that. Also make sure that you end the string with a double \0
Or steal the code that's already been done - sendmail and wu-ftpd both have code to do this....
Signature · 3 lines
Valdis Kletnieks Computer Systems Senior Engineer Virginia Tech
Hi Philippe :)
Quoted 2 lines
You just overwrote all your arguments (argv[0] and others) and part of the environment.
Oh, sh*t, you're true, and that is the problem I was afraid to
suffer from. Then, all I can do is overwrite argv[0] with a new string whose length is less or equal than the existing one.
Well, I suppose I must go with that limitation.
Thanks, Philippe, for the code snipped and the explanation.
Raúl
Hi Mark :)
Quoted 5 lines
Quoted 1 line
In any event, a "whole line of text" isn't going to overrun it.
Looking at the code, it looks to me as if argv[0] can be any size up to
_SC_ARG_MAX, with the restraining factor being that the environment variables and the other arguments must fit in the same space. Is this not correct?
This is correct, but it is a maximum, not a minimum.
Raúl
Quoted 9 lines · DervishD
Hi Philippe :)
Quoted 2 lines
You just overwrote all your arguments (argv[0] and others) and part of the environment.
Oh, sh*t, you're true, and that is the problem I was afraid to
suffer from. Then, all I can do is overwrite argv[0] with a new string whose length is less or equal than the existing one.
Quoted 6 lines
Well, I suppose I must go with that limitation.
Thanks, Philippe, for the code snipped and the explanation.
Raúl
-
Or you can copy your all your args and env to a temporary place and then re-build your args and env with the new argv[0] in it's place. But you must be carefull that your new argv[0] length plus the length of all remaining args, envp and pointers is not greater than the system defined size for this space.
Signature · 2 lines
Bob Miller Email: [email protected] Open Source Development Lab Phone: 503.626.2455 Ext. 17
Quoted 14 lines · Bob Miller
Quoted 13 lines · DervishD
Hi Philippe :)
Quoted 2 lines
You just overwrote all your arguments (argv[0] and others) and part of the environment.
Oh, sh*t, you're true, and that is the problem I was afraid to
suffer from. Then, all I can do is overwrite argv[0] with a new string whose length is less or equal than the existing one.Well, I suppose I must go with that limitation.
Thanks, Philippe, for the code snipped and the explanation.
Quoted 9 lines
Quoted 2 lines
Raúl
-Or you can copy your all your args and env to a temporary place and then re-build your args and env with the new argv[0] in it's place. But you must be carefull that your new argv[0] length plus the length of all remaining args, envp and pointers is not greater than the system defined size for this space.
In thinking about this more this will NOT work. The user stack starts right after your envp. So, writing more info there would blow away your stack.
Signature · 2 lines
Bob Miller Email: [email protected] Open Source Development Lab Phone: 503.626.2455 Ext. 17
Quoted 9 lines · Bob Miller
Quoted 5 lines · Bob Miller
Or you can copy your all your args and env to a temporary place and then re-build your args and env with the new argv[0] in it's place. But you must be carefull that your new argv[0] length plus the length of all remaining args, envp and pointers is not greater than the system defined size for this space.
In thinking about this more this will NOT work. The user stack starts right after your envp. So, writing more info there would blow away your stack.
I can smell the next hack... memmove() the stack down to make room... :-)
mark
Signature · 9 lines
[email protected]/[email protected]/[email protected] __________________________ . . _ ._ . . .__ . . ._. .__ . . . .__ | Neighbourhood Coder |\/| |_| |_| |/ |_ |\/| | |_ | |/ |_ | | | | | | \ | \ |__ . | | .|. |__ |__ | \ |__ | Ottawa, Ontario, Canada One ring to rule them all, one ring to find them, one ring to bring them all and in the darkness bind them... http://mark.mielke.cc/
Quoted 7 lines · Mark Mielke
Quoted 6 lines · Bob Miller
Quoted 5 lines · Bob Miller
Or you can copy your all your args and env to a temporary place and then re-build your args and env with the new argv[0] in it's place. But you must be carefull that your new argv[0] length plus the length of all remaining args, envp and pointers is not greater than the system defined size for this space.
Quoted 5 lines
Quoted 3 lines
In thinking about this more this will NOT work. The user stack starts right after your envp. So, writing more info there would blow away your stack.
I can smell the next hack...
memmove()the stack down to make room... :-)
No need. You can memcpy the environment. See setenv(3), putenv(3) and related library routines.
Once you've parsed your argv who cares if you overwrite it, put a double NULL at the end, set argc = 1 and argv[1] = NULL. If argv[argc] - argv[0] + strlen(argv[argc] is shorter than what you overwrite it with you won't even need to relocate the environment block if you wish to preserve that. Just don't leave any loose ends to confuse /proc and the ps utils.
Signature · 5 lines
________________________________________________________________ J.W. Schultz Pegasystems Technologies email address: [email protected] Remember Cernan and Schmitt
Hi JW :)
Quoted 5 lines
Quoted 3 lines
Quoted 2 lines
right after your envp. So, writing more info there would blow away your stack.
I can smell the next hack...
memmove()the stack down to make room... :-)No need. You can memcpy the environment. See setenv(3), putenv(3) and related library routines.
I'm afraid that the best solution, well, the one which involves
less code and less problems (no need to relocate the environment or things like that) is to write to argv[0] a shorter string that the existing one, and overwrite with nulls the rest of arguments, just in case the stack layout is not what expected.
Really, I'm thinking seriously about not rewritting argv[0] at
all. The problem is that may confuse the user when issuing 'ps' or looking at /proc :((
Raúl
Hi Miquel :))
Quoted 3 lines
Quoted 2 lines
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
No cigar. This stuff is all set up by the kernel on the stack;
Thanks a lot for your help :)) FYI, this question is related to
the virtual-console-only init clone that I wrote some time ago (I used sysvinit for inspiration and good advice), I think I wrote you about this. Anyway, you are in the acknowledgement list doubly, now ;))) I'm going to release this init in a week or so, after having using it for more than a year at home without problems.
Quoted 4 lines
If you want to modify argv[0] etc, loop over argv[], count howmuch space there is (strlen(argv[0] + 1 + strlen(argv[1] + 1 ... etc) and make sure you do NOT write a string longer than that. Also make sure that you end the string with a double \0
How about portability? Not that worries me, since this code will
go to a Linux-only program, just curiosity. Other OSes do the same stack layout?
Raúl
Hi Bob :)
Quoted 2 lines
Or you can copy your all your args and env to a temporary place and then re-build your args and env with the new argv[0] in it's place.
Yes, this is a good solution, too. The problem with all solutions
is that they involve a good bunch of code for a thing that doesn't deserve it ;))
Moreover, since I must preserve the environment and I'm pretty
sure that there is no arg except argv[0], I end up with the same problem. The user may install this bit of crap under name '/i', for example, and then I have only two characters for the new name :((
Thanks for your help :)
Raúl
Quoted 14 lines · DervishD
Hi JW :)
Quoted 5 lines
Quoted 3 lines
Quoted 2 lines
right after your envp. So, writing more info there would blow away your stack.
I can smell the next hack...
memmove()the stack down to make room... :-)No need. You can memcpy the environment. See setenv(3), putenv(3) and related library routines.
I'm afraid that the best solution, well, the one which involves
less code and less problems (no need to relocate the environment or things like that) is to write to argv[0] a shorter string that the existing one, and overwrite with nulls the rest of arguments, just in case the stack layout is not what expected.
Quoted 3 lines
Really, I'm thinking seriously about not rewritting argv[0] at
all. The problem is that may confuse the user when issuing 'ps' or looking at /proc :((
What about
int main(int argc, char **argv) {
if (argc != 2 || (argv == 2 && !strcmp(argv[1], "--very-magic"))) {
char argv0[512];
memcpy(argv0, 'a', 511);
argv0[511] = 0;
char *const args[] = { argv0, "--very-magic", 0 }; execv(argv[0], args);
}
strcpy(argv[0], "my proggy");
/* your code here */
}
This should ensure that you have 511 bytes of argv[0] storage available, if I read the previous posts correctly.
For the same effect without the --very-magic argument, you could simply do an "if (argc != 2 || strlen(argv[0]) != 511)" instead.
Am I smoking crack, or could the above work?
Signature · 6 lines
................................................................ : [email protected] : And I see the elder races, : :.........................: putrid forms of man : : Jakob Østergaard : See him rise and claim the earth, : : OZ9ABN : his downfall is at hand. : :.........................:............{Konkhra}...............:
Quoted 20 lines · Mark Mielke
Quoted 5 lines · Richard B. Johnson
Quoted 4 lines · Mark Mielke
Quoted 3 lines · Richard B. Johnson
Well I just grepped through
usr/include/bits/posix1_lim.hand it shows 255 (with this 'C' library) so you are probably right. In any event, a "whole line of text" isn't going to overrun it.Quoted 7 lines
Quoted 4 lines
Looking at the code, it looks to me as if argv[0] can be any size up to
_SC_ARG_MAX, with the restraining factor being that the environment variables and the other arguments must fit in the same space. Is this not correct?Don't think so. In my headers
_SC_ARG_MAXis an enumerated type that is numerically equal to 0. It's inconfname.h, the first element in the enumerated list.
_SC_ARG_MAXis one of the identifiers that are used withsysconf()to lookup a system-wide configuration value:$ perl -MPOSIX -e 'print sysconf(_SC_ARG_MAX), "\n"' 131072
Quoted 9 lines
The environment size for a program invoked using
exec()can be up to 131072 bytes long (my configuration). This environment holds the command arguments as well as the environment.On my system,
_SC_ARG_MAXis telling me that it is possible to have argv[0] be just under 131072 bytes long.mark
The following program shows why it's not "safe" to do anything with argv[0].
#include <stdio.h>
int main(int c, char *argv[], char *env[])
{
int i;
i = 0;
printf("Stack is at %p\n", &i);
while(argv[i])
{
printf("Pointer at %p = %s\n", argv[i], argv[i]);
i++;
}
i = 0;
while(env[i])
{
printf("Pointer at %p = %s\n", env[i], env[i]);
i++; }
return 0;
}
Everything is lined-up, sitting on the stack, and all variable- length.
I looked at sendmail and it just does:
strcpy(argv[0] ,"sendmail:accepting connections");
But sendmail doesn't use the environment so if it gets trashed it doesn't make any difference. It looks as though, if the environment was small, i.e., only "TERM=vt100", sendmail might have problems if main() ever returns to _start. The stack will be trashed. But, most 'C' code doesn't do "return N;" from main, certainly not a daemon, most call exit().
Anyway, overwriting argv[0] is done, but it's not "safe".
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
Hi Jakob :)
Quoted 4 lines
Quoted 3 lines
Really, I'm thinking seriously about not rewritting argv[0] at
all. The problem is that may confuse the user when issuing 'ps' or looking at /proc :((What about
[...]
Mmm, interesting idea. A simpler solution is just copy the needed
argv0. In your example, about 500 bytes are wasted ;))) By using the needed size at argv0, we have the space needed.
If execv doesn't do any magic with the supplied argv array, then
this should work.
Quoted 2 lines
For the same effect without the --very-magic argument, you could simply do an "if (argc != 2 ||
strlen(argv[0])!= 511)" instead.
No, because the len of argv[0] being 'my proggy' is 9, that is not
511 ;)) We cannot tell the allocated space, I'm afraid O:)
Quoted 1 line
Am I smoking crack, or could the above work?
I should smoke crack, definitely. That way I would not mess with
that argv thing XDDDD
Thanks :)
Raúl
Well, I just can't give this up! Here is a procedure plus a test program that reallocates and copies environment strings so the process title can be altered. The procedure returns the amount of space available for the new name so that strncpy() can be used to prevent damage.
If you don't like me pretending that main() gets the environment after args[], you can access environ directly anyway with the same result. Have fun!
If you don't have enough string-space to make a large enough name, just increase the size of your environment.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
extern char **environ;
size_t init_settitle(char *argv[], char *env[])
{
size_t i, len;
char *limit;
char *var;
i = 0;
while(env[i] != NULL)
{
len = strlen(env[i]) + 1; /* Room for the '\0' */
var = (char *) malloc(len);
memcpy(var, env[i], len); /* Copy the '\0' also */
limit = env[i]; /* Start of last string */
env[i++] = var; /* New environment ptr */
}
while(*limit) /* End of last string */
limit++; return (limit - argv[0]); /* Space we can use */
}
int main(int c, char *argv[], char *env[])
{
size_t len, i;
len = init_settitle(argv, env);
i = 0;
while(environ[i] != NULL)
puts(environ[i++]);
printf("Length allowed = %u\n", len);
fflush(stdout);
strncpy(argv[0], "Antidesestablishmentarianism", len);
i = 0;
while(environ[i] != NULL)
puts(environ[i++]);
fflush(stdout);
pause();
return 0;
}Quoted 11 lines · DervishD
Hi Jakob :)
Quoted 4 lines
Quoted 3 lines
Really, I'm thinking seriously about not rewritting argv[0] at
all. The problem is that may confuse the user when issuing 'ps' or looking at /proc :((What about
[...]
Mmm, interesting idea. A simpler solution is just copy the needed
argv0. In your example, about 500 bytes are wasted ;))) By using the needed size at argv0, we have the space needed.
The point of the program is to exec() it once again, but with a larger argv[0].
So what happens is that if the program is not called with --very-magic, then it will call itself, with the following changes:
1) argv[0] is 512 bytes long (511 bytes usable)
2) --very-magic is supplied
Change 512 to whatever the limit you need is. But the program should (well that was the idea at least) never reach later parts of main() unless it has a 512 (or whatever) byte argv[0].
Quoted 3 lines
If execv doesn't do any magic with the supplied argv array, then
this should work.
Yep, that's what I though. Can anyone shoot this down? ;)
Quoted 6 lines
Quoted 3 lines
For the same effect without the --very-magic argument, you could simply do an "if (argc != 2 ||
strlen(argv[0])!= 511)" instead.No, because the len of argv[0] being 'my proggy' is 9, that is not
511 ;)) We cannot tell the allocated space, I'm afraid O:)
Ok, I commented it to try to explain what it was I really meant to
say... ;)
int main(int argc, char **argv)
{
/* Check the length of argv[0] - we wat to make sure that 512 bytes are
* allocated */
if (strlen(argv[0]) != 511) {
/* argv[0] is shorter than 511 non-zero bytes, so we can't be sure
* it's really allocated big enough. Now build an argv[0] buffer the
* size we want it to be */
char argv0[512];
memcpy(argv0, 'a', 511);
argv0[511] = 0;
char *const args[] = { argv0, 0 }; /* Exec ourselves, with the new argv[0] supplied - this means, we
* will actually just re-execute ourselves, but our new "self" will
* have a bigger argv[0] - since it's filled with 511 'a' characters,
* our initial if() statement will evaluate to false and we will
* not enter this block again */
execv(argv[0], args);
/* never to return... Let's play it safe and make sure nothing bad
* happens */
perror("You're fscked... execv says"); abort();
}
/* Cool - argv[0] was big - let's put a meaningful name in there */
strcpy(argv[0], "my proggy");
/* your code here - argv[0] is now 512 bytes long - putting the short
* string into it just above, doesn't change the allocation of course */
}
Can anyone point out a problem in the above? I'd be happy to see it shot down, mainly because it's ugly - and I hate programs that mess with argv[0].
Signature · 6 lines
................................................................ : [email protected] : And I see the elder races, : :.........................: putrid forms of man : : Jakob Østergaard : See him rise and claim the earth, : : OZ9ABN : his downfall is at hand. : :.........................:............{Konkhra}...............:
Hi Richard :)
Quoted 1 line
Well, I just can't give this up!
It's an interesting issue ;)))
Quoted 3 lines
If you don't like me pretending that
main()gets the environment after args[], you can access environ directly anyway with the same result. Have fun!
Anyway, I'm not sure that all argv members are contiguous. I
mean, you can have argv[0] at 0x0c123456, length 3, and argv[1] not at 0x0c123459, but at 0xdeadbeaf. I know, this is VERY improbable, but argv is just an array of strings :((
Anyway this code is brilliant ;)) Nice solution :) Raúl
Hi Jakob :)
Quoted 3 lines
Quoted 2 lines
If execv doesn't do any magic with the supplied argv array, then
this should work.Yep, that's what I though. Can anyone shoot this down? ;)
Not me ;)) The only problem would arise if the argv[0] passed to
exec is 511 bytes long but its strlen is low, because exec can choose to copy the array to a new location (in fact, I think it does it...).
If you provide a filled argv[0], and soon after the exec you
change it to a proper value, there is only a brief chunk of time where argv[0] will have long and strange contents. It doesn't matter, because you can use spaces and anyway this is not important.
[Code snippet... snipped]
Quoted 3 lines
Can anyone point out a problem in the above? I'd be happy to see it shot down, mainly because it's ugly - and I hate programs that mess with argv[0].
I like your code ;))) I don't think it's ugly, on the contrary, I
find it quite elegant ;)) And I hate programs that mess with argv[0], too. In fact, I'm against that, but I need it... You deserve an
explanation: it's a virtual console only init clone, and has a builtin getty and login, and a builtin syslogd+klogd, too, all in less than 17k... Well, due to the 'builtin nature' of this program, we don't want ps show '/sbin/init' or just 'init' for the klogd process, for example, or in the login process. We want 'ps' to show 'login' for the login process or 'klogd' for the klog builtin emulator. That's all.
By now I just assumed that at least I had four spare characters,
but this is not true anymore when testing, since I provided init=/i to lilo, for example. And anybody can use that parameter and screw my init totally, just for the sake of the proc string issue :((
Your exec solution seems to be the easiest and cleanest one, and
should work, IMHO... I'm going to test right now ;))
Thanks for your help.
Raúl
Changing argv[0] under Linux. This MUST work...
Hi Jakob :)
Your solution of exec'ing ourselves MUST undoubtly work (well, I
know that this an affirmation that I will lament XDDDD), because it only relies on 'exec()' passing the argv[0] you provide as the argv[0] of the invoked binary, and that should work or programs like '/bin/login' will stop working... They rely on the same principle, since they need to prepend an '-' to the shell name to make it a login shell :))) Didn't remember this until now!
So, if you do 'execl(ourselves, "my new name", ..., NULL)', the
argv[0] received by the binary specified in 'ourselves' MUST be 'my new name'. Otherwise '/bin/login' and a good bunch of shells won't work...
If you happen to come to Spain at any point in the future, just
tell me, I'll buy you a beer (or crack, or whatever you use XDDD).
Thanks :)
Raúl
Jakob Oestergaard <[email protected]> writes:
|> Can anyone point out a problem in the above? I'd be happy to see it shot |> down, mainly because it's ugly - and I hate programs that mess with |> argv[0].
argv[0] is not required to point to the actual file name of the executable, and in fact, most of the time it won't.
Btw, don't use it for setuid programs, it's a huge security hole you can drive a truck through.
Andreas.
Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected] SuSE Linux AG, Deutschherrnstr. 15-19, D-90429 Nürnberg Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Quoted 7 lines · Andreas Schwab
Jakob Oestergaard <[email protected]> writes:
|> Can anyone point out a problem in the above? I'd be happy to see it shot |> down, mainly because it's ugly - and I hate programs that mess with |> argv[0].argv[0] is not required to point to the actual file name of the executable, and in fact, most of the time it won't.
And don't count on it for portability - Some systems take a copy of arg0 for the process tables, and changing it will NOT alter the process name. It is only the default action for shell programs. All others can make arg0 anything they want - as login effectively does ..
execl ("pathtoshell", "-", 0)Signature · 5 lines
------------------------------------------------------------------------- Jesse I Pollard, II Email: [email protected] Any opinions expressed are solely my own.
Hi Andreas :)
Quoted 6 lines
|> down, mainly because it's ugly - and I hate programs that mess with |> argv[0].
argv[0] is not required to point to the actual file name of the executable, and in fact, most of the time it won't.
Btw, don't use it for setuid programs, it's a huge security hole you can drive a truck through.
Yes, I suppose that exec'ing whatever is in argv0 is not a good
idea :((( Didn't think about it.
Any suggestion on how to get the binary name from the core image?
Thanks a lot for the warning, Andreas :)
Raúl
Quoted 3 lines · DervishD
Yes, I suppose that exec'ing whatever is in argv0 is not a good
idea :((( Didn't think about it.
Any suggestion on how to get the binary name from the core image?
Does it have to be an exec?
Perhaps something like this:
int main(int argc, char **argv)
{
if (fork ()) {
strcpy (argv[0], "Fake name 00001");
setpgrp (); /* very important when dealing with stuff like this */
pause(); /* code for personality "Fake name 00001" */
return 0;
}
strcpy (argv[0], "Fake name 00002");
setpgrp ();
pause(); /* code for personality "Fake name 00002" */}
this thing works - at least on my box...
But, of course, I could be mistaken, and I miss to see some other
important details. Good luck.
Dorin.
Signature · 2 lines
Dorin "sp00ky" Lazar, programmer Registered Linux user #162515
Quoted 7 lines · DervishD
Quoted 3 lines
Quoted 1 line
libc, but I think that is more on the kernel side, that's why I ask
Last time I checked argv[0] was 512 bytes. Many daemons overwrite it with no problem.
Any header where I can see the length for argv[0] or is this some
kind of unoficial standard? Just doing strcpy seems dangerous to me (you can read 'paranoid'...).
The method used in INN is to make arg 1 some space. So
nnrpd -s' ' -D ...
You can check that argv[1] is -s, and what its length is, then happily write over argv[0]. That's portable in practical terms, since most C implementations just have the variable length args in sequence, while a few have a fixed length array for args. You're safe in either case.
Ex:
if (strncmp(argv[1], "-s", 2) && strlen(argv[1]) > REPLACELEN) {
sprintf(argv[0], "format", atuff...);}
Some systems have setproctitle() but it doesn't appear to be posix.
Signature · 3 lines
bill davidsen <[email protected]> CTO, TMR Associates, Inc Doing interesting things with little computers since 1979.
Quoted 1 line
The method used in INN is to make arg 1 some space. So
Unfortunately, the process in this case is 'init', so we cannot
easily do this :((
Quoted 1 line
Some systems have
setproctitle()but it doesn't appear to be posix.
Linux doesn't have setproctitle(), AFAIK, and seems to belong to
NetBSD :??? What a pity, because will be a very clean solution :7
Thanks a lot for answering :)
Raúl
Quoted 4 lines · DervishD
I want to change the argv[0] a program shows, in order to be pretty-printed when issuing 'ps', 'top' or other commands.
Sorry about the late reply.
This is done nicely in PostgreSQL. Check source at early initializing parts of the postmaster.
Anuradha
Signature · 5 lines
Debian GNU/Linux (kernel 2.4.20) It may be better to be a live jackal than a dead lion, but it is better still to be a live lion. And usually easier. -- Lazarus Long