Copyright (C) 2022-2024 phantom (phantom@syslbnth.com)
(See end of file for copying information.)
Within this directory is a file, "domme.asm", that contains a
short routine, $domme, that attaches itself to a user-provided
SIGSEGV signal handler. When a segfault (short for "segmentation
fault", an illegal memory access) occurs, the routine will print a
randomly-selected message and then jump directly to the start of the
handler; conceptually, it is like a preamble prepended to the start of
the handler. On arrival at the handler, any arguments passed by the
kernel will appear unmodified in their expected registers; if the
default behavior for SIGSEGV on UNIX-like systems--crash and core
dump--is registered via $domme, $domme will not appear on the call
stack in a subsequent backtrace. In both these ways $domme attempts
to appear as though it had never executed, and so avoid getting in the
way of error correction and debugging, respectively. Furthermore, for
this reason, $domme must assure the preservation, while executing, of
certain registers set by the kernel on entering userspace, which are
inaccessible from the glibc ABI but may, in principle, be accessed by
the handler, as the handler could have been written in any language--
for instance, Assembly. On top of that, a handler originally written
to be run without interception, may have been written to expect the
address of the signal trampoline to be at the top of the stack, and
for kernel-provided data to be at a known offset from the top of the
stack. To accomplish this, $domme has to be able jump directly to
the start of the handler, rather than making a subroutine call and
consequently pushing a new return address onto the stack. The result
of all of this is that $domme is itself written in Assembly. Like
most assembly programs, it is highly playform-specific; it was written
for an x86-64 CPU interfacing with the Linux kernel.
Before $domme is run, it may be initialized by calling
$DOMME_init and passing it the address of a sigaction, the primary
signal-handling data structure on UNIX-like systems; if this address
is 0, $DOMME_init allocates its own sigaction with default settings and
passes it directly to the kernel, removing the need to declare your
own. If no such initialization is detected when a segfault occurs,
$domme will register the default behavior for the signal and return.
The program will then re-attempt the illegal access and properly fall
to pieces (and this is why $domme will not appear in the resulting
backtrace). You can also call $domme during normal execution; it will
print a randomly selected message and return.
$DOMME_init accepts two more arguments: the address of a
buffer to store a program's previous SIGSEGV sigaction in, if any
(this is optional; null pointers are ignored,) and a non-optional
$sigsetsize, the size of the sigset_t datatype used by your standard
library or programming environment, as opposed to the sigset_t datatype
used internally by the kernel (which $domme converts your sigset_t
into). In C, you would typically write
DOMME_init(NULL, NULL, sizeof(sigset_t));
at or near the beginning of $main (ideally before you have a chance to
segfault!) and that would be the end of it. This returns 0 if
successful, or -$EFAULT if either of the addresses passed is neither
zero nor mapped to anything.
This file, "domme.asm", is position-independent. You can
assemble it, turn it into a shared library with "ld" (with the name
"libdomme.so", for example,) then link it into any program you like
(with an "-ldomme" option from GCC, for example). It even implements
its own signal trampoline, so you don't need libc--or even C--to use
it. (I am now obligated to say: This is the work of an amateur
tinkerer going way out of their league. Run at your own risk.)
To install:
1. Run "make" to compile the library.
2. Run "make check" to run a short test program.
You can run this if you feel nervous about building a recent
commit. You should _definitely_ run this if you make changes to
either "domme.asm" or "domme.h". Essentially, the test program
makes sure the variables defined in "domme.h" point to valid
memory, then jumps to address 0 to force a segfault and see if
"domme" reacts as expected.
3. Run "make install" to place the library and header where your
compiler can find them (typically "/usr/lib64/" and
"/usr/include/", repectively).
4. Run "make clean" to remove files left over after compilation.
Note that, in case you haven't noticed already, program symbols
are prefixed with a '$' in comments and documentation.
------------------------------------------------------------------------
...and now that all of this has been established, let's talk
about what we're really looking at here. segfaults are probably the most
common error in C code ($domme was originally drafted in C, before the
technical requirements detailed above forced me to switch to assembly)
and can be painful to pick apart. often you'll patch one bad access only
to run into another as a result of the patch. chains of function
pointers, webs of multilinked data structures, layers of address
arithmetic--all of it can be very complex, precise, demanding. the worst
bugs can take a long time to trace.
but i like it. and not in the stuffy way someone brags about
walking to school in the snow, uphill both ways, like some escherian
sisyphus. i mean i'm into it. i mean, i'm _really_ into it. i thrill
at the cyborg trance i fall into as i debug these errors, the cycle of
edit, recompile, crash, tweak, recompile, burn, edit again. i drop out
of the world, flow from action to action; it is painful, and
suspenseful, and excruciating, and the pain is what makes it work. the
pain, transfixed, electrifies it.
i am fascinated by the eroticism latent in, inherent to,
human-machine interaction, the unreal appeal of getting totally
fucking wired. it's a subtext that has run like an undercurrent
through humanity's interactions with machines, particularly industrial
machines, and especially computers, almost from first contact. on rare
and fortunate occasions, it becomes the text. this cute little program
is an exploration of this concept, one among many. it was also, if
we're being completely honest, written to spice up those long
debugging sessions. i am maybe some kind of Actual Masochist. we'll
see. the "randomly selected messages" i kept nudging at above are
alternately absurd, suggestive and explicit, and, i hope, slip between
the three frequently enough to catch you off guard, like any good
flirt. it's not safe for work in the literal sense that you probably
don't want this in the source code of a public-facing repository. but
otherwise, you may do as you please.
-----------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.