The Linux kernel offers a vast array of functions that can be influenced from userspace, accessible through virtual filesystems like /proc or /sys.
While some functions are well known and used by many, IP Forwarding for example, there are also many functions which are not so frequently used, and probably unknown to the majority of users.
Nonetheless there are some interesting ways to influence your system’s behavior.

One of these functions is binfmt_misc, a kernel module with the ability to make virtually any file executable.

Let’s get right into it with an example: Let’s say you have a PHP script you want to execute in your shell of choice as well as through the web server.
And let’s further assume that your PHP executable is not available through ${PATH}, so that every time you want to run your script you need to type something like

/long/path/goes/here/php awesomescript.php

I guess you certainly would prefer running it like this:

./awesomescript.php

And you could do so by using the well known shebang at the top of your script, like this:

#!/long/path/goes/here/php

Just like you do in shell scripts.
The problem here is that this will cause the script to output this line or possibly fail when accessed from the web.
PHP does not recognize the shebang, not even as a comment. Therefore the line will be passed to the web server, as part of the scripts output.
And if you use a function that wants to specify HTTP headers, like header() or setcookie(), without output buffering being active in PHP’s configuration the script will fail with an error, because PHP cannot manipulate the headers once output has started.

The solution for this is, you may have guessed it, binfmt_misc.

Before you can start using it you need to make sure the module is load and its virtual filesystem is mounted. This may not be necessary, depending on your distribution. On my Fedora 14 installation binfmt_misc doesn’t seem to be compiled as module, and the filesystem apparently is mounted by default, or by some init-script, as, for example, Wine registers a format in order to enable users to execute Windows executables directly through Wine.

modprobe binfmt_misc
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

By the way, the magic word here is virtual, as in “changes won’t survive a reboot”. Therefore you will need to find a way to apply your changes on system startup.
For example with an init script.

But back to our example of running a PHP script without having to specify the path to the interpreter, or using the shebang.

echo “:PHP:M::<?php::/long/path/goes/here/php:” > /proc/sys/fs/binfmt_misc/register

This will register the format PHP. PHP files will, in this example, not be recognized by their extension .php, but by starting with <?php.
If you want the kernel to recognize PHP files by their extension you can issue this command:

echo “:PHP:E::php::/long/path/goes/here/php:” > /proc/sys/fs/binfmt_misc/register

That’s all there is to it.

Be aware that names are unique, so don’t be surprised if you get an error message if you try both examples without unregistering first.

Unregistering is done like this:

echo “-1” > /proc/sys/fs/binfmt_register/FORMAT

For our example format PHP this looks like this:

echo “-1” > /proc/sys/fs/binfmt_register/PHP

Now let me spend a few words on explaining the format of that line you pass to the kernel for registration.
Wikipedia says this:

:name:type:offset:magic:mask:interpreter:

  • name: Obviously each registered format needs a name for identification. That comes in handy in case you want to remove an entry.
  • type: The type specifies if the files get recognized by a magic value (M) or by their extension (E).
  • offset: A magic value does not necessarily need to be right at the start of a file. With this you can specify the offset.
  • magic: This is your magic value or file extension, depending on the type you have chosen.
  • mask: The mask is used to mask out certain bits of your magic value.
  • interpreter: This is the command that’s called upon execution of a registered format. The executed file is passed as parameter, but other parameters apparently are not supported.

Beyond running scripts through their respective interpreters there also some more unusual things you can implement using binfmt_misc.

How about self extracting archives?

echo “:GZIP:E::gz::/usr/bin/gunzip:” > /proc/sys/fs/binfmt_misc/register
echo “:BZIP:E::bz2::/usr/bin/bunzip2:” > /proc/sys/fs/binfmt_misc/register
echo “:XZ:E::xz::/usr/bin/unxz:” > /proc/sys/fs/binfmt_misc/register

Or opening text files in an editor when executed?

echo “:TXT:E:txt::/usr/bin/joe:” > /proc/sys/fs/binfmt_misc/register

As you can see, there are pretty much no limits on what kind of file you can turn into an “executable”.
More complicated tasks, like automatically burning ISO files to disc, or booting them in QEmu, require wrapper scripts, as the interpreter value apparently cannot contain any parameters.

I am sure, with a little bit of imagination you can find lots of ways how this can make certain things a little easier for you.

Thank you!
Dennis Wronka

Advertisements