The following c language code can trigger KASAN's global variable
out-of-bounds access error in kobject_action_type():
int main() {
int fd;
char *filename = "/sys/block/ram12/uevent";
char str[86] = "offline";
int len = 0x56;
fd = open(filename, O_WRONLY);
if (fd == -1) {
printf("open");
exit(1);
}
if (write(fd, str, len) == -1) {
printf("write");
exit(1);
}
close(fd);
return 0;
}
Function kobject_action_type() receives the input parameters buf and count,
where count is the length of the string buf.
In the use case we provided, count is 86, the count_first is 85.
Buf points to a string with a length of 86, and its first seven
characters are "offline".
In line 87 of the code, kobject_actions[action] is the string "offline"
with the length of 7,an out-of-boundary access will appear:
kobject_actions[action][85].
Modify the comparison logic to determine whether count_first is equal to
the length of string kobject_actions[action]. This can fix the problem.
Fixes: f36776fafbaa ("kobject: support passing in variables for synthetic uevents")
Signed-off-by: Xia Fukun <[email protected]>
---
lib/kobject_uevent.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 7c44b7ae4c5c..668346bd28fa 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -84,7 +84,7 @@ static int kobject_action_type(const char *buf, size_t count,
for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
if (strncmp(kobject_actions[action], buf, count_first) != 0)
continue;
- if (kobject_actions[action][count_first] != '\0')
+ if (strlen(kobject_actions[action]) != count_first)
continue;
if (args)
*args = args_start;
--
2.17.1
On Tue, Mar 07, 2023 at 02:37:57PM +0800, Xia Fukun wrote:
> The following c language code can trigger KASAN's global variable
> out-of-bounds access error in kobject_action_type():
>
> int main() {
> int fd;
> char *filename = "/sys/block/ram12/uevent";
> char str[86] = "offline";
> int len = 0x56;
Nit, set len to 86 so we don't have to do a hex-to-decimal conversion in
our heads (or calculator) to figure out what you are trying to do here :)
>
> fd = open(filename, O_WRONLY);
> if (fd == -1) {
> printf("open");
> exit(1);
> }
>
> if (write(fd, str, len) == -1) {
> printf("write");
> exit(1);
> }
>
> close(fd);
> return 0;
> }
>
> Function kobject_action_type() receives the input parameters buf and count,
> where count is the length of the string buf.
>
> In the use case we provided, count is 86, the count_first is 85.
> Buf points to a string with a length of 86, and its first seven
> characters are "offline".
> In line 87 of the code, kobject_actions[action] is the string "offline"
> with the length of 7,an out-of-boundary access will appear:
>
> kobject_actions[action][85].
>
> Modify the comparison logic to determine whether count_first is equal to
> the length of string kobject_actions[action]. This can fix the problem.
>
> Fixes: f36776fafbaa ("kobject: support passing in variables for synthetic uevents")
> Signed-off-by: Xia Fukun <[email protected]>
> ---
> lib/kobject_uevent.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
> index 7c44b7ae4c5c..668346bd28fa 100644
> --- a/lib/kobject_uevent.c
> +++ b/lib/kobject_uevent.c
> @@ -84,7 +84,7 @@ static int kobject_action_type(const char *buf, size_t count,
> for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
> if (strncmp(kobject_actions[action], buf, count_first) != 0)
> continue;
> - if (kobject_actions[action][count_first] != '\0')
> + if (strlen(kobject_actions[action]) != count_first)
> continue;
> if (args)
> *args = args_start;
Yes, this will stop us from reading a read-only location somewhere in
the kernel outside of the string array, but is it still doing the same
functional logic here?
In your change, this call to strlen will cause the length check to fail,
so the loop will continue on, and the type will never be set properly.
Is that correct in your testing? You just prevented a string of
"offline\0\0\0\0\0\0\0\0\0\0" from properly being parsed as an offline
event, which I don't think is what you meant to do, right?
Or am I reading this code incorrectly? It really could be cleaned up,
it's not obvious at all. Parsing strings in C is a mess...
thanks,
greg k-h
> --
> 2.17.1
>
Thanks for your reply.
Your understanding is correct."offline\0\0\0\0\0\0\0\0\0\0" is indeed blocked
from matching "offline" and returns a failed result.
I'm not sure whether to relax the restrictions to make it match successfully.
After all, the incoming count is too large and not the actual length of
"offline".
在 2023/3/7 16:16, Greg KH 写道:
> On Tue, Mar 07, 2023 at 02:37:57PM +0800, Xia Fukun wrote:
>> The following c language code can trigger KASAN's global variable
>> out-of-bounds access error in kobject_action_type():
>>
>>
>> diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
>> index 7c44b7ae4c5c..668346bd28fa 100644
>> --- a/lib/kobject_uevent.c
>> +++ b/lib/kobject_uevent.c
>> @@ -84,7 +84,7 @@ static int kobject_action_type(const char *buf, size_t count,
>> for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
>> if (strncmp(kobject_actions[action], buf, count_first) != 0)
>> continue;
>> - if (kobject_actions[action][count_first] != '\0')
>> + if (strlen(kobject_actions[action]) != count_first)
>> continue;
>> if (args)
>> *args = args_start;
>
> Yes, this will stop us from reading a read-only location somewhere in
> the kernel outside of the string array, but is it still doing the same
> functional logic here?
>
> In your change, this call to strlen will cause the length check to fail,
> so the loop will continue on, and the type will never be set properly.
> Is that correct in your testing? You just prevented a string of
> "offline\0\0\0\0\0\0\0\0\0\0" from properly being parsed as an offline
> event, which I don't think is what you meant to do, right?
>
> Or am I reading this code incorrectly? It really could be cleaned up,
> it's not obvious at all. Parsing strings in C is a mess...
>
> thanks,
>
> greg k-h
>
>
A: http://en.wikipedia.org/wiki/Top_post
Q: Were do I find info about this thing called top-posting?
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?
A: No.
Q: Should I include quotations after my reply?
http://daringfireball.net/2007/07/on_top
On Tue, Mar 07, 2023 at 05:08:02PM +0800, Xia Fukun wrote:
> Thanks for your reply.
> Your understanding is correct."offline\0\0\0\0\0\0\0\0\0\0" is indeed blocked
> from matching "offline" and returns a failed result.
>
> I'm not sure whether to relax the restrictions to make it match successfully.
> After all, the incoming count is too large and not the actual length of
> "offline".
But that doesn't matter at all. Sometimes you do not have control over
the buffer length when writing to a file like this, what matters is the
content of the buffer and we should stop at the first \0 as that's the
"end of a string" in this type of api.
So your change here might break existing userspace code, and we can't do
that, sorry.
thanks,
greg k-h
I know how to modify it to meet your requirements:
for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
if (strncmp(kobject_actions[action], buf, count_first) != 0)
continue;
if (strlen(kobject_actions[action]) > count_first)
continue;
if (args)
*args = args_start;
*type = action;
ret = 0;
break;
}
So I will modify the patch and resubmit it. Please review it again
在 2023/3/7 17:27, Greg KH 写道:
>
> On Tue, Mar 07, 2023 at 05:08:02PM +0800, Xia Fukun wrote:
>> Thanks for your reply.
>> Your understanding is correct."offline\0\0\0\0\0\0\0\0\0\0" is indeed blocked
>> from matching "offline" and returns a failed result.
>>
>> I'm not sure whether to relax the restrictions to make it match successfully.
>> After all, the incoming count is too large and not the actual length of
>> "offline".
>
> But that doesn't matter at all. Sometimes you do not have control over
> the buffer length when writing to a file like this, what matters is the
> content of the buffer and we should stop at the first \0 as that's the
> "end of a string" in this type of api.
>
> So your change here might break existing userspace code, and we can't do
> that, sorry.
>
> thanks,
>
> greg k-h
On Tue, Mar 07, 2023 at 05:49:25PM +0800, Xia Fukun wrote:
> I know how to modify it to meet your requirements:
Again, please stop top-posting, as I can't follow what you are trying to
do here at all otherwise.
>
> for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
> if (strncmp(kobject_actions[action], buf, count_first) != 0)
> continue;
> if (strlen(kobject_actions[action]) > count_first)
> continue;
> if (args)
> *args = args_start;
> *type = action;
> ret = 0;
> break;
> }
>
> So I will modify the patch and resubmit it. Please review it again
Please test your change and submit it and then I will add it to my
review queue like everything else I get :)
But again, this whole function feels very fragile, shouldn't it be
rewritten to be more clear?
thanks,
greg k-h