Project: libyang (cesnet/libyang), language: c++
Vulnerability instance: libyang.cve-2023-26916
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/CESNET/libyang/issues/1979
## Description:
Issue: CESNET/libyang#1979
Title: `lys_implement`: NULL pointer dereference via `lys_parse_mem`
State: closed
Created by: thonsun
Created at: 2023-02-11 09:30:34+00:00
Labels: is:bug, status:completed

Issue Body:
Hello, I find a null pointer derefence error in `lys_implement()` when I try to fuzz libyang via `lys_parse_mem.c` .In function `lys_implement()`, it doesn't check whether the value of  mod->revision is NULL. In some cases, it can be NULL, which leads to the operation of `strcmp(m->revision, mod->revision) > 0`  in line 1760 that results in a crash:
```bash
AddressSanitizer:DEADLYSIGNAL
=================================================================
==147319==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000004b9215 bp 0x7ffd6b71ad90 sp 0x7ffd6b71a530 T0)
==147319==The signal is caused by a READ memory access.
==147319==Hint: address points to the zero page.
    #0 0x4b9215 in strcmp (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x4b9215)
    #1 0x650885 in lys_implement /home/thonsun/Fuzz-Codehub/libyang-2.1.30/src/schema_compile.c:1760:44
    #2 0x70f919 in _lys_set_implemented /home/thonsun/Fuzz-Codehub/libyang-2.1.30/src/tree_schema.c:765:9
    #3 0x72417c in lys_parse /home/thonsun/Fuzz-Codehub/libyang-2.1.30/src/tree_schema.c:1917:11
    #4 0x724c59 in lys_parse_mem /home/thonsun/Fuzz-Codehub/libyang-2.1.30/src/tree_schema.c:1951:11
    #5 0x54dd9c in LLVMFuzzerTestOneInput (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x54dd9c)
    #6 0x4587b1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x4587b1)
    #7 0x457ef5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x457ef5)
    #8 0x45a197 in fuzzer::Fuzzer::MutateAndTestOne() (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x45a197)
    #9 0x45ae95 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x45ae95)
    #10 0x44984e in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x44984e)
    #11 0x472692 in main (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x472692)
    #12 0x7fc39e6fa082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #13 0x41e5ed in _start (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x41e5ed)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/lys_parse_mem+0x4b9215) in strcmp
==147319==ABORTING
```
And a gdb debug details:
```bash
Breakpoint 1, lys_implement (mod=0x60c000010180, features=0x0, unres=0x6130000000a0)
    at /home/thonsun/Fuzz-Codehub/libyang-2.1.30/src/schema_compile.c:1760
1760            if (!strcmp(mod->name, "yang") && (strcmp(m->revision, mod->revision) > 0)) {
(gdb) p *mod
$3 = {
  ctx = 0x613000000040,
  name = 0x602000000110 "yang",
  revision = 0x0,
  ns = 0x60d000008170 "ht/www.example.c;\n-versin~ 0.1   container", 'L' <repeats 40 times>, "re lse;\nif-feature ", 'D' <repeats 12 times>, ",DDLLLLLLLLLTL)ont1 { //x",
  prefix = 0x602000002c30 "abc",
  filepath = 0x60b00000a3e0 "/home/thonsun/Fuzz-Codehub/libyang-2.1.30/tests/fuzz/crash-7fb621a3b64179d326e4322e6edaa5ae0d9ca840",
  org = 0x0,
  contact = 0x0,
  dsc = 0x0,
  ref = 0x0,
  parsed = 0x60c000010240,
  compiled = 0x0,
  identities = 0x0,
  augmented_by = 0x0,
  deviated_by = 0x0,
  implemented = 0 '\000',
  to_compile = 0 '\000',
  latest_revision = 0 '\000'
}
(gdb)
```


Comments:
Comment by michalvasko on 2023-02-13 09:26:45+00:00:
Right, only a fuzzer could have found this use-case. It should be fixed now because I have completely removed the check, it allowed for 2 modules with the same name and namespace to be implemented.

---

Comment by abergmann on 2023-04-04 05:33:52+00:00:
[CVE-2023-26916](https://nvd.nist.gov/vuln/detail/CVE-2023-26916) was assigned to this issue.

Commit References:
7fb621a3b64179d326e4322e6edaa5ae0d9ca840

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
sed -i 's/add_subdirectory/#add_subdirectory/g' ./tools/CMakeLists.txt
mkdir -p build && cd build
cmake ../ -DENABLE_STATIC=ON
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y autoconf automake libtool subversion
RUN git clone https://github.com/cesnet/libyang libyang
RUN git -C libyang checkout a0cc89516ab5eca84d01c85309f320a94752a64c
WORKDIR $SRC/libyang
COPY build.sh $SRC/

Additional files: