2009-10-02 22:01:09

by Timo Sirainen

[permalink] [raw]
Subject: setproctitle()

I'd like to get BSD's setproctitle() implemented for glibc so that more
programs could start using it. The current method of messing around with
argv and environment to implement it is horribly ugly, fragile and I
find it dangerous enough that I haven't dared to use it in my programs.

Any chance of making all this easier so it could actually be implemented
in a generic and safe way in glibc?

I guess there are several different ways it could be done. My first idea
was to have some magic value in beginning of cmdline (\0 followed by a
few characters) followed by a pointer to the actual string. But that's a
bit ugly and userspace can't easily figure out if this is supported by
kernel.

So the second idea, perhaps this will work? Reserve space for the
pointer between arg_end and env_start. If it's NULL, use the old way. If
it's non-NULL, use it for the cmdline. Userspace can check if this is
supported by seeing if environ[0] - (argv[argc-1] + strlen(argv[argc-1])
+ 1) == sizeof(void *).


Attachments:
signature.asc (197.00 B)
This is a digitally signed message part

2009-10-02 22:53:26

by Bryan Donlan

[permalink] [raw]
Subject: Re: setproctitle()

On Fri, Oct 2, 2009 at 5:37 PM, Timo Sirainen <[email protected]> wrote:
> I'd like to get BSD's setproctitle() implemented for glibc so that more
> programs could start using it. The current method of messing around with
> argv and environment to implement it is horribly ugly, fragile and I
> find it dangerous enough that I haven't dared to use it in my programs.
>
> Any chance of making all this easier so it could actually be implemented
> in a generic and safe way in glibc?
>
> I guess there are several different ways it could be done. My first idea
> was to have some magic value in beginning of cmdline (\0 followed by a
> few characters) followed by a pointer to the actual string. But that's a
> bit ugly and userspace can't easily figure out if this is supported by
> kernel.
>
> So the second idea, perhaps this will work? Reserve space for the
> pointer between arg_end and env_start. If it's NULL, use the old way. If
> it's non-NULL, use it for the cmdline. Userspace can check if this is
> supported by seeing if environ[0] - (argv[argc-1] + strlen(argv[argc-1])
> + 1) == sizeof(void *).
>

This won't work - the start of the env variables is _defined_ by the
end of the argument vector, as found on the initial stack when the
program is loaded - see the initial stack diagram at [1].

Interestingly, there is some code that purports to handle
setproctitle(): (fs/proc/base.c)
res = access_process_vm(task, mm->arg_start, buffer, len, 0);

// If the nul at the end of args has been overwritten, then
// assume application is using setproctitle(3).
if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
len = strnlen(buffer, res);
if (len < res) {
res = len;
} else {
len = mm->env_end - mm->env_start;
if (len > PAGE_SIZE - res)
len = PAGE_SIZE - res;
res += access_process_vm(task, mm->env_start, buffer+res, len, 0);
res = strnlen(buffer, res);
}
}

This would seem to allow the argument space to be extended up until
the end of the environment variable area (although it seems to have a
bug where it will ignore errors when reading this extra bit!)

Nevertheless, if one were to insist on a more controllable method, a
better way might be to simply define a syscall that userspace can use
to select a new command line buffer. Overwrite mm->arg_end and
mm->arg_start, and there you go. Of course, the logic over here needs
to be disabled in this case, as env variables will no longer be found
immediately after the argument vector.

[1] - http://manugarg.googlepages.com/aboutelfauxiliaryvectors

2009-10-02 23:41:14

by Timo Sirainen

[permalink] [raw]
Subject: Re: setproctitle()

On Oct 2, 2009, at 6:53 PM, Bryan Donlan wrote:

> On Fri, Oct 2, 2009 at 5:37 PM, Timo Sirainen <[email protected]> wrote:
>> I'd like to get BSD's setproctitle() implemented for glibc so that
>> more
>> programs could start using it. The current method of messing around
>> with
>> argv and environment to implement it is horribly ugly, fragile and I
>> find it dangerous enough that I haven't dared to use it in my
>> programs.
>>
>> Any chance of making all this easier so it could actually be
>> implemented
>> in a generic and safe way in glibc?
>
> Interestingly, there is some code that purports to handle
> setproctitle(): (fs/proc/base.c)
> res = access_process_vm(task, mm->arg_start, buffer, len, 0);
>
> // If the nul at the end of args has been overwritten, then
> // assume application is using setproctitle(3).

Yes, I saw this. It's especially interesting that it mentions
setproctitle(3), which doesn't exist in Linux.

> if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
> len = strnlen(buffer, res);
> if (len < res) {
> res = len;
> } else {
> len = mm->env_end - mm->env_start;
> if (len > PAGE_SIZE - res)
> len = PAGE_SIZE - res;
> res += access_process_vm(task, mm->env_start, buffer+res,
> len, 0);
> res = strnlen(buffer, res);
> }
> }
>
> This would seem to allow the argument space to be extended up until
> the end of the environment variable area (although it seems to have a
> bug where it will ignore errors when reading this extra bit!)

That is the ugliness I referred to in my previous mail. It also looks
to me like if the environment is very small, the process title length
is also very limited.

> Nevertheless, if one were to insist on a more controllable method, a
> better way might be to simply define a syscall that userspace can use
> to select a new command line buffer. Overwrite mm->arg_end and
> mm->arg_start, and there you go. Of course, the logic over here needs
> to be disabled in this case, as env variables will no longer be found
> immediately after the argument vector.

That sounds good to me. Someone else mentioned prctl(PR_SET_NAME) that
does something related already, so perhaps a new flag for prctl()?
Something like: prctl(PR_SET_PROCTITLE, proctitle_start,
proctitle_end). I could try implementing that this weekend (with my
almost non-existent kernel coding skills) if no one else wants to.