|
1 | 1 | ---
|
2 | 2 | description: "Learn more about: Warning C6029"
|
3 | 3 | title: Warning C6029
|
4 |
| -ms.date: 10/04/2022 |
| 4 | +ms.date: 2/07/2023 |
5 | 5 | f1_keywords: ["C6029", "USING_TAINTED_DATA", "__WARNING_USING_TAINTED_DATA"]
|
6 | 6 | helpviewer_keywords: ["C6029"]
|
7 |
| -ms.assetid: 07f89261-1b77-4597-9f34-12ce5d569b60 |
8 | 7 | ---
|
9 | 8 | # Warning C6029
|
10 | 9 |
|
11 |
| -> Possible buffer overrun in call to '*function*': use of unchecked value |
| 10 | +> Possible buffer overrun in call to '*function*' |
12 | 11 |
|
13 |
| -## Remarks |
| 12 | +Possible buffer overrun in called function due to an unchecked buffer length/size parameter. |
14 | 13 |
|
15 |
| -This warning indicates that a function that takes a buffer and a size is being passed an unchecked size. The data read-in from some external source hasn't been verified to see whether it's smaller than the buffer size. An attacker might intentionally specify a much larger than expected value for the size, which will lead to a buffer overrun. |
| 14 | +## Remarks |
16 | 15 |
|
17 |
| -Generally, whenever you read data from an untrusted external source, make sure to verify it for validity. It's appropriate to verify the size to make sure it's in the expected range. |
| 16 | +This warning indicates that code passes an unchecked size to a function that takes a buffer and a size. The code doesn't verify that the data read from some external source is smaller than the buffer size. An attacker might intentionally specify a larger than expected value for the size, which can lead to a buffer overrun. Generally, whenever you read data from an untrusted external source, make sure to verify it for validity. It's appropriate to verify the size to make sure it's in the expected range. |
18 | 17 |
|
19 | 18 | Code analysis name: `USING_TAINTED_DATA`
|
20 | 19 |
|
21 | 20 | ## Example
|
22 | 21 |
|
23 |
| -The following code generates this warning by calling the annotated function [`ReadFile`](/windows/desktop/api/fileapi/nf-fileapi-readfile) two times. After the first call, the Post attribute property marks the second parameter value untrusted. Therefore, passing an untrusted value in the second call to `ReadFile` generates this warning as shown in the following code: |
| 22 | +The following code generates this warning when it calls the annotated function `std::fread` two times. The code uses the first call to determine the length of the data to read in later calls. After the first call, analysis marks `dataSize` as coming from an untrusted source. Therefore, when the code passes the untrusted value to the second `std::fread` call, the analyzer generates this warning. A malicious actor could modify the file and cause the call to `std::fread` to overflow the `buffer` array. In real world code, you should also handle error recovery based on the return value of `std::fread`. For simplicity, these examples intentionally leave out error recovery code. |
24 | 23 |
|
25 | 24 | ```cpp
|
26 |
| -#include "windows.h" |
| 25 | +void processData(FILE* file) |
| 26 | +{ |
| 27 | + const size_t MAX_BUFFER_SIZE = 100; |
| 28 | + uint32_t buffer[MAX_BUFFER_SIZE]{}; |
| 29 | + uint8_t dataSize = 0; |
| 30 | + |
| 31 | + // Read length data from the beginning of the file |
| 32 | + fread(&dataSize, sizeof(uint8_t), 1, file); |
| 33 | + // Read the rest of the data based on the dataSize |
| 34 | + fread(buffer, sizeof(uint32_t), dataSize, file); |
| 35 | +} |
| 36 | +``` |
27 | 37 |
|
28 |
| -bool f(HANDLE hFile) |
| 38 | +The fix for the issue depends on the nature of the data and the behavior of the annotated function that triggers the diagnostic. For more information, see the documentation for that function. A straightforward fix is to check the size before the second call to `std:fread`. In the next example, we throw an exception to terminate the function. Most real-world code would instead have an error recovery strategy that's specific to the scenario. |
| 39 | +
|
| 40 | +```cpp |
| 41 | +void processData(FILE* file) |
29 | 42 | {
|
30 |
| - char buff[MAX_PATH]; |
| 43 | + const size_t MAX_BUFFER_SIZE = 100; |
| 44 | + uint32_t buffer[MAX_BUFFER_SIZE]{}; |
| 45 | + uint8_t dataSize = 0; |
31 | 46 |
|
32 |
| - DWORD cbLen; |
33 |
| - DWORD cbRead; |
| 47 | + fread(&dataSize, sizeof(uint32_t), 1, file); |
34 | 48 |
|
35 |
| - // Read the number of byte to read (cbLen). |
36 |
| - if (!ReadFile (hFile, &cbLen, sizeof (cbLen), &cbRead, NULL)) |
37 |
| - { |
38 |
| - return false; |
39 |
| - } |
40 |
| - // Read the bytes |
41 |
| - if (!ReadFile (hFile, buff, cbLen, &cbRead, NULL)) // warning C6029 |
| 49 | + if (dataSize > MAX_BUFFER_SIZE) |
42 | 50 | {
|
43 |
| - return false; |
| 51 | + throw std::runtime_error("file data unexpected size"); |
44 | 52 | }
|
45 | 53 |
|
46 |
| - return true; |
| 54 | + fread(buffer, sizeof(uint32_t), dataSize, file); |
47 | 55 | }
|
48 | 56 | ```
|
49 | 57 |
|
50 |
| -To correct this warning, check the buffer size as shown in the following code: |
| 58 | +In `std:fread` and similar functions, the code may need to read large amounts of data. To handle large data, you can allocate the size of the buffer dynamically after the size becomes known. Or, you can call `std:fread` multiple times as needed to read in the rest of the data. If you allocate the buffer dynamically, we recommend you put a limit on the size to avoid introducing an out-of-memory exploit for large values. We don't use this approach in our example because it's already bounded by the size of `uint8_t`. |
51 | 59 |
|
52 | 60 | ```cpp
|
53 |
| -bool f(HANDLE hFile) |
| 61 | +void processDataDynamic(FILE* file) |
54 | 62 | {
|
55 |
| - char buff[MAX_PATH]; |
| 63 | + uint8_t dataSize = 0; |
| 64 | + fread(&dataSize, sizeof(uint8_t), 1, file); |
| 65 | + |
| 66 | + // Vector with `dataSize` default initialized objects |
| 67 | + std::vector<uint32_t> vecBuffer(dataSize); |
56 | 68 |
|
57 |
| - DWORD cbLen; |
58 |
| - DWORD cbRead; |
| 69 | + fread(&vecBuffer[0], sizeof(uint32_t), dataSize, file); |
| 70 | +} |
| 71 | +void processDataMultiple(FILE* file) |
| 72 | +{ |
| 73 | + const size_t MAX_BUFFER_SIZE = 100; |
| 74 | + uint32_t buffer[MAX_BUFFER_SIZE]{}; |
| 75 | + uint8_t dataSize = 0; |
59 | 76 |
|
60 |
| - // Read the number of byte to read (cbLen). |
61 |
| - if (!ReadFile (hFile, &cbLen, sizeof (cbLen), &cbRead, NULL)) |
62 |
| - { |
63 |
| - return false; |
64 |
| - } |
65 |
| - // Ensure that there's enough space in the buffer to read that many bytes. |
66 |
| - if (cbLen > sizeof(buff)) |
67 |
| - { |
68 |
| - return false; |
69 |
| - } |
70 |
| - // Read the bytes |
71 |
| - if (!ReadFile (hFile, buff, cbLen, &cbRead, NULL)) // warning C6029 |
| 77 | + fread(&dataSize, sizeof(uint32_t), 1, file); |
| 78 | + |
| 79 | + while( dataSize > 0 ) |
72 | 80 | {
|
73 |
| - return false; |
| 81 | + size_t readSize = dataSize > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : dataSize; |
| 82 | + readSize = fread(buffer, sizeof(uint32_t), readSize, file); |
| 83 | + dataSize = dataSize - readSize; |
| 84 | + // Process the data in `buffer`... |
74 | 85 | }
|
75 |
| -
|
76 |
| - return true; |
77 | 86 | }
|
78 | 87 | ```
|
79 | 88 |
|
80 | 89 | ## See also
|
81 | 90 |
|
82 |
| -- [Using SAL Annotations to reduce code defects](using-sal-annotations-to-reduce-c-cpp-code-defects.md) |
| 91 | +[Rule sets for C++ code](./using-rule-sets-to-specify-the-cpp-rules-to-run.md)\ |
| 92 | +[Using SAL Annotations to reduce code defects](using-sal-annotations-to-reduce-c-cpp-code-defects.md) |
0 commit comments