Skip to content

Commit 79d9a72

Browse files
montywivuvova
authored andcommitted
Added checking to protect against simultaneous double free in safemalloc
If two threads would call sf_free() / free_memory() at the same time, bad_ptr() would not detect this. Fixed by adding extra detection when working with the memory region under sf_mutex. Other things: - If safe_malloc crashes while mutex is hold, stack trace printing will hang because we malloc is called by my_open(), which is used by stack trace printing code. Fixed by adding MY_NO_REGISTER flag to my_open, which will disable the malloc() call to remmeber the file name.
1 parent 744a538 commit 79d9a72

File tree

4 files changed

+21
-6
lines changed

4 files changed

+21
-6
lines changed

include/my_sys.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ C_MODE_START
7474
#define MY_SHORT_WAIT64U/* my_lock() don't wait if can't lock */
7575
#define MY_FORCE_LOCK 128U /* use my_lock() even if disable_locking */
7676
#define MY_NO_WAIT 256U/* my_lock() don't wait at all */
77+
#define MY_NO_REGISTER 8196U /* my_open(), no malloc for file name */
7778
/*
7879
If old_mode is UTF8_IS_UTF8MB3, then pass this flag. It mean utf8 is
7980
alias for utf8mb3. Otherwise utf8 is alias for utf8mb4.

mysys/my_open.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
135135
if ((int) fd >= MY_FILE_MIN)
136136
{
137137
my_atomic_add32_explicit(&my_file_opened, 1, MY_MEMORY_ORDER_RELAXED);
138-
if ((uint) fd >= my_file_limit)
138+
if ((uint) fd >= my_file_limit || (MyFlags & MY_NO_REGISTER))
139139
DBUG_RETURN(fd);
140140
my_file_info[fd].name = my_strdup(key_memory_my_file_info, FileName, MyFlags);
141141
statistic_increment(my_file_total_opened,&THR_LOCK_open);

mysys/safemalloc.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static void *sf_min_adress= (void*) (intptr)~0ULL,
7878
static struct st_irem *sf_malloc_root = 0;
7979

8080
#define MAGICSTART 0x14235296 /* A magic value for underrun key */
81+
#define MAGICEND 0x12345678 /* Value for freed block */
8182

8283
#define MAGICEND0 0x68 /* Magic values for overrun keys */
8384
#define MAGICEND1 0x34 /* " */
@@ -255,6 +256,7 @@ static void print_stack(void **frame)
255256
static void free_memory(void *ptr)
256257
{
257258
struct st_irem *irem= (struct st_irem *)ptr - 1;
259+
size_t end_offset;
258260

259261
if ((irem->flags & MY_THREAD_SPECIFIC) && irem->thread_id &&
260262
irem->thread_id != sf_malloc_dbug_id())
@@ -266,6 +268,14 @@ static void free_memory(void *ptr)
266268
}
267269

268270
pthread_mutex_lock(&sf_mutex);
271+
/* Protect against double free at same time */
272+
if (irem->marker != MAGICSTART)
273+
{
274+
pthread_mutex_unlock(&sf_mutex); /* Allow stack trace alloc mem */
275+
DBUG_ASSERT(irem->marker == MAGICSTART); /* Crash */
276+
pthread_mutex_lock(&sf_mutex); /* Impossible, but safer */
277+
}
278+
269279
/* Remove this structure from the linked list */
270280
if (irem->prev)
271281
irem->prev->next= irem->next;
@@ -277,10 +287,13 @@ static void free_memory(void *ptr)
277287

278288
/* Handle the statistics */
279289
sf_malloc_count--;
290+
291+
irem->marker= MAGICEND; /* Double free detection */
280292
pthread_mutex_unlock(&sf_mutex);
281293

282-
/* only trash the data and magic values, but keep the stack trace */
283-
TRASH_FREE((uchar*)(irem + 1) - 4, irem->datasize + 8);
294+
/* Trash the data and magic values, but keep the stack trace */
295+
end_offset= sizeof(*irem) - ((char*) &irem->marker - (char*) irem);
296+
TRASH_FREE((uchar*)(irem + 1) - end_offset, irem->datasize + 4 + end_offset);
284297
free(irem);
285298
return;
286299
}

sql/signal_handler.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ static inline void output_core_info()
6565
(int) len, buff);
6666
}
6767
#ifdef __FreeBSD__
68-
if ((fd= my_open("/proc/curproc/rlimit", O_RDONLY, MYF(0))) >= 0)
68+
if ((fd= my_open("/proc/curproc/rlimit", O_RDONLY, MYF(MY_NO_REGISTER))) >= 0)
6969
#else
70-
if ((fd= my_open("/proc/self/limits", O_RDONLY, MYF(0))) >= 0)
70+
if ((fd= my_open("/proc/self/limits", O_RDONLY, MYF(MY_NO_REGISTER))) >= 0)
7171
#endif
7272
{
7373
my_safe_printf_stderr("Resource Limits:\n");
@@ -78,7 +78,8 @@ static inline void output_core_info()
7878
my_close(fd, MYF(0));
7979
}
8080
#ifdef __linux__
81-
if ((fd= my_open("/proc/sys/kernel/core_pattern", O_RDONLY, MYF(0))) >= 0)
81+
if ((fd= my_open("/proc/sys/kernel/core_pattern", O_RDONLY,
82+
MYF(MY_NO_REGISTER))) >= 0)
8283
{
8384
len= my_read(fd, (uchar*)buff, sizeof(buff), MYF(0));
8485
my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);

0 commit comments

Comments
 (0)