From patchwork Tue Aug 20 14:12:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11103859 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DA98C1398 for ; Tue, 20 Aug 2019 14:14:46 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ABA57214DA for ; Tue, 20 Aug 2019 14:14:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="s15Cqj8N" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ABA57214DA Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i04sk-0000Tf-MN; Tue, 20 Aug 2019 14:13:06 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i04sj-0000Ta-Qv for xen-devel@lists.xen.org; Tue, 20 Aug 2019 14:13:05 +0000 X-Inumbo-ID: a02a6086-c354-11e9-8bf9-12813bfff9fa Received: from smtp-fw-9102.amazon.com (unknown [207.171.184.29]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a02a6086-c354-11e9-8bf9-12813bfff9fa; Tue, 20 Aug 2019 14:13:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1566310385; x=1597846385; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=bMJ/b0iBWCIKBsty/SNLaDlddrOWfcIq0NopnU6NEZE=; b=s15Cqj8N7SS0DJCo4TiuloLJDb7v+iM0O/bsdKzTvYLqBz8M1Jrvu+ju 4nznswwNIm4aeeSYWT6RG0VI90ucM74OYqxB8Rb2CFwfoWGClcMBoYP9n DJCUPyEvr/XcwLrAzkSQRsoYaPtd+SGki3txpHjwzcIM6YqqQj7bPdloj Q=; X-IronPort-AV: E=Sophos;i="5.64,408,1559520000"; d="scan'208";a="695541694" Received: from sea3-co-svc-lb6-vlan3.sea.amazon.com (HELO email-inbound-relay-2a-22cc717f.us-west-2.amazon.com) ([10.47.22.38]) by smtp-border-fw-out-9102.sea19.amazon.com with ESMTP; 20 Aug 2019 14:13:02 +0000 Received: from EX13MTAUEA001.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan3.pdx.amazon.com [10.170.41.166]) by email-inbound-relay-2a-22cc717f.us-west-2.amazon.com (Postfix) with ESMTPS id F3E3EA1BB2; Tue, 20 Aug 2019 14:13:01 +0000 (UTC) Received: from EX13D03EUC003.ant.amazon.com (10.43.164.192) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 20 Aug 2019 14:13:01 +0000 Received: from EX13MTAUWC001.ant.amazon.com (10.43.162.135) by EX13D03EUC003.ant.amazon.com (10.43.164.192) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 20 Aug 2019 14:13:00 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.162.232) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Tue, 20 Aug 2019 14:12:58 +0000 From: Pawel Wieczorkiewicz To: Date: Tue, 20 Aug 2019 14:12:40 +0000 Message-ID: <20190820141240.118321-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 In-Reply-To: <20190808125132.10484-1-wipawel@amazon.de> References: <20190808125132.10484-1-wipawel@amazon.de> MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [livepatch-build-tools part3 v3 3/3] create-diff-object: Strip all undefined entires of known size X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: mpohlack@amazon.de, ross.lagerwall@citrix.com, wipawel@amazon.de, konrad.wilk@oracle.com Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" The patched ELF object file contains all sections and symbols as resulted from the compilation. However, certain symbols may not be copied over to the resulting object file, due to being unchanged or not included for other reasons. In such situation the resulting object file has the entire sections copied along (with all their entries unchanged), while some of the corresponding symbols are not copied along at all. This leads to having incorrect undefined (STN_UNDEF) entries in the final hotpatch ELF file. The newly added function livepatch_strip_undefined_elements() detects and removes all undefined RELA entries as well as their corresponding PROGBITS section entries. Since the sections may contain elements of unknown size (sh.sh_entsize == 0), perform the strip only on sections with well defined entry sizes. After replacing the stripped rela list, it is assumed that the next invocation of the kpatch_rebuild_rela_section_data() will adjust all section header parameters according to the current state. The livepatch_strip_undefined_elements() is a superset of the kpatch_regenerate_special_section() in both scope (covers all RELA sections instead of just special sections) and granularity (checks all entries instead of whole groups) modulo the entries validity predicate. Unifying the functions results in a complicated code, which is hard to reason about. Thus, the kpatch_regenerate_special_section() is kept separate with its own predicate for special sections only, and livepatch_strip_undefined_elements() follows for all sections with the undefined symbol detecting predicate. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Martin Pohlack Reviewed-by: Bjoern Doebel Reviewed-by: Norbert Manthey Reviewed-by: Andra-Irina Paraschiv --- v3: * Added to the commit message a reason for needing the livepatch_strip_undefined_elements() in addition to kpatch_regenerate_special_section() v2: * Kept lines limits to 80 chars (whereever possible) * Fixed commit message --- create-diff-object.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/create-diff-object.c b/create-diff-object.c index 1c84f81..f01f1da 100644 --- a/create-diff-object.c +++ b/create-diff-object.c @@ -1560,6 +1560,13 @@ static inline int get_section_entry_size(const struct section *sec, return entry_size; } +/* Check if RELA entry has undefined or unchanged/not-included symbols. */ +static inline bool has_rela_undefined_symbol(const struct rela *rela) +{ + return (GELF_R_SYM(rela->rela.r_info) == STN_UNDEF) || + (!rela->sym->include && (rela->sym->status == SAME)); +} + static int kpatch_section_has_undef_symbols(struct kpatch_elf *kelf, const struct section *sec) { @@ -1579,8 +1586,7 @@ static int kpatch_section_has_undef_symbols(struct kpatch_elf *kelf, continue; } - if ((GELF_R_SYM(rela->rela.r_info) == STN_UNDEF) || - (!rela->sym->include && rela->sym->status == SAME)) { + if (has_rela_undefined_symbol(rela)) { log_normal("section %s has an entry with an undefined symbol: %s\n", sec->name, rela->sym->name ?: "none"); return true; @@ -1994,6 +2000,125 @@ static void livepatch_create_patches_sections(struct kpatch_elf *kelf, } +/* + * The patched ELF object file contains all sections and symbols as resulted + * from the compilation. However, certain symbols may not be copied over to + * the resulting object file, due to being unchanged or not included for other + * reasons. + * In such situation the resulting object file has the entire sections copied + * along (with all their entries unchanged), while some of the corresponding + * symbols are not copied along at all. + * This leads to having incorrect dummy (STN_UNDEF) entries in the final + * hotpatch ELF file. + * This functions removes all undefined entries of known size from both + * RELA and PROGBITS sections of the patched elf object. + */ +static void livepatch_strip_undefined_elements(struct kpatch_elf *kelf) +{ + struct section *sec; + + list_for_each_entry(sec, &kelf->sections, list) { + struct rela *rela, *safe; + int src_offset = 0, dst_offset = 0; + int entry_size, align, aligned_size; + char *src, *dst; + LIST_HEAD(newrelas); + + /* use RELA section to find all its undefined entries */ + if (!is_rela_section(sec)) + continue; + + /* only known, fixed-size entries can be stripped */ + entry_size = get_section_entry_size(sec->base, kelf); + if (entry_size == 0) + continue; + + /* alloc buffer for new base section */ + dst = malloc(sec->base->sh.sh_size); + if (!dst) + ERROR("malloc"); + + /* + * Iterate through all entries of a corresponding base section + * for this RELA section. + */ + for ( src = sec->base->data->d_buf; + src_offset < sec->base->sh.sh_size; + src_offset += entry_size ) { + bool found_valid = false; + + list_for_each_entry_safe(rela, safe, &sec->relas, list) { + /* + * Check all RELA elements looking for + * corresponding entry references. + */ + if (rela->offset < src_offset || + rela->offset >= src_offset + entry_size) { + continue; + } + + /* + * Ignore all undefined (STN_UNDEF) or + * unchanged/not-included elements. + */ + if (has_rela_undefined_symbol(rela)) { + log_normal("Found a STN_UNDEF symbol %s in section %s\n", + rela->sym->name, sec->name); + continue; + } + + /* + * A correct match has been found, so move it + * to a new list. Original list will be destroyed + * along with the entire kelf object, so the + * reference must be preserved. + */ + found_valid = true; + list_del(&rela->list); + list_add_tail(&rela->list, &newrelas); + + rela->offset -= src_offset - dst_offset; + rela->rela.r_offset = rela->offset; + } + + /* there is a valid RELA entry, so copy current entry */ + if (found_valid) { + /* copy base section group */ + memcpy(dst + dst_offset, src + src_offset, entry_size); + dst_offset += entry_size; + } + } + + /* verify that entry_size is a divisor of aligned section size */ + align = sec->base->sh.sh_addralign; + aligned_size = ((sec->base->sh.sh_size + align - 1) / align) * align; + if (src_offset != aligned_size) { + ERROR("group size mismatch for section %s\n", + sec->base->name); + } + + if (!dst_offset) { + /* no changed or global functions referenced */ + sec->status = sec->base->status = SAME; + sec->include = sec->base->include = 0; + free(dst); + continue; + } + + /* overwrite with new relas list */ + list_replace(&newrelas, &sec->relas); + + /* + * Update text section data buf and size. + * + * The rela section's data buf and size will be + * regenerated in kpatch_rebuild_rela_section_data(). + */ + sec->base->data->d_buf = dst; + sec->base->data->d_size = dst_offset; + } +} + static int is_null_sym(struct symbol *sym) { return !strlen(sym->name); @@ -2190,6 +2315,8 @@ int main(int argc, char *argv[]) log_debug("Process special sections\n"); kpatch_process_special_sections(kelf_patched); + log_debug("Strip undefined elements of known size\n"); + livepatch_strip_undefined_elements(kelf_patched); log_debug("Verify patchability\n"); kpatch_verify_patchability(kelf_patched);