5 ms·
It seems abundantly clear that programs are allowed to pass an empty list as argv to execve, although these programs might not be POSIX-compliant. As for the "
by dmatech 5y ago
It seems abundantly clear that programs are allowed to pass an empty list as argv to execve, although these programs might not be POSIX-compliant. As for the "main" function, argc is only guaranteed to be nonnegative. A well-written program therefore cannot assume that argc is not zero. Additionally, there is no guarantee that a POSIX-compliant program will be called by another POSIX-compliant program.
So it looks like pkexec made the mistake here by not carefully adhering to the standard. One can argue that argc==0 is a bad idea, and it is. But it's technically legal, and changing this would break userspace programs.
1. https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/e...
2. https://eel.is/c++draft/basic.start.main https://eel.is/c++draft/basic.start.main
- tptacek 5y agoObviously Linux programs can pass an empty list to argv, since that's how we got the pkexec vulnerability.
- stefan_ 5y agoargc = 0 is a bad idea? When did we enter into this insane parallel universe? When I first came across (argc, argv) a long long time ago I was befuddled by the choice of having argv[0] be something vaguely related to your binary, maybe the path to it. That seemed a very weird choice seeing how most programs have no use for that and now all the arguments you actually care about are shifted. So now you have a patch to ensure argc is always 1. Only of course if you accept that there are programs that misbehave with argc=0, surely you must also accept there are programs that misbehave if argv[0] is not the program path? This is after all the convention that got you into this misery in the first place! That's the moment the stupidity fully sets in. So now you write a patch to make sure argv[0] is really the path! Except just as we have discovered with this innocuous patch, you could write a dissertation on the question of "what exactly is meant with the program path" alone. And that really whoever was relying on some specific interpretation on the value of argv[0] would have been much better off with some other syscall to tell him what he was after.
- Someone 5y ago> When I first came across (argc, argv) a long long time ago I was befuddled by the choice of having argv[0] be something vaguely related to your binary, maybe the path to it. I’ve seen a Unix (¿maybe HP-UX?) that seemed to construct the argv strings by taking a copy of the entire command line and writing zero bytes at the end of each argument. I don’t think that’s too weird. Why do multiple allocations to make room for the strings if you know a reasonably tight upper limit to the number of bytes you need to store all of them? (Reasonably tight because the command line _could_ contain consecutive spaces and because of backspaces and quotes around arguments) On that OS, argv* strings also were writable, so programs could even replace those zeroes by spaces to, in many cases (I don’t remember how that worked with quoted arguments), get back the command line used to launch the program: for(i=1; i<argc; ++i) argv[i][-1] = ‘ ‘; printf(“%s\n”, argv[0]); (Yes, on top of, AFAIK, not being guaranteed to work by any standard, that’s undefined behavior in C, but it did work on that OS) So, I guess passing something resembling the executable’s name was something they got for free. It might even originally have been a bug, for all I know.
- garaetjjte 5y ago>but it did work on that OS This will probably work correctly on any POSIX system (well, except that it completely ignores escaping). Also I'm not sure why you would want to reconstruct cmdline in your program (that will lead to Windows-like horror where kernel only passes single string as cmdline and every component along the way interprets it with different escaping rules).
- saagarjha 5y agoargv is defined to be non-const by the standard.
- josefx 5y agoOne could argue that the main problem here was writing from argv into env^1 , so if one wants to break userland APIs to secure this the best start would be to hit the memory region argv resides in with write protection. ^1 We all know that buffer overflows in C are extremely common so fixing argv[0] alone would be insufficient to fix the majority of bugs.