You can do a lot with an empty file
rachelbythebay.com
rachelbythebay.com
https://en.wikipedia.org/wiki/I_Am_Rich
>I am rich
>I deserv [sic] it
>I am good,
>healthy & successful
> Send Me To Heaven (officially stylized as S.M.T.H.) is an Android application developed by Carrot Pop which measures the vertical distance that a mobile phone is thrown. Players compete against each other by seeking to throw their phones higher than others, often at the risk of damaging their phones.
The compilation command line for anyone curious. Clever.
That was exactly the implementation of /bin/true in Unix v7: <https://github.com/v7unix/v7unix/blob/master/v7/bin/true>
I'd say it isn't (and the same goes for false); but whether it's patentable is more debatable.
Here's the most recent, with the most comments: https://news.ycombinator.com/item?id=28257666
Edit: I was wrong, it is actually GNU 'yes': https://www.teddit.net/r/unix/comments/6gxduc/how_is_gnu_yes...
[1] Which is a valid assumption, as it's often the default (not sure if it's POSIX[2]), e.g. this gets clearly executed by my shell despite not having a shebang or anything else:
echo 'echo $SHELL' > /tmp/foo; chmod +x /tmp/foo; /tmp/foo
[2] Edit: It is POSIX, I know now because there's a whole subthread about it further down, that even quotes the standard, thanks gnarula.> write(2, "strace: exec: Exec format error\n", 32strace: exec: Exec format error
So the empty file is not exec()able. I think it can only be invoked from a shell.
subprocess.call("/tmp/foo", shell=xxxx) demonstrates it.
I wonder if that was the case for Unix v7 that had it zero length? (...mentioned in another thread.)
You always have to read the inode to determine whether the file is executable. The inode included the locations of the first "direct" blocks of the file's contents. So if the file is empty you know that immediately.
If the file even had a single comment line, it would mean having to do a disk seek to read it. So it would effectively double the disk I/O needed to run "/bin/true"
[1] https://github.com/torvalds/linux/blob/3e732ebf7316ac83e8562...
zsh: Exec format error: empty-file
(last command returned 127.)
(127 is the exit status for other failures, so I've used it here. The second line is intended to be part of my PS1, the first zsh's normal reporting. The string used here is what I get from perror() for that code.)> If the execl() function fails due to an error equivalent to the [ENOEXEC] error defined in the System Interfaces volume of POSIX.1-2017, the shell shall execute a command equivalent to having a shell invoked with the pathname resulting from the search as its first operand, with any remaining arguments passed to the new shell, except that the value of "$0" in the new shell may be set to the command name. If the executable file is not a text file, the shell may bypass this command execution. In this case, it shall write an error message, and shall return an exit status of 126.
[1] https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V... [2] https://unix.stackexchange.com/a/373229
Does POSIX define what a "text file" is?
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1...
An empty file actually contains zero of everything in the universe.
$ touch empty
$ chmod a+x empty
$ ./empty # Works
$ valgrind -q ./empty # Works
$ timeout 10s ./empty # Works
$ /usr/bin/time ./empty # Works
$ perl -e 'exec("./empty") or die' # Works
$ python -c 'import subprocess; subprocess.check_call("./empty", shell=True)' # Works
$ python -c 'import subprocess; subprocess.check_call("./empty")' # Fails
...
OSError: [Errno 8] Exec format error
$ ruby -e 'exec "./empty"' # Fails
-e:1:in `exec': Exec format error - ./empty (Errno::ENOEXEC)
from -e:1
$ strace ./empty # Fails
execve("./empty", ["./empty"], 0x7fff6639f3a0 /* 84 vars */) = -1 ENOEXEC (Exec format error)
strace: exec: Exec format error
+++ exited with 1 +++
It can be quite fun to track down why a program executes successfully and then later fails to execute, with no changes made to the program in between. $ strace -c ./empty
strace: exec: Erreur de format pour exec()
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0,00 0,000000 0 1 1 execve
------ ----------- ----------- --------- --------- ----------------
100,00 0,000000 0 1 1 total
$ strace -c /bin/true
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
54,05 0,000060 15 4 mprotect
24,32 0,000027 27 1 set_tid_address
10,81 0,000012 12 1 set_robust_list
8,11 0,000009 9 1 munmap
2,70 0,000003 3 1 prlimit64
0,00 0,000000 0 1 read
0,00 0,000000 0 2 close
0,00 0,000000 0 8 mmap
0,00 0,000000 0 1 brk
0,00 0,000000 0 4 pread64
0,00 0,000000 0 1 1 access
0,00 0,000000 0 1 execve
0,00 0,000000 0 2 1 arch_prctl
0,00 0,000000 0 2 openat
0,00 0,000000 0 2 newfstatat
------ ----------- ----------- --------- --------- ----------------
100,00 0,000111 3 32 2 total
the multiple execution seems to be much slower with the empty executable than with /bin/true using the multitime tool https://tratt.net/laurie/src/multitime/ $ multitime -n 10 ./empty
===> multitime results
1: ./empty
Mean Std.Dev. Min Median Max
real 0.006 0.000 0.005 0.006 0.006
user 0.001 0.001 0.000 0.002 0.002
sys 0.000 0.001 0.000 0.000 0.002
$ multitime -n 10 /bin/true
===> multitime results
1: /bin/true
Mean Std.Dev. Min Median Max
real 0.002 0.000 0.001 0.002 0.003
user 0.001 0.000 0.001 0.001 0.001
sys 0.000 0.000 0.000 0.000 0.000That's because it reports an error and does not actually execute the file.
>strace: exec: Erreur de format pour exec()
`strace` uses one of the exec()-style functions that don't automatically invoke a shell here. And if it did, it would invoke an entire shell (/bin/sh, typically), which might have more overhead.
----
You need to be very careful when measuring this, because what happens is that a shell executes the shebangless empty file.
If you try launching it from e.g. a C program using execlp(), it will have to first start that shell.
If you try launching it from e.g. bash, it might directly run that in-process or at least after a fork() or similar, skipping some of the shell setup.
So the overhead might depend on context.
The amount of time spent by the web browser is fairly small, but the parent comment mentioned it in context of an attack, so that small per-page effort multiplied by many connections makes for more of a substantial load.
In fact, instead of serving a malicious client a 200 empty file, you might want to serve up <script>while(1){}</script> .
wonder what unix2dos would do to it
https://web.archive.org/web/20140813120630/http://www.bernar...
but is bloated in comparison, being one byte in size.
I don't understand why this is surprising. Of course an empty file is a valid file, just like an empty piece of paper is a valid piece of paper.
I mean, yes, a piece of paper is also different. Paper is a physical object with volume and weight; a file is a sequence of bytes representing information. But, step out of your programmer mindset for a moment. Almost every user interface represents files as objects containing information, not information itself.
You can spot a lot of mistakes by asking code to compute with a 0-by-0 matrix or to write zero rows of data.
For example, the matrix case was fixed in the GSL in 2017: https://git.savannah.gnu.org/cgit/gsl.git/tree/matrix/Change.... In $DAYJOB I have seen multiple generations of systems get the no rows edge case wrong in the API design.
Zero goes back fewer millenia than one might think: https://en.wikipedia.org/wiki/0
Does not change that this does not always apply. Having no piece of paper is valid as "no PhD", but an empty piece of paper is not a valid PhD. In the same sense, an empty piece of paper is also not a "$0 banknote", it's not a banknote, period.
It is true that in many cases, empty files are valid for their context (e.g. CSV, plain text files, shell scripts), in many other cases, they are not (e.g. any file format at all that requires a magic number in a header or footer, which is many many file formats). Try to open these in those contexts, and you would usually get an error, for example: "You told me this was supposed to be a JPEG, but this file does not start with ff d8 ff e0 [Trivially true for an empty file! No, files are not equivalent to sets in the Zermelo-Fraenkel sense!] What is wrong with you?"
I don't get the discussion here. This is all obvious, and it was obvious in the original sentence from context.
The empty set is a valid set. Perfectly reasonable, and completely necessary in many cases.
But the empty Group is not a valid Group. A Group requires an identity element, which means non-empty. The smallest valid Group, the Trivial Group, still requires an element.
I would argue a diploma or a banknote resemble a Group more than a Set. There are required elements, such as an issuing institution.
Yes. It used to be. Here's the history from Rob Pike https://twitter.com/rob_pike/status/966896123548872705
Is this actually a result of exec(2) treating the file as text?
My intuition is something else: that this is instead a long-inherited compatibility shim for very, very old executable object formats (e.g. COM, a.out) for systems without virtual memory — where in these executable formats, you’d expect to be able to have the instruction pointer “run off the end” of an executable, with the effect of that being to cleanly quit the program — rather than trapping on an undefined op, hitting a HLT, or getting anything like a protection fault. The OS would ensure control returns to it after program “run-out” execution, by the OS exec(2)-alike syscall ensuring it writes a RET op or the like just past the end of the memory it copied the loaded program into, before jumping to the beginning of said memory.
Mind you, jumps into “hyperspace” (beyond where anything bothered to write; perhaps beyond where any chips are mapped on the bus) won’t take you to a clean RET op written by the OS, but rather likely to a 00 (active-high logic) or FF (active-low logic) op. Which is precisely why CPU designers usually make the relevant one of those for their logic into the ISA’s HLT op!
(Fun fact: even bytecode abstract machines do this. Read “off the end” of an Ethereum contract and you get 00 bytes — and, no surprise, 00 is the EVM ISA HLT op.)
$ strace ./empty
execve("./empty", ["./empty"], 0x7ffe0156c9d0 /* 61 vars */) = -1 ENOEXEC (Exec format error)
strace: exec: Exec format error
+++ exited with 1 +++
(I'm not very good with gdb so maybe this is wrong) gdb empty
"0x7ffd34c7dc30s": not in executable format: file format not recognized
(gdb) exec-file
No executable file now
I think what's actually happening is that bash is `source`-ing the file, so that's what causes the exit code to be zero.> If the execve() function fails due to an error equivalent to the [ENOEXEC] error defined in the System Interfaces volume of IEEE Std 1003.1-2001, the shell shall execute a command equivalent to having a shell invoked with the pathname resulting from the search as its first operand, with any remaining arguments passed to the new shell, except that the value of "$0" in the new shell may be set to the command name. If the executable file is not a text file, the shell may bypass this command execution. In this case, it shall write an error message, and shall return an exit status of 126.
https://pubs.opengroup.org/onlinepubs/009604499/utilities/xc...
Well, doesn't work on Windows though. I get "Access is denied" when I try to run an empty .exe. Even when I do it with an elevated prompt I get the same. Yeah, so..¯\_(ツ)_/¯
I think this was neatly explained by Ray in one of his older entries. The OS tries to load the .exe's header, then assign heap+stack according to that header, and only then will start the execution at entry point pointed by the header.
So, empty file -> no header -> OS complains -> no execution + above error.
A zero-byte executable doesn’t work on macOS either. This article is about command shell behavior, not UI shell behavior.
"> emptyfilename"
"rpm -qV" is a command that will audit the signatures of a package's contents. I don't know if dpkg has something similar but it would be cool if it did.
But regardless of the signature algorithm, thanks for sharing the mechanism.
debsums is intended primarily as a way of determining what installed files have been locally modified by the administrator or damaged by media errors and is of limited use as a security tool.
Jammy comes out next month.
Though if you encounter an md5 second preimage attack that's pretty impressive.
Though one notes that rifle-based storage incorporates the pipe and executable.
Total commander allows you to assign custom icons to extensions and lots of other things that make this very handy.
In the former case, I would have expected a shebang to be needed, so that execv(2) would know what to execute (as it needs some magic bytes to determine what loader to use, or whether to treat it as a script, and I didn't think it had a fallback). (And I'm right… in a sense. The actual behavior is more complex & more horrifying, and covered in other comments.)