Skip to content
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 Issue 2765 - rule option: migrate to GeoIP2 database and libmaxminddb API. #3610

Closed
wants to merge 6 commits into from

Conversation

bmeeks8
Copy link
Contributor

@bmeeks8 bmeeks8 commented Jan 9, 2019

Make sure these boxes are signed before submitting your Pull Request -- thank you.

Link to redmine ticket: #2765

Describe changes:

  • Update "geoip" rule option support code to use the libmaxminddb library for reading "iso_country" code for an IP address from the GeoIP2/GeoLite2 database format. The legacy GeoIP database format and supporting library (libgeoip) has been discontinued by MaxMind and replaced by GeoIP2 and the libmaxminddb library.

PRScript output (if applicable):

@bmeeks8 bmeeks8 requested review from norg and a team as code owners January 9, 2019 00:27
@bmeeks8
Copy link
Contributor Author

bmeeks8 commented Jan 9, 2019

Apparently there is no libmaxminddb library package available for Cygwin, thus the test build on appveyor is failing because it says it cannot find the library. I've searched the web and did not find a binary package for Cygwin I could reference. I did find source code for maybe creating a binary package, though, using cygport.

So does this mean "geoip" support in Suricata is going to die with the end-of-life of the legacy GeoIP database, or is there another alternative for including the GeoIP2 format supported by libmaxminddb in Suricata?

Copy link
Member

@victorjulien victorjulien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking on this work Bill! Some minor questions/requests.

src/detect-geoip.c Show resolved Hide resolved
/* If ISO country code was found, then return it */
if (entry_data.has_data) {
if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
char *country_code = strndup((char *)entry_data.utf8_string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the string copied here? It seems unnecessary. If it is needed, please use SCStrdup instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library uses memory-mapped file I/O, so there is a remote chance that a string pointer returned may be voided later, especially if the database is closed. The MaxMind sample code makes a copy of the string, so I felt that was the safer route here. I will switch to the SCStrdup() function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After another more careful look I realized the function needed here is strndup() (a string copy with specified length) and not strdup(). This is because the MaxMind DB entries are not null-terminated strings. The data length is given as part of the returned data structure. I did not find an equivalent Suricata function for strndup(). I see SCStrdup() but I do not see SCStrndup().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok fair enough, but then I would prefer a proper SCStrndup implementation to be introduced. It should be quite simple to add that.

src/detect-geoip.c Outdated Show resolved Hide resolved
@victorjulien
Copy link
Member

Our Windows support efforts are now focused on MinGW, which does have a libmaxminddb package. In any case I would like to get this work merged, even if not all platforms support it.

@victorjulien
Copy link
Member

victorjulien commented Jan 14, 2019 via email

@bmeeks8
Copy link
Contributor Author

bmeeks8 commented Jan 14, 2019

I believe all review comments have been resolved and this request is ready for acceptance and merging.

@bmeeks8 bmeeks8 closed this Jan 15, 2019
@bmeeks8 bmeeks8 deleted the geoip2-fix-v2 branch January 15, 2019 18:15
victorjulien added a commit to victorjulien/suricata that referenced this pull request Apr 28, 2020
In case of bad IPv4, TCP or UDP, the per packet ip4vars/tcpvars/udpvar
structures would not be cleaned up because the cleanup depends on the
'header' pointer being set, but the error handling would unset that.

This could mean these structures were already filled with values before
the error was detected. As packets were recycled, the next packet decoding
would use this unclean structure.

To make things worse these structures are part of unions. IPv4/IPv6 and
TCP/ICMPv4/ICMPv6 share the same memory location.

LibFuzzer+UBSAN found this both locally and in Oss-Fuzz:

decode-ipv6.c:654:9: runtime error: load of value 6, which is not a valid value for type 'bool'
    #0 0x6146f0 in DecodeIPV6 /src/suricata/src/decode-ipv6.c:654:9
    #1 0x617e96 in DecodeNull /src/suricata/src/decode-null.c:70:13
    #2 0x9dd8a4 in DecodePcapFile /src/suricata/src/source-pcap-file.c:412:9
    #3 0x4c8ed2 in LLVMFuzzerTestOneInput /src/suricata/src/tests/fuzz/fuzz_sigpcap.c:158:25
    #4 0x457e51 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:556:15
    #5 0x457575 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:470:3
    #6 0x459917 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:698:19
    #7 0x45a6a5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:830:5
    #8 0x448728 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:824:6
    #9 0x472552 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:19:10
    #10 0x7ff0d097b82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #11 0x41bde8 in _start (/out/fuzz_sigpcap+0x41bde8)

Bug: OISF#3610
victorjulien added a commit to victorjulien/suricata that referenced this pull request Apr 28, 2020
In case of bad IPv4, TCP or UDP, the per packet ip4vars/tcpvars/udpvar
structures would not be cleaned up because the cleanup depends on the
'header' pointer being set, but the error handling would unset that.

This could mean these structures were already filled with values before
the error was detected. As packets were recycled, the next packet decoding
would use this unclean structure.

To make things worse these structures are part of unions. IPv4/IPv6 and
TCP/ICMPv4/ICMPv6 share the same memory location.

LibFuzzer+UBSAN found this both locally and in Oss-Fuzz:

decode-ipv6.c:654:9: runtime error: load of value 6, which is not a valid value for type 'bool'
    #0 0x6146f0 in DecodeIPV6 /src/suricata/src/decode-ipv6.c:654:9
    #1 0x617e96 in DecodeNull /src/suricata/src/decode-null.c:70:13
    #2 0x9dd8a4 in DecodePcapFile /src/suricata/src/source-pcap-file.c:412:9
    #3 0x4c8ed2 in LLVMFuzzerTestOneInput /src/suricata/src/tests/fuzz/fuzz_sigpcap.c:158:25
    #4 0x457e51 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:556:15
    #5 0x457575 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:470:3
    #6 0x459917 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:698:19
    #7 0x45a6a5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:830:5
    #8 0x448728 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:824:6
    #9 0x472552 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:19:10
    #10 0x7ff0d097b82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #11 0x41bde8 in _start (/out/fuzz_sigpcap+0x41bde8)

Bug: OISF#3610
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants