This is a nice and easy to understand example of a memory-safety bug that CHERI [1] prevents (among other classes of vulnerabilities). Given that the SYSCTL_PROC() macro installs a pointer to an uint16_t value in the oid_arg1 field, a CHERI pure-capability kernel would construct a capability with bounds set to sizeof(uint16_t) and later the dereference of (int *)oidp->oid_arg1 in sysctl_udp_log_port() would trigger a capability bounds violation.
`sysctl -a` would simply crash on CHERI allowing a developer to catch this without KASAN being involved.
I am not surprised. First, it's a subtle bug. Second, in C/C++. a lot of times you get unlucky when reading uninitialized memory. Basically, the bug does not occur when you test the code on your machine or when you run the automated tests.
Another problem is writing good automated tests is hard and often skipped. Lots of software engineering teams talk about the wonders of automated tests. Unfortunately, many automated tests are not very good and either do not ensure the major functionality works or just do not test some of the code. There are also limits to how much time a software engineer has to test. No one can test everything.
Basically, I am not surprised developers make mistakes and I am not surprised the tests either did not catch this mistake or even did not exist. Software is very hard and software engineers are far from perfect.
If the linker puts a pointer there, this would let you leak part of the pointer which could let you bypass kaslr. Not too likely for that to occur. If I were submitting this bug I would feel complete if they bought me a sandwich.
Yeah, you could probably contrive a situation where you get more interesting information (page numbers maybe?), but it definitely doesn't seem likely to me-
Good to find the bug regardless! I appreciated the succinct and not overly dramatic write-up. I don't think anything significant was claimed other than the fact that it is a kernel bug (which is significant in itself don't get me wrong).
- int new_value = *(int *)oidp->oid_arg1;
+ int new_value = *(uint16_t *)oidp->oid_arg1;
Why not just have `uint16_t new_value = ...`?
Ahh, because `new_value` is being given to `sysctl_handle_int(..., &new_value, ...);` which of course expects an `int`. So then it begs the question: if the value is really a `uint16_t`, then why is it being handled through a plain `int`? It smells like there could easily be tons of other memory-safety and/or type confusion problems endemic to the sysctl API.
Nit: "begs the question" means "raises the question" in many contemporary colloquial contexts. It can _also_ refer to a type of logical fallacy in philosophical contexts.
The phrase can be confusing because of its overloaded definitions, so it's best to avoid it. But if you understood what someone meant when they used it, then... you understood it's meaning.
Remember to treat the study of language descriptively rather than prescriptively!
Well there's the so-called usual arithmetic conversions that will basically convert every uint16_t to an unsigned int. The C and C++ languages do a silent conversion on your back anyways so you might as well make it explicit.
Leaking two random bytes and in some cases just padding bytes to user space is not the end of the world and I don't get why there are so many negative comments blaming Apple for not handing out a handsome bounty for this bug.
It's still a security bug. Often, multiple bugs like this are chained together to create one very nasty exploit. I agree that this bug probably does not deserve a massive payout, but I think $3,000-5,000$ is appropriate.
Is there any reason to assume a conspiracy and drama around the bounty here other that just being bored and cynical? Apple has a well known security bounty program https://security.apple.com/bounty/
This is a nice and easy to understand example of a memory-safety bug that CHERI [1] prevents (among other classes of vulnerabilities). Given that the SYSCTL_PROC() macro installs a pointer to an uint16_t value in the oid_arg1 field, a CHERI pure-capability kernel would construct a capability with bounds set to sizeof(uint16_t) and later the dereference of (int *)oidp->oid_arg1 in sysctl_udp_log_port() would trigger a capability bounds violation.
`sysctl -a` would simply crash on CHERI allowing a developer to catch this without KASAN being involved.
[1] http://cheri-cpu.org
Not only, SPARC ADI and ARM MTE as well.
Seems like something to be integration tested in the future. Honestly surprised this slipped through.
I saw that types are different, but I was thinking "must be some weird C thing that I don't know about"
I am not surprised. First, it's a subtle bug. Second, in C/C++. a lot of times you get unlucky when reading uninitialized memory. Basically, the bug does not occur when you test the code on your machine or when you run the automated tests.
Another problem is writing good automated tests is hard and often skipped. Lots of software engineering teams talk about the wonders of automated tests. Unfortunately, many automated tests are not very good and either do not ensure the major functionality works or just do not test some of the code. There are also limits to how much time a software engineer has to test. No one can test everything.
Basically, I am not surprised developers make mistakes and I am not surprised the tests either did not catch this mistake or even did not exist. Software is very hard and software engineers are far from perfect.
Right, but this was caught basically instantly by Asan.
He had time to test it. /s
Did you get a bounty payout for this? I got the impression that Apple wasn't particularly on the ball with those.
Is it even exploitable in the real world?
Correct me if I'm wrong but you get 2 bytes of kernel data (potentially blank padding) and the same two bytes each time?
If the linker puts a pointer there, this would let you leak part of the pointer which could let you bypass kaslr. Not too likely for that to occur. If I were submitting this bug I would feel complete if they bought me a sandwich.
The bottom 2 bytes of a pointer contain two bits of the slide, assuming it's even a pointer into the kernelcache itself.
I'd take half a sandwich.
Little endianness considered harmful
Yeah, you could probably contrive a situation where you get more interesting information (page numbers maybe?), but it definitely doesn't seem likely to me-
Good to find the bug regardless! I appreciated the succinct and not overly dramatic write-up. I don't think anything significant was claimed other than the fact that it is a kernel bug (which is significant in itself don't get me wrong).
You are correct. It's clearly a bug, but the impact in shipping kernels appears to be limited to "leaking" some non-sensitive data.
Ahh, because `new_value` is being given to `sysctl_handle_int(..., &new_value, ...);` which of course expects an `int`. So then it begs the question: if the value is really a `uint16_t`, then why is it being handled through a plain `int`? It smells like there could easily be tons of other memory-safety and/or type confusion problems endemic to the sysctl API.
> So then it begs the question: if the value is really a `uint16_t`, then why is it being handled through a plain `int`?
I don't think it begs the question, but it does raise one!
Nit: "begs the question" means "raises the question" in many contemporary colloquial contexts. It can _also_ refer to a type of logical fallacy in philosophical contexts.
The phrase can be confusing because of its overloaded definitions, so it's best to avoid it. But if you understood what someone meant when they used it, then... you understood it's meaning.
Remember to treat the study of language descriptively rather than prescriptively!
https://en.wiktionary.org/wiki/beg_the_question
https://en.wikipedia.org/wiki/Begging_the_question
Well there's the so-called usual arithmetic conversions that will basically convert every uint16_t to an unsigned int. The C and C++ languages do a silent conversion on your back anyways so you might as well make it explicit.
Usually promotions are to signed int, not unsigned. (With some exceptions. But every uint16_t value can fit in int.)
Unless int is 16-bit. Code like this is potentially UB; you should use int32_t as the target.
You should use long, and don't ever assume it's exactly 32-bits. The fixed size types are often an overused crutch that hampers future portability.
There are no mainstream 16-bit int platforms. It's fine to know what you target.
The promotions that are really surprising are from uint64_t bitfields to int (because it's based on value representability).
A well-configured C++ compiler will error-out on such a silent conversion.
The C++ compiler is required to perform this silent conversion according to the standard: https://en.cppreference.com/w/cpp/language/implicit_conversi...
Leaking two random bytes and in some cases just padding bytes to user space is not the end of the world and I don't get why there are so many negative comments blaming Apple for not handing out a handsome bounty for this bug.
It's still a security bug. Often, multiple bugs like this are chained together to create one very nasty exploit. I agree that this bug probably does not deserve a massive payout, but I think $3,000-5,000$ is appropriate.
You're joking. This is a $10 bug.
Dammit I gave a kid $20 in amazon books credit for "your site has a phpinfo() page".
kid probably put it there :-D
You got had !
[flagged]
Is there any reason to assume a conspiracy and drama around the bounty here other that just being bored and cynical? Apple has a well known security bounty program https://security.apple.com/bounty/
So the researcher didn't get a bounty from Apple then, no?
we don't know
It's not possible to apply human morale and principles to companies. It just does not work that way.
Why would they pay if no profit if pay and they are not forced to pay?
Do not fall into the trap of anthropomorphising Apple
To inspire more of the same.
Ideally Apple would incentivise people reporting security issues to them, instead of risking people selling them to someone else who pays more.
[dead]
I appreciate the among us.
Interestingly, ChatGPT correctly points out this exact issue:
https://chatgpt.com/share/6793a2d1-5f84-8006-8e78-16be4d4908...