- 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.