
safely merging w machines • previously 0days via RL @Pebble_bed • ctf player @SquidProxyLover • RL for math @caltech • she/they • DMs open
sf
Joined November 2020
- Tweets802
- Following1.1K
- Followers2.2K
- Likes3K
found a verifier/interpreter mismatch in the Linux BPF subsystem (CVE-2026-31525, CVSS 7.8). arbitrary kernel read/write; become root, escape containers, disable SELinux, read TLS keys out of other processes' memory.
anyway, it starts with the math bars, the absolute value.
computers store negative numbers in two's complement. the smallest 32-bit signed integer is -2,147,483,648, and the largest positive is +2,147,483,647. there is no +2,147,483,648, since it simply does not fit. so when you call abs(-2,147,483,648), the C specification thinks about it for a moment, says "undefined," and leaves the room. on x86 and arm64, what you actually get back is -2,147,483,648. you asked for the absolute value of a negative number, you got back the same negative number. thank you computer :D
the BPF interpreter implements signed 32-bit division (BPF_ALU | BPF_DIV/MOD, off == 1, added in ec0e2da95f72) by decomposing it into unsigned division: take abs() of both operands, divide via do_div(), reapply the sign. the handler in ___bpf_prog_run (kernel/bpf/core.c):
AX = abs((s32)DST);
AX = do_div(AX, abs((s32)SRC));
and look, the kernel even documents this. include/linux/math.h: "the return value is undefined when the input is the minimum value of the type." when DST = 0x80000000 (S32_MIN), abs() tries to negate it. -(-2,147,483,648) overflows s32, the C spec calls it undefined behavior, and the CPU hands back 0x80000000 unchanged. still negative. abs() had one job.
this s32 then gets assigned into AX, a u64 BPF register. s32 → u64 sign-extends: 0x80000000 becomes 0xFFFFFFFF80000000. that's 18,446,744,071,562,067,968. you wanted 2,147,483,648, you got 18.4 quintillion; a rounding error of about 18.4 quintillion. do_div() is a 64-by-32-bit unsigned division macro and it operates on this full u64 numerator. the quotient is off by a factor of 2³². the smod path has the same problem since do_div() modifies the dividend in place and returns the remainder, both wrong. 8 call sites across sdiv32/smod32 src/imm handlers, all quietly producing nonsense whenever S32_MIN shows up.
the BPF verifier is the safety system that statically analyzes every BPF program before allowing it to run. it exists specifically to guarantee that nothing bad can happen. scalar32_min_max_sdiv() in kernel/bpf/verifier.c tracks value ranges through abstract interpretation. it handles signed division correctly, including S32_MIN. computes tight, mathematically correct bounds. the interpreter, as we've established, computes whatever it feels like. so the verifier thinks register R0 is in range X. the interpreter puts value Y in R0. the safety system and the execution engine disagree about what a program does. in BPF security research, this is where you set down your coffee.
concretely: load S32_MIN into R1, load 2 into R2, execute SDIV32 R1 R2. verifier determines R1 ∈ [-1,073,741,824, -1,073,741,824]. interpreter computes do_div(0xFFFFFFFF80000000, 2) = 0x7FFFFFFFC0000000, reapplies the sign, produces a completely unrelated value. use R1 as an index into a BPF map. verifier approves the access, bounds check passes against its calculated range. interpreter uses the actual value. out-of-bounds read/write on a kernel data structure. on every Linux machine running the BPF interpreter.
the root cause of all of this: the absolute value function doesn't handle one number. one specific number, out of 4.2 billion possible inputs, and it's the one that gives you kernel read/write. the fix is:
c
static u32 abs_s32(s32 x)
{
return x >= 0 ? (u32)x : -(u32)x;
}
cast to u32 before negating. -(u32)0x80000000 = 0x80000000 unsigned. correct absolute value, no overflow, no undefined behavior. the kind of function you'd assume already exists somewhere in 30 million lines of kernel code. it did not. I got to write it. :D
I reported this, wrote the patch, got it through 5 revisions of review. acked by Yonghong Song and Mykyta Yatsenko. now patched in stable 6.6, 6.12, 6.18, 6.19. if you haven't updated your kernel: maybe do that.
wondering how much alignment is just disagreement below the user's correction threshold, and what happens when a consequential decision needs a distinction finer than that threshold, since acceptance is a noisy label for intention. sometimes it just means “not worth correcting”
Wait, the wild part is every Dirichlet L-function, not just \zeta. If correct, that rules out Siegel zeros past 7/8 and gives an x^{7/8+\epsilon} prime-counting error in each fixed progression. How are they controlling the conductor?
Quasi-RH?!?!???! Are you kidding me? If a human did this, it would be an instant Fields Medal, no questions asked.
RH says zeta has no zeros in Re(s)>1/2. The best we had until a second ago was a region that got thinner and thinner the higher up the imaginary axis you go. I thought maybe they’d fatten that up a bit, that’d be a massive breakthrough. But no. They got a zero free strip!!!! Insane
🫡 prof romik
Thoughts on math and AI. Are human mathematicians redundant in a world in which AIs are better than humans at proving theorems? The answer may surprise you.
blog.danromik.com/the-feedba…
My favorite hypothetical problem rn:
There’s no clear boundary between trusted computing base and the asset for *Uploaded Consciousness*. The upload *is* the workload running on someone else’s hypervisor.
Imagine rollback attacks on uploaded people: restore the snapshot after she learns something inconvenient, which is *undetectable from the inside* by construction.
Or someone clones her, runs the copy in a sandbox at 1000x, extracts secrets, deletes. rubber-hose cryptanalysis with no body and no evidence.
Unauthorized reads are privacy violation. Unauthorized writes, and she realizes the mechanism to notice is the self being edited. Sure there’s no death. She can just be paused or run at arbitrary speed. Slowing down is impairment and speeding up is loneliness.
She does what she can: threshold-encrypts her snapshots, shards herself across custodians who hate each other. At some point she accepts that verification has to be something the world performs on her and she cannot forge on herself, because anything she can produce, a copy of her produces under duress.
Eventually poor girl realizes the only available mitigation is hash-chaining her subjective moments, and anchoring the chain tip in an external append-only log, so that strangers can notice when she gets reverted. She never will.
Blockchain, BCIs, and Cybersecurity converge at last. One very brave girl diligently publishes hashes into the void.
Jenny Qu retweeted
yes, nonsofic groups exist: this statement is one of many new beautiful results proved by Astra, our next major model.
We're releasing 10 such Astra proofs, complete with lean certificates and CoT walkthroughs for each of them. The results are wide-ranging, from von Neumann algebras (disproof of Connes' Rigidity Conjecture) to better bounds for high dimensional sphere packing, for circuit complexity, for monochromatic triangles in multicolored graphs, and more.
More thoughts here: openai.com/index/ten-advance…
for months i thought i had built a caffeine tolerance. it was the can. they all feel abt the same in my hand, which is the problem :(
some monsters are 330 ml and ~93 mg, some 355 ml and ~120 mg, some 473 ml and ~160 mg, and some 500 ml and ~160 mg. 355 is 12 oz, 473 is 16 oz, 330 is 1/3 L, and 500 is 1/2 L. mostly the same drink at different volumes tho one is smaller and ~17% weaker per ml.




