request2size can cause unintentional overflow in the program

just4you just4you_jongun@protonmail.com
Tue Nov 11 12:09:23 GMT 2025


// demo


#include <stdio.h>

#define INTERNAL_SIZE_T         size_t

struct malloc_chunk {
    INTERNAL_SIZE_T         mchunk_prev_size;
    INTERNAL_SIZE_T         mchunk_size;
    struct malloc_chunk*    fd;
    struct malloc_chunk*    bk;
    struct malloc_chunk*    fd_nextsize;
    struct malloc_chunk*    bk_nextsize;
};

#define SIZE_SZ                 (sizeof (INTERNAL_SIZE_T))
#define CHUNK_HDR_SZ            (2 * SIZE_SZ)
#define MALLOC_ALIGNMENT        (2 * SIZE_SZ < __alignof__ (long double) ? __alignof__ (long double) : 2 * SIZE_SZ)
#define MALLOC_ALIGN_MASK       (MALLOC_ALIGNMENT - 1)
#define offsetof(type,ident)    ((size_t)&(((type*)0)->ident))
#define MIN_CHUNK_SIZE          (offsetof(struct malloc_chunk, fd_nextsize))
#define MINSIZE                 (unsigned long)(((MIN_CHUNK_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))

#define request2size(req)                                       \
    (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?         \
    MINSIZE : ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

#define ALLOC_LEN_A             0x36
#define ALLOC_LEN_B             0x39

static void request2size_run(int alloc_size)
{
    int real_size, usable_size;

    real_size = (int) request2size(alloc_size);
    printf("actual size obtained = 0x%x\n", real_size);

    usable_size = real_size - CHUNK_HDR_SZ;
    printf("actual usable size = 0x%x\n", real_size);

    if (usable_size < alloc_size) {
        printf("when alloc size 0x%x, marco [request2size] gave us an incorrect value\n", alloc_size);
    }
    else {
        printf("alloc size 0x%x succeed, has enough space to use\n", alloc_size);
    }
}

int main(void)
{
    printf("a demo used to expose the dangers of request2size\n");

    request2size_run(ALLOC_LEN_A);
    request2size_run(ALLOC_LEN_B);

    return 0;
}


/* stdout:a demo used to expose the dangers of request2size
actual size obtained = 0x40
actual usable size = 0x40
when alloc size 0x36, marco [request2size] gave us an incorrect value
actual size obtained = 0x50
actual usable size = 0x50
alloc size 0x39 succeed, has enough space to use */


problem description:
I'm learning about off-by-one operations in heap scenarios. While understanding the `request2size` macro, I noticed that during the size conversion process, it splits the value into the form `n * 0x10 + x`. For example, 0x36 becomes `0x3 * 0x10 + 0x6`, then offsets upwards and aligns with `MALLOC_ALIGN_MASK`.

 If `x` is less than or equal to 8, the `request2size` macro returns `(n + 1) * 0x10` as the chunk size. However, because the chunk needs to reserve space for `CHUNK_HDR_SZ`, the actual usable space is only `n * 0x10`, which is `x` bytes less than the actual required space.
 This situation can cause unintentional overflow in the program.


my patch:

+ #ifdef MALLOC_SECURE
+ #define request2size_secure(req) \
+   ((((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + \
+    ((req) > ((((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) - SIZE_SZ) ? \
+     MALLOC_ALIGNMENT : 0))
+ #endif

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20251111/a00a9b09/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: publickey - just4you_jongun@protonmail.com - 0xA0C5999E.asc
Type: application/pgp-keys
Size: 868 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20251111/a00a9b09/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 343 bytes
Desc: OpenPGP digital signature
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20251111/a00a9b09/attachment-0001.sig>


More information about the Libc-alpha mailing list