From d89a400ed664e0b57fd8667db5637792a185e831 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Wed, 26 Sep 2018 03:10:53 +0000 Subject: [PATCH 1/5] fuzz: add a fuzzer for dhcp6_client --- src/fuzz/fuzz-dhcp6-client.c | 59 ++++++++++++++++++++++++ src/fuzz/meson.build | 9 ++++ src/libsystemd-network/sd-dhcp6-client.c | 8 ++++ src/systemd/sd-dhcp6-client.h | 2 + 4 files changed, 78 insertions(+) create mode 100644 src/fuzz/fuzz-dhcp6-client.c diff --git a/src/fuzz/fuzz-dhcp6-client.c b/src/fuzz/fuzz-dhcp6-client.c new file mode 100644 index 0000000000..32a3c30643 --- /dev/null +++ b/src/fuzz/fuzz-dhcp6-client.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include + +#include "sd-dhcp6-client.h" +#include "sd-event.h" + +#include "dhcp6-internal.h" +#include "dhcp6-protocol.h" +#include "fd-util.h" +#include "fuzz.h" + +static int test_dhcp_fd[2]; + +int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, + const void *packet, size_t len) { + return len; +} + +int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { + assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) >= 0); + return test_dhcp_fd[0]; +} + +static void fuzz_client(const uint8_t *data, size_t size, bool is_information_request_enabled) { + _cleanup_(sd_event_unrefp) sd_event *e; + _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; + struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; + + assert_se(sd_event_new(&e) >= 0); + assert_se(sd_dhcp6_client_new(&client) >= 0); + assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); + assert_se(sd_dhcp6_client_set_ifindex(client, 42) == 0); + assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_set_information_request(client, is_information_request_enabled) == 0); + + assert_se(sd_dhcp6_client_start(client) >= 0); + + if (size >= sizeof(DHCP6Message)) + assert_se(sd_dhcp6_client_set_transaction_id(client, htobe32(0x00ffffff) & ((const DHCP6Message *) data)->transaction_id) == 0); + + assert_se(write(test_dhcp_fd[1], data, size) == (ssize_t) size); + + sd_event_run(e, (uint64_t) -1); + + assert_se(sd_dhcp6_client_stop(client) >= 0); + + test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + /* This triggers client_receive_advertise */ + fuzz_client(data, size, false); + + /* This triggers client_receive_reply */ + fuzz_client(data, size, true); + + return 0; +} diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build index f66d8883c4..066737c175 100644 --- a/src/fuzz/meson.build +++ b/src/fuzz/meson.build @@ -9,6 +9,15 @@ fuzzers += [ libgpg_error, libm]], + [['src/fuzz/fuzz-dhcp6-client.c', + 'src/libsystemd-network/dhcp-identifier.h', + 'src/libsystemd-network/dhcp-identifier.c', + 'src/libsystemd-network/dhcp6-internal.h', + 'src/systemd/sd-dhcp6-client.h'], + [libshared, + libsystemd_network], + []], + [['src/fuzz/fuzz-dhcp-server.c'], [libsystemd_network, libshared], diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index b793fc0285..9c097cc334 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -368,6 +368,14 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) { return 0; } +int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, be32_t transaction_id) { + assert_return(client, -EINVAL); + + client->transaction_id = transaction_id; + + return 0; +} + int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { assert_return(client, -EINVAL); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 7024ad84d6..639339d181 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -25,6 +25,7 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -127,6 +128,7 @@ int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request); int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request); +int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, be32_t transaction_id); int sd_dhcp6_client_get_lease( sd_dhcp6_client *client, From 45a7becfeaba0ab50b1aae9cddbb5c32789d56b2 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sat, 29 Sep 2018 02:47:18 +0000 Subject: [PATCH 2/5] tests: make fuzz-dhcp6-client work in containers provided by the OSS-Fuzz project The containers come with an empty machine-id, which causes the fuzzer to fail as soon as it starts. See https://github.com/systemd/systemd/pull/9014#discussion_r189594104 --- src/libsystemd-network/dhcp-identifier.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 531cf6783b..77c584ee60 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -108,8 +108,13 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { assert(len); r = sd_id128_get_machine(&machine_id); - if (r < 0) + if (r < 0) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10); +#else return r; +#endif + } unaligned_write_be16(&duid->type, DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); From b387d3c1327a3ad2a2509bd3d3491e674392ff21 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sat, 29 Sep 2018 03:06:10 +0000 Subject: [PATCH 3/5] dhcp6: fix an off-by-one error in dhcp6_option_parse_domainname ==14==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200055fa9c at pc 0x0000005458f1 bp 0x7ffc78940d90 sp 0x7ffc78940d88 READ of size 1 at 0x60200055fa9c thread T0 #0 0x5458f0 in dhcp6_option_parse_domainname /work/build/../../src/systemd/src/libsystemd-network/dhcp6-option.c:555:29 #1 0x54706e in dhcp6_lease_set_domains /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-lease.c:242:13 #2 0x53fce0 in client_parse_message /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:984:29 #3 0x53f3bc in client_receive_advertise /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:1083:13 #4 0x53d57f in client_receive_message /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:1182:21 #5 0x7f0f7159deee in source_dispatch /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3042:21 #6 0x7f0f7159d431 in sd_event_dispatch /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3455:21 #7 0x7f0f7159ea8d in sd_event_run /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3512:21 #8 0x531f2b in fuzz_client /work/build/../../src/systemd/src/fuzz/fuzz-dhcp6-client.c:44:9 #9 0x531bc1 in LLVMFuzzerTestOneInput /work/build/../../src/systemd/src/fuzz/fuzz-dhcp6-client.c:53:9 #10 0x57bec8 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:570:15 #11 0x579d67 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/libfuzzer/FuzzerLoop.cpp:479:3 #12 0x57dc92 in fuzzer::Fuzzer::MutateAndTestOne() /src/libfuzzer/FuzzerLoop.cpp:707:19 #13 0x580ca6 in fuzzer::Fuzzer::Loop(std::__1::vector, std::__1::allocator >, fuzzer::fuzzer_allocator, std::__1::allocator > > > const&) /src/libfuzzer/FuzzerLoop.cpp:838:5 #14 0x55e968 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:764:6 #15 0x551a1c in main /src/libfuzzer/FuzzerMain.cpp:20:10 #16 0x7f0f701a082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #17 0x41e928 in _start (/out/fuzz-dhcp6-client+0x41e928) --- src/libsystemd-network/dhcp6-option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 18196b1257..05f589e911 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -563,7 +563,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * /* Literal label */ label = (const char *)&optval[pos]; pos += c; - if (pos > optlen) + if (pos >= optlen) return -EMSGSIZE; if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { From ac41b5e8c5c867ef937b713629ebe0885d463135 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sat, 29 Sep 2018 03:09:23 +0000 Subject: [PATCH 4/5] tests: add a reproducer for the heap-buffer-overflow fixed in b387d3c1327a3ad2 --- .../crash-4003c06fce43a11fbd22f02584df2807ac333eae | Bin 0 -> 14 bytes test/fuzz-regressions/meson.build | 1 + 2 files changed, 1 insertion(+) create mode 100644 test/fuzz-regressions/fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae diff --git a/test/fuzz-regressions/fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae b/test/fuzz-regressions/fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae new file mode 100644 index 0000000000000000000000000000000000000000..630ee6632cc9ddbb44258646ff705b84bb71b735 GIT binary patch literal 14 VcmZQqW?*2DU|?fq;Ny{C000By0Du4h literal 0 HcmV?d00001 diff --git a/test/fuzz-regressions/meson.build b/test/fuzz-regressions/meson.build index b98436a4af..a4602b4c8f 100644 --- a/test/fuzz-regressions/meson.build +++ b/test/fuzz-regressions/meson.build @@ -12,6 +12,7 @@ sanitize_address = custom_target( sanitizers = [['address', sanitize_address]] fuzz_regression_tests = ''' + fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae fuzz-dns-packet/issue-7888 fuzz-dns-packet/oss-fuzz-5465 fuzz-journal-remote/crash-5a8f03d4c3a46fcded39527084f437e8e4b54b76 From c1bc37a18baab861658f6e2c2001eff1d0a60e75 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sat, 29 Sep 2018 03:25:34 +0000 Subject: [PATCH 5/5] tests: add a reproducer for the heap-buffer-overflow fixed in cb1bdeaf56852275e6b ==14==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020001c761a at pc 0x000000540abc bp 0x7ffd0caf2c50 sp 0x7ffd0caf2c48 READ of size 2 at 0x6020001c761a thread T0 #0 0x540abb in client_parse_message /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:849:73 #1 0x53f3bc in client_receive_advertise /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:1083:13 #2 0x53d57f in client_receive_message /work/build/../../src/systemd/src/libsystemd-network/sd-dhcp6-client.c:1182:21 #3 0x7f71d8c3eeee in source_dispatch /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3042:21 #4 0x7f71d8c3e431 in sd_event_dispatch /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3455:21 #5 0x7f71d8c3fa8d in sd_event_run /work/build/../../src/systemd/src/libsystemd/sd-event/sd-event.c:3512:21 #6 0x531f2b in fuzz_client /work/build/../../src/systemd/src/fuzz/fuzz-dhcp6-client.c:44:9 #7 0x531bc1 in LLVMFuzzerTestOneInput /work/build/../../src/systemd/src/fuzz/fuzz-dhcp6-client.c:53:9 #8 0x57bef8 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:570:15 #9 0x579d97 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /src/libfuzzer/FuzzerLoop.cpp:479:3 #10 0x57dcc2 in fuzzer::Fuzzer::MutateAndTestOne() /src/libfuzzer/FuzzerLoop.cpp:707:19 #11 0x580cd6 in fuzzer::Fuzzer::Loop(std::__1::vector, std::__1::allocator >, fuzzer::fuzzer_allocator, std::__1::allocator > > > const&) /src/libfuzzer/FuzzerLoop.cpp:838:5 #12 0x55e998 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:764:6 #13 0x551a4c in main /src/libfuzzer/FuzzerMain.cpp:20:10 #14 0x7f71d784182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #15 0x41e928 in _start (/out/fuzz-dhcp6-client+0x41e928) --- .../crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef | Bin 0 -> 9 bytes test/fuzz-regressions/meson.build | 1 + 2 files changed, 1 insertion(+) create mode 100644 test/fuzz-regressions/fuzz-dhcp6-client/crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef diff --git a/test/fuzz-regressions/fuzz-dhcp6-client/crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef b/test/fuzz-regressions/fuzz-dhcp6-client/crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef new file mode 100644 index 0000000000000000000000000000000000000000..44883be9f0be6f2ba225812ea93526e8d7523048 GIT binary patch literal 9 QcmZQ_5s-3WVPIeY00gT5xc~qF literal 0 HcmV?d00001 diff --git a/test/fuzz-regressions/meson.build b/test/fuzz-regressions/meson.build index a4602b4c8f..043d3f3154 100644 --- a/test/fuzz-regressions/meson.build +++ b/test/fuzz-regressions/meson.build @@ -13,6 +13,7 @@ sanitizers = [['address', sanitize_address]] fuzz_regression_tests = ''' fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae + fuzz-dhcp6-client/crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef fuzz-dns-packet/issue-7888 fuzz-dns-packet/oss-fuzz-5465 fuzz-journal-remote/crash-5a8f03d4c3a46fcded39527084f437e8e4b54b76