From patchwork Tue Oct 19 15:15:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng, ZhihongX" X-Patchwork-Id: 102260 X-Patchwork-Delegate: david.marchand@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9498EA0C41; Tue, 19 Oct 2021 17:17:17 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5D24741171; Tue, 19 Oct 2021 17:17:17 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id 5DF9041164 for ; Tue, 19 Oct 2021 17:17:14 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10142"; a="227314690" X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="227314690" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:50 -0700 X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="494143997" Received: from unknown (HELO localhost.localdomain) ([10.240.183.65]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:46 -0700 From: zhihongx.peng@intel.com To: david.marchand@redhat.com, thomas@monjalon.net, anatoly.burakov@intel.com, konstantin.ananyev@intel.com, stephen@networkplumber.org, cristian.dumitrescu@intel.com, john.mcnamara@intel.com, bruce.richardson@intel.com Cc: dev@dpdk.org, xueqin.lin@intel.com, Zhihong Peng Date: Tue, 19 Oct 2021 23:15:21 +0800 Message-Id: <20211019151524.2005442-1-zhihongx.peng@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211019101207.1451058-4-zhihongx.peng@intel.com> References: <20211019101207.1451058-4-zhihongx.peng@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v12 1/4] Enable ASan AddressSanitizer X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Zhihong Peng `AddressSanitizer `_ (ASan) is a widely-used debugging tool to detect memory access errors. It helps detect issues like use-after-free, various kinds of buffer overruns in C/C++ programs, and other similar errors, as well as printing out detailed debug information whenever an error is detected. We can enable ASan by adding below compilation options: -Dbuildtype=debug -Db_lundef=false -Db_sanitize=address "-Dbuildtype=debug": This is a non-essential option. When this option is added, if a memory error occurs, ASan can clearly show where the code is wrong. "-Db_lundef=false": When use clang to compile DPDK, this option must be added. Signed-off-by: Xueqin Lin Signed-off-by: Zhihong Peng --- v7: 1) Split doc and code into two. 2) Modify asan.rst doc v8: No change. v9: 1) Add the check of libasan library. 2) Add release notes. v10:1) Split doc and code into two. 2) Meson supports asan. v11:Modify the document. v12:No change. --- config/meson.build | 16 +++++++++++ devtools/words-case.txt | 1 + doc/guides/prog_guide/asan.rst | 40 ++++++++++++++++++++++++++ doc/guides/prog_guide/index.rst | 1 + doc/guides/rel_notes/release_21_11.rst | 9 ++++++ 5 files changed, 67 insertions(+) create mode 100644 doc/guides/prog_guide/asan.rst diff --git a/config/meson.build b/config/meson.build index 4cdf589e20..f02b0e9c6d 100644 --- a/config/meson.build +++ b/config/meson.build @@ -411,6 +411,22 @@ if get_option('b_lto') endif endif +if get_option('b_sanitize') == 'address' or get_option('b_sanitize') == 'address,undefined' + if is_windows + error('ASan is not supported on windows') + endif + + if cc.get_id() == 'gcc' + asan_dep = cc.find_library('asan', required: true) + if (not cc.links('int main(int argc, char *argv[]) { return 0; }', + dependencies: asan_dep)) + error('broken dependency, "libasan"') + endif + add_project_link_arguments('-lasan', language: 'c') + dpdk_extra_ldflags += '-lasan' + endif +endif + if get_option('default_library') == 'both' error( ''' Unsupported value "both" for "default_library" option. diff --git a/devtools/words-case.txt b/devtools/words-case.txt index 0bbad48626..ada6910fa0 100644 --- a/devtools/words-case.txt +++ b/devtools/words-case.txt @@ -5,6 +5,7 @@ API Arm armv7 armv8 +ASan BAR CRC DCB diff --git a/doc/guides/prog_guide/asan.rst b/doc/guides/prog_guide/asan.rst new file mode 100644 index 0000000000..969676ebe8 --- /dev/null +++ b/doc/guides/prog_guide/asan.rst @@ -0,0 +1,40 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2021 Intel Corporation + +Running Address Sanitizer +========================= + +`AddressSanitizer +`_ (ASan) +is a widely-used debugging tool to detect memory access errors. +It helps detect issues like use-after-free, various kinds of buffer +overruns in C/C++ programs, and other similar errors, as well as +printing out detailed debug information whenever an error is detected. + +AddressSanitizer is a part of LLVM (3.1+) and GCC (4.8+). + +Usage +----- + +meson build +^^^^^^^^^^^ + +To enable ASan in meson build system, use following meson build command: + +Example usage:: + +* gcc:: + + meson build -Dbuildtype=debug -Db_sanitize=address + ninja -C build + +* clang:: + + meson build -Dbuildtype=debug -Db_lundef=false -Db_sanitize=address + ninja -C build + +.. Note:: + + a) To compile with gcc in centos, libasan needs to be installed separately. + b) If the program being tested uses cmdline you will need to execute the + "stty echo" command when a error occurs. diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index 89af28dacb..b95c460b19 100644 --- a/doc/guides/prog_guide/index.rst +++ b/doc/guides/prog_guide/index.rst @@ -71,4 +71,5 @@ Programmer's Guide writing_efficient_code lto profile_app + asan glossary diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index d5435a64aa..63d9fef1b4 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -167,6 +167,15 @@ New Features * Added tests to verify tunnel header verification in IPsec inbound. * Added tests to verify inner checksum. +* **Enable ASan AddressSanitizer.** + + `AddressSanitizer + `_ (ASan) + is a widely-used debugging tool to detect memory access errors. + It helps detect issues like use-after-free, various kinds of buffer + overruns in C/C++ programs, and other similar errors, as well as + printing out detailed debug information whenever an error is detected. + Removed Items ------------- From patchwork Tue Oct 19 15:15:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng, ZhihongX" X-Patchwork-Id: 102261 X-Patchwork-Delegate: david.marchand@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E78F4A0C41; Tue, 19 Oct 2021 17:17:22 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4252B41210; Tue, 19 Oct 2021 17:17:21 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id 6683A41164 for ; Tue, 19 Oct 2021 17:17:16 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10142"; a="227314709" X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="227314709" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:54 -0700 X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="494144020" Received: from unknown (HELO localhost.localdomain) ([10.240.183.65]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:50 -0700 From: zhihongx.peng@intel.com To: david.marchand@redhat.com, thomas@monjalon.net, anatoly.burakov@intel.com, konstantin.ananyev@intel.com, stephen@networkplumber.org, cristian.dumitrescu@intel.com, john.mcnamara@intel.com, bruce.richardson@intel.com Cc: dev@dpdk.org, xueqin.lin@intel.com, Zhihong Peng Date: Tue, 19 Oct 2021 23:15:22 +0800 Message-Id: <20211019151524.2005442-2-zhihongx.peng@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211019151524.2005442-1-zhihongx.peng@intel.com> References: <20211019101207.1451058-4-zhihongx.peng@intel.com> <20211019151524.2005442-1-zhihongx.peng@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v12 2/4] DPDK code adapts to ASan X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Zhihong Peng DPDK ASan functionality is currently only supported Linux x86_64. Support other platforms, need to define ASAN_SHADOW_OFFSET value according to google ASan document, and configure meson (config/meson.build). Here is an example of heap-buffer-overflow bug: ...... char *p = rte_zmalloc(NULL, 7, 0); p[7] = 'a'; ...... Here is an example of use-after-free bug: ...... char *p = rte_zmalloc(NULL, 7, 0); rte_free(p); *p = 'a'; ...... Signed-off-by: Xueqin Lin Signed-off-by: Zhihong Peng --- v7: Split doc and code into two. v8: No change. v9: Modify the definition of RTE_MALLOC_ASAN. v10:Modify the definition of RTE_MALLOC_ASAN. v11:No change. v12:No change. --- config/meson.build | 4 + doc/guides/prog_guide/asan.rst | 68 +++++++++++- lib/eal/common/malloc_elem.c | 26 ++++- lib/eal/common/malloc_elem.h | 194 ++++++++++++++++++++++++++++++++- lib/eal/common/malloc_heap.c | 12 ++ lib/eal/common/rte_malloc.c | 9 +- 6 files changed, 306 insertions(+), 7 deletions(-) diff --git a/config/meson.build b/config/meson.build index f02b0e9c6d..bf751583bd 100644 --- a/config/meson.build +++ b/config/meson.build @@ -425,6 +425,10 @@ if get_option('b_sanitize') == 'address' or get_option('b_sanitize') == 'address add_project_link_arguments('-lasan', language: 'c') dpdk_extra_ldflags += '-lasan' endif + + if is_linux and arch_subdir == 'x86' + dpdk_conf.set10('RTE_MALLOC_ASAN', true) + endif endif if get_option('default_library') == 'both' diff --git a/doc/guides/prog_guide/asan.rst b/doc/guides/prog_guide/asan.rst index 969676ebe8..0cb2ca8751 100644 --- a/doc/guides/prog_guide/asan.rst +++ b/doc/guides/prog_guide/asan.rst @@ -13,6 +13,68 @@ printing out detailed debug information whenever an error is detected. AddressSanitizer is a part of LLVM (3.1+) and GCC (4.8+). +DPDK ASan functionality is currently only supported Linux x86_64. +Support other platforms, need to define ASAN_SHADOW_OFFSET value +according to google ASan document, and configure meson +(config/meson.build). + +Example heap-buffer-overflow error +---------------------------------- + +Following error was reported when ASan was enabled:: + + Applied 9 bytes of memory, but accessed the 10th byte of memory, + so heap-buffer-overflow appeared. + +Below code results in this error:: + + Add code to helloworld: + char *p = rte_zmalloc(NULL, 9, 0); + if (!p) { + printf("rte_zmalloc error."); + return -1; + } + p[9] = 'a'; + +The error log:: + + ==369953==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7fb17f465809 at pc 0x5652e6707b84 bp 0x7ffea70eea20 sp 0x7ffea70eea10 WRITE of size 1 at 0x7fb17f465809 thread T0 + #0 0x5652e6707b83 in main ../examples/helloworld/main.c:47 + #1 0x7fb94953c0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) + #2 0x5652e67079bd in _start (/home/pzh/asan_test/x86_64-native-linuxapp-gcc/examples/dpdk-helloworld+0x8329bd) + + Address 0x7fb17f465809 is a wild pointer. + SUMMARY: AddressSanitizer: heap-buffer-overflow ../examples/helloworld/main.c:47 in main + +Example use-after-free error +---------------------------- + +Following error was reported when ASan was enabled:: + + Applied for 9 bytes of memory, and accessed the first byte after + released, so heap-use-after-free appeared. + +Below code results in this error:: + + Add code to helloworld: + char *p = rte_zmalloc(NULL, 9, 0); + if (!p) { + printf("rte_zmalloc error."); + return -1; + } + rte_free(p); + *p = 'a'; + +The error log:: + + ==417048==ERROR: AddressSanitizer: heap-use-after-free on address 0x7fc83f465800 at pc 0x564308a39b89 bp 0x7ffc8c85bf50 sp 0x7ffc8c85bf40 WRITE of size 1 at 0x7fc83f465800 thread T0 + #0 0x564308a39b88 in main ../examples/helloworld/main.c:48 + #1 0x7fd0079c60b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) + #2 0x564308a399bd in _start (/home/pzh/asan_test/x86_64-native-linuxapp-gcc/examples/dpdk-helloworld+0x8329bd) + + Address 0x7fc83f465800 is a wild pointer. + SUMMARY: AddressSanitizer: heap-use-after-free ../examples/helloworld/main.c:48 in main + Usage ----- @@ -35,6 +97,8 @@ Example usage:: .. Note:: - a) To compile with gcc in centos, libasan needs to be installed separately. - b) If the program being tested uses cmdline you will need to execute the + a) Some of the features of ASan (for example, 'Display memory application location, currently + displayed as a wild pointer') are not currently supported by DPDK's implementation. + b) To compile with gcc in centos, libasan needs to be installed separately. + c) If the program being tested uses cmdline you will need to execute the "stty echo" command when a error occurs. diff --git a/lib/eal/common/malloc_elem.c b/lib/eal/common/malloc_elem.c index c2c9461f1d..bdd20a162e 100644 --- a/lib/eal/common/malloc_elem.c +++ b/lib/eal/common/malloc_elem.c @@ -446,6 +446,8 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align, struct malloc_elem *new_free_elem = RTE_PTR_ADD(new_elem, size + MALLOC_ELEM_OVERHEAD); + asan_clear_split_alloczone(new_free_elem); + split_elem(elem, new_free_elem); malloc_elem_free_list_insert(new_free_elem); @@ -458,6 +460,8 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align, elem->state = ELEM_BUSY; elem->pad = old_elem_size; + asan_clear_alloczone(elem); + /* put a dummy header in padding, to point to real element header */ if (elem->pad > 0) { /* pad will be at least 64-bytes, as everything * is cache-line aligned */ @@ -470,12 +474,18 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align, return new_elem; } + asan_clear_split_alloczone(new_elem); + /* we are going to split the element in two. The original element * remains free, and the new element is the one allocated. * Re-insert original element, in case its new size makes it * belong on a different list. */ + split_elem(elem, new_elem); + + asan_clear_alloczone(new_elem); + new_elem->state = ELEM_BUSY; malloc_elem_free_list_insert(elem); @@ -601,6 +611,8 @@ malloc_elem_hide_region(struct malloc_elem *elem, void *start, size_t len) if (next && next_elem_is_adjacent(elem)) { len_after = RTE_PTR_DIFF(next, hide_end); if (len_after >= MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { + asan_clear_split_alloczone(hide_end); + /* split after */ split_elem(elem, hide_end); @@ -615,6 +627,8 @@ malloc_elem_hide_region(struct malloc_elem *elem, void *start, size_t len) if (prev && prev_elem_is_adjacent(elem)) { len_before = RTE_PTR_DIFF(hide_start, elem); if (len_before >= MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { + asan_clear_split_alloczone(hide_start); + /* split before */ split_elem(elem, hide_start); @@ -628,6 +642,8 @@ malloc_elem_hide_region(struct malloc_elem *elem, void *start, size_t len) } } + asan_clear_alloczone(elem); + remove_elem(elem); } @@ -641,8 +657,10 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size) const size_t new_size = size + elem->pad + MALLOC_ELEM_OVERHEAD; /* if we request a smaller size, then always return ok */ - if (elem->size >= new_size) + if (elem->size >= new_size) { + asan_clear_alloczone(elem); return 0; + } /* check if there is a next element, it's free and adjacent */ if (!elem->next || elem->next->state != ELEM_FREE || @@ -661,9 +679,15 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size) /* now we have a big block together. Lets cut it down a bit, by splitting */ struct malloc_elem *split_pt = RTE_PTR_ADD(elem, new_size); split_pt = RTE_PTR_ALIGN_CEIL(split_pt, RTE_CACHE_LINE_SIZE); + + asan_clear_split_alloczone(split_pt); + split_elem(elem, split_pt); malloc_elem_free_list_insert(split_pt); } + + asan_clear_alloczone(elem); + return 0; } diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h index a1e5f7f02c..a06c11ac8b 100644 --- a/lib/eal/common/malloc_elem.h +++ b/lib/eal/common/malloc_elem.h @@ -36,10 +36,20 @@ struct malloc_elem { uint64_t header_cookie; /* Cookie marking start of data */ /* trailer cookie at start + size */ #endif +#ifdef RTE_MALLOC_ASAN + size_t user_size; + uint64_t asan_cookie[2]; /* must be next to header_cookie */ +#endif } __rte_cache_aligned; +static const unsigned int MALLOC_ELEM_HEADER_LEN = sizeof(struct malloc_elem); + #ifndef RTE_MALLOC_DEBUG -static const unsigned MALLOC_ELEM_TRAILER_LEN = 0; +#ifdef RTE_MALLOC_ASAN +static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE; +#else +static const unsigned int MALLOC_ELEM_TRAILER_LEN; +#endif /* dummy function - just check if pointer is non-null */ static inline int @@ -55,7 +65,7 @@ set_trailer(struct malloc_elem *elem __rte_unused){ } #else -static const unsigned MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE; +static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE; #define MALLOC_HEADER_COOKIE 0xbadbadbadadd2e55ULL /**< Header cookie. */ #define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/ @@ -90,9 +100,187 @@ malloc_elem_cookies_ok(const struct malloc_elem *elem) #endif -static const unsigned MALLOC_ELEM_HEADER_LEN = sizeof(struct malloc_elem); #define MALLOC_ELEM_OVERHEAD (MALLOC_ELEM_HEADER_LEN + MALLOC_ELEM_TRAILER_LEN) +#ifdef RTE_MALLOC_ASAN + +#ifdef RTE_ARCH_X86_64 +#define ASAN_SHADOW_OFFSET 0x00007fff8000 +#endif + +#define ASAN_SHADOW_GRAIN_SIZE 8 +#define ASAN_MEM_FREE_FLAG 0xfd +#define ASAN_MEM_REDZONE_FLAG 0xfa +#define ASAN_SHADOW_SCALE 3 + +#define ASAN_MEM_SHIFT(mem) ((void *)((uintptr_t)(mem) >> ASAN_SHADOW_SCALE)) +#define ASAN_MEM_TO_SHADOW(mem) \ + RTE_PTR_ADD(ASAN_MEM_SHIFT(mem), ASAN_SHADOW_OFFSET) + +#if defined(__clang__) +__attribute__((no_sanitize("address", "hwaddress"))) +#else +__attribute__((no_sanitize_address)) +#endif +static inline void +asan_set_shadow(void *addr, char val) +{ + *(char *)addr = val; +} + +static inline void +asan_set_zone(void *ptr, size_t len, uint32_t val) +{ + size_t offset, i; + void *shadow; + size_t zone_len = len / ASAN_SHADOW_GRAIN_SIZE; + if (len % ASAN_SHADOW_GRAIN_SIZE != 0) + zone_len += 1; + + for (i = 0; i < zone_len; i++) { + offset = i * ASAN_SHADOW_GRAIN_SIZE; + shadow = ASAN_MEM_TO_SHADOW((uintptr_t)ptr + offset); + asan_set_shadow(shadow, val); + } +} + +/* + * When the memory is released, the release mark is + * set in the corresponding range of the shadow area. + */ +static inline void +asan_set_freezone(void *ptr, size_t size) +{ + asan_set_zone(ptr, size, ASAN_MEM_FREE_FLAG); +} + +/* + * When the memory is allocated, memory state must set as accessible. + */ +static inline void +asan_clear_alloczone(struct malloc_elem *elem) +{ + asan_set_zone((void *)elem, elem->size, 0x0); +} + +static inline void +asan_clear_split_alloczone(struct malloc_elem *elem) +{ + void *ptr = RTE_PTR_SUB(elem, MALLOC_ELEM_TRAILER_LEN); + asan_set_zone(ptr, MALLOC_ELEM_OVERHEAD, 0x0); +} + +/* + * When the memory is allocated, the memory boundary is + * marked in the corresponding range of the shadow area. + * Requirement: redzone >= 16, is a power of two. + */ +static inline void +asan_set_redzone(struct malloc_elem *elem, size_t user_size) +{ + uintptr_t head_redzone; + uintptr_t tail_redzone; + void *front_shadow; + void *tail_shadow; + uint32_t val; + + if (elem != NULL) { + if (elem->state != ELEM_PAD) + elem = RTE_PTR_ADD(elem, elem->pad); + + elem->user_size = user_size; + + /* Set mark before the start of the allocated memory */ + head_redzone = (uintptr_t)RTE_PTR_ADD(elem, + MALLOC_ELEM_HEADER_LEN - ASAN_SHADOW_GRAIN_SIZE); + front_shadow = ASAN_MEM_TO_SHADOW(head_redzone); + asan_set_shadow(front_shadow, ASAN_MEM_REDZONE_FLAG); + front_shadow = ASAN_MEM_TO_SHADOW(head_redzone + - ASAN_SHADOW_GRAIN_SIZE); + asan_set_shadow(front_shadow, ASAN_MEM_REDZONE_FLAG); + + /* Set mark after the end of the allocated memory */ + tail_redzone = (uintptr_t)RTE_PTR_ADD(elem, + MALLOC_ELEM_HEADER_LEN + + elem->user_size); + tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone); + val = (tail_redzone % ASAN_SHADOW_GRAIN_SIZE); + val = (val == 0) ? ASAN_MEM_REDZONE_FLAG : val; + asan_set_shadow(tail_shadow, val); + tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone + + ASAN_SHADOW_GRAIN_SIZE); + asan_set_shadow(tail_shadow, ASAN_MEM_REDZONE_FLAG); + } +} + +/* + * When the memory is released, the mark of the memory boundary + * in the corresponding range of the shadow area is cleared. + * Requirement: redzone >= 16, is a power of two. + */ +static inline void +asan_clear_redzone(struct malloc_elem *elem) +{ + uintptr_t head_redzone; + uintptr_t tail_redzone; + void *head_shadow; + void *tail_shadow; + + if (elem != NULL) { + elem = RTE_PTR_ADD(elem, elem->pad); + + /* Clear mark before the start of the allocated memory */ + head_redzone = (uintptr_t)RTE_PTR_ADD(elem, + MALLOC_ELEM_HEADER_LEN - ASAN_SHADOW_GRAIN_SIZE); + head_shadow = ASAN_MEM_TO_SHADOW(head_redzone); + asan_set_shadow(head_shadow, 0x00); + head_shadow = ASAN_MEM_TO_SHADOW(head_redzone + - ASAN_SHADOW_GRAIN_SIZE); + asan_set_shadow(head_shadow, 0x00); + + /* Clear mark after the end of the allocated memory */ + tail_redzone = (uintptr_t)RTE_PTR_ADD(elem, + MALLOC_ELEM_HEADER_LEN + elem->user_size); + tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone); + asan_set_shadow(tail_shadow, 0x00); + tail_shadow = ASAN_MEM_TO_SHADOW(tail_redzone + + ASAN_SHADOW_GRAIN_SIZE); + asan_set_shadow(tail_shadow, 0x00); + } +} + +static inline size_t +old_malloc_size(struct malloc_elem *elem) +{ + if (elem->state != ELEM_PAD) + elem = RTE_PTR_ADD(elem, elem->pad); + + return elem->user_size; +} +#else +static inline void +asan_set_freezone(void *ptr __rte_unused, size_t size __rte_unused) { } + +static inline void +asan_clear_alloczone(struct malloc_elem *elem __rte_unused) { } + +static inline void +asan_clear_split_alloczone(struct malloc_elem *elem __rte_unused) { } + +static inline void +asan_set_redzone(struct malloc_elem *elem __rte_unused, + size_t user_size __rte_unused) { } + +static inline void +asan_clear_redzone(struct malloc_elem *elem __rte_unused) { } + +static inline size_t +old_malloc_size(struct malloc_elem *elem) +{ + return elem->size - elem->pad - MALLOC_ELEM_OVERHEAD; +} +#endif + /* * Given a pointer to the start of a memory block returned by malloc, get * the actual malloc_elem header for that block. diff --git a/lib/eal/common/malloc_heap.c b/lib/eal/common/malloc_heap.c index ee400f38ec..775d6789df 100644 --- a/lib/eal/common/malloc_heap.c +++ b/lib/eal/common/malloc_heap.c @@ -237,6 +237,7 @@ heap_alloc(struct malloc_heap *heap, const char *type __rte_unused, size_t size, unsigned int flags, size_t align, size_t bound, bool contig) { struct malloc_elem *elem; + size_t user_size = size; size = RTE_CACHE_LINE_ROUNDUP(size); align = RTE_CACHE_LINE_ROUNDUP(align); @@ -250,6 +251,8 @@ heap_alloc(struct malloc_heap *heap, const char *type __rte_unused, size_t size, /* increase heap's count of allocated elements */ heap->alloc_count++; + + asan_set_redzone(elem, user_size); } return elem == NULL ? NULL : (void *)(&elem[1]); @@ -270,6 +273,8 @@ heap_alloc_biggest(struct malloc_heap *heap, const char *type __rte_unused, /* increase heap's count of allocated elements */ heap->alloc_count++; + + asan_set_redzone(elem, size); } return elem == NULL ? NULL : (void *)(&elem[1]); @@ -841,6 +846,8 @@ malloc_heap_free(struct malloc_elem *elem) if (!malloc_elem_cookies_ok(elem) || elem->state != ELEM_BUSY) return -1; + asan_clear_redzone(elem); + /* elem may be merged with previous element, so keep heap address */ heap = elem->heap; msl = elem->msl; @@ -848,6 +855,9 @@ malloc_heap_free(struct malloc_elem *elem) rte_spinlock_lock(&(heap->lock)); + void *asan_ptr = RTE_PTR_ADD(elem, MALLOC_ELEM_HEADER_LEN + elem->pad); + size_t asan_data_len = elem->size - MALLOC_ELEM_OVERHEAD - elem->pad; + /* mark element as free */ elem->state = ELEM_FREE; @@ -1001,6 +1011,8 @@ malloc_heap_free(struct malloc_elem *elem) rte_mcfg_mem_write_unlock(); free_unlock: + asan_set_freezone(asan_ptr, asan_data_len); + rte_spinlock_unlock(&(heap->lock)); return ret; } diff --git a/lib/eal/common/rte_malloc.c b/lib/eal/common/rte_malloc.c index 9d39e58c08..d0bec26920 100644 --- a/lib/eal/common/rte_malloc.c +++ b/lib/eal/common/rte_malloc.c @@ -162,6 +162,8 @@ rte_calloc(const char *type, size_t num, size_t size, unsigned align) void * rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket) { + size_t user_size; + if (ptr == NULL) return rte_malloc_socket(NULL, size, align, socket); @@ -171,6 +173,8 @@ rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket) return NULL; } + user_size = size; + size = RTE_CACHE_LINE_ROUNDUP(size), align = RTE_CACHE_LINE_ROUNDUP(align); /* check requested socket id and alignment matches first, and if ok, @@ -181,6 +185,9 @@ rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket) RTE_PTR_ALIGN(ptr, align) == ptr && malloc_heap_resize(elem, size) == 0) { rte_eal_trace_mem_realloc(size, align, socket, ptr); + + asan_set_redzone(elem, user_size); + return ptr; } @@ -192,7 +199,7 @@ rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket) if (new_ptr == NULL) return NULL; /* elem: |pad|data_elem|data|trailer| */ - const size_t old_size = elem->size - elem->pad - MALLOC_ELEM_OVERHEAD; + const size_t old_size = old_malloc_size(elem); rte_memcpy(new_ptr, ptr, old_size < size ? old_size : size); rte_free(ptr); From patchwork Tue Oct 19 15:15:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng, ZhihongX" X-Patchwork-Id: 102262 X-Patchwork-Delegate: david.marchand@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3582DA0C41; Tue, 19 Oct 2021 17:17:30 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3DB6641217; Tue, 19 Oct 2021 17:17:22 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id A50E04120A for ; Tue, 19 Oct 2021 17:17:19 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10142"; a="227314732" X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="227314732" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:57 -0700 X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="494144045" Received: from unknown (HELO localhost.localdomain) ([10.240.183.65]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:54 -0700 From: zhihongx.peng@intel.com To: david.marchand@redhat.com, thomas@monjalon.net, anatoly.burakov@intel.com, konstantin.ananyev@intel.com, stephen@networkplumber.org, cristian.dumitrescu@intel.com, john.mcnamara@intel.com, bruce.richardson@intel.com Cc: dev@dpdk.org, xueqin.lin@intel.com, Zhihong Peng Date: Tue, 19 Oct 2021 23:15:23 +0800 Message-Id: <20211019151524.2005442-3-zhihongx.peng@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211019151524.2005442-1-zhihongx.peng@intel.com> References: <20211019101207.1451058-4-zhihongx.peng@intel.com> <20211019151524.2005442-1-zhihongx.peng@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v12 3/4] Code changes to avoid the ASan error X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Zhihong Peng Code changes to avoid the following ASan error: "Control reaches end of non-void function". Cc: cristian.dumitrescu@intel.com Signed-off-by: Xueqin Lin Signed-off-by: Zhihong Peng --- v7: no change. v8: no change. v9: Modify the submit log. v10:no change. v11:no change. v12:Modify the commit log. --- lib/pipeline/rte_swx_pipeline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index 1cd09a4b44..0acd6c6752 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -4642,7 +4642,7 @@ instr_meter_translate(struct rte_swx_pipeline *p, return 0; } - CHECK(0, EINVAL); + return -EINVAL; } static inline void @@ -5937,7 +5937,7 @@ instr_translate(struct rte_swx_pipeline *p, instr, data); - CHECK(0, EINVAL); + return -EINVAL; } static struct instruction_data * From patchwork Tue Oct 19 15:15:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng, ZhihongX" X-Patchwork-Id: 102263 X-Patchwork-Delegate: david.marchand@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id A3ACBA0C41; Tue, 19 Oct 2021 17:17:38 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D32C941216; Tue, 19 Oct 2021 17:17:28 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id C5C2E4121C; Tue, 19 Oct 2021 17:17:22 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10142"; a="227314750" X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="227314750" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:16:01 -0700 X-IronPort-AV: E=Sophos;i="5.87,164,1631602800"; d="scan'208";a="494144081" Received: from unknown (HELO localhost.localdomain) ([10.240.183.65]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Oct 2021 08:15:57 -0700 From: zhihongx.peng@intel.com To: david.marchand@redhat.com, thomas@monjalon.net, anatoly.burakov@intel.com, konstantin.ananyev@intel.com, stephen@networkplumber.org, cristian.dumitrescu@intel.com, john.mcnamara@intel.com, bruce.richardson@intel.com Cc: dev@dpdk.org, xueqin.lin@intel.com, Zhihong Peng , stable@dpdk.org Date: Tue, 19 Oct 2021 23:15:24 +0800 Message-Id: <20211019151524.2005442-4-zhihongx.peng@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211019151524.2005442-1-zhihongx.peng@intel.com> References: <20211019101207.1451058-4-zhihongx.peng@intel.com> <20211019151524.2005442-1-zhihongx.peng@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v12 4/4] performance-thread: Fix cross compilation failed X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Zhihong Peng The gcc(arm-linux-gcc) will check code more stricter when ASan enabled. "strncpy specified bound XX equals destination size" error occurs here. Fixes: 116819b9ed0d ("examples/performance-thread: add lthread subsystem") Cc: stable@dpdk.org Signed-off-by: Xueqin Lin Signed-off-by: Zhihong Peng --- v11: Use rte_strlcpy to replace strncpy. v12: Delete rte_strlcpy's rte_. --- examples/performance-thread/common/lthread.c | 4 ++-- examples/performance-thread/common/lthread_cond.c | 6 +++--- examples/performance-thread/common/lthread_mutex.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/performance-thread/common/lthread.c b/examples/performance-thread/common/lthread.c index 3f1f48db43..190e5874b1 100644 --- a/examples/performance-thread/common/lthread.c +++ b/examples/performance-thread/common/lthread.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -463,6 +464,5 @@ void lthread_set_funcname(const char *f) { struct lthread *lt = THIS_LTHREAD; - strncpy(lt->funcname, f, sizeof(lt->funcname)); - lt->funcname[sizeof(lt->funcname)-1] = 0; + strlcpy(lt->funcname, f, sizeof(lt->funcname)); } diff --git a/examples/performance-thread/common/lthread_cond.c b/examples/performance-thread/common/lthread_cond.c index cdcc7a7b5a..e7be17089a 100644 --- a/examples/performance-thread/common/lthread_cond.c +++ b/examples/performance-thread/common/lthread_cond.c @@ -20,6 +20,7 @@ #include #include +#include #include "lthread_api.h" #include "lthread_diag_api.h" @@ -57,10 +58,9 @@ lthread_cond_init(char *name, struct lthread_cond **cond, } if (name == NULL) - strncpy(c->name, "no name", sizeof(c->name)); + strlcpy(c->name, "no name", sizeof(c->name)); else - strncpy(c->name, name, sizeof(c->name)); - c->name[sizeof(c->name)-1] = 0; + strlcpy(c->name, name, sizeof(c->name)); c->root_sched = THIS_SCHED; diff --git a/examples/performance-thread/common/lthread_mutex.c b/examples/performance-thread/common/lthread_mutex.c index 01da6cad4f..709ab9f553 100644 --- a/examples/performance-thread/common/lthread_mutex.c +++ b/examples/performance-thread/common/lthread_mutex.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "lthread_api.h" #include "lthread_int.h" @@ -52,10 +53,9 @@ lthread_mutex_init(char *name, struct lthread_mutex **mutex, } if (name == NULL) - strncpy(m->name, "no name", sizeof(m->name)); + strlcpy(m->name, "no name", sizeof(m->name)); else - strncpy(m->name, name, sizeof(m->name)); - m->name[sizeof(m->name)-1] = 0; + strlcpy(m->name, name, sizeof(m->name)); m->root_sched = THIS_SCHED; m->owner = NULL;