-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix TAINTED_SCALAR
Coverity issues for pkg_editor.c
#277
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @IlanTruanovsky. Could you split these into two commits? They fix different issues and one of them is more involved, so you want to be able to review, test, and/or revert the latter individually if it turns out to cause a (performance) regression.
Instead of mallocing and allocating memory, I added a while loop to reuse a constant sized array for multiple iterations. The only problem with this that I can foresee is it taking too much time and having multiple iterations of the while loop. However, when I ran the unit tests with and without this change, it took the same amount of time (although I'm not sure if the unit tests cover this case thoroughly). Are there any issues with this that come to mind, @pcolberg?
Your solution is the right approach; you generally want to avoid allocating an unbounded buffer to copy between two files. The question is which buffer size to pick. read_data()
contains a loop as well. Running the unit tests, how often is that inner loop executed in a single call to read_data()
using your chunk size of 64 kB? How does it change if you decrease the chunk size?
This will need an integration test since |
I did some testing, seems like the loop in |
a37cf9a
to
730b1ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @IlanTruanovsky! This is ready for integration testing. (Not sure why GitHub actions did not run. You could try force-pushing a rebase onto main
.)
730b1ae
to
02e3818
Compare
@IlanTruanovsky, it looks like the |
@IlanTruanovsky From a quick test, it looks like the unit test
--- a/lib/pkg_editor/test/pkg_editor_test.cpp
+++ b/lib/pkg_editor/test/pkg_editor_test.cpp
@@ -445,6 +445,14 @@ TEST(package, unpack_buffer) {
PACK_UNPACK_DIR "/src/pkg_editor.c"));
CHECK_EQUAL(true, files_same("test/pkg_editor_test.cpp",
PACK_UNPACK_DIR "/test/pkg_editor_test.cpp"));
+ CHECK_EQUAL(true, files_same("test/test.1G",
+ PACK_UNPACK_DIR "/test/test.1G"));
+ CHECK_EQUAL(true, files_same("test/test.100M",
+ PACK_UNPACK_DIR "/test/test.100M"));
+ CHECK_EQUAL(false, files_same("test/test.100M",
+ PACK_UNPACK_DIR "/test/test.1G"));
+ CHECK_EQUAL(false, files_same("test/test.1G",
+ PACK_UNPACK_DIR "/test/test.100M"));
}
TEST(package, unpack_buffer_stdin) {
The above should pass, but instead fails (and suspiciously quickly for a 1 GB file); it appears |
I tried replicating your experiment, but mine passes. I think you're inserting the 1GB and 100MB files in the wrong place, it should be located under |
Thanks, now it's taking the expected time; either way, |
c59383f
to
bc7b9f6
Compare
bc7b9f6 is causing a regression when decompressing a zero-length file:
|
So far we have found the following gaps in the
|
@pcolberg thanks for all your debugging! I'll take a look at what needs to be done and commit the necessary changes. |
Funnily enough, this check fails when I add a check to see if the file exists. I need to investigate this a bit more. |
You could enable exceptions on the input file streams: static bool files_same(const char *f1, const char *f2) {
std::ifstream file1(f1, std::ifstream::ate | std::ifstream::binary);
std::ifstream file2(f2, std::ifstream::ate | std::ifstream::binary);
file1.exceptions(std::ifstream::failbit | std::ifstream::badbit);
file2.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
It seems like CMakeLists.txt was never packed to begin with, so it doesn't exist. It also doesn't exist in the cwd while the unit test is running. I'll go ahead and replace the file name with something that exists. |
Ideally you could generate the input files with a desired range of sizes on the fly. Internally in the runtime, we can make full use of C++17. |
acd44e2
to
f4a172c
Compare
@pcolberg I added better unit testing for the unpacking part of the pkg_editor unit tests, including:
Your review is much appreciated! |
2f13287
to
2477203
Compare
This commit adds randomness to the pkg_editor unit tests that deal with packing and unpacking files. This ensures that we can cover all file sizes and all types of file contents and improves the robustness of our pkg_editor code.
The info.name_length variable was not being checked to see if it was less than the size of name when passed into read_data. This was a simple fix. Fixes: ``` lib/pkg_editor/src/pkg_editor.c:1632:5: Type: Untrusted value as argument (TAINTED_SCALAR) lib/pkg_editor/src/pkg_editor.c:1591:3: Tainted data flows to a taint sink 1. path: Condition "buffer != NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1596:5: 2. path: Condition "input != NULL", taking true branch. lib/pkg_editor/src/pkg_editor.c:1596:5: 3. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1601:3: 4. path: Condition "ret != 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 5. path: Condition "z_info.strm.avail_in > 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 6. path: Condition "input != NULL", taking true branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 7. path: Condition "!feof(input)", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 8. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 9. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 10. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 11. path: Condition "!read_data(name, info.name_length, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1642:5: 12. path: Condition "out_dir_length + 2 > 12288UL /* 3 * 4096 */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1652:5: 13. path: Condition "info.kind == PACK_DIR", taking true branch. lib/pkg_editor/src/pkg_editor.c:1654:5: 14. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1711:3: 15. path: Jumping back to the beginning of the loop. lib/pkg_editor/src/pkg_editor.c:1612:3: 16. path: Condition "z_info.strm.avail_in > 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 17. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 18. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 19. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 20. path: Condition "!read_data(name, info.name_length, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1642:5: 21. path: Condition "out_dir_length + 2 > 12288UL /* 3 * 4096 */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1652:5: 22. path: Condition "info.kind == PACK_DIR", taking true branch. lib/pkg_editor/src/pkg_editor.c:1654:5: 23. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1711:3: 24. path: Jumping back to the beginning of the loop. lib/pkg_editor/src/pkg_editor.c:1612:3: 25. path: Condition "z_info.strm.avail_in > 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 26. tainted_argument: Calling function "read_data" taints argument "info". lib/pkg_editor/src/pkg_editor.c:1530:3: Tainted data flows to a taint sink 26.1. var_assign_parm: Assigning: "z_info->strm.next_out" = "data". lib/pkg_editor/src/pkg_editor.c:1534:5: 26.2. path: Condition "z_info->strm.avail_in == 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 26.3. path: Condition "in_fd == NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 26.4. path: Condition "feof(in_fd)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1541:7: 26.5. tainted_data_argument: Calling function "fread" taints parameter "*z_info->buffer". [Note: The source code implementation of the function has been overridden by a builtin model.] lib/pkg_editor/src/pkg_editor.c:1542:7: 26.6. path: Condition "count < 1", taking false branch. lib/pkg_editor/src/pkg_editor.c:1547:7: 26.7. var_assign_alias: Assigning: "z_info->strm.next_in" = "z_info->buffer", which taints "z_info->strm.next_in". lib/pkg_editor/src/pkg_editor.c:1550:5: 26.8. tainted_data_transitive: Calling function "inflate" with tainted argument "*z_info->strm.next_in" taints "*z_info->strm.next_out". lib/pkg_editor/src/pkg_editor.c:1551:5: 26.9. path: Condition "ret != -2", taking true branch. lib/pkg_editor/src/pkg_editor.c:1551:5: 26.10. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1552:5: 26.11. path: Condition "ret == 1", taking true branch. lib/pkg_editor/src/pkg_editor.c:1554:7: 26.12. path: Condition "z_info->strm.avail_out == 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 27. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 28. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 29. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 30. tainted_data: Passing tainted expression "info.name_length" to "read_data", which uses it as an offset. lib/pkg_editor/src/pkg_editor.c:1531:3: Tainted data flows to a taint sink 30.1. var_assign_parm: Assigning: "z_info->strm.avail_out" = "size", which taints "z_info->strm.avail_out". lib/pkg_editor/src/pkg_editor.c:1534:5: 30.2. path: Condition "z_info->strm.avail_in == 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 30.3. path: Condition "in_fd == NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 30.4. path: Condition "feof(in_fd)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1542:7: 30.5. path: Condition "count < 1", taking false branch. lib/pkg_editor/src/pkg_editor.c:1550:5: 30.6. taint_sink_lv_call: Passing tainted expression "z_info->strm.avail_out" to taint sink "inflate". lib/pkg_editor/src/pkg_editor.c:1632:5: 31. remediation: Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range. ```
Fixes: ``` lib/pkg_editor/src/pkg_editor.c:1681:11: Type: Untrusted allocation size (TAINTED_SCALAR) lib/pkg_editor/src/pkg_editor.c:1591:3: Tainted data flows to a taint sink 1. path: Condition "buffer != NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1596:5: 2. path: Condition "input != NULL", taking true branch. lib/pkg_editor/src/pkg_editor.c:1596:5: 3. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1601:3: 4. path: Condition "ret != 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 5. path: Condition "z_info.strm.avail_in > 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 6. path: Condition "input != NULL", taking true branch. lib/pkg_editor/src/pkg_editor.c:1612:3: 7. path: Condition "!feof(input)", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 8. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 9. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 10. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 11. path: Condition "!read_data(name, info.name_length, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1642:5: 12. path: Condition "out_dir_length + 2 > 12288UL /* 3 * 4096 */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1652:5: 13. path: Condition "info.kind == PACK_DIR", taking true branch. lib/pkg_editor/src/pkg_editor.c:1654:5: 14. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1711:3: 15. path: Jumping back to the beginning of the loop. lib/pkg_editor/src/pkg_editor.c:1612:3: 16. path: Condition "z_info.strm.avail_in > 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 17. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 18. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 19. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 20. path: Condition "!read_data(name, info.name_length, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1642:5: 21. path: Condition "out_dir_length + 2 > 12288UL /* 3 * 4096 */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1652:5: 22. path: Condition "info.kind == PACK_DIR", taking true branch. lib/pkg_editor/src/pkg_editor.c:1654:5: 23. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1711:3: 24. path: Jumping back to the beginning of the loop. lib/pkg_editor/src/pkg_editor.c:1612:3: 25. path: Condition "z_info.strm.avail_in > 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 26. tainted_argument: Calling function "read_data" taints argument "info". lib/pkg_editor/src/pkg_editor.c:1530:3: Tainted data flows to a taint sink 26.1. var_assign_parm: Assigning: "z_info->strm.next_out" = "data". lib/pkg_editor/src/pkg_editor.c:1534:5: 26.2. path: Condition "z_info->strm.avail_in == 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 26.3. path: Condition "in_fd == NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1537:7: 26.4. path: Condition "feof(in_fd)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1541:7: 26.5. tainted_data_argument: Calling function "fread" taints parameter "*z_info->buffer". [Note: The source code implementation of the function has been overridden by a builtin model.] lib/pkg_editor/src/pkg_editor.c:1542:7: 26.6. path: Condition "count < 1", taking false branch. lib/pkg_editor/src/pkg_editor.c:1547:7: 26.7. var_assign_alias: Assigning: "z_info->strm.next_in" = "z_info->buffer", which taints "z_info->strm.next_in". lib/pkg_editor/src/pkg_editor.c:1550:5: 26.8. tainted_data_transitive: Calling function "inflate" with tainted argument "*z_info->strm.next_in" taints "*z_info->strm.next_out". lib/pkg_editor/src/pkg_editor.c:1551:5: 26.9. path: Condition "ret != -2", taking true branch. lib/pkg_editor/src/pkg_editor.c:1551:5: 26.10. path: Falling through to end of if statement. lib/pkg_editor/src/pkg_editor.c:1552:5: 26.11. path: Condition "ret == 1", taking true branch. lib/pkg_editor/src/pkg_editor.c:1554:7: 26.12. path: Condition "z_info->strm.avail_out == 0", taking false branch. lib/pkg_editor/src/pkg_editor.c:1614:5: 27. path: Condition "!read_data(&info, 20UL /* sizeof (info) */, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1619:5: 28. path: Condition "info.magic != 3203399403U", taking false branch. lib/pkg_editor/src/pkg_editor.c:1627:5: 29. path: Condition "info.kind == PACK_END", taking false branch. lib/pkg_editor/src/pkg_editor.c:1632:5: 30. path: Condition "!read_data(name, info.name_length, &z_info, input)", taking false branch. lib/pkg_editor/src/pkg_editor.c:1642:5: 31. path: Condition "out_dir_length + 2 > 12288UL /* 3 * 4096 */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1652:5: 32. path: Condition "info.kind == PACK_DIR", taking false branch. lib/pkg_editor/src/pkg_editor.c:1657:7: 33. path: Condition "out_file == NULL", taking false branch. lib/pkg_editor/src/pkg_editor.c:1663:7: 34. path: Condition "info.file_length > 0", taking true branch. lib/pkg_editor/src/pkg_editor.c:1663:7: 35. lower_bounds: Checking lower bounds of unsigned scalar "info.file_length" by taking the true branch of "info.file_length > 0U". lib/pkg_editor/src/pkg_editor.c:1665:9: 36. path: Condition "info.file_length < 65536UL /* sizeof (buf) */", taking false branch. lib/pkg_editor/src/pkg_editor.c:1665:9: 37. lower_bounds: Checking lower bounds of unsigned scalar "info.file_length" by taking the false branch of "info.file_length < 65536UL". lib/pkg_editor/src/pkg_editor.c:1681:11: 38. tainted_data: Passing tainted expression "info.file_length" to "malloc", which uses it as an allocation size. lib/pkg_editor/src/pkg_editor.c:1681:11: 39. remediation: Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range. ```
@pcolberg It's been a while, but I was able to get this PR to pass, though there was one complication that I'd like your input on. I'm using this flow to remove the tmp dir when creating the random files during our testing. This code does pass CI, but it did not work when I tested locally on a Windows machine (it errors out with So what should be done about this? We can either:
I think option 2 is the best, but I'd like to know what you think. |
I had an offline discussion with Ilan. Ideally we don't want to create tmp files in the tmp directory during the unit testing without cleaning them up. @tylerzhao7684 , can you please investigate the error code that Ilan posted in the earlier comment to see what that means on the windows machine and how we can avoid it? We definitely don't want to have intermittent build failures. You can reach Ilan or me for help! Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Windows unit tests now passing
Can you please do an integration testing as well? Thanks! |
It passed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Tyler. The change looks good to me. Just need a few hw tests to pass and I will merge.
Requested change implemented and Peter's role changed.
Thanks Tyler! |
Several values that were being read through files were not being checked to see if they meet certain requirements.
For one of the issues, the
info.name_length
variable was not being checked to see if it was less than the size ofname
when passed intoread_data
. This was a simple fix.For the other
TAINTED_SCALAR
issue, theinfo.file_length
value was never checked. Since this was being passed into amalloc
call, it would be possible for the malloc call to use too much memory if theinfo.file_length
number was purposefully set to be large. There were two possible solutions to this that I could think ofinfo.file_length
. This maintains much of the same code, but also increases the restrictions of the data being passed into theacl_pkg_unpack_buffer_or_file
function.info.file_length
and instead reuse a constant sized array. This is the solution I implemented.Instead of mallocing and allocating memory, I added a while loop to reuse a constant sized array for multiple iterations. The only problem with this that I can foresee is it taking too much time and having multiple iterations of the while loop. However, when I ran the unit tests with and without this change, it took the same amount of time (although I'm not sure if the unit tests cover this case thoroughly). Are there any issues with this that come to mind, @pcolberg?
The error output is large, so I'll trim it down to just the issue without the code trace.
Fixes: