AIARTICLE

When the executable is a SQLite database: Farid Zakaria's trick

A SQLite file that the Linux kernel runs as a native binary, with no wrapper or hack. Zakaria's proof of concept blurs the line between data and code.

When the executable is a SQLite database: Farid Zakaria's trick
Image: Alan Andrade

Simon Willison highlighted, on his link blog (the link is published alongside this text), an experiment by Farid Zakaria that raises an uncomfortable question: what is the real difference between a data file and a program? His answer is a SQLite file that the Linux kernel can execute directly, as if it were a native binary. It's not a terminal hack or a wrapper workaround: it's the database format itself carrying, inside it, everything the operating system needs to run code.

The trick is elegant precisely because it doesn't force anything. SQLite and ELF (Linux's executable format) have distinct headers, and Zakaria found a meeting point between them that the kernel accepts to interpret.

How the trick works under the hood

The SQLite file format reserves, at offset 68 (68 bytes from the start), a 4-byte field called the application ID. It's a generic space designed precisely so applications can mark that a given database belongs to them, without breaking compatibility with SQLite. Zakaria writes the string SELF there, which he reinterprets as Structured Executable & Linkable Format, a direct pun on ELF.

The next step is where the idea takes shape: the various components of an ELF executable (segments, sections, symbol tables) are disassembled and stored as rows in SQLite tables, following a schema defined by the author. In other words, the binary stops being an opaque blob and becomes structured, queryable data, one you can inspect with SELECT if you want to look at the pieces.

To turn this back into something executable, there's an interpreter written in C, self-exec, which opens the SQLite file, reads the tables, reassembles the ELF pieces in memory, and executes them. At that moment, the "database" becomes a running program again.

The role of binfmt_misc

The detail that closes the loop is binfmt_misc, a Linux kernel mechanism that lets you teach the system to recognize and execute arbitrary file formats by associating them with an interpreter. It's the same feature that lets Linux run .jar files by calling the JVM, or binaries from another architecture via QEMU, without you having to invoke the interpreter by hand.

Zakaria uses NixOS, but Willison notes what the manual registration would look like on a typical distro:

printf '%s\n' ':self:M:68:SELF::/usr/local/bin/self-exec:' \
  > /proc/sys/fs/binfmt_misc/register

Reading the string is straightforward: register a format called self, of magic type (M), whose pattern appears at offset 68 and equals SELF, delegating execution to the interpreter at /usr/local/bin/self-exec. From there, a ./meu-arquivo.db with the right application ID is executed by the kernel like any other binary. The user doesn't even notice they're running a SQLite file.

Why this is more than a curiosity

The immediate value of the experiment is conceptual. It exposes that the distinction between "data" and "code" is a convention, not a law of physics: the same file can be inspected with SQL tools, versioned as a database, and still be executed. For those who work with packaging and distribution, this opens an interesting line of thinking.

SQLite has been stable for decades, has libraries in practically every language, and is widely used as a general-purpose file format, not just as an embedded database. An executable that's also a database inherits all of that for free: you can pack, in the same file, the binary and the data it consumes (assets, configuration, indexes, migrations), all queryable and all in a single, portable artifact. CLI tools and desktop utilities that today ship a binary plus a handful of supporting files could, in theory, become a single file that carries its own state.

In the Brazilian context, where bandwidth and storage remain a concrete limitation for a large part of the user base, the idea of single, self-contained, inspectable artifacts has appeal. Fewer loose files means less chance of corrupted installs, fewer setup steps, and more predictable distribution. It's the same spirit that already makes SQLite attractive for applications that don't want to depend on a database server.

Where this clearly isn't worth it

It's important to treat the experiment for what it is: a thought-provoking proof of concept, not a production recommendation. Several trade-offs weigh against immediate use.

  • Real portability is the opposite of the promise. Depending on binfmt_misc ties execution to the Linux kernel with that specific registration configured. Without the self-exec interpreter installed and the format registered, the "executable" is just an inert .db file. That's less portable than a plain ELF, not more.
  • Privilege and configuration. Registering a format in binfmt_misc requires writing to /proc/sys/fs/binfmt_misc/register, which is an administrator operation. Distributing a utility that only runs after the user has poked at a kernel interface is high friction.
  • Security surface. An interpreter that reassembles ELF segments from SQLite tables and executes them is exactly the kind of component that needs heavy scrutiny. It's executable code embedded in a format that most tools would treat as harmless data, the kind of ambiguity that usually turns into a security headache.
  • No gain where a mature solution already exists. For self-contained binaries, the ecosystem has already solved this with AppImage, Flatpak, static linking, and packagers like PyInstaller. None of them require touching the kernel.

What remains open

Zakaria's experiment works better as a lens than as a tool. It reinforces a line of thinking that Willison has followed for a while: SQLite isn't just an embedded database, it's a file format good enough to carry things it was never designed for. The question that remains is whether there will ever be an official, portable path to "executing data" without depending on kernel-specific mechanisms, or whether this stays in the category of a brilliant trick we admire without putting into production. For now, the most valuable part is what it teaches about the boundaries between format, data, and code, and it's worth reading the author's schema and C code to understand the ELF reassembly in detail.

Translated from the Brazilian Portuguese original · Read the original

View profile →