From patchwork Mon May 22 19:48:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tristan Gingold X-Patchwork-Id: 97571 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp1679726vqo; Mon, 22 May 2023 12:48:32 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7RzlkbE/bBpqx8cHsWR1KPT/oOZqF/f6zv9ryUgS4OOlhLYTsNBoBVeXO7XLySZCtt6vxF X-Received: by 2002:a17:907:1c94:b0:969:c354:7d9a with SMTP id nb20-20020a1709071c9400b00969c3547d9amr12073423ejc.12.1684784912574; Mon, 22 May 2023 12:48:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684784912; cv=none; d=google.com; s=arc-20160816; b=CWJppTy2BqYh/P0w08X2mj7gBNWDlOk/C/dsN4Nftt7+QvYVTxsveTH5Z4rnBUWmdV PjJae80UBO03iZFrItMfFyx+teihcB7iHvxVr4C1/gPSqcvJ4ZIHRCsKy+LP80Glcr07 tlY3RQTyfL334RuDDteFbcNjilzumv0fY3XO22lbN/lUfX3g49L2vP+Yw1xu9g0hLskf nsvLZZuVDHiLKjJMQFKxvSDnFJ23EZkiXV5FdSVbnOTZ8NpPavTTQrHyD4L543ThLx9+ e8bGHog1XT26NFMg7aVzguQUyjmM2XY3U8uxFBFu2wLrH07XF8jvxaSRMhrySZaZP1sg wLZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:subject:to:content-language:user-agent :mime-version:date:message-id:dmarc-filter:delivered-to :dkim-signature:dkim-filter; bh=sc0/8eELnN9p1e1DJGy9K7uw7GpWaOYwOdm5ErbYdUQ=; b=ZcJqsHQrHLipjad30dSKLVb2Nn72Kcb80011Q9NNwi5Tt7R8wJBAfxOz9rI55W4yjn SUJ7PHpFooxCEm1FGFrsBlxYwWP8Mbict1+rpabLaT15Hpj2r2gyDykaItxJBiEF2Ray gErVPJzQ/lpizJaAjWoq3m8mPODhPJugzJsSfAKk/RV9nUXR72iA1UCqC6SzeHsNombn VzeKipXy8ESd+1wfvNSXXe8uJdArudId2u1aFNUGdtgNzb7b9Cyda4wLtl9tW1VL4ptW uRLb5aVGqjyoI7WsAlVewwXIaC4rUR4GIkpcnZhKEGruy9/WhUISv6QKaSXHIhqj7BfC 1Nlw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=JPsDzbgV; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sourceware.org Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id p4-20020a17090628c400b009584c5bcbc2si2806227ejd.992.2023.05.22.12.48.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 May 2023 12:48:32 -0700 (PDT) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=JPsDzbgV; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7B5DC3858D38 for ; Mon, 22 May 2023 19:48:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7B5DC3858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1684784911; bh=sc0/8eELnN9p1e1DJGy9K7uw7GpWaOYwOdm5ErbYdUQ=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=JPsDzbgVf5q800Pk09NIaN6+Vf4HnUoaChdkl4aTti74Yr6ccCsCPZsGqZV4gphVZ 7Q+j6DW1ueNRc7TCpXWTSCjWTkd84Y+x/PKgcY+NLdOap4lfhBnhyE5S3qI/ZFaT2I QkYpiy/NAQ0lmdD0LdlAlraYLNWgQFjSMh9moF74= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from smtp4-g21.free.fr (smtp4-g21.free.fr [212.27.42.4]) by sourceware.org (Postfix) with ESMTPS id E75153858D35 for ; Mon, 22 May 2023 19:48:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E75153858D35 Received: from [192.168.2.42] (unknown [88.173.63.180]) (Authenticated sender: tgingold@free.fr) by smtp4-g21.free.fr (Postfix) with ESMTPSA id C767E19F746 for ; Mon, 22 May 2023 21:48:22 +0200 (CEST) Message-ID: Date: Mon, 22 May 2023 21:48:22 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0 Content-Language: en-US To: binutils Subject: [PATCH v2] pe/coff - add support for base64 encoded long section names X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tristan Gingold via Binutils From: Tristan Gingold Reply-To: Tristan Gingold Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1765574391996623211?= X-GMAIL-MSGID: =?utf-8?q?1766625024370812367?= Hello, so new version of the patch, including generation of base64 encoded section name indexes. I was able to assemble the test from PR 30444 (using -mbig-obj to overcome the 2^16 sections number limit). I haven't added a test due to its size. No failures on x86_64-gnu-linux for binutils configured for x86_64-pc-mingw64. Tristan. 2023-05-22 Tristan Gingold PR 30444 * coffcode.h (coff_write_object_contents): Handle base64 encoding on PE. Also check for too large string table. * coffgen.c (extract_long_section_name): New function extracted from ... (make_a_section_from_file): ... here. Add support for base64 long section names. (decode_base64): New function. diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 974c8ad9854..097afe9d16c 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -3625,18 +3625,54 @@ coff_write_object_contents (bfd * abfd) len = strlen (current->name); if (len > SCNNMLEN) { - /* The s_name field is defined to be NUL-padded but need not be - NUL-terminated. We use a temporary buffer so that we can still - sprintf all eight chars without splatting a terminating NUL - over the first byte of the following member (s_paddr). */ - /* PR 21096: The +20 is to stop a bogus warning from gcc7 about - a possible buffer overflow. */ - char s_name_buf[SCNNMLEN + 1 + 20]; /* An inherent limitation of the /nnnnnnn notation used to indicate the offset of the long name in the string table is that we cannot address entries beyone the ten million byte boundary. */ - if (string_size >= 10000000) + if (string_size < 10000000) + { + /* The s_name field is defined to be NUL-padded but need not + be NUL-terminated. We use a temporary buffer so that we + can still sprintf all eight chars without splatting a + terminating NUL over the first byte of the following + member (s_paddr). */ + /* PR 21096: The +20 is to stop a bogus warning from gcc7 + about a possible buffer overflow. */ + char s_name_buf[SCNNMLEN + 1 + 20]; + + /* We do not need to use snprintf here as we have already + verified that string_size is not too big, plus we have + an overlarge buffer, just in case. */ + sprintf (s_name_buf, "/%lu", (unsigned long) string_size); + /* Then strncpy takes care of any padding for us. */ + strncpy (section.s_name, s_name_buf, SCNNMLEN); + } + else +#ifdef COFF_WITH_PE + { + /* PE use a bae64 encoding for long section names whose + index is very large. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + unsigned long off = string_size; + unsigned i; + + section.s_name[0] = '/'; + section.s_name[1] = '/'; + for (i = SCNNMLEN - 1; i >=2; i--) + { + section.s_name[i] = base64[off & 0x3f]; + off >>= 6; + } + } +#endif + if (string_size > 0xffffffffUL - (len + 1) +#ifndef COFF_WITH_PE + || string_size >= 10000000 +#endif + ) { bfd_set_error (bfd_error_file_too_big); _bfd_error_handler @@ -3646,12 +3682,6 @@ coff_write_object_contents (bfd * abfd) return false; } - /* We do not need to use snprintf here as we have already verfied - that string_size is not too big, plus we have an overlarge - buffer, just in case. */ - sprintf (s_name_buf, "/%lu", (unsigned long) string_size); - /* Then strncpy takes care of any padding for us. */ - strncpy (section.s_name, s_name_buf, SCNNMLEN); string_size += len + 1; long_section_names = true; } diff --git a/bfd/coffgen.c b/bfd/coffgen.c index ac936def566..970e06bf2c0 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -43,6 +43,69 @@ #include "coff/internal.h" #include "libcoff.h" +/* Extract a long section name at STRINDEX and copy it to the bfd objstack. + Return NULL in case of error. */ + +static char * +extract_long_section_name(bfd *abfd, unsigned long strindex) +{ + const char *strings; + char *name; + + strings = _bfd_coff_read_string_table (abfd); + if (strings == NULL) + return NULL; + if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) + return NULL; + strings += strindex; + name = (char *) bfd_alloc (abfd, (bfd_size_type) strlen (strings) + 1); + if (name == NULL) + return NULL; + strcpy (name, strings); + + return name; +} + +/* Decode a base64 coded string at STR of length LEN, and write the result + to RES. Return true on success. + Return false in case of invalid character or overflow. */ + +static bool +decode_base64 (const char *str, unsigned len, uint32_t *res) +{ + unsigned i; + uint32_t val; + + val = 0; + for (i = 0; i < len; i++) + { + char c = str[i]; + unsigned d; + + if (c >= 'A' && c <= 'Z') + d = c - 'A'; + else if (c >= 'a' && c <= 'z') + d = c - 'a' + 26; + else if (c >= '0' && c <= '9') + d = c - '0' + 52; + else if (c == '+') + d = 62; + else if (c == '/') + d = 63; + else + return false; + + /* Check for overflow. */ + if ((val >> 26) != 0) + return false; + + val = (val << 6) + d; + } + + *res = val; + return true; +} + /* Take a section header read from a coff file (in HOST byte order), and make a BFD "section" out of it. This is used by ECOFF. */ @@ -67,32 +130,46 @@ make_a_section_from_file (bfd *abfd, if (bfd_coff_set_long_section_names (abfd, bfd_coff_long_section_names (abfd)) && hdr->s_name[0] == '/') { - char buf[SCNNMLEN]; - long strindex; - char *p; - const char *strings; - /* Flag that this BFD uses long names, even though the format might expect them to be off by default. This won't directly affect the format of any output BFD created from this one, but the information can be used to decide what to do. */ bfd_coff_set_long_section_names (abfd, true); - memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1); - buf[SCNNMLEN - 1] = '\0'; - strindex = strtol (buf, &p, 10); - if (*p == '\0' && strindex >= 0) + + if (hdr->s_name[1] == '/') { - strings = _bfd_coff_read_string_table (abfd); - if (strings == NULL) - return false; - if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) + /* LLVM extension: the '/' is followed by another '/' and then by + the index in the strtab encoded in base64 without NUL at the + end. */ + uint32_t strindex; + + /* Decode the index. No overflow is expected as the string table + length is at most 2^32 - 1 (the length is written on the first + four bytes). */ + if (!decode_base64 (hdr->s_name + 2, SCNNMLEN - 2, &strindex)) return false; - strings += strindex; - name = (char *) bfd_alloc (abfd, - (bfd_size_type) strlen (strings) + 1 + 1); + + name = extract_long_section_name (abfd, strindex); if (name == NULL) return false; - strcpy (name, strings); + } + else + { + /* PE classic long section name. The '/' is followed by the index + in the strtab. The index is formatted as a decimal string. */ + char buf[SCNNMLEN]; + long strindex; + char *p; + + memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1); + buf[SCNNMLEN - 1] = '\0'; + strindex = strtol (buf, &p, 10); + if (*p == '\0' && strindex >= 0) + { + name = extract_long_section_name (abfd, strindex); + if (name == NULL) + return false; + } } }