summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2014-01-09 21:37:07 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2014-01-16 10:17:39 +0100
commit7ab237b025cbb4c25d345604da32e894379c1721 (patch)
tree92d147029519c55d57db4273066d57b960ad7158
parent7f5dce4116bf4e62e0cd3ef16730157e17625e1c (diff)
downloadrockbox-7ab237b025cbb4c25d345604da32e894379c1721.tar.gz
rockbox-7ab237b025cbb4c25d345604da32e894379c1721.zip
buflib: Add crc field protecting buflib cookie integrity
This should catch the case of buffer misuse which results in corrupted cookie of next allocation. The check is performed on move_block() so it may be a bit late. There is buflib_check_valid() provided which checks the integrity of all cookies for given context. On DEBUG build with --sdl-thread this check is carried out for core_ctx on every context switch to catch problems earlier. Change-Id: I999d4576084592394e3dbd3bdf0f32935ff5f601 Reviewed-on: http://gerrit.rockbox.org/711 Reviewed-by: Thomas Martitz <kugel@rockbox.org>
-rw-r--r--apps/plugin.h2
-rw-r--r--firmware/buflib.c72
-rw-r--r--firmware/common/crc32.c4
-rw-r--r--firmware/core_alloc.c7
-rw-r--r--firmware/include/buflib.h6
-rw-r--r--firmware/include/core_alloc.h3
-rw-r--r--firmware/include/crc32.h4
-rw-r--r--firmware/target/hosted/sdl/thread-sdl.c4
-rw-r--r--firmware/thread.c6
9 files changed, 95 insertions, 13 deletions
diff --git a/apps/plugin.h b/apps/plugin.h
index 8a0d0562ff..1d1e9ee26e 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -457,7 +457,7 @@ struct plugin_api {
457 int numberlen IF_CNFN_NUM_(, int *num)); 457 int numberlen IF_CNFN_NUM_(, int *num));
458 bool (*file_exists)(const char *file); 458 bool (*file_exists)(const char *file);
459 char* (*strip_extension)(char* buffer, int buffer_size, const char *filename); 459 char* (*strip_extension)(char* buffer, int buffer_size, const char *filename);
460 unsigned (*crc_32)(const void *src, unsigned len, unsigned crc32); 460 uint32_t (*crc_32)(const void *src, uint32_t len, uint32_t crc32);
461 461
462 int (*filetype_get_attr)(const char* file); 462 int (*filetype_get_attr)(const char* file);
463 463
diff --git a/firmware/buflib.c b/firmware/buflib.c
index db09d3efc9..0a87a4c4d8 100644
--- a/firmware/buflib.c
+++ b/firmware/buflib.c
@@ -31,6 +31,8 @@
31#include "buflib.h" 31#include "buflib.h"
32#include "string-extra.h" /* strlcpy() */ 32#include "string-extra.h" /* strlcpy() */
33#include "debug.h" 33#include "debug.h"
34#include "panic.h"
35#include "crc32.h"
34#include "system.h" /* for ALIGN_*() */ 36#include "system.h" /* for ALIGN_*() */
35 37
36/* The main goal of this design is fast fetching of the pointer for a handle. 38/* The main goal of this design is fast fetching of the pointer for a handle.
@@ -54,13 +56,14 @@
54 * 56 *
55 * Example: 57 * Example:
56 * |<- alloc block #1 ->|<- unalloc block ->|<- alloc block #2 ->|<-handle table->| 58 * |<- alloc block #1 ->|<- unalloc block ->|<- alloc block #2 ->|<-handle table->|
57 * |L|H|C|cccc|L2|XXXXXX|-L|YYYYYYYYYYYYYYYY|L|H|C|cc|L2|XXXXXXXXXXXXX|AAA| 59 * |L|H|C|cccc|L2|crc|XXXXXX|-L|YYYYYYYYYYYYYYYY|L|H|C|cc|L2|crc|XXXXXXXXXXXXX|AAA|
58 * 60 *
59 * L - length marker (negative if block unallocated) 61 * L - length marker (negative if block unallocated)
60 * H - handle table enry pointer 62 * H - handle table enry pointer
61 * C - pointer to struct buflib_callbacks 63 * C - pointer to struct buflib_callbacks
62 * c - variable sized string identifier 64 * c - variable sized string identifier
63 * L2 - second length marker for string identifier 65 * L2 - second length marker for string identifier
66 * crc - crc32 protecting buflib cookie integrity
64 * X - actual payload 67 * X - actual payload
65 * Y - unallocated space 68 * Y - unallocated space
66 * 69 *
@@ -224,8 +227,17 @@ static bool
224move_block(struct buflib_context* ctx, union buflib_data* block, int shift) 227move_block(struct buflib_context* ctx, union buflib_data* block, int shift)
225{ 228{
226 char* new_start; 229 char* new_start;
227 union buflib_data *new_block, *tmp = block[1].handle; 230 union buflib_data *new_block, *tmp = block[1].handle, *crc_slot;
228 struct buflib_callbacks *ops = block[2].ops; 231 struct buflib_callbacks *ops = block[2].ops;
232 crc_slot = (union buflib_data*)tmp->alloc - 1;
233 int cookie_size = (crc_slot - block)*sizeof(union buflib_data);
234 uint32_t crc = crc_32((void *)block, cookie_size, 0xffffffff);
235
236 /* check for cookie validity */
237 if (crc != crc_slot->crc)
238 panicf("buflib cookie corrupted, crc: 0x%08x, expected: 0x%08x",
239 (unsigned int)crc, (unsigned int)crc_slot->crc);
240
229 if (!IS_MOVABLE(block)) 241 if (!IS_MOVABLE(block))
230 return false; 242 return false;
231 243
@@ -299,6 +311,7 @@ buflib_compact(struct buflib_context *ctx)
299 ret = true; 311 ret = true;
300 /* Move was successful. The memory at block is now free */ 312 /* Move was successful. The memory at block is now free */
301 block->val = -len; 313 block->val = -len;
314
302 /* add its length to shift */ 315 /* add its length to shift */
303 shift += -len; 316 shift += -len;
304 /* Reduce the size of the hole accordingly 317 /* Reduce the size of the hole accordingly
@@ -474,9 +487,9 @@ buflib_alloc_ex(struct buflib_context *ctx, size_t size, const char *name,
474 size += name_len; 487 size += name_len;
475 size = (size + sizeof(union buflib_data) - 1) / 488 size = (size + sizeof(union buflib_data) - 1) /
476 sizeof(union buflib_data) 489 sizeof(union buflib_data)
477 /* add 4 objects for alloc len, pointer to handle table entry and 490 /* add 5 objects for alloc len, pointer to handle table entry and
478 * name length, and the ops pointer */ 491 * name length, the ops pointer and crc */
479 + 4; 492 + 5;
480handle_alloc: 493handle_alloc:
481 handle = handle_alloc(ctx); 494 handle = handle_alloc(ctx);
482 if (!handle) 495 if (!handle)
@@ -555,14 +568,22 @@ buffer_alloc:
555 /* Set up the allocated block, by marking the size allocated, and storing 568 /* Set up the allocated block, by marking the size allocated, and storing
556 * a pointer to the handle. 569 * a pointer to the handle.
557 */ 570 */
558 union buflib_data *name_len_slot; 571 union buflib_data *name_len_slot, *crc_slot;
559 block->val = size; 572 block->val = size;
560 block[1].handle = handle; 573 block[1].handle = handle;
561 block[2].ops = ops; 574 block[2].ops = ops;
562 strcpy(block[3].name, name); 575 strcpy(block[3].name, name);
563 name_len_slot = (union buflib_data*)B_ALIGN_UP(block[3].name + name_len); 576 name_len_slot = (union buflib_data*)B_ALIGN_UP(block[3].name + name_len);
564 name_len_slot->val = 1 + name_len/sizeof(union buflib_data); 577 name_len_slot->val = 1 + name_len/sizeof(union buflib_data);
565 handle->alloc = (char*)(name_len_slot + 1); 578 crc_slot = (union buflib_data*)(name_len_slot + 1);
579 crc_slot->crc = crc_32((void *)block,
580 (crc_slot - block)*sizeof(union buflib_data),
581 0xffffffff);
582 handle->alloc = (char*)(crc_slot + 1);
583
584 BDEBUGF("buflib_alloc_ex: size=%d handle=%p clb=%p crc=0x%0x name=\"%s\"\n",
585 (unsigned int)size, (void *)handle, (void *)ops,
586 (unsigned int)crc_slot->crc, block[3].name);
566 587
567 block += size; 588 block += size;
568 /* alloc_end must be kept current if we're taking the last block. */ 589 /* alloc_end must be kept current if we're taking the last block. */
@@ -778,6 +799,8 @@ buflib_alloc_maximum(struct buflib_context* ctx, const char* name, size_t *size,
778bool 799bool
779buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t new_size) 800buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t new_size)
780{ 801{
802 union buflib_data *crc_slot;
803 int cookie_size;
781 char* oldstart = buflib_get_data(ctx, handle); 804 char* oldstart = buflib_get_data(ctx, handle);
782 char* newstart = new_start; 805 char* newstart = new_start;
783 char* newend = newstart + new_size; 806 char* newend = newstart + new_size;
@@ -823,6 +846,11 @@ buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t ne
823 block = new_block; 846 block = new_block;
824 } 847 }
825 848
849 /* update crc of the cookie */
850 crc_slot = (union buflib_data*)new_block[1].handle->alloc - 1;
851 cookie_size = (crc_slot - new_block)*sizeof(union buflib_data);
852 crc_slot->crc = crc_32((void *)new_block, cookie_size, 0xffffffff);
853
826 /* Now deal with size changes that create free blocks after the allocation */ 854 /* Now deal with size changes that create free blocks after the allocation */
827 if (old_next_block != new_next_block) 855 if (old_next_block != new_next_block)
828 { 856 {
@@ -847,11 +875,37 @@ const char* buflib_get_name(struct buflib_context *ctx, int handle)
847 union buflib_data *data = ALIGN_DOWN(buflib_get_data(ctx, handle), sizeof (*data)); 875 union buflib_data *data = ALIGN_DOWN(buflib_get_data(ctx, handle), sizeof (*data));
848 if (!data) 876 if (!data)
849 return NULL; 877 return NULL;
850 size_t len = data[-1].val; 878 size_t len = data[-2].val;
851 if (len <= 1) 879 if (len <= 1)
852 return NULL; 880 return NULL;
853 return data[-len].name; 881 return data[-len-1].name;
882}
883
884#ifdef DEBUG
885void buflib_check_valid(struct buflib_context *ctx)
886{
887 union buflib_data *crc_slot;
888 int cookie_size;
889 uint32_t crc;
890
891 for(union buflib_data* this = ctx->buf_start;
892 this < ctx->alloc_end;
893 this += abs(this->val))
894 {
895 if (this->val < 0)
896 continue;
897
898 crc_slot = (union buflib_data*)
899 ((union buflib_data*)this[1].handle)->alloc - 1;
900 cookie_size = (crc_slot - this)*sizeof(union buflib_data);
901 crc = crc_32((void *)this, cookie_size, 0xffffffff);
902
903 if (crc != crc_slot->crc)
904 panicf("buflib check crc: 0x%08x, expected: 0x%08x",
905 (unsigned int)crc, (unsigned int)crc_slot->crc);
906 }
854} 907}
908#endif
855 909
856#ifdef BUFLIB_DEBUG_BLOCKS 910#ifdef BUFLIB_DEBUG_BLOCKS
857void buflib_print_allocs(struct buflib_context *ctx, 911void buflib_print_allocs(struct buflib_context *ctx,
diff --git a/firmware/common/crc32.c b/firmware/common/crc32.c
index 1cd0ca0bd5..c8c70e415c 100644
--- a/firmware/common/crc32.c
+++ b/firmware/common/crc32.c
@@ -25,7 +25,7 @@
25 25
26/* Tool function to calculate a CRC32 across some buffer */ 26/* Tool function to calculate a CRC32 across some buffer */
27/* third argument is either 0xFFFFFFFF to start or value from last piece */ 27/* third argument is either 0xFFFFFFFF to start or value from last piece */
28unsigned crc_32(const void *src, unsigned len, unsigned crc32) 28uint32_t crc_32(const void *src, uint32_t len, uint32_t crc32)
29{ 29{
30 const unsigned char *buf = (const unsigned char *)src; 30 const unsigned char *buf = (const unsigned char *)src;
31 31
@@ -39,7 +39,7 @@ unsigned crc_32(const void *src, unsigned len, unsigned crc32)
39 }; 39 };
40 40
41 unsigned char byte; 41 unsigned char byte;
42 unsigned t; 42 uint32_t t;
43 43
44 while (len--) 44 while (len--)
45 { 45 {
diff --git a/firmware/core_alloc.c b/firmware/core_alloc.c
index aa662fbee5..e9f9795917 100644
--- a/firmware/core_alloc.c
+++ b/firmware/core_alloc.c
@@ -96,3 +96,10 @@ void core_print_block_at(int block_num, char* buf, size_t bufsize)
96{ 96{
97 buflib_print_block_at(&core_ctx, block_num, buf, bufsize); 97 buflib_print_block_at(&core_ctx, block_num, buf, bufsize);
98} 98}
99
100#ifdef DEBUG
101void core_check_valid(void)
102{
103 buflib_check_valid(&core_ctx);
104}
105#endif
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h
index 0b26c04bcd..171ab5bcd7 100644
--- a/firmware/include/buflib.h
+++ b/firmware/include/buflib.h
@@ -40,6 +40,7 @@ union buflib_data
40 struct buflib_callbacks* ops; 40 struct buflib_callbacks* ops;
41 char* alloc; 41 char* alloc;
42 union buflib_data *handle; 42 union buflib_data *handle;
43 uint32_t crc;
43}; 44};
44 45
45struct buflib_context 46struct buflib_context
@@ -346,4 +347,9 @@ int buflib_get_num_blocks(struct buflib_context *ctx);
346 */ 347 */
347void buflib_print_block_at(struct buflib_context *ctx, int block_num, 348void buflib_print_block_at(struct buflib_context *ctx, int block_num,
348 char* buf, size_t bufsize); 349 char* buf, size_t bufsize);
350
351/**
352 * Check integrity of given buflib context
353 */
354void buflib_check_valid(struct buflib_context *ctx);
349#endif 355#endif
diff --git a/firmware/include/core_alloc.h b/firmware/include/core_alloc.h
index a100b7cc6c..095cb5da11 100644
--- a/firmware/include/core_alloc.h
+++ b/firmware/include/core_alloc.h
@@ -17,6 +17,9 @@ bool core_shrink(int handle, void* new_start, size_t new_size);
17int core_free(int handle); 17int core_free(int handle);
18size_t core_available(void); 18size_t core_available(void);
19size_t core_allocatable(void); 19size_t core_allocatable(void);
20#ifdef DEBUG
21void core_check_valid(void);
22#endif
20 23
21/* DO NOT ADD wrappers for buflib_buffer_out/in. They do not call 24/* DO NOT ADD wrappers for buflib_buffer_out/in. They do not call
22 * the move callbacks and are therefore unsafe in the core */ 25 * the move callbacks and are therefore unsafe in the core */
diff --git a/firmware/include/crc32.h b/firmware/include/crc32.h
index 034c3984ab..8e1f868988 100644
--- a/firmware/include/crc32.h
+++ b/firmware/include/crc32.h
@@ -18,10 +18,12 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdint.h>
22
21#ifndef _CRC32_H 23#ifndef _CRC32_H
22#define _CRC32_H 24#define _CRC32_H
23 25
24unsigned crc_32(const void *src, unsigned len, unsigned crc32); 26uint32_t crc_32(const void *src, uint32_t len, uint32_t crc32);
25 27
26#endif 28#endif
27 29
diff --git a/firmware/target/hosted/sdl/thread-sdl.c b/firmware/target/hosted/sdl/thread-sdl.c
index eaffa86aee..fbc26c8a9f 100644
--- a/firmware/target/hosted/sdl/thread-sdl.c
+++ b/firmware/target/hosted/sdl/thread-sdl.c
@@ -32,6 +32,7 @@
32#include "kernel.h" 32#include "kernel.h"
33#include "thread.h" 33#include "thread.h"
34#include "debug.h" 34#include "debug.h"
35#include "core_alloc.h"
35 36
36/* Define this as 1 to show informational messages that are not errors. */ 37/* Define this as 1 to show informational messages that are not errors. */
37#define THREAD_SDL_DEBUGF_ENABLED 0 38#define THREAD_SDL_DEBUGF_ENABLED 0
@@ -382,6 +383,9 @@ void switch_thread(void)
382 } /* STATE_SLEEPING: */ 383 } /* STATE_SLEEPING: */
383 } 384 }
384 385
386#ifdef DEBUG
387 core_check_valid();
388#endif
385 cores[CURRENT_CORE].running = current; 389 cores[CURRENT_CORE].running = current;
386 390
387 if (threads_status != THREADS_RUN) 391 if (threads_status != THREADS_RUN)
diff --git a/firmware/thread.c b/firmware/thread.c
index ce9252ccc6..b687144f4f 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -39,6 +39,7 @@
39#ifdef RB_PROFILE 39#ifdef RB_PROFILE
40#include <profile.h> 40#include <profile.h>
41#endif 41#endif
42#include "core_alloc.h"
42#include "gcc_extensions.h" 43#include "gcc_extensions.h"
43 44
44/**************************************************************************** 45/****************************************************************************
@@ -1161,6 +1162,11 @@ void switch_thread(void)
1161 * to this call. */ 1162 * to this call. */
1162 store_context(&thread->context); 1163 store_context(&thread->context);
1163 1164
1165#ifdef DEBUG
1166 /* Check core_ctx buflib integrity */
1167 core_check_valid();
1168#endif
1169
1164 /* Check if the current thread stack is overflown */ 1170 /* Check if the current thread stack is overflown */
1165 if (UNLIKELY(thread->stack[0] != DEADBEEF) && thread->stack_size > 0) 1171 if (UNLIKELY(thread->stack[0] != DEADBEEF) && thread->stack_size > 0)
1166 thread_stkov(thread); 1172 thread_stkov(thread);