Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752627AbdHRQSD (ORCPT ); Fri, 18 Aug 2017 12:18:03 -0400 Received: from mx2.suse.de ([195.135.220.15]:49994 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750987AbdHRQSC (ORCPT ); Fri, 18 Aug 2017 12:18:02 -0400 Date: Fri, 18 Aug 2017 18:18:00 +0200 From: Petr Mladek To: Joe Lawrence Cc: live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, Josh Poimboeuf , Jessica Yu , Jiri Kosina , Miroslav Benes Subject: Re: [PATCH v4] livepatch: introduce shadow variable API Message-ID: <20170818161800.GE25223@pathway.suse.cz> References: <1502740963-31310-1-git-send-email-joe.lawrence@redhat.com> <1502740963-31310-2-git-send-email-joe.lawrence@redhat.com> <20170817140545.GF601@pathway.suse.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3231 Lines: 98 On Fri 2017-08-18 09:46:08, Joe Lawrence wrote: > On 08/17/2017 10:05 AM, Petr Mladek wrote: > > On Mon 2017-08-14 16:02:43, Joe Lawrence wrote: > >> [ ... snip ... ] > >> diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c > >> new file mode 100644 > >> index 000000000000..5acc838463d1 > >> --- /dev/null > >> +++ b/samples/livepatch/livepatch-shadow-fix1.c > >> +void livepatch_fix1_dummy_free(struct dummy *d) > >> +{ > >> + void **shadow_leak; > >> + > >> + /* > >> + * Patch: fetch the saved SV_LEAK shadow variable, detach and > >> + * free it. Note: handle cases where this shadow variable does > >> + * not exist (ie, dummy structures allocated before this livepatch > >> + * was loaded.) > >> + */ > >> + shadow_leak = klp_shadow_get(d, SV_LEAK); > >> + if (shadow_leak) { > >> + klp_shadow_detach(d, SV_LEAK); > >> + kfree(*shadow_leak); > > > > This should get removed. The buffer used for the shadow variable > > is freed by kfree_rcu() called from klp_shadow_detach(). > > > > Same problem is also in the other livepatch. > > > >> + pr_info("%s: dummy @ %p, prevented leak @ %p\n", > >> + __func__, d, *shadow_leak); > > > > This might access shadow_leak after it was (double) freed. > > > >> + } else { > >> + pr_info("%s: dummy @ %p leaked!\n", __func__, d); > >> + } > >> + > >> + kfree(d); > >> +} > > Hi Petr, > > I think you're half correct. > > The kfree is the crux of the memory leak patch, so it needs to stay. > However, the shadow variable is holding a copy of the pointer to the > memory leak area, so you're right that it can't be safely dereferenced > after the shadow variable is detached*. Ah, I see. The extra kftree does not free the shadow->data but it frees the data that the shadow variable points to. > The code should to be rearranged like: > > void livepatch_fix1_dummy_free(struct dummy *d) > { > void **p_shadow_leak, *shadow_leak; > > p_shadow_leak = klp_shadow_get(d, SV_LEAK); > if (p_shadow_leak) { > shadow_leak = *p_shadow_leak; << deref before detach I would rename shadow_leak -> leak. It will make it more clear that it is the original leak pointer. Well, we could actually free the data before we detach/destroy the shadow variable. But then it might deserve a comment to avoid confusion that I had. I mean: shadow_leak = klp_shadow_get(d, SV_LEAK); if (shadow_leak) { pr_info("%s: dummy @ %p, prevented leak @ %p\n", __func__, d, *shadow_leak); /* Free the previously leaked data */ kfree(*shadow_leak); /* Free the shadow variable */ klp_shadow_detach(d, SV_LEAK); > klp_shadow_detach(d, SV_LEAK); > kfree(shadow_leak); > ... > > * Aside: I usually develop with slub_debug=FZPU set to catch silly > use-after-frees like this. Sounds like a good practice. > released via kfree_rcu(), I think there was a window before the grace > period where this one worked out okay... once I added a > synchronize_rcu() call in between the klp_shadow_detch() and kfree() > calls, I did see the poison pattern. This is my first time using > kfree_rcu(), so it was interesting to dig into. Yup. Best Regards, Petr