Global-buffer-overflow in `coap_parse_oscore_conf_mem` function in `src/coap_oscore.c`
grandnew opened this issue · comments
grandnew commented
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
- 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
- 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
- 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]
Jon Shallow commented
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.
Robert Scott commented
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?
Jon Shallow commented