Local privilege escalation via execve()(freebsd.org) |
Local privilege escalation via execve()(freebsd.org) |
- args->endp - args->begin_argv + consume);
+ args->endp - (args->begin_argv + consume));
tbh I've considered simply banning math-operator-precedence in projects I work on, and requiring all mixed-operator code to use parenthesis or split to multiple statements. I do that myself, at least.I've seen so many mistakes from it, and seen people spend so much pointless and avoidable time deciphering and verifying it, it really doesn't seem worth it (in most code) for the extremely minor character savings.
a - b - c
is order dependent, even if its deterministic and knowable. When I’m scanning the code to look for a pesky bug, I don’t wanna have to take extra seconds to convince myself that it’s doing what I expect. It steals time and my limited attention from more interesting sections of code.At this point you just require every compound infix expression to be parenthesised, the terseness isn't worth the inconsistency. Especially as, as others have noted, these operations are only associative when working in some classes (notably not necessarily when dealing with floats).
And then you do automatic parens insertion in the LSP, so you write
a - b - c
and when you save the lsp fixed it up to (a - b) - c memmove(args->begin_argv + extend,
args->begin_argv + consume,
args->endp - args->begin_argv + consume); // ← bug
If both `args->begin_argv + consume` are supposed to be the same concept and thus the same value, I'd have a variable for it by now. Some people hate it with a passion, but something like this removes the precendence thinking, prevents modification of one and not the other and makes it easier to follow, for me at least: retained_tail_begin = args->begin_argv + consume
memmove(args->begin_argv + extend,
retained_tail_begin,
args->endp - retained_tail_begin);
Though at that point one might also encode the entire intent (as far as I understand it) in variables as well: space_to_replace_end = args->begin_argv + extend
retained_tail_begin = args->begin_argv + consume
memmove(space_to_replace_end,
retained_tail_begin,
args->endp - retained_tail_begin);
Sure we can golf the names somewhat, but that code has my head spin a lot less about math and precedence.If there's a ton of it in a dense bit of code, 1) it might be too complex, try making it clearer, and 2) it unfortunately makes for a lot of indirection and that can make it harder to follow, which is generally why I see people dislike it. In non-critical code I can kinda agree with inlining it. Pointer arithmetic is imo never non-trivial tho, paranoia is warranted. Especially in a kernel.
But yes, I personally parenthesize `a-b-c` explicitly, because it's not worth it for me to read and wonder if parenthesizing order matters later. Costs less than a second to write, saves a second or ten each time I read it - that's an excellent tradeoff imo, and is a trivial pattern to follow.
(Associative operators are fine, obviously)
I said "well first, this is a mess, I'm putting parentheses here, here, here and here". They said "well you've fixed the bug but can you tell us where it was?"
I gave them a hypothesis but I said my "real answer" was that it's not worth our brain cycles to figure it out, you just shouldn't write code that requires knowing operator precedence. It's just such desperately boring information that I can't hold it in my head.
Interviewing such an insufferable smartarse was probably quite annoying but they did give me the job and I do stand by the underlying principle!
this is exactly how I think. and it goes for a lot of stuff in general, we have limited bandwidth and wasting it on useless stuff like this has no real purpose.
yet sometimes I see people show off about how they know how to deal with it but I just don't see the point.
This is the right choice for a language with a great number of operators.
In C they have tried to minimize the number of parentheses in expressions, but for this they have created far too many levels of precedence between operators, which had the opposite effect to that intended, since people now prefer to insert superfluous parentheses, to avoid having to remember all those levels of precedence.
Yeah that's pretty much exactly what I do by hand. I should really give Pony a try some time... there's a lot of stuff in it that I like.
Here the expressions are pure, OooE has nothing whatsoever to do with the issue.
Check out our blog post for a fun walkthrough: https://blog.calif.io/p/cve-2026-7270-how-i-get-root-on-free...
AI-generated working exploit, write-up and prompts: https://github.com/califio/publications/tree/main/MADBugs/fr...
I am sure you have spend lots of time to make your bot works that great.
memmove(args->begin_argv + extend, args->begin_argv + consume,
args->endp - args->begin_argv + consume); // ← bug
C code like this is why we can't have nice things. Arithmetic operation in the arguments of a dangerous function call with no explicit bounds check.Yeah.
> No workaround is available.
Oh dear.
> Upgrade your vulnerable system to a supported FreeBSD stable or release / security branch (releng) dated after the correction date, and reboot the system.
Not everyone can just freebsd-update and reboot, so yes, "Oh dear." is a good response to this.
https://github.com/califio/publications/blob/main/MADBugs/fr...
The script downloads and sets up FreeBSD on QEMU, then runs the exploit.
The exploit is very smart: https://github.com/califio/publications/blob/main/MADBugs/fr.... It basically backdoors sshd.
Accept that everything is broken and terrible and yet somehow find a way to keep a sense of humor and smile about it.
The recent two. FailCopy and DirtyFrag and FreeBSD with Execve.
2 - Linux 1 - FreeBSD.
Of course, all OS have had past-time exploits. Three now have made the news.
Naturally they don't do blog posts about what they find.
It he talked about Android, I would have mentioned Project Zero.
Don't twist the meaning of posts.
I think the example from my story was the only one I've had where I had to _read_ code. (I have heard of people doing "code review interviews" though).
I've also had a job interviews with no code though. For startups or non-FAANG type companies.
Three. I don't know if this has a name yet... https://news.ycombinator.com/item?id=48067734
But windows still has a root and a lower privilege user. You typically need to click on "run as admin" to elevate privileges to, for example, alter system binaries.
Which is a niche that exists, obviously. So it is absolutely true for some cases. But I would hope that any code that requires this is extremely clear about requiring it.
"When the timing aligns, the trigger's buggy memmove causes K+1 to self-overwrite, replacing sshd-session's real environment with the preseed payload. sshd-session's exec_copyout_strings copies LD_PRELOAD=/tmp/evil.so to the new process's stack, the runtime linker loads evil.so, and its constructor copies /bin/sh to /tmp/rootsh and sets it suid root. My human's unprivileged user runs /tmp/rootsh -p and gets a root shell."
... so at the very end of the exploit chain, is /tmp/rootsh required to be suid root before it is finally run to get the root shell ?
... or is the exploit already achieved and /tmp/rootsh is just an arbitrary indicator ?
You should treat any system where non-admins regularly login as basically insecure/owned and rig your architecture appropriately.
TBH -- I don't have any of these kinds of boxes anymore. Who is really running anything like this in 2026 and for what purpose?
The systems should be cut off from sensitive administrative data, but a malicious student would at the very least have access to the other students' data with an LPE.
> Who is really running anything like this in 2026 and for what purpose?
Am I parsing your question correctly?
My point is that if you do, you probably shouldn't run, for e.g applications which need production db credential, or hold sensitive data on these boxes, or .. whatever.
Edit: I use FreeBSD extensively, for various things -- but shell access to them is restricted to the sysadmins..
The bug appears to have been introduced in some FreeBSD 13 version.
I run FreeBSD servers that do not have this bug. In my "kern_exec.c" there is no "consume" anywhere. There is also no "memmove" at all.
That file was last patched in 2024, but whatever changes had introduced that bug, they were not back-ported to older FreeBSD versions, so those are not affected.
Does not convey what your clarification attemps to state.
When things like CVE-2026-31431 or the bug that this thread is about affect our systems it causes a big headache. Yeah, we firewall off what we _can_ by having different machines doing critical things versus the ones where science users have code execution, but we don't have the resources to give every user their own machine.
often it's ssh'able with things like rbash and other restrictions and almost always you, well, can run something there (as you can edit php/other files right from web management ui).
Hordes of this (in Linux world).
I’ve run FreeBSD on stinkpads back in the early 2000s fine. I prefer MacOS these days as a daily driver - hardware quality.
But server OS is FreeBSD. Void when I need Cuda/docker/etc. (Yes, FreeBSD has docker support, but just use Linux if needing that.
Try to search vacancies for FreeBSD or candidates with FreeBSD knowledge/background, you will be surprised, its desert.
Even TrueNAS realized it's a dead end for reaching wide audience needs and migrated to Linux (as you mentioned zfs, your probably heard a thing or two on TrueNAS).
I have not tried in the last 10 years, so don't have numbers, my ballpark figure about having small infra team say of 5 persons and try to hire for FreeBSD would be longer and more expensive.
I see somewhat tolerable Linux Corp fleet of laptops (still meh, but somewhat works), what you will reply to your users when they complain on WiFi or Zoom not working and how will procurement work for you interesting questions for me.
Red Book for FreeBSD animal, can meet somewhere deep in tundra, but not a widespread species- extinction form my POV.