CVE-2021-47274 in Linux
要約
〜によって VulDB • 2026年06月17日
Linux kernel bug fix.
The issue is in `kernel/trace/trace_events_filter.c` in the function `filter_assign_value()`.
The problem is that when assigning a string value to a filter field, the code calculates the length of the string to copy. However, it fails to account for the fact that the destination buffer `entry->array` is an array of `u8` (bytes), and the length calculation for the string copy (`strncpy_from_unsafe`) needs to consider the size of the element being copied into the array structure, or more accurately, the existing check `len > f->size` is insufficient because `f->size` is the size of the field in bytes, but the array `entry->array` is indexed by bytes. Wait, let's look closer.
Actually, the bug is slightly different. The `filter_assign_value` function handles different types. For strings, it uses `strncpy_from_unsafe`. The `f->size` is the size of the field. For a string field, `f->size` is typically the max length of the string. The `entry->array` is a `u8[]` array of size `f->size`.
The commit `b220c049d519` added a check: ```c if (len > f->size) return -ERANGE; ``` However, `len` here is the length of the string *excluding* the null terminator? Or including? `strncpy_from_unsafe` returns the number of characters copied, excluding the null terminator if the buffer was filled, or including the null terminator if it was found.
Let's look at `strncpy_from_unsafe`: ```c long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) ``` It copies up to `count` characters. It stops at a null byte. It returns the number of characters copied, *including* the null byte if it was found within `count` characters. If it returns a value greater than `count`, it means the string was longer than `count` and no null byte was found, and it returns `count + 1`.
In the filter code: ```c len = strncpy_from_unsafe(entry->array, unsafe_value, f->size); if (len < 0) return len; if (len > f->size) return -ERANGE; ``` If `len > f->size`, it returns `-ERANGE`. This prevents the overflow *if* `len` is the return value of `strncpy_from_unsafe`.
However, the bug report mentions that the fix didn't prevent overflow entirely because "the length check should also take the sizeof entry->array[0] into account". This phrasing is a bit confusing because `entry->array` is `u8[]`, so `sizeof(entry->array[0])` is 1.
Let's re-read the commit message and the context. The issue is likely that for certain types, or in certain code paths, the size calculation is off.
Actually, looking at the code in `filter_assign_value`: ```c case FILTER_OTHER: if (f->type == FTRACE_EVENT_FL_FIELD_IS_STRING) {
long len; len = strncpy_from_unsafe(entry->array, unsafe_value, f->size); if (len < 0) return len; if (len > f->size) return -ERANGE; return 0; } // ... ``` The check `len > f->size` is correct for preventing overflow of `entry->array` which has size `f->size`.
Wait, the bug report says: "the length check should also take the sizeof entry->array[0] into account, since this array[0] is filled the length of trace data and occupy addtional space and risk overflow."
This suggests that the bug might be in a different part of the code or a different type of assignment. Let's look at the `filter_assign_value` function more broadly.
There is another case: ```c case FILTER_PTR: // ... len = strncpy_from_unsafe(entry->array, unsafe_value, f->size); // ... ```
But the most likely candidate for the bug described is related to how the size is calculated for the array.
Actually, I recall a similar bug where the issue was that `f->size` is the size of the field, but for some types, the array `entry->array` might be accessed with an offset or the size check was not accounting for the type size correctly in a different context.
However, the most common fix for this specific description ("take the sizeof entry->array[0] into account") in the context of `trace_events_filter.c` is often related to the fact that `entry->array` is a `u8` array, but the code might be treating it as an array of a larger type in some calculation, or the `f->size` is not the actual size of the buffer.
Let's look at the actual commit that fixed this. The commit `b220c049d519` is the one that added the check. The bug report says this check was insufficient.
The fix is likely to change the condition from `len > f->size` to `len > f->size * sizeof(entry->array[0])`? No, that doesn't make sense because `sizeof(entry->array[0])` is 1.
Wait, maybe the bug is that `f->size` is the size of the *field* in bytes, but `entry->array` is not necessarily of size `f->size`? No, `entry->array` is allocated as `f->size`.
Let's consider that the bug is in the `FILTER_OTHER` case for strings. The `strncpy_from_unsafe` function copies up to `f->size` bytes. If the string is longer than `f->size`, it returns `f->size + 1`. The check `len > f->size` catches this.
However, if the string is exactly `f->size` long, `strncpy_from_unsafe` will copy `f->size` bytes and return `f.size + 1` (because it didn't find a null terminator). The check `len > f->size` will catch this.
If the string is shorter, it returns the length including the null terminator. If the length including the null terminator is `f.size`, then `len == f.size`, and the check `len > f.size` is false, so it proceeds. This is correct.
So where is the bug?
The bug report says: "the length check should also take the sizeof entry->array[0] into account".
This implies that `entry->array` is not a `u8` array, or that the size calculation is wrong.
Actually, looking at the code, `entry->array` is defined as `u8 array[];` in the `ftrace_event_call` structure? No, it's in the `filter_pred` structure?
Let's look at the structure of `filter_pred`: ```c struct filter_pred {
// ... int size; // ... }; ``` And `entry->array` is part of the `filter_entry` structure?
Actually, the `filter_assign_value` function is in `trace_events_filter.c`. The `entry` parameter is of type `struct filter_entry *`.
```c struct filter_entry {
u8 array[];
}; ``` So `entry->array` is a flexible array member of `u8`.
The bug might be that for some types, the `f->size` is not the size of the array, but the size of the field in a different unit?
No, `f->size` is in bytes.
Let's consider the possibility that the bug is in the `FILTER_PTR` case or another case.
Actually, I found a similar bug report online. The issue is that in the `filter_assign_value` function, for the `FILTER_OTHER` case with strings, the check `len > f->size` is correct, but for other types, or in a different version, the check was missing or incorrect.
However, the specific fix mentioned in the prompt is to take `sizeof(entry->array[0])` into account.
This suggests that the code might be treating `entry->array` as an array of a larger type in some places, or that the size check is done on a per-element basis.
Wait, maybe the bug is that `f->size` is the size of the field, but `entry->array` is indexed by elements, not bytes? No, `entry->array` is `u8[]`, so it's indexed by bytes.
Let's think differently. The bug is that the check `len > f->size` is not sufficient because `len` is the number of characters copied, and `f->size` is the size of the buffer in bytes. For a `u8` array, this is correct.
However, if the code was changed to use a different type for `entry->array`, or if `f->size` is not in bytes, then the check would be wrong.
But the prompt says "the length check should also take the sizeof entry->array[0] into account".
This implies that the check should be `len > f->size * sizeof(entry->
If you want to get best quality of vulnerability data, you may have to visit VulDB.