From patchwork Mon Nov 23 15:42:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Earnshaw X-Patchwork-Id: 41153 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E58AF386F825; Mon, 23 Nov 2020 15:43:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E58AF386F825 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1606146181; bh=dk1oOCp024lGIJEoomSIIBQm6VbjKpShF4O/stQ4sKA=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=X5JwXfMqBkpE5JZfiqS1U60CMjgdixGfawz1L9ysnOtSmBpvgy7a6mgF2eeHnfJvE rIcUkl5Rz6RMYgb6iTP8efD3sZdLAjZl26/Doyh9pF2AwmKPESvJMILfC62e9g0fod eaBTL4/aVdmbhE9ho/XfBodlFUDCw4AfcOyp0xD0= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 19CF3386F81C for ; Mon, 23 Nov 2020 15:42:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 19CF3386F81C Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CC43914BF; Mon, 23 Nov 2020 07:42:56 -0800 (PST) Received: from eagle.buzzard.freeserve.co.uk (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1F4073F718; Mon, 23 Nov 2020 07:42:56 -0800 (PST) To: libc-alpha@sourceware.org Subject: [PATCH v3 4/8] malloc: Clean up commentary Date: Mon, 23 Nov 2020 15:42:32 +0000 Message-Id: <20201123154236.25809-5-rearnsha@arm.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201123154236.25809-1-rearnsha@arm.com> References: <20201123154236.25809-1-rearnsha@arm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Richard Earnshaw via Libc-alpha From: Richard Earnshaw Reply-To: Richard Earnshaw Cc: Richard Earnshaw Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" This patch will be merged with its predecessor before being committed, it is kept separate for now to ease reviewing. --- malloc/arena.c | 8 +++ malloc/malloc.c | 112 +++++++++++++++++++++++++++++------- sysdeps/generic/libc-mtag.h | 2 +- 3 files changed, 101 insertions(+), 21 deletions(-) diff --git a/malloc/arena.c b/malloc/arena.c index 835fcc0fb3..e348b10978 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -288,6 +288,10 @@ libc_hidden_proto (_dl_open_hook); #endif #ifdef _LIBC_MTAG + +/* Generate a new (random) tag value for PTR and tag the memory it + points to upto __malloc_usable_size (PTR). Return the newly tagged + pointer. */ static void * __mtag_tag_new_usable (void *ptr) { @@ -297,6 +301,10 @@ __mtag_tag_new_usable (void *ptr) return ptr; } +/* Generate a new (random) tag value for PTR, set the tags for the + memory to the new tag and initialize the memory contents to VAL. + In practice this function will only be called with VAL=0, but we + keep this parameter to maintain the same prototype as memset. */ static void * __mtag_tag_new_memset (void *ptr, int val, size_t size) { diff --git a/malloc/malloc.c b/malloc/malloc.c index b866e87bc3..deabeb010b 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -381,7 +381,65 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line, void * __default_morecore (ptrdiff_t); void *(*__morecore)(ptrdiff_t) = __default_morecore; +/* Memory tagging. */ + +/* Some systems support the concept of tagging (sometimes known as + coloring) memory locations on a fine grained basis. Each memory + location is given a color (normally allocated randomly) and + pointers are also colored. When the pointer is dereferenced, the + pointer's color is checked against the memory's color and if they + differ the access is faulted (sometimes lazily). + + We use this in glibc by maintaining a single color for the malloc + data structures that are interleaved with the user data and then + assigning separate colors for each block allocation handed out. In + this way simple buffer overruns will be rapidly detected. When + memory is freed, the memory is recolored back to the glibc default + so that simple use-after-free errors can also be detected. + + If memory is reallocated the buffer is recolored even if the + address remains the same. This has a performance impact, but + guarantees that the old pointer cannot mistakenly be reused (code + that compares old against new will see a mismatch and will then + need to behave as though realloc moved the data to a new location). + + Internal API for memory tagging support. + + The aim is to keep the code for memory tagging support as close to + the normal APIs in glibc as possible, so that if tagging is not + enabled in the library, or is disabled at runtime then standard + operations can continue to be used. Support macros are used to do + this: + + void *TAG_NEW_MEMSET (void *ptr, int, val, size_t size) + + Has the same interface as memset(), but additionally allocates a + new tag, colors the memory with that tag and returns a pointer that + is correctly colored for that location. The non-tagging version + will simply call memset. + + void *TAG_REGION (void *ptr, size_t size) + + Color the region of memory pointed to by PTR and size SIZE with + the color of PTR. Returns the original pointer. + + void *TAG_NEW_USABLE (void *ptr) + + Allocate a new random color and use it to color the region of + memory starting at PTR and of size __malloc_usable_size() with that + color. Returns PTR suitably recolored for accessing the memory there. + + void *TAG_AT (void *ptr) + + Read the current color of the memory at the address pointed to by + PTR (ignoring it's current color) and return PTR recolored to that + color. PTR must be valid address in all other respects. When + tagging is not enabled, it simply returns the original pointer. +*/ + #ifdef _LIBC_MTAG + +/* Default implementaions when memory tagging is supported, but disabled. */ static void * __default_tag_region (void *ptr, size_t size) { @@ -413,21 +471,6 @@ static void *(*__tag_at)(void *) = __default_tag_nop; # define TAG_AT(ptr) (ptr) #endif -/* When using tagged memory, we cannot share the end of the user block - with the header for the next chunk, so ensure that we allocate - blocks that are rounded up to the granule size. Take care not to - overflow from close to MAX_SIZE_T to a small number. */ -static inline size_t -ROUND_UP_ALLOCATION_SIZE(size_t bytes) -{ -#ifdef _LIBC_MTAG - return (bytes + ~__mtag_granule_mask) & __mtag_granule_mask; -#else - return bytes; -#endif -} - - #include /* @@ -1234,10 +1277,26 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---------- Size and alignment checks and conversions ---------- */ -/* conversion from malloc headers to user pointers, and back */ +/* Conversion from malloc headers to user pointers, and back. When + using memory tagging the user data and the malloc data structure + headers have distinct tags. Converting fully from one to the other + involves extracting the tag at the other address and creating a + suitable pointer using it. That can be quite expensive. There are + many occasions, though when the pointer will not be dereferenced + (for example, because we only want to assert that the pointer is + correctly aligned). In these cases it is more efficient not + to extract the tag, since the answer will be the same either way. + chunk2rawmem() can be used in these cases. + */ -#define chunk2mem(p) ((void*)TAG_AT (((char*)(p) + 2*SIZE_SZ))) +/* Convert a user mem pointer to a chunk address without correcting + the tag. */ #define chunk2rawmem(p) ((void*)((char*)(p) + 2*SIZE_SZ)) + +/* Convert between user mem pointers and chunk pointers, updating any + memory tags on the pointer to respect the tag value at that + location. */ +#define chunk2mem(p) ((void*)TAG_AT (((char*)(p) + 2*SIZE_SZ))) #define mem2chunk(mem) ((mchunkptr)TAG_AT (((char*)(mem) - 2*SIZE_SZ))) /* The smallest possible chunk */ @@ -1257,7 +1316,8 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ & MALLOC_ALIGN_MASK) /* pad request bytes into a usable size -- internal version */ - +/* Note: This must be a macro that evaluates to a compile time constant + if passed a literal constant. */ #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ @@ -1272,7 +1332,18 @@ checked_request2size (size_t req, size_t *sz) __nonnull (1) { if (__glibc_unlikely (req > PTRDIFF_MAX)) return false; - req = ROUND_UP_ALLOCATION_SIZE (req); + +#ifdef _LIBC_MTAG + /* When using tagged memory, we cannot share the end of the user + block with the header for the next chunk, so ensure that we + allocate blocks that are rounded up to the granule size. Take + care not to overflow from close to MAX_SIZE_T to a small + number. Ideally, this would be part of request2size(), but that + must be a macro that produces a compile time constant if passed + a constant literal. */ + req = (req + ~__mtag_granule_mask) & __mtag_granule_mask; +#endif + *sz = request2size (req); return true; } @@ -3391,6 +3462,7 @@ _mid_memalign (size_t alignment, size_t bytes, void *address) return 0; } + /* Make sure alignment is power of 2. */ if (!powerof2 (alignment)) { @@ -4784,7 +4856,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, check_inuse_chunk (av, newp); return TAG_NEW_USABLE (chunk2rawmem (newp)); - } +} /* ------------------------------ memalign ------------------------------ diff --git a/sysdeps/generic/libc-mtag.h b/sysdeps/generic/libc-mtag.h index 3e9885451c..07f0203253 100644 --- a/sysdeps/generic/libc-mtag.h +++ b/sysdeps/generic/libc-mtag.h @@ -1,5 +1,5 @@ /* libc-internal interface for tagged (colored) memory support. - Copyright (C) 2019 Free Software Foundation, Inc. + Copyright (C) 2020 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or