Received: by 2002:a25:824b:0:0:0:0:0 with SMTP id d11csp92839ybn; Thu, 3 Oct 2019 02:02:34 -0700 (PDT) X-Google-Smtp-Source: APXvYqwzpTo+Wh4kh/alCivhXUMXVG+oBu9I4MiQKoQXj3t7sXbaafEDQFd0wqrYqEj7JQylbffa X-Received: by 2002:a17:906:7d0:: with SMTP id m16mr6833893ejc.95.1570093354650; Thu, 03 Oct 2019 02:02:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570093354; cv=none; d=google.com; s=arc-20160816; b=Uva/sKiE0j5o2Q3xnc7drwUzqy4tnW+i/BOCGUcYtuF+BnarYoNt6gmTGMUhJX9xrp CTiPul71apOPzv1UItCBbxX9cR3wbWhH3djKfBdgvygx/JeGA4amorw/D6WgLG72zhXI HqkPlB6nuBj6zayIdxZyIX+u5rXn1Or/8i5sWlhzfm+2Si6rOwg86lO102TJelgqUDwG KrptTn1sdRKnwL/VmAx+dPrRCmskwdwBdqcfO6NDiYRBlld47swtkoyMzASS9yDINQjK Zk9hp5Sur2/MT0y1ES8UOwFokjVg8UBZPeDiq504k6QeeliWwquVdRaEyVlXv4rIJUSE +JIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=iazGPgO8x5KeMYJsYa246vs2CgsJnAF7seQvBnhji78=; b=XNG88oqEZsWiTDSlgdMLQP8RhR7kGNkwHcO08zOgSgbWEDc6W0L2d3KZCI/8+68aPE uydR0f04va+KcmmzS2OHrMND7D1K7OGbeztasqJzBgOHwGiYnqMrXCgnd55BbNbgNtcI 2ERvF84EAei/XHUbxvb729fVZVWd5Jd0i7G2T5h0Xbhrcyh3VrTKcxkimRyWyeuabc5b lPLS8QaEKh4HpXEtmKQj/hdY+bO2q8AW7Tv4YsR5X6YjgIS2QOgC99u2zNQEk7grMZ0h OIgVSdRwmIfF77ucsbSO5U3ROYmwRYHEH2Ado0Ui/9iAQLel1LK4fvqrjMCtFn/c/YIc PLsw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v20si1038877edq.195.2019.10.03.02.02.09; Thu, 03 Oct 2019 02:02:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728987AbfJCJB4 (ORCPT + 99 others); Thu, 3 Oct 2019 05:01:56 -0400 Received: from mx2.suse.de ([195.135.220.15]:50292 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727611AbfJCJB4 (ORCPT ); Thu, 3 Oct 2019 05:01:56 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 36C40B14B; Thu, 3 Oct 2019 09:01:54 +0000 (UTC) From: Petr Mladek To: Jiri Kosina , Josh Poimboeuf , Miroslav Benes Cc: Joe Lawrence , Kamalesh Babulal , Nicolai Stange , live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, Petr Mladek Subject: [PATCH v3 1/5] livepatch: Keep replaced patches until post_patch callback is called Date: Thu, 3 Oct 2019 11:01:33 +0200 Message-Id: <20191003090137.6874-2-pmladek@suse.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20191003090137.6874-1-pmladek@suse.com> References: <20191003090137.6874-1-pmladek@suse.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Pre/post (un)patch callbacks might manipulate the system state. Cumulative livepatches might need to take over the changes made by the replaced ones. For this they might need to access some data stored or referenced by the old livepatches. Therefore the replaced livepatches have to stay around until post_patch() callback is called. It is achieved by calling the free functions later. It is the same location where disabled livepatches have already been freed. Signed-off-by: Petr Mladek Acked-by: Miroslav Benes --- kernel/livepatch/core.c | 36 ++++++++++++++++++++++++++---------- kernel/livepatch/core.h | 5 +++-- kernel/livepatch/transition.c | 12 ++++++------ 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index ab4a4606d19b..1e1d87ead55c 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -632,7 +632,7 @@ static void klp_free_objects_dynamic(struct klp_patch *patch) * The operation must be completed by calling klp_free_patch_finish() * outside klp_mutex. */ -void klp_free_patch_start(struct klp_patch *patch) +static void klp_free_patch_start(struct klp_patch *patch) { if (!list_empty(&patch->list)) list_del(&patch->list); @@ -677,6 +677,23 @@ static void klp_free_patch_work_fn(struct work_struct *work) klp_free_patch_finish(patch); } +void klp_free_patch_async(struct klp_patch *patch) +{ + klp_free_patch_start(patch); + schedule_work(&patch->free_work); +} + +void klp_free_replaced_patches_async(struct klp_patch *new_patch) +{ + struct klp_patch *old_patch, *tmp_patch; + + klp_for_each_patch_safe(old_patch, tmp_patch) { + if (old_patch == new_patch) + return; + klp_free_patch_async(old_patch); + } +} + static int klp_init_func(struct klp_object *obj, struct klp_func *func) { if (!func->old_name) @@ -1022,12 +1039,13 @@ int klp_enable_patch(struct klp_patch *patch) EXPORT_SYMBOL_GPL(klp_enable_patch); /* - * This function removes replaced patches. + * This function unpatches objects from the replaced livepatches. * * We could be pretty aggressive here. It is called in the situation where - * these structures are no longer accessible. All functions are redirected - * by the klp_transition_patch. They use either a new code or they are in - * the original code because of the special nop function patches. + * these structures are no longer accessed from the ftrace handler. + * All functions are redirected by the klp_transition_patch. They + * use either a new code or they are in the original code because + * of the special nop function patches. * * The only exception is when the transition was forced. In this case, * klp_ftrace_handler() might still see the replaced patch on the stack. @@ -1035,18 +1053,16 @@ EXPORT_SYMBOL_GPL(klp_enable_patch); * thanks to RCU. We only have to keep the patches on the system. Also * this is handled transparently by patch->module_put. */ -void klp_discard_replaced_patches(struct klp_patch *new_patch) +void klp_unpatch_replaced_patches(struct klp_patch *new_patch) { - struct klp_patch *old_patch, *tmp_patch; + struct klp_patch *old_patch; - klp_for_each_patch_safe(old_patch, tmp_patch) { + klp_for_each_patch(old_patch) { if (old_patch == new_patch) return; old_patch->enabled = false; klp_unpatch_objects(old_patch); - klp_free_patch_start(old_patch); - schedule_work(&old_patch->free_work); } } diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h index ec43a40b853f..38209c7361b6 100644 --- a/kernel/livepatch/core.h +++ b/kernel/livepatch/core.h @@ -13,8 +13,9 @@ extern struct list_head klp_patches; #define klp_for_each_patch(patch) \ list_for_each_entry(patch, &klp_patches, list) -void klp_free_patch_start(struct klp_patch *patch); -void klp_discard_replaced_patches(struct klp_patch *new_patch); +void klp_free_patch_async(struct klp_patch *patch); +void klp_free_replaced_patches_async(struct klp_patch *new_patch); +void klp_unpatch_replaced_patches(struct klp_patch *new_patch); void klp_discard_nops(struct klp_patch *new_patch); static inline bool klp_is_object_loaded(struct klp_object *obj) diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index cdf318d86dd6..f6310f848f34 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c @@ -78,7 +78,7 @@ static void klp_complete_transition(void) klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); if (klp_transition_patch->replace && klp_target_state == KLP_PATCHED) { - klp_discard_replaced_patches(klp_transition_patch); + klp_unpatch_replaced_patches(klp_transition_patch); klp_discard_nops(klp_transition_patch); } @@ -446,14 +446,14 @@ void klp_try_complete_transition(void) klp_complete_transition(); /* - * It would make more sense to free the patch in + * It would make more sense to free the unused patches in * klp_complete_transition() but it is called also * from klp_cancel_transition(). */ - if (!patch->enabled) { - klp_free_patch_start(patch); - schedule_work(&patch->free_work); - } + if (!patch->enabled) + klp_free_patch_async(patch); + else if (patch->replace) + klp_free_replaced_patches_async(patch); } /* -- 2.16.4