Bug 12140 - mallopt(M_PERTURB) free() anomaly
Summary: mallopt(M_PERTURB) free() anomaly
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: malloc (show other bugs)
Version: 2.12
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-10-20 02:39 UTC by Michael Kerrisk
Modified: 2014-06-30 07:25 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
test program (566 bytes, text/plain)
2010-10-20 02:42 UTC, Michael Kerrisk
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Kerrisk 2010-10-20 02:39:40 UTC
If mallopt() is used to set M_PERTURB, then, as expected, the bytes of allocated memory are allocated to the complement of the byte in the 'value' argument.

When that memory is freed, then the bytes of the region are initialized to the byte specified in 'value'. However, there is an off-by-sizeof(size_t) error in the code: instead of initializing precisely the block of memory being freed, the block starting at p+sizeof(size_t) is initialized.

It looks like the two lines of this form in malloc/malloc.c

      free_perturb (chunk2mem(p), size - SIZE_SZ);

should instead be

      free_perturb (p, size);
Comment 1 Michael Kerrisk 2010-10-20 02:42:48 UTC
Created attachment 5071 [details]
test program

The following sample run of the attached program demonstrates the problem.

$ ./a.out 8 0x0f      # Allocate 8 bytes, M_PERTURB=0x0f
f0 f0 f0 f0 f0 f0 f0 f0 00 00 00 00 
7b 7b 7b 7b 7b 7b 7b 7b 00 00 00 00 
00 00 00 00 0f 0f 0f 0f 0f 0f 0f 0f
Comment 2 Ulrich Drepper 2010-10-25 02:37:35 UTC
I checked in a patch.
Comment 3 Michael Kerrisk 2012-03-18 20:31:24 UTC
The patch of 2010-10-25 changed the problem, but didn't remove it. The test program now produces the following output: 

$ ./a.out 8 0x0f      # Allocate 8 bytes, M_PERTURB=0x0f
f0 f0 f0 f0 f0 f0 f0 f0 00 00 00 00 
7b 7b 7b 7b 7b 7b 7b 7b 00 00 00 00 
00 00 00 00 0f 0f 0f 0f 00 00 00 00 

The last line of output should be:

0f 0f 0f 0f 0f 0f 0f 0f 00 00 00 00
Comment 4 Siddhesh Poyarekar 2012-10-17 12:34:47 UTC
This is tricky because it conflicts with the design of malloc.  The user-visible memory area is used by fd and bk pointers to make the internal free list.  I don't think there is a good way to fix this.  The best I can do is add a note in the documentation about it.
Comment 5 Michael Kerrisk 2012-10-17 12:55:27 UTC
(In reply to comment #4)
> This is tricky because it conflicts with the design of malloc.  The
> user-visible memory area is used by fd and bk pointers to make the internal
> free list.  I don't think there is a good way to fix this.  The best I can do
> is add a note in the documentation about it.

This isn't correct. I am not talking about the bytes that re used by the fd/bk pointers. This concerns what happens to the bytes in the usable malloc()ed area. Please look more closely at the test program.
Comment 6 Siddhesh Poyarekar 2012-10-17 13:02:01 UTC
Yes, that's the fun part.  The fd and bk pointers are written within the usable area for a free block - it saves 2*sizeof(void *) per chunk.  In any case, a user should not expect to be able to use them anyway for doing a check similar to what you did after free, because that is undefined - you could cause a segfault if the chunk was allocated using mmap.
Comment 7 Michael Kerrisk 2012-10-17 14:11:05 UTC
(In reply to comment #6)
> Yes, that's the fun part.  The fd and bk pointers are written within the usable
> area for a free block - it saves 2*sizeof(void *) per chunk.  In any case, a
> user should not expect to be able to use them anyway for doing a check similar
> to what you did after free, because that is undefined - you could cause a
> segfault if the chunk was allocated using mmap.

Ahhh yes, I see what you mean.

However, that begs the question: why do the values in the first 2* sizeof(void *) not look like pointers. (Okay, the zero could be a NULL pointer, but that seems unlikely.) I think imagine that the reason is this: this particular block of memory is in a FASTBIN, and IIRC, pointers are used there, just bitmaps of free and in use slots. Sound reasonable?
Comment 8 Siddhesh Poyarekar 2012-10-17 14:33:13 UTC
(In reply to comment #7)
> However, that begs the question: why do the values in the first 2* sizeof(void
> *) not look like pointers. (Okay, the zero could be a NULL pointer, but that
> seems unlikely.) I think imagine that the reason is this: this particular block
> of memory is in a FASTBIN, and IIRC, pointers are used there, just bitmaps of
> free and in use slots. Sound reasonable?

They're NULL pointers as you guessed, since the fastbins are empty in this case.  In a more elaborate usage, you'll find actual pointers there, especially if a block is used long enough after it has been freed.
Comment 9 Siddhesh Poyarekar 2012-10-18 02:59:57 UTC
Resolved with an update in the documentation.  It should appear on the website with the 2.17 release:

http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b741de23e214763ba4ffcd95829315dd315897ea