From patchwork Thu May 28 13:48:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Cote X-Patchwork-Id: 11575869 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 0DB3E90 for ; Thu, 28 May 2020 13:49:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E1D992084C for ; Thu, 28 May 2020 13:49:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HtT/Njkv" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390550AbgE1NtC (ORCPT ); Thu, 28 May 2020 09:49:02 -0400 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:53503 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2390514AbgE1NtB (ORCPT ); Thu, 28 May 2020 09:49:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590673739; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TJL20W3ir/b9MVshm2OPM91U5HXtTb+5zv6fUX0lrTk=; b=HtT/Njkv8+nbSIQvIVK9aSqxJsCJUcUcBR7szaTro33Y//AGxtP8uj057u+PJSh8d61C2z C2Kcj7vDAAHRVF/YkLw1nz09DhvcpZczwrJLvd2xC6Mx0CmSR/PeJnCPZh/pXXw02KREtI uYPjxKX6jF+UkIxYJjNevGT4LZGKyNo= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-39-bU2HXs-YPTyO22tTMBRIRg-1; Thu, 28 May 2020 09:48:57 -0400 X-MC-Unique: bU2HXs-YPTyO22tTMBRIRg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 628CD107ACCA; Thu, 28 May 2020 13:48:56 +0000 (UTC) Received: from dm.redhat.com (ovpn-114-140.rdu2.redhat.com [10.10.114.140]) by smtp.corp.redhat.com (Postfix) with ESMTP id D20B9797EB; Thu, 28 May 2020 13:48:55 +0000 (UTC) From: Yannick Cote To: live-patching@vger.kernel.org Cc: linux-kselftest@vger.kernel.org, joe.lawrence@redhat.com Subject: [PATCH 1/4] selftests/livepatch: rework test-klp-callbacks to use completion variables Date: Thu, 28 May 2020 09:48:46 -0400 Message-Id: <20200528134849.7890-2-ycote@redhat.com> In-Reply-To: <20200528134849.7890-1-ycote@redhat.com> References: <20200528134849.7890-1-ycote@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Joe Lawrence The test-klp-callbacks script includes a few tests which rely on kernel task timings that may not always execute as expected under system load. These will generate out of sequence kernel log messages that result in test failure. Instead of using sleep timing windows to orchestrate the test, rework the test_klp_callbacks_busy module to use completion variables. Signed-off-by: Joe Lawrence Signed-off-by: Yannick Cote --- lib/livepatch/test_klp_callbacks_busy.c | 42 +++++++++++++++---- .../selftests/livepatch/test-callbacks.sh | 29 +++++++------ 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/livepatch/test_klp_callbacks_busy.c b/lib/livepatch/test_klp_callbacks_busy.c index 40beddf8a0e2..c3df12f47e5e 100644 --- a/lib/livepatch/test_klp_callbacks_busy.c +++ b/lib/livepatch/test_klp_callbacks_busy.c @@ -5,34 +5,58 @@ #include #include +#include #include #include -static int sleep_secs; -module_param(sleep_secs, int, 0644); -MODULE_PARM_DESC(sleep_secs, "sleep_secs (default=0)"); +/* load/run-time control from sysfs writer */ +static bool block_transition; +module_param(block_transition, bool, 0644); +MODULE_PARM_DESC(block_transition, "block_transition (default=false)"); static void busymod_work_func(struct work_struct *work); -static DECLARE_DELAYED_WORK(work, busymod_work_func); +static DECLARE_WORK(work, busymod_work_func); +static DECLARE_COMPLETION(busymod_work_complete); static void busymod_work_func(struct work_struct *work) { - pr_info("%s, sleeping %d seconds ...\n", __func__, sleep_secs); - msleep(sleep_secs * 1000); + bool early_complete = block_transition; + + pr_info("%s enter\n", __func__); + + /* + * When blocking the livepatch transition, set completion flag + * early so subsequent test commands see the transition. + */ + if (early_complete) + complete(&busymod_work_complete); + + while (block_transition) + msleep(1000); + pr_info("%s exit\n", __func__); + + /* + * In non-blocking case, wait until we're done to complete to + * ensure kernel log ordering + */ + if (!early_complete) + complete(&busymod_work_complete); } static int test_klp_callbacks_busy_init(void) { pr_info("%s\n", __func__); - schedule_delayed_work(&work, - msecs_to_jiffies(1000 * 0)); + schedule_work(&work); + wait_for_completion(&busymod_work_complete); + return 0; } static void test_klp_callbacks_busy_exit(void) { - cancel_delayed_work_sync(&work); + block_transition = false; + cancel_work_sync(&work); pr_info("%s\n", __func__); } diff --git a/tools/testing/selftests/livepatch/test-callbacks.sh b/tools/testing/selftests/livepatch/test-callbacks.sh index a35289b13c9c..32b57ba07f4f 100755 --- a/tools/testing/selftests/livepatch/test-callbacks.sh +++ b/tools/testing/selftests/livepatch/test-callbacks.sh @@ -356,9 +356,7 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete echo -n "TEST: multiple target modules ... " dmesg -C -load_mod $MOD_TARGET_BUSY sleep_secs=0 -# give $MOD_TARGET_BUSY::busymod_work_func() a chance to run -sleep 5 +load_mod $MOD_TARGET_BUSY block_transition=N load_lp $MOD_LIVEPATCH load_mod $MOD_TARGET unload_mod $MOD_TARGET @@ -366,9 +364,9 @@ disable_lp $MOD_LIVEPATCH unload_lp $MOD_LIVEPATCH unload_mod $MOD_TARGET_BUSY -check_result "% modprobe $MOD_TARGET_BUSY sleep_secs=0 +check_result "% modprobe $MOD_TARGET_BUSY block_transition=N $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init -$MOD_TARGET_BUSY: busymod_work_func, sleeping 0 seconds ... +$MOD_TARGET_BUSY: busymod_work_func enter $MOD_TARGET_BUSY: busymod_work_func exit % modprobe $MOD_LIVEPATCH livepatch: enabling patch '$MOD_LIVEPATCH' @@ -404,11 +402,10 @@ livepatch: '$MOD_LIVEPATCH': unpatching complete $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" - # TEST: busy target module # # A similar test as the previous one, but force the "busy" kernel module -# to do longer work. +# to block the livepatch transition. # # The livepatching core will refuse to patch a task that is currently # executing a to-be-patched function -- the consistency model stalls the @@ -417,8 +414,7 @@ $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" # function for a long time. Meanwhile, load and unload other target # kernel modules while the livepatch transition is in progress. # -# - Load the "busy" kernel module, this time make it do 10 seconds worth -# of work. +# - Load the "busy" kernel module, this time make its work function loop # # - Meanwhile, the livepatch is loaded. Notice that the patch # transition does not complete as the targeted "busy" module is @@ -438,20 +434,23 @@ $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" echo -n "TEST: busy target module ... " dmesg -C -load_mod $MOD_TARGET_BUSY sleep_secs=10 +load_mod $MOD_TARGET_BUSY block_transition=Y load_lp_nowait $MOD_LIVEPATCH -# Don't wait for transition, load $MOD_TARGET while the transition -# is still stalled in $MOD_TARGET_BUSY::busymod_work_func() -sleep 5 + +# Wait until the livepatch reports in-transition state, i.e. that it's +# stalled on $MOD_TARGET_BUSY::busymod_work_func() +loop_until 'grep -q '^1$' /sys/kernel/livepatch/$MOD_LIVEPATCH/transition' || + die "failed to stall transition" + load_mod $MOD_TARGET unload_mod $MOD_TARGET disable_lp $MOD_LIVEPATCH unload_lp $MOD_LIVEPATCH unload_mod $MOD_TARGET_BUSY -check_result "% modprobe $MOD_TARGET_BUSY sleep_secs=10 +check_result "% modprobe $MOD_TARGET_BUSY block_transition=Y $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init -$MOD_TARGET_BUSY: busymod_work_func, sleeping 10 seconds ... +$MOD_TARGET_BUSY: busymod_work_func enter % modprobe $MOD_LIVEPATCH livepatch: enabling patch '$MOD_LIVEPATCH' livepatch: '$MOD_LIVEPATCH': initializing patching transition From patchwork Thu May 28 13:48:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Cote X-Patchwork-Id: 11575871 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 9D1C1912 for ; Thu, 28 May 2020 13:49:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7D46420814 for ; Thu, 28 May 2020 13:49:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="InHOioVL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390505AbgE1NtE (ORCPT ); Thu, 28 May 2020 09:49:04 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:22413 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2390486AbgE1NtC (ORCPT ); Thu, 28 May 2020 09:49:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590673740; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l2cvqJB46KTH7f8SdbqkLsCyORUTxh86VAPFNgoiJ8k=; b=InHOioVLtldu0i+BRMgmoyaCQZ51ccI/1dnPQERh3kker3VnkiQ76rKzqkvjdmoBmrnoqp XQN9jiJNX0wJ8mRMWrrHrcnCEHsKrP3lrjpR5D27nSvr+BFv0B7BtGsUCdRvw82py9EBCr KdIuQzJ5Z4IcFB8Ov7q2b7WKv0CyMzs= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-469-ZwwtmLHRPLuHp3q13nE7EA-1; Thu, 28 May 2020 09:48:58 -0400 X-MC-Unique: ZwwtmLHRPLuHp3q13nE7EA-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1F51A100CCC1; Thu, 28 May 2020 13:48:57 +0000 (UTC) Received: from dm.redhat.com (ovpn-114-140.rdu2.redhat.com [10.10.114.140]) by smtp.corp.redhat.com (Postfix) with ESMTP id 913647A8BB; Thu, 28 May 2020 13:48:56 +0000 (UTC) From: Yannick Cote To: live-patching@vger.kernel.org Cc: linux-kselftest@vger.kernel.org, joe.lawrence@redhat.com Subject: [PATCH 2/4] selftests/livepatch: rework test-klp-shadow-vars Date: Thu, 28 May 2020 09:48:47 -0400 Message-Id: <20200528134849.7890-3-ycote@redhat.com> In-Reply-To: <20200528134849.7890-1-ycote@redhat.com> References: <20200528134849.7890-1-ycote@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org The initial idea was to make a change to please cppcheck and remove void pointer arithmetics found a few times: portability: 'obj' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined. [arithOperationsOnVoidPointer] The rest of the changes are to help make the test read as an example while continuing to verify the shadow variable code. The logic of the test is unchanged but restructured to use descriptive names. Signed-off-by: Yannick Cote Reviewed-by: Petr Mladek --- lib/livepatch/test_klp_shadow_vars.c | 101 +++++++++++++++------------ 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c index f0b5a1d24e55..ec2635cff974 100644 --- a/lib/livepatch/test_klp_shadow_vars.c +++ b/lib/livepatch/test_klp_shadow_vars.c @@ -109,8 +109,7 @@ static void shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) static void shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) { klp_shadow_free_all(id, dtor); - pr_info("klp_%s(id=0x%lx, dtor=PTR%d)\n", - __func__, id, ptr_id(dtor)); + pr_info("klp_%s(id=0x%lx, dtor=PTR%d)\n", __func__, id, ptr_id(dtor)); } @@ -124,8 +123,7 @@ static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data) return -EINVAL; *sv = *var; - pr_info("%s: PTR%d -> PTR%d\n", - __func__, ptr_id(sv), ptr_id(*var)); + pr_info("%s: PTR%d -> PTR%d\n", __func__, ptr_id(sv), ptr_id(*var)); return 0; } @@ -138,49 +136,63 @@ static void shadow_dtor(void *obj, void *shadow_data) __func__, ptr_id(obj), ptr_id(sv)); } -static int test_klp_shadow_vars_init(void) -{ - void *obj = THIS_MODULE; - int id = 0x1234; - gfp_t gfp_flags = GFP_KERNEL; +/* dynamically created obj fields have the following shadow var id values */ +#define SV_ID1 0x1234 +#define SV_ID2 0x1235 - int var1, var2, var3, var4; - int *pv1, *pv2, *pv3, *pv4; - int **sv1, **sv2, **sv3, **sv4; +/* + * The main test case adds/removes new fields (shadow var) to each of these + * test structure instances. The last group of fields in the struct represent + * the idea that shadow variables may be added and removed to and from the + * struct during execution. + */ +struct test_object { + /* add anything here below and avoid to define an empty struct */ + struct shadow_ptr sp; - int **sv; + /* these represent shadow vars added and removed with SV_ID{1,2} */ + /* char nfield1; */ + /* int nfield2; */ +}; - pv1 = &var1; - pv2 = &var2; - pv3 = &var3; - pv4 = &var4; +static int test_klp_shadow_vars_init(void) +{ + struct test_object obj1, obj2, obj3; + char nfield1, nfield2, *pnfield1, *pnfield2, **sv1, **sv2; + int nfield3, nfield4, *pnfield3, *pnfield4, **sv3, **sv4; + void **sv; + + pnfield1 = &nfield1; + pnfield2 = &nfield2; + pnfield3 = &nfield3; + pnfield4 = &nfield4; ptr_id(NULL); - ptr_id(pv1); - ptr_id(pv2); - ptr_id(pv3); - ptr_id(pv4); + ptr_id(pnfield1); + ptr_id(pnfield2); + ptr_id(pnfield3); + ptr_id(pnfield4); /* * With an empty shadow variable hash table, expect not to find * any matches. */ - sv = shadow_get(obj, id); + sv = shadow_get(&obj1, SV_ID1); if (!sv) pr_info(" got expected NULL result\n"); /* * Allocate a few shadow variables with different and . */ - sv1 = shadow_alloc(obj, id, sizeof(pv1), gfp_flags, shadow_ctor, &pv1); + sv1 = shadow_alloc(&obj1, SV_ID1, sizeof(pnfield1), GFP_KERNEL, shadow_ctor, &pnfield1); if (!sv1) return -ENOMEM; - sv2 = shadow_alloc(obj + 1, id, sizeof(pv2), gfp_flags, shadow_ctor, &pv2); + sv2 = shadow_alloc(&obj2, SV_ID1, sizeof(pnfield2), GFP_KERNEL, shadow_ctor, &pnfield2); if (!sv2) return -ENOMEM; - sv3 = shadow_alloc(obj, id + 1, sizeof(pv3), gfp_flags, shadow_ctor, &pv3); + sv3 = shadow_alloc(&obj1, SV_ID2, sizeof(pnfield3), GFP_KERNEL, shadow_ctor, &pnfield3); if (!sv3) return -ENOMEM; @@ -188,23 +200,24 @@ static int test_klp_shadow_vars_init(void) * Verify we can find our new shadow variables and that they point * to expected data. */ - sv = shadow_get(obj, id); + sv = shadow_get(&obj1, SV_ID1); if (!sv) return -EINVAL; - if (sv == sv1 && *sv1 == pv1) + if ((char **)sv == sv1 && *sv1 == pnfield1) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv1), ptr_id(*sv1)); - sv = shadow_get(obj + 1, id); + sv = shadow_get(&obj2, SV_ID1); if (!sv) return -EINVAL; - if (sv == sv2 && *sv2 == pv2) + if ((char **)sv == sv2 && *sv2 == pnfield2) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv2), ptr_id(*sv2)); - sv = shadow_get(obj, id + 1); + + sv = shadow_get(&obj1, SV_ID2); if (!sv) return -EINVAL; - if (sv == sv3 && *sv3 == pv3) + if ((int **)sv == sv3 && *sv3 == pnfield3) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv3), ptr_id(*sv3)); @@ -212,14 +225,14 @@ static int test_klp_shadow_vars_init(void) * Allocate or get a few more, this time with the same , . * The second invocation should return the same shadow var. */ - sv4 = shadow_get_or_alloc(obj + 2, id, sizeof(pv4), gfp_flags, shadow_ctor, &pv4); + sv4 = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); if (!sv4) return -ENOMEM; - sv = shadow_get_or_alloc(obj + 2, id, sizeof(pv4), gfp_flags, shadow_ctor, &pv4); + sv = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); if (!sv) return -EINVAL; - if (sv == sv4 && *sv4 == pv4) + if ((int **)sv == sv4 && *sv4 == pnfield4) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv4), ptr_id(*sv4)); @@ -227,36 +240,36 @@ static int test_klp_shadow_vars_init(void) * Free the shadow variables and check that we can no * longer find them. */ - shadow_free(obj, id, shadow_dtor); /* sv1 */ - sv = shadow_get(obj, id); + shadow_free(&obj1, SV_ID1, shadow_dtor); /* sv1 */ + sv = shadow_get(&obj1, SV_ID1); if (!sv) pr_info(" got expected NULL result\n"); - shadow_free(obj + 1, id, shadow_dtor); /* sv2 */ - sv = shadow_get(obj + 1, id); + shadow_free(&obj2, SV_ID1, shadow_dtor); /* sv2 */ + sv = shadow_get(&obj2, SV_ID1); if (!sv) pr_info(" got expected NULL result\n"); - shadow_free(obj + 2, id, shadow_dtor); /* sv4 */ - sv = shadow_get(obj + 2, id); + shadow_free(&obj3, SV_ID1, shadow_dtor); /* sv4 */ + sv = shadow_get(&obj3, SV_ID1); if (!sv) pr_info(" got expected NULL result\n"); /* * We should still find an variable. */ - sv = shadow_get(obj, id + 1); + sv = shadow_get(&obj1, SV_ID2); if (!sv) return -EINVAL; - if (sv == sv3 && *sv3 == pv3) + if ((int **)sv == sv3 && *sv3 == pnfield3) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv3), ptr_id(*sv3)); /* * Free all the variables, too. */ - shadow_free_all(id + 1, shadow_dtor); /* sv3 */ - sv = shadow_get(obj, id); + shadow_free_all(SV_ID2, shadow_dtor); /* sv3 */ + sv = shadow_get(&obj1, SV_ID1); if (!sv) pr_info(" shadow_get() got expected NULL result\n"); From patchwork Thu May 28 13:48:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Cote X-Patchwork-Id: 11575873 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 10C1213B4 for ; Thu, 28 May 2020 13:49:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DFA3020814 for ; Thu, 28 May 2020 13:49:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="QBWYvkpE" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390486AbgE1NtE (ORCPT ); Thu, 28 May 2020 09:49:04 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:37029 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2390538AbgE1NtD (ORCPT ); Thu, 28 May 2020 09:49:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590673740; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vCTvVYkxlXoh7jPeCyIDl93N6AKkB5CbqaJp3ZyE8Ro=; b=QBWYvkpEmlxbpgBl6zSnv50jcT85go+EhSmFnCjhRG6CbSsb8c4YZ2U5owFC3A0TWBwRAN FAjoDDXNTp7aNB1Wlbv+U2RHSjZsIKNowcLxcpePRxqWJpnNuPt89IiymiFXemBcj1akqs 16j9+pCMdkV1zX3NjacHDFgYLZ2ADH0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-473-rKUw2BtEP5mOcGcCvY2AcQ-1; Thu, 28 May 2020 09:48:58 -0400 X-MC-Unique: rKUw2BtEP5mOcGcCvY2AcQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CF01A107ACF5; Thu, 28 May 2020 13:48:57 +0000 (UTC) Received: from dm.redhat.com (ovpn-114-140.rdu2.redhat.com [10.10.114.140]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4D1C0797EB; Thu, 28 May 2020 13:48:57 +0000 (UTC) From: Yannick Cote To: live-patching@vger.kernel.org Cc: linux-kselftest@vger.kernel.org, joe.lawrence@redhat.com Subject: [PATCH 3/4] selftests/livepatch: more verification in test-klp-shadow-vars Date: Thu, 28 May 2020 09:48:48 -0400 Message-Id: <20200528134849.7890-4-ycote@redhat.com> In-Reply-To: <20200528134849.7890-1-ycote@redhat.com> References: <20200528134849.7890-1-ycote@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This change makes the test feel more familiar with narrowing to a typical usage by operating on a number of identical structure instances and populating the same two new shadow variables symmetrically while keeping the same testing and verification criteria for the extra variables. Signed-off-by: Yannick Cote --- lib/livepatch/test_klp_shadow_vars.c | 182 ++++++++---------- .../selftests/livepatch/test-shadow-vars.sh | 85 +++++--- 2 files changed, 135 insertions(+), 132 deletions(-) diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c index ec2635cff974..195309e1edf3 100644 --- a/lib/livepatch/test_klp_shadow_vars.c +++ b/lib/livepatch/test_klp_shadow_vars.c @@ -128,6 +128,11 @@ static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data) return 0; } +/* + * With more than one item to free in the list, order is not determined and + * shadow_dtor will not be passed to shadow_free_all() which would make the + * test fail. (see pass 6) + */ static void shadow_dtor(void *obj, void *shadow_data) { int **sv = shadow_data; @@ -136,6 +141,9 @@ static void shadow_dtor(void *obj, void *shadow_data) __func__, ptr_id(obj), ptr_id(sv)); } +/* number of objects we simulate that need kpatch-patch shadow vars */ +#define NUM_OBJS 3 + /* dynamically created obj fields have the following shadow var id values */ #define SV_ID1 0x1234 #define SV_ID2 0x1235 @@ -157,122 +165,96 @@ struct test_object { static int test_klp_shadow_vars_init(void) { - struct test_object obj1, obj2, obj3; - char nfield1, nfield2, *pnfield1, *pnfield2, **sv1, **sv2; - int nfield3, nfield4, *pnfield3, *pnfield4, **sv3, **sv4; + struct test_object objs[NUM_OBJS]; + char nfields1[NUM_OBJS], *pnfields1[NUM_OBJS], **sv1[NUM_OBJS]; + char *pndup[NUM_OBJS]; + int nfields2[NUM_OBJS], *pnfields2[NUM_OBJS], **sv2[NUM_OBJS]; void **sv; - - pnfield1 = &nfield1; - pnfield2 = &nfield2; - pnfield3 = &nfield3; - pnfield4 = &nfield4; + int i; ptr_id(NULL); - ptr_id(pnfield1); - ptr_id(pnfield2); - ptr_id(pnfield3); - ptr_id(pnfield4); /* * With an empty shadow variable hash table, expect not to find * any matches. */ - sv = shadow_get(&obj1, SV_ID1); + sv = shadow_get(&objs[0], SV_ID1); if (!sv) pr_info(" got expected NULL result\n"); - /* - * Allocate a few shadow variables with different and . - */ - sv1 = shadow_alloc(&obj1, SV_ID1, sizeof(pnfield1), GFP_KERNEL, shadow_ctor, &pnfield1); - if (!sv1) - return -ENOMEM; - - sv2 = shadow_alloc(&obj2, SV_ID1, sizeof(pnfield2), GFP_KERNEL, shadow_ctor, &pnfield2); - if (!sv2) - return -ENOMEM; - - sv3 = shadow_alloc(&obj1, SV_ID2, sizeof(pnfield3), GFP_KERNEL, shadow_ctor, &pnfield3); - if (!sv3) - return -ENOMEM; - - /* - * Verify we can find our new shadow variables and that they point - * to expected data. - */ - sv = shadow_get(&obj1, SV_ID1); - if (!sv) - return -EINVAL; - if ((char **)sv == sv1 && *sv1 == pnfield1) - pr_info(" got expected PTR%d -> PTR%d result\n", - ptr_id(sv1), ptr_id(*sv1)); - - sv = shadow_get(&obj2, SV_ID1); - if (!sv) - return -EINVAL; - if ((char **)sv == sv2 && *sv2 == pnfield2) - pr_info(" got expected PTR%d -> PTR%d result\n", - ptr_id(sv2), ptr_id(*sv2)); - - sv = shadow_get(&obj1, SV_ID2); - if (!sv) - return -EINVAL; - if ((int **)sv == sv3 && *sv3 == pnfield3) - pr_info(" got expected PTR%d -> PTR%d result\n", - ptr_id(sv3), ptr_id(*sv3)); - - /* - * Allocate or get a few more, this time with the same , . - * The second invocation should return the same shadow var. - */ - sv4 = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); - if (!sv4) - return -ENOMEM; - - sv = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); - if (!sv) - return -EINVAL; - if ((int **)sv == sv4 && *sv4 == pnfield4) - pr_info(" got expected PTR%d -> PTR%d result\n", - ptr_id(sv4), ptr_id(*sv4)); - - /* - * Free the shadow variables and check that we can no - * longer find them. - */ - shadow_free(&obj1, SV_ID1, shadow_dtor); /* sv1 */ - sv = shadow_get(&obj1, SV_ID1); - if (!sv) - pr_info(" got expected NULL result\n"); + /* pass 1: init & alloc a char+int pair of svars for each objs */ + for (i = 0; i < NUM_OBJS; i++) { + pnfields1[i] = &nfields1[i]; + pnfields2[i] = &nfields2[i]; + ptr_id(pnfields1[i]); + ptr_id(pnfields2[i]); + + /* alloc a few svars with different and . */ + sv1[i] = shadow_alloc(&objs[i], SV_ID1, sizeof(pnfields1[i]), + GFP_KERNEL, shadow_ctor, &pnfields1[i]); + if (!sv1[i]) + return -ENOMEM; + sv2[i] = shadow_alloc(&objs[i], SV_ID2, sizeof(pnfields2[i]), + GFP_KERNEL, shadow_ctor, &pnfields2[i]); + if (!sv2[i]) + return -ENOMEM; + } - shadow_free(&obj2, SV_ID1, shadow_dtor); /* sv2 */ - sv = shadow_get(&obj2, SV_ID1); - if (!sv) - pr_info(" got expected NULL result\n"); + /* pass 2: verify we find allocated svars and where they point to */ + for (i = 0; i < NUM_OBJS; i++) { + /* check the "char" svar for all objects */ + sv = shadow_get(&objs[i], SV_ID1); + if (!sv) + return -EINVAL; + if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) + pr_info(" got expected PTR%d -> PTR%d result\n", + ptr_id(sv1[i]), ptr_id(*sv1[i])); + + /* check the "int" svar for all objects */ + sv = shadow_get(&objs[i], SV_ID2); + if (!sv) + return -EINVAL; + if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) + pr_info(" got expected PTR%d -> PTR%d result\n", + ptr_id(sv2[i]), ptr_id(*sv2[i])); + } - shadow_free(&obj3, SV_ID1, shadow_dtor); /* sv4 */ - sv = shadow_get(&obj3, SV_ID1); - if (!sv) - pr_info(" got expected NULL result\n"); + /* pass 3: verify that 'get_of_alloc' returns already allocated svars */ + for (i = 0; i < NUM_OBJS; i++) { + sv = shadow_get_or_alloc(&objs[i], SV_ID1, sizeof(pndup[i]), + GFP_KERNEL, shadow_ctor, &pndup[i]); + if (!sv) + return -EINVAL; + if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) + pr_info(" got expected PTR%d -> PTR%d result\n", + ptr_id(sv1[i]), ptr_id(*sv1[i])); + } - /* - * We should still find an variable. - */ - sv = shadow_get(&obj1, SV_ID2); - if (!sv) - return -EINVAL; - if ((int **)sv == sv3 && *sv3 == pnfield3) - pr_info(" got expected PTR%d -> PTR%d result\n", - ptr_id(sv3), ptr_id(*sv3)); + /* pass 4: free pairs of svars, verify removal */ + for (i = 0; i < NUM_OBJS; i++) { + shadow_free(&objs[i], SV_ID1, shadow_dtor); /* 'char' pairs */ + sv = shadow_get(&objs[i], SV_ID1); + if (!sv) + pr_info(" got expected NULL result\n"); + } - /* - * Free all the variables, too. - */ - shadow_free_all(SV_ID2, shadow_dtor); /* sv3 */ - sv = shadow_get(&obj1, SV_ID1); - if (!sv) - pr_info(" shadow_get() got expected NULL result\n"); + /* pass 5: check we still find svar pairs */ + for (i = 0; i < NUM_OBJS; i++) { + sv = shadow_get(&objs[i], SV_ID2); /* 'int' pairs */ + if (!sv) + return -EINVAL; + if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) + pr_info(" got expected PTR%d -> PTR%d result\n", + ptr_id(sv2[i]), ptr_id(*sv2[i])); + } + /* pass 6: free all the svar pairs too. */ + shadow_free_all(SV_ID2, NULL); /* 'int' pairs */ + for (i = 0; i < NUM_OBJS; i++) { + sv = shadow_get(&objs[i], SV_ID2); + if (!sv) + pr_info(" shadow_get() got expected NULL result\n"); + } free_ptr_list(); diff --git a/tools/testing/selftests/livepatch/test-shadow-vars.sh b/tools/testing/selftests/livepatch/test-shadow-vars.sh index 1aae73299114..469ceb345b3a 100755 --- a/tools/testing/selftests/livepatch/test-shadow-vars.sh +++ b/tools/testing/selftests/livepatch/test-shadow-vars.sh @@ -19,42 +19,63 @@ load_mod $MOD_TEST unload_mod $MOD_TEST check_result "% modprobe $MOD_TEST -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR0 $MOD_TEST: got expected NULL result -$MOD_TEST: shadow_ctor: PTR6 -> PTR1 -$MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR1 = PTR6 -$MOD_TEST: shadow_ctor: PTR8 -> PTR2 -$MOD_TEST: klp_shadow_alloc(obj=PTR9, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR2 = PTR8 -$MOD_TEST: shadow_ctor: PTR10 -> PTR3 -$MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR3 = PTR10 -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR6 -$MOD_TEST: got expected PTR6 -> PTR1 result -$MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR8 -$MOD_TEST: got expected PTR8 -> PTR2 result -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 -$MOD_TEST: got expected PTR10 -> PTR3 result -$MOD_TEST: shadow_ctor: PTR11 -> PTR4 -$MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 -$MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 -$MOD_TEST: got expected PTR11 -> PTR4 result -$MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR6) -$MOD_TEST: klp_shadow_free(obj=PTR5, id=0x1234, dtor=PTR13) -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 +$MOD_TEST: shadow_ctor: PTR4 -> PTR2 +$MOD_TEST: klp_shadow_alloc(obj=PTR1, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR2 = PTR4 +$MOD_TEST: shadow_ctor: PTR6 -> PTR3 +$MOD_TEST: klp_shadow_alloc(obj=PTR1, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR3 = PTR6 +$MOD_TEST: shadow_ctor: PTR9 -> PTR7 +$MOD_TEST: klp_shadow_alloc(obj=PTR10, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR7 = PTR9 +$MOD_TEST: shadow_ctor: PTR11 -> PTR8 +$MOD_TEST: klp_shadow_alloc(obj=PTR10, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR8 = PTR11 +$MOD_TEST: shadow_ctor: PTR14 -> PTR12 +$MOD_TEST: klp_shadow_alloc(obj=PTR15, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR12 = PTR14 +$MOD_TEST: shadow_ctor: PTR16 -> PTR13 +$MOD_TEST: klp_shadow_alloc(obj=PTR15, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR13 = PTR16 +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR4 +$MOD_TEST: got expected PTR4 -> PTR2 result +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR6 +$MOD_TEST: got expected PTR6 -> PTR3 result +$MOD_TEST: klp_shadow_get(obj=PTR10, id=0x1234) = PTR9 +$MOD_TEST: got expected PTR9 -> PTR7 result +$MOD_TEST: klp_shadow_get(obj=PTR10, id=0x1235) = PTR11 +$MOD_TEST: got expected PTR11 -> PTR8 result +$MOD_TEST: klp_shadow_get(obj=PTR15, id=0x1234) = PTR14 +$MOD_TEST: got expected PTR14 -> PTR12 result +$MOD_TEST: klp_shadow_get(obj=PTR15, id=0x1235) = PTR16 +$MOD_TEST: got expected PTR16 -> PTR13 result +$MOD_TEST: klp_shadow_get_or_alloc(obj=PTR1, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR17 = PTR4 +$MOD_TEST: got expected PTR4 -> PTR2 result +$MOD_TEST: klp_shadow_get_or_alloc(obj=PTR10, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR18 = PTR9 +$MOD_TEST: got expected PTR9 -> PTR7 result +$MOD_TEST: klp_shadow_get_or_alloc(obj=PTR15, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR5, ctor_data=PTR19 = PTR14 +$MOD_TEST: got expected PTR14 -> PTR12 result +$MOD_TEST: shadow_dtor(obj=PTR1, shadow_data=PTR4) +$MOD_TEST: klp_shadow_free(obj=PTR1, id=0x1234, dtor=PTR20) +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR0 $MOD_TEST: got expected NULL result -$MOD_TEST: shadow_dtor(obj=PTR9, shadow_data=PTR8) -$MOD_TEST: klp_shadow_free(obj=PTR9, id=0x1234, dtor=PTR13) -$MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR0 +$MOD_TEST: shadow_dtor(obj=PTR10, shadow_data=PTR9) +$MOD_TEST: klp_shadow_free(obj=PTR10, id=0x1234, dtor=PTR20) +$MOD_TEST: klp_shadow_get(obj=PTR10, id=0x1234) = PTR0 $MOD_TEST: got expected NULL result -$MOD_TEST: shadow_dtor(obj=PTR12, shadow_data=PTR11) -$MOD_TEST: klp_shadow_free(obj=PTR12, id=0x1234, dtor=PTR13) -$MOD_TEST: klp_shadow_get(obj=PTR12, id=0x1234) = PTR0 +$MOD_TEST: shadow_dtor(obj=PTR15, shadow_data=PTR14) +$MOD_TEST: klp_shadow_free(obj=PTR15, id=0x1234, dtor=PTR20) +$MOD_TEST: klp_shadow_get(obj=PTR15, id=0x1234) = PTR0 $MOD_TEST: got expected NULL result -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 -$MOD_TEST: got expected PTR10 -> PTR3 result -$MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR10) -$MOD_TEST: klp_shadow_free_all(id=0x1235, dtor=PTR13) -$MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR6 +$MOD_TEST: got expected PTR6 -> PTR3 result +$MOD_TEST: klp_shadow_get(obj=PTR10, id=0x1235) = PTR11 +$MOD_TEST: got expected PTR11 -> PTR8 result +$MOD_TEST: klp_shadow_get(obj=PTR15, id=0x1235) = PTR16 +$MOD_TEST: got expected PTR16 -> PTR13 result +$MOD_TEST: klp_shadow_free_all(id=0x1235, dtor=PTR0) +$MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR0 $MOD_TEST: shadow_get() got expected NULL result -% rmmod test_klp_shadow_vars" +$MOD_TEST: klp_shadow_get(obj=PTR10, id=0x1235) = PTR0 +$MOD_TEST: shadow_get() got expected NULL result +$MOD_TEST: klp_shadow_get(obj=PTR15, id=0x1235) = PTR0 +$MOD_TEST: shadow_get() got expected NULL result +% rmmod $MOD_TEST" exit 0 From patchwork Thu May 28 13:48:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Cote X-Patchwork-Id: 11575875 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 45895166C for ; Thu, 28 May 2020 13:49:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 246AC20814 for ; Thu, 28 May 2020 13:49:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="edLz5lT2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390496AbgE1NtE (ORCPT ); Thu, 28 May 2020 09:49:04 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:43575 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2390497AbgE1NtD (ORCPT ); Thu, 28 May 2020 09:49:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590673741; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9ZuEdoQFokpyh7ut5OfaaYt9boo3QR1gcKg76iY9Rcs=; b=edLz5lT2sKwScCh66HUaQqB5se1ZQyvJJgYo2y/wgTRSUHy1Z08bzLO7Yq2ONTHLg1hy/1 RPFgmLTwo1Nudsq29fqwezJxsjwpkn3tFzkhBMB0u4Em1LtlU8ngcz/pVbP+RQVAB9Suyb DypiI5BnbAgtdnGXTyaU89e74kiF4v0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-1-d38MtTYUP8im97rlVecp3g-1; Thu, 28 May 2020 09:48:59 -0400 X-MC-Unique: d38MtTYUP8im97rlVecp3g-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 8D4E218FF661; Thu, 28 May 2020 13:48:58 +0000 (UTC) Received: from dm.redhat.com (ovpn-114-140.rdu2.redhat.com [10.10.114.140]) by smtp.corp.redhat.com (Postfix) with ESMTP id 09A5C797EB; Thu, 28 May 2020 13:48:57 +0000 (UTC) From: Yannick Cote To: live-patching@vger.kernel.org Cc: linux-kselftest@vger.kernel.org, joe.lawrence@redhat.com Subject: [PATCH 4/4] selftests/livepatch: fix mem leaks in test-klp-shadow-vars Date: Thu, 28 May 2020 09:48:49 -0400 Message-Id: <20200528134849.7890-5-ycote@redhat.com> In-Reply-To: <20200528134849.7890-1-ycote@redhat.com> References: <20200528134849.7890-1-ycote@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In some cases, when an error occurs during testing and the main test routine returns, a memory leak occurs via leaving previously registered shadow variables allocated in the kernel as well as shadow_ptr list elements. From now on, in case of error, remove all allocated shadow variables and shadow_ptr struct elements. Signed-off-by: Yannick Cote Reviewed-by: Petr Mladek --- lib/livepatch/test_klp_shadow_vars.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c index 195309e1edf3..c6d631d826e0 100644 --- a/lib/livepatch/test_klp_shadow_vars.c +++ b/lib/livepatch/test_klp_shadow_vars.c @@ -170,6 +170,7 @@ static int test_klp_shadow_vars_init(void) char *pndup[NUM_OBJS]; int nfields2[NUM_OBJS], *pnfields2[NUM_OBJS], **sv2[NUM_OBJS]; void **sv; + int ret = -EINVAL; int i; ptr_id(NULL); @@ -192,12 +193,16 @@ static int test_klp_shadow_vars_init(void) /* alloc a few svars with different and . */ sv1[i] = shadow_alloc(&objs[i], SV_ID1, sizeof(pnfields1[i]), GFP_KERNEL, shadow_ctor, &pnfields1[i]); - if (!sv1[i]) - return -ENOMEM; + if (!sv1[i]) { + ret = -ENOMEM; + goto out; + } sv2[i] = shadow_alloc(&objs[i], SV_ID2, sizeof(pnfields2[i]), GFP_KERNEL, shadow_ctor, &pnfields2[i]); - if (!sv2[i]) - return -ENOMEM; + if (!sv2[i]) { + ret = -ENOMEM; + goto out; + } } /* pass 2: verify we find allocated svars and where they point to */ @@ -205,7 +210,7 @@ static int test_klp_shadow_vars_init(void) /* check the "char" svar for all objects */ sv = shadow_get(&objs[i], SV_ID1); if (!sv) - return -EINVAL; + goto out; if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv1[i]), ptr_id(*sv1[i])); @@ -213,7 +218,7 @@ static int test_klp_shadow_vars_init(void) /* check the "int" svar for all objects */ sv = shadow_get(&objs[i], SV_ID2); if (!sv) - return -EINVAL; + goto out; if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv2[i]), ptr_id(*sv2[i])); @@ -224,7 +229,7 @@ static int test_klp_shadow_vars_init(void) sv = shadow_get_or_alloc(&objs[i], SV_ID1, sizeof(pndup[i]), GFP_KERNEL, shadow_ctor, &pndup[i]); if (!sv) - return -EINVAL; + goto out; if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv1[i]), ptr_id(*sv1[i])); @@ -242,7 +247,7 @@ static int test_klp_shadow_vars_init(void) for (i = 0; i < NUM_OBJS; i++) { sv = shadow_get(&objs[i], SV_ID2); /* 'int' pairs */ if (!sv) - return -EINVAL; + goto out; if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) pr_info(" got expected PTR%d -> PTR%d result\n", ptr_id(sv2[i]), ptr_id(*sv2[i])); @@ -259,6 +264,12 @@ static int test_klp_shadow_vars_init(void) free_ptr_list(); return 0; +out: + shadow_free_all(SV_ID1, NULL); /* 'char' pairs */ + shadow_free_all(SV_ID2, NULL); /* 'int' pairs */ + free_ptr_list(); + + return ret; } static void test_klp_shadow_vars_exit(void)