6 ms·
So obviously claiming that there's no good reason for process to read argv[0] is either demonstrating the author's ignorance or needs a much stronger defense; I
by yjftsjthsd-h 2y ago
So obviously claiming that there's no good reason for process to read argv[0] is either demonstrating the author's ignorance or needs a much stronger defense; I'd be fascinated to hear how they think busybox should work on an OpenWrt box with a 16MB root filesystem.
However, I am willing to consider the discussion about whether there could be merit to restricting the ability to write that value; I could imagine a system that populated it only from the actual file name and did not allow it to be written by the parent process or the child process at runtime. The obvious place this still falls apart is that an attacker could just
ln /bin/curl ./some\ other\ name
but there are sometimes security measures that we use even though they're less than 100% effective so it at least conceivable that this might be a trade off worth making.
- kazinator 2y agoIf hard linking (no symbolic) is used to install the BusyBox commands, then instead of argv[0], BusyBox could use the platform-specific means of obtaining the executable name, and take the basename of that path. On Linux this means /proc/self/exe; _NSGetExecutablePath on Drawin; getexecname on Solaris; GetModuleFilename on Windows; ...
- mzs 2y agohttps://github.com/util-linux/util-linux/blob/master/login-utils/login.c#L1565 https://github.com/util-linux/util-linux/blob/master/login-u... edit: basically login(1) execes your shell with - prepended, so an example where POSIX expects this
- pie_flavor 2y agoAnother example program that reads argv[0] is Rustup, the version manager for Rust. Rust versions can be set per directory either as a machine-specific override or via a file. Rustup is symlinked to all the Rust commands like rustc and cargo, and when invoked as one of those commands, it checks what version it is supposed to be using, and then forwards to that version. I don't see how you'd do this without argv[0] (or a dozen slightly different pointlessly recompiled binaries).
- red_admiral 2y agoYeah, never mind shutdown/reboot, has the author heard of busybox?
- wietze 2y agoFor busybox/toybox the argv[0] thing is great, and seems to be the prime example of why argv[0] shouldn't go - yet it is a bit of an anomaly in how argv[0] is used. If there really is a need for having one executable that comprises multiple commands, is `busybox whoami` instead of `whoami` so much more effort? To me, that would make more sense in terms of what is going on; aliases could be used if one-word commands are preferred. In most non busybox contexts, argv[0] is just an unnecessary addition that, as the linked article shows, can introduce weirdness. It's clear from the comments there are still many who think argv[0] is a good thing, which is great - I'm glad the post sparked this debate.
- hinkley 2y agoI think you’re both forgetting that bash has been using this trick for decades. Bash has an sh compatibility mode that runs when you invoke it as sh.
- epcoa 2y agohttps://pubs.opengroup.org/onlinepubs/9699919799/ https://pubs.opengroup.org/onlinepubs/9699919799/ You appear not to realize that busybox is an essential component of a POSIX like system.
- mbrumlow 2y agoYes. Anybody who has shipped software would say. I really don’t think it is a debate. The usage of arg[0] is massively understated by the article. Just go look at gcc or any modern day compiler. Its use so much that the conversion of should we has been hashes out by many different groups yet they still chose to implement it. The security concerns are a non issue. As arg[0] was not the problem. It was the lack of technical knowledge of how systems work and a flaw in the security application.
- blenderob 2y ago> is `busybox whoami` instead of `whoami` so much more effort? It's not the "more effort" that is the deal breaker here. It is a matter of compliance with specs and user expectations. What you're suggesting would make Busybox very non-POSIXy, very non-Unixy. All scripts written over the last many decades would need to be updated to call `busybox ls` instead of `ls`? How is that a viable solution? > I'm glad the post sparked this debate. This is a very strange way to deflect concerns about quality of the article!
- rzwitserloot 2y agoThat seems unnecessarily harsh. I don't think that's the gist of the article, but the throwaway suggestion of 'just make lots of copies, who cares about diskspace' is insufficient and thus distracts. It's.. a single line about solutions in an article that isn't _about_ solving problems, it's about highlighting a problem exists and that it's worth solving. I read the article more as: There is __often__ no good reason to use argv[0], and it should be avoided if at all possible, and if it cannot be avoided, it would behoove the industry to work on ways to make sure in the future it can be avoidable. For example, why in the blazes does windows taskman.exe list argv[0] in the GUI table view? That's just asking for trouble. Show the actual file path, and always an absolute one - that way you avoid confusion about which executable you're actually running, and it's just as readable if not more readable for every app _except_ those who care about argv[0], e.g. if you ran `/bin/dd` and it's actually busybox, in taskman you'd see `/bin/busybox` instead which'd be worse than seeing 'dd'. That is simple enough to solve (add an API call to update _your own process name_ or at least update your own process 'title' which interfaces like ps/taskman can use accordingly), but, now we're talking about coordinating between OS, glibc, busybox, and so on - lots of parties. I don't mind that the article doesn't delve that deep, as that wasn't the point of it. The point is simply to show the problems the kludge of 'we will show argv[0] instead of the executable name' causes. This article feels more about explaining that in the distant past, a mistake was made with some history as to why that mistake was made and the deleterious practical effects that this mistake is causing or is likely to cause (most of them security related). It's not really about solving the problem; that presumably comes later and should be sketched out by those who are knowledgable on _that_ subject. That doesn't imply the author is ignorant or that the article is insufficiently defended. Just that it hasn't covered all aspects of what it's writing about.
- Maxatar 2y ago>Show the actual file path, and always an absolute one There are numerous reasons why this is not desirable, for example knowing whether an application was called from one symbolic link or a relative path dictates what that application's working directory is.
- kelnos 2y ago> it's about highlighting a problem exists and that it's worth solving. If so, then I disagree with the premise of the article, fundamentally. I don't see a problem. If someone is writing security software and doesn't already know about the mutability of argv[0], and doesn't know that (on Linux at least) /proc/$PID/exe is the only correct way to gt the binary backing a process... well, then they have no business writing security software. There is no problem here. The author is making a big deal about nothing, either because they have a weird axe to grind, or because they're ignorant.
- Arch-TK 2y agoRestricting setting it would break login. Not that it couldn't be fixed by changing how we handle login shells but still. Worth remembering. Similarly the busybox situation could be solved by having busybox ship posix shell wrapper scripts which use `#!/bin/busybox sh` as the shebang and simply consist of a line like `exec /bin/busybox ls "$@"`.
- nrclark 2y agoIt can already do that, afaik. When I last checked, BusyBox supported installations via 4 methods: - symlink - hardlink - shell script wrappers - executable binary wrappers around libbusybox
- Arch-TK 2y agoNice!
- zekica 2y agoYou are over-complicating it, you only need `#!/bin/busybox ls` as the entire contents of the file.
- Arch-TK 2y agoThis doesn't work. The eventual command would be /bin/busybox ls /path/to/ls/wrapper ...
- deleted 2y ago[deleted]
- marcosdumay 2y agoIs there a good reason for allowing writes to argv at all? I think any reason one will find are based on backwards compatibility.
- Hizonner 2y agoAs the original author says (but seems to forget within a paragraph or two), the program should already know what program it is. If you're looking at argv to find out what program you are, you are doing it deeply wrong. It's an argument. One good use for it is to make a guess as to where your executable is installed. Yes, it would be nice if there were a more certain way to get that... but not for security purposes. You don't want to rely on filenames for security anyway, because anybody can make copies and symlinks and rename files at will, and it's really, really hard to catch all the cases of that. Much harder than, for instance, remembering that argv[0] is a hint from your caller, not gospel from the OS. In the same way, I know that it's fashionable nowadays for incompetent idiots to write security tools, but a security tool that trusts an argv value for anything much was obviously written by an incompetent idiot, because that's not what they're for.
- mariusor 2y agoAm I missing something, you didn't seem to address the case where you actually need to know which program you are? The way busybox provides the whole suite of linux-utils in one binary and require the command under which it was invoked to know what to do.
- Hizonner 2y agoBusybox still knows that it's busybox, and it is using that argument to decide which of its many functions to execute. This person is arguing that that's somehow wrong because busybox, or more importantly some other software that's trying to monitor it, might get confused about whether it's busybox.
- mariusor 2y agoBusybox is quite well known project, but frankly from the way you write about it, it does not look like you know how it works so apologies if I'm explaining something that you already know. Busybox is a reimplementation of the standard linux utils (ls, find, dir, etc..) for resource limited machines. To quote from the man page: > BusyBox is a multi-call binary that combines many common Unix > utilities into a single executable. How it works is that it symlinks the binary to each of the commands it implements and then it executes the corresponding functionality based on the value of argv[0].
- surajrmal 2y agoYou can write a 2 liner shell script that prepends busybox per command. I've done this on a 16MiB restricted system and while ate maybe 4k per command, it wasn't a big deal with only 20-30 commands.
- blenderob 2y agoWhat about compiled binaries that for one reason or another is doing an execve() on "/usr/bin/cmp" or some such thing? Do you propose changing every script and every binary on earth that expects Busybox to be a POSIXy, Unixy environment?
- pzmarzly 2y agoOn Unixes it doesn't matter if /usr/bin/cmp is a script or a compiled binary. If the script has correct shebang, kernel takes care of executing it.
- deleted 2y ago[deleted]
- oguz-ismail 2y agoShebangs are not part of the UNIX specification. What happens if an executable starts with `#!' is implementation-defined.
- immibis 2y agois being able to run busybox part of that specification? Linux ELF files are tagged for Linux OS, not generic Unix OS.
- blenderob 2y ago> is being able to run busybox part of that specification? It's the other way round. This is like asking if running RHEL is part of the specification? Obviously not. But RHEL provides an environment that is quite close to the specification. So is running a busybox part of the specification? Obviously not. But Busybox provides an environment that is close to the speficiation.
- deleted 2y ago[deleted]
- pzmarzly 2y agoNot an author, but there's a good alternative. If busybox was edited to ignore argv[2], then applets could be called via shebangs, instead of symlinks: $ echo '#!/path/to/busybox echo' > myecho $ chmod +x myecho $ ./myecho 123 ./myecho 123 Right now this doesn't work properly, because "./myecho" (argv[0]) gets placed into argv[2] of the process. Otherwise, this technique IMHO is better than symlinks: - Each applet uses the same amount of disk space (0 blocks, i.e. the content fits into inode). - Doesn't read or write to argv[0]. - You could finally rename the applets. This is not that useful if busybox is your only posix userspace implementation, but very useful if you want many implementations to live side-by-side. E.g. on macOS, I'd like to have readlink point to BSD/macOS's readlink, greadlink to GNU coreutil's, bbreadlink to busybox's. But as I said, this doesn't work for now. The best you can do now is to write shell two-liners https://news.ycombinator.com/item?id=41436012 https://news.ycombinator.com/item?id=41436012. Some of such two-liners may also fit into the inode inlining limit, so that's a plus. But you will have performance penalty on every call (since sh needs to start up).
- account42 2y agoAre shebangs recursive? Otherwise this means that busybox can no longer provide /bin/sh.
- alerighi 2y agoWell that would be inefficient. For each command you run the kernel has to read the file, detect that it has a shebang, parse the shebang line, and then finally load the actual executable in memory. That could be a performance problem, since busybox is used typically in embedded systems that doesn't have a lot of resources: imagine a shell script that runs a command in a loop, it has to do a lot of extra work. Finally, symlinks can be relative, while the solution you proposed is not. This is particularly useful for distributing software, e.g. distributing a tar file with the busybox itself and their symlinks. In fact, you don't even need symlinks at all: you can even have hard links, that could even save disk space on embedded filesystems, that are readonly images anyway.
- Too 2y ago
- zokier 2y agoIsn't the reason for busybox multi-call binary mostly just ELF being bloated? So the answer for resource constrained systems would be to have more efficient executable format. I don't see why multi-call binary + bunch of symlinks would be intrisically much more size-efficient than something purpose-built.
- yuliyp 2y agoa lot of code is shared between different tools. Busybox has one copy of those. Before you mention shared libraries. There is still overhead, as well as complicating the usage (it needs to find a shared lib when starting instead of just having all it needs in the binary). This isn't really a property of the executable format. Any format would have the same problem.
- gwbas1c 2y agoI agree, I think the author really shot themselves in the foot when they, at length, criticized the merits of a program using argv[0]. The real point are the security flaws in a calling program setting argv[0], because it really, really should be set by the operating system. (As a programmer, I shouldn't have to defend against these kinds of attacks. The OS should block it.) The criticisms of valid programming practices, IMO, hurt the author's credibility and distract from the real point of the article.
- nrdvana 2y agoThe real security flaw is extracting a value from a process's own memory to identify what the process is. If you want a secure way to identify what a process is and where it came from, that needs to be a new feature in the OS. argv[0] was designed to be part of the arguments to the program, and it succeeds perfectly at that task. The problem is that it has been abused by external tools as a way to identify the program just because there was no other alternative. It has to be writable because the entire argv string (in program memory) is writable and declared as int main(int argc, char **argv) not int main(int argc, const char **argv) and needs to preserve back-compat. Classic C code might be calling strtok on the arguments, so that block of memory needs to remain writable.
- Joker_vD 2y ago> The real security flaw is extracting a value from a process's own memory to identify what the process is. If you want a secure way to identify what a process is and where it came from, that needs to be a new feature in the OS. How would that help? After all, even if this info comes from the OS, the decision logic still lives in your process's memory which the parent process still has full access to.
- gwbas1c 2y agoTake a closer look at the exploits listed, they all have to do with malware manipulating argv[0] when creating a new process; not with a process manipulating argv after it starts. There is no mention of mutable memory attacks. (If I was on a computer I'd fire up a C IDE to even see what happens when I mutate argv. I suspect the OS keeps its own copy of what the process was started with.)
- deleted 2y ago[deleted]