obgm / libcoap

A CoAP (RFC 7252) implementation in C

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Global-buffer-overflow in `coap_parse_oscore_conf_mem` function in `src/coap_oscore.c`

grandnew opened this issue · comments

Environment

  • libcoap version: v4.3.1-162-g6f79db0
  • Build System: Make
  • Operating System: Linux
  • Operating System Version: Debian GNU/Linux 11 (bullseye)
  • Hosted Environment: None

Problem Description

There is a global-buffer-overflow bug in the coap_parse_oscore_conf_mem function in src/coap_oscore.c.

Expected Behavior

No crash.

Actual Behavior

Crash when enhanced with ASan.

Steps to reproduce

  1. Build libcoap with ASan
CC=clang CFLAGS="-g -fsanitize=address" ./autogen.sh
CC=clang CFLAGS="-g -fsanitize=address" ./configure --disable-doxygen --disable-manpages --enable-tests --disable-documentation --enable-examples --enable-shared
CC=clang CFLAGS="-g -fsanitize=address" make -j
  1. Compile overflow.c (as shown follows)
clang overflow.c -I/root/libcoap/include -I/root/libcoap /root/libcoap/.libs/libcoap-3-gnutls.a  /usr/local/lib/libgnutls.so -g -fsanitize=address -o overflow
  1. Run overflow and detect ASan error
==869262==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5567c1231cea at pc 0x5567c1079006 bp 0x7ffcdaa591c0 sp 0x7ffcdaa58970
READ of size 12 at 0x5567c1231cea thread T0
    #0 0x5567c1079005 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) (/root/libcoap/overflow+0x57005) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)
    #1 0x5567c10794f9 in memcmp (/root/libcoap/overflow+0x574f9) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)
    #2 0x5567c1128e03 in coap_parse_oscore_conf_mem /root/libcoap/src/coap_oscore.c:1849:11
    #3 0x5567c112849d in coap_new_oscore_conf /root/libcoap/src/coap_oscore.c:2020:37
    #4 0x5567c111ca1f in main /root/libcoap/overflow.c:24:17
    #5 0x7fb67e995d09 in __libc_start_main csu/../csu/libc-start.c:308:16
    #6 0x5567c105da29 in _start (/root/libcoap/overflow+0x3ba29) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)

0x5567c1231cea is located 54 bytes to the left of global variable '.str.74' defined in '/root/libcoap/src/coap_oscore.c:1790' (0x5567c1231d20) of size 14
  '.str.74' is ascii string 'replay_window'
0x5567c1231cea is located 22 bytes to the left of global variable '.str.73' defined in '/root/libcoap/src/coap_oscore.c:1788' (0x5567c1231d00) of size 11
  '.str.73' is ascii string 'id_context'
0x5567c1231cea is located 0 bytes to the right of global variable '.str.72' defined in '/root/libcoap/src/coap_oscore.c:1787' (0x5567c1231ce0) of size 10
  '.str.72' is ascii string 'sender_id'
SUMMARY: AddressSanitizer: global-buffer-overflow (/root/libcoap/overflow+0x57005) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25) in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long)
Shadow bytes around the buggy address:
  0x0aad7823e340: 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 04 f9 f9 f9
  0x0aad7823e350: f9 f9 f9 f9 00 00 00 00 00 00 03 f9 f9 f9 f9 f9
  0x0aad7823e360: 05 f9 f9 f9 06 f9 f9 f9 00 00 00 00 00 00 06 f9
  0x0aad7823e370: f9 f9 f9 f9 06 f9 f9 f9 04 f9 f9 f9 00 f9 f9 f9
  0x0aad7823e380: 05 f9 f9 f9 05 f9 f9 f9 00 04 f9 f9 00 00 07 f9
=>0x0aad7823e390: f9 f9 f9 f9 00 06 f9 f9 00 04 f9 f9 00[02]f9 f9
  0x0aad7823e3a0: 00 03 f9 f9 00 06 f9 f9 00 01 f9 f9 00 01 f9 f9
  0x0aad7823e3b0: 00 01 f9 f9 00 06 f9 f9 00 04 f9 f9 00 00 01 f9
  0x0aad7823e3c0: f9 f9 f9 f9 00 00 04 f9 f9 f9 f9 f9 00 00 02 f9
  0x0aad7823e3d0: f9 f9 f9 f9 00 00 02 f9 f9 f9 f9 f9 00 00 04 f9
  0x0aad7823e3e0: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==869262==ABORTING

Code to reproduce this issue

// overflow.c
#include "coap3/coap_internal.h"
#include "oscore/oscore.h"
#include "oscore/oscore_context.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
 static const char conf_data[] =
    "master_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\n"
    "master_salt,hex,\"9e7ca92223786340\"\n"
    "sender_id,hex,\"\"\n"
    "recipient_id,hex,\"01\"\n";
  const coap_str_const_t conf = { sizeof(conf_data)-1,
                                  (const uint8_t *)conf_data };
  coap_context_t ctx[1];
  coap_oscore_conf_t *oscore_conf;
  cose_encrypt0_t cose[1];
  uint8_t nonce_buffer[13];
  coap_bin_const_t nonce = { 13, nonce_buffer };

  memset(&ctx, 0, sizeof(ctx));
  oscore_conf = coap_new_oscore_conf(conf, NULL, NULL, 0);

  oscore_free_contexts(ctx);
  return 0;
}

Debug Logs

(gdb) b coap_oscore.c:1849
Breakpoint 1 at 0x106d39: file src/coap_oscore.c, line 1849.
(gdb) r
Starting program: /root/libcoap/overflow 
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
(gdb) display oscore_config[i]
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
(gdb) display keyword
2: keyword = {length = 13, 
  s = 0x562f62279660 <main.conf_data> "master_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\nmaster_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 11, s = 0x562f62279695 <main.conf_data+53> "master_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 11, s = 0x562f62279695 <main.conf_data+53> "master_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227ace0 <str> "sender_id", encoding = 3, offset = 16, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227ace0 <str> "sender_id", encoding = 3, offset = 16, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

[Then crashes]

It is appreciated that you are checking the libcoap code for potential issues and giving detail to be able to reproduce the issue. This has been fixed in #1118 which is ready for further testing.

Note that you need to add coap_context_oscore_server(ctx, oscore_conf); before oscore_free_contexts(ctx); to your overflow.c file to prevent memory leak errors being reported.

CVE-2023-35862 claims this makes 4.3.1 vulnerable, but I think I'm right in saying oscore code wasn't even present in 4.3.1?

@risicle You are correct. The OSCORE code was added in sometime after 4.3.1 was released, and this issue is fixed in #1118 which is included in 4.3.2rc1 and later..