Skip to content

Panic during fuse-fuzzer #38

@hgarrereyn

Description

@hgarrereyn

PromptFuzz hit a crash trying to run fuse-fuzzer on a c-ares fuzz harness file.

Seems like the error is that the size > 16 ? 16 : size generates a clang Node with kind=Other, and that is not handled during some processing code.

id_000359.infer.cc:

#include "FDSan.h"
#include <ares.h>
#include <ares_dns.h>
#include <ares_nameser.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
//<ID> 359
//<Prompt> []
/*<Combination>: [
*/
//<score> 0, nr_unique_branch: 0
//<Quality> {"density":0,"unique_branches":{},"library_calls":[],"critical_calls":[],"visited":0}
/*Certainly! Let's break down how to create a fuzz driver that uses the selected c-ares APIs based on your requirements and input.

### 1. **Event Design**

Given the APIs:
- `ares_dns_record_query_get` - Gets query info from a DNS record.
- `ares_dns_record_rr_del` - Deletes a resource record from a DNS record.
- `ares_version` - Queries the c-ares version.
- `ares_process_fd` - Processes a file descriptor for ares events.
- `ares_dns_rr_add_abin` - Adds binary data to a DNS RR (resource record).

**Event**:  
Given a byte stream which is a DNS message (output from c-ares), we will:
- Parse it into a DNS record.
- Access its queries.
- Remove a resource record.
- Add some binary data to a resource record.
- Simulate event handling via file descriptors.
- Report the c-ares version.

### 2. **Resource Management**

- We'll parse the DNS message directly from the fuzzer input.
- To get file descriptors, we'll use `fmemopen`.
- We'll manage all memory and cleanup.

### 3. **Code Walkthrough**

*/


extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
	if(size<0) return 0;

  if (size < 8) {
	return 0;
	}
	 // Not enough for a meaningful DNS message

  // 1. Parse DNS message from input data into a record
  ares_dns_record_t *dnsrec = nullptr;
  ares_status_t status = ares_dns_parse(data, size, 0, &dnsrec);
  if (status != ARES_SUCCESS || !dnsrec) {
	return 0;
	}
	

  // 2. Get query info if present
  size_t query_cnt = ares_dns_record_query_cnt(dnsrec);
  if (query_cnt > 0) {
    const char *qname = nullptr;
    ares_dns_rec_type_t qtype;
    ares_dns_class_t qclass;
    ares_dns_record_query_get(dnsrec, 0, &qname, &qtype, &qclass); // Use first query
  }

  // 3. Delete a resource record if present in answer section
  size_t rr_cnt = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
  if (rr_cnt > 0) {
    ares_dns_record_rr_del(dnsrec, ARES_SECTION_ANSWER, 0);
  }

  // 4. Add binary data as an attribute to a resource record if possible
  const ares_dns_rr_t *rr = nullptr;
  if (ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER) > 0) {
    rr = ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, 0);
  }
  // Make a mutable copy by duplicating the record and getting RR 0
  ares_dns_record_t *dnsrec_dup = nullptr;
  if (rr) {
    dnsrec_dup = ares_dns_record_duplicate(dnsrec);
    if (dnsrec_dup) {
      ares_dns_rr_t *rr_mut = const_cast<ares_dns_rr_t*>(
                                  ares_dns_record_rr_get_const(dnsrec_dup, ARES_SECTION_ANSWER, 0));
      // Choose key 0 (arbitrary, for fuzzing)
      ares_dns_rr_add_abin(rr_mut, (ares_dns_rr_key_t)0, data, size > 16 ? 16 : size);
    }
  }

  // 5. Report c-ares version
  int ver = 0;
  ares_version(&ver);

  // 6. Use file descriptors to simulate network events.
  // Here we'll create a fake channel and process some fd events with the input fd.
  ares_channel_t *channel = nullptr;
  if (ares_library_init(ARES_LIB_INIT_ALL) == ARES_SUCCESS) {
    if (ares_init_options(&channel, nullptr, 0) == ARES_SUCCESS && channel) {
      FILE *in_file = fmemopen((void *)data, size, "rb");
      if (in_file) {
        int fd = fuzz_fileno(in_file);
        ares_process_fd(channel, fd, fd);
        assert_file_closed(&in_file);;
      }
      ares_destroy(channel);
    }
    ares_library_cleanup();
  }

  // Cleanup
  if (dnsrec_dup)
    ares_dns_record_destroy(dnsrec_dup);
  if (dnsrec)
    ares_dns_record_destroy(dnsrec);

  return 0;
}

This runs into:

thread 'main' panicked at src/ast/helper.rs:161:18:
not implemented: Node {
    id: Id(0x5555567bea30),
    kind: Other,
    inner: [
        Node {
            id: Id(0x5555567be9a0),
            kind: BinaryOperator(
                BinaryOperator {
                    range: SourceRange {
                        begin: SourceLocation {
                            spelling_loc: Some(
                                BareSourceLocation {
                                    offset: 3036,
                                    file: "/root/promptfuzz/output/c-ares/work/id_000359/id_000359.infer.cc",
                                    line: 93,
                                    presumed_file: None,
                                    presumed_line: None,
                                    col: 64,
                                    tok_len: 4,
                                    included_from: None,
                                    is_macro_arg_expansion: false,
                                },
                            ),
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions