Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751331AbdFASZf (ORCPT ); Thu, 1 Jun 2017 14:25:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49698 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751122AbdFASZc (ORCPT ); Thu, 1 Jun 2017 14:25:32 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8EE2C7F6A1 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=joe.lawrence@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8EE2C7F6A1 From: Joe Lawrence To: live-patching@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Josh Poimboeuf , Jessica Yu , Jiri Kosina , Miroslav Benes , Petr Mladek Subject: [PATCH 1/3] livepatch: introduce shadow variable API Date: Thu, 1 Jun 2017 14:25:24 -0400 Message-Id: <1496341526-19061-2-git-send-email-joe.lawrence@redhat.com> In-Reply-To: <1496341526-19061-1-git-send-email-joe.lawrence@redhat.com> References: <1496341526-19061-1-git-send-email-joe.lawrence@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Thu, 01 Jun 2017 18:25:31 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4687 Lines: 164 Add three exported API for livepatch modules: void *klp_shadow_attach(void *obj, char *var, gfp_t gfp, void *data); void klp_shadow_detach(void *obj, char *var); void *klp_shadow_get(void *obj, char *var); that implement "shadow" variables, which allow callers to associate new shadow fields to existing data structures. Signed-off-by: Joe Lawrence --- include/linux/livepatch.h | 4 ++ kernel/livepatch/Makefile | 2 +- kernel/livepatch/shadow.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 kernel/livepatch/shadow.c diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 194991ef9347..a0d068ecf7f8 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -164,6 +164,10 @@ static inline bool klp_have_reliable_stack(void) IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE); } +void *klp_shadow_attach(void *obj, char *var, gfp_t gfp, void *data); +void klp_shadow_detach(void *obj, char *var); +void *klp_shadow_get(void *obj, char *var); + #else /* !CONFIG_LIVEPATCH */ static inline int klp_module_coming(struct module *mod) { return 0; } diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile index 2b8bdb1925da..b36ceda6488e 100644 --- a/kernel/livepatch/Makefile +++ b/kernel/livepatch/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o -livepatch-objs := core.o patch.o transition.o +livepatch-objs := core.o patch.o shadow.o transition.o diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c new file mode 100644 index 000000000000..72d5e567dff9 --- /dev/null +++ b/kernel/livepatch/shadow.c @@ -0,0 +1,115 @@ +/* + * shadow.c - Shadow Variables + * + * Copyright (C) 2014 Josh Poimboeuf + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2017 Joe Lawrence + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +static DEFINE_HASHTABLE(klp_shadow_hash, 12); +static DEFINE_SPINLOCK(klp_shadow_lock); + +struct klp_shadow { + struct hlist_node node; + struct rcu_head rcu_head; + void *obj; + char *var; + void *data; +}; + +void *klp_shadow_attach(void *obj, char *var, gfp_t gfp, void *data) +{ + unsigned long flags; + struct klp_shadow *shadow; + + shadow = kmalloc(sizeof(*shadow), gfp); + if (!shadow) + return NULL; + + shadow->obj = obj; + + shadow->var = kstrdup(var, gfp); + if (!shadow->var) { + kfree(shadow); + return NULL; + } + + shadow->data = data; + + spin_lock_irqsave(&klp_shadow_lock, flags); + hash_add_rcu(klp_shadow_hash, &shadow->node, (unsigned long)obj); + spin_unlock_irqrestore(&klp_shadow_lock, flags); + + return shadow->data; +} +EXPORT_SYMBOL_GPL(klp_shadow_attach); + +static void klp_shadow_rcu_free(struct rcu_head *head) +{ + struct klp_shadow *shadow; + + shadow = container_of(head, struct klp_shadow, rcu_head); + + kfree(shadow->var); + kfree(shadow); +} + +void klp_shadow_detach(void *obj, char *var) +{ + unsigned long flags; + struct klp_shadow *shadow; + + spin_lock_irqsave(&klp_shadow_lock, flags); + + hash_for_each_possible(klp_shadow_hash, shadow, node, + (unsigned long)obj) { + if (shadow->obj == obj && !strcmp(shadow->var, var)) { + hash_del_rcu(&shadow->node); + spin_unlock_irqrestore(&klp_shadow_lock, flags); + call_rcu(&shadow->rcu_head, klp_shadow_rcu_free); + return; + } + } + + spin_unlock_irqrestore(&klp_shadow_lock, flags); +} +EXPORT_SYMBOL_GPL(klp_shadow_detach); + +void *klp_shadow_get(void *obj, char *var) +{ + struct klp_shadow *shadow; + + rcu_read_lock(); + + hash_for_each_possible_rcu(klp_shadow_hash, shadow, node, + (unsigned long)obj) { + if (shadow->obj == obj && !strcmp(shadow->var, var)) { + rcu_read_unlock(); + return shadow->data; + } + } + + rcu_read_unlock(); + + return NULL; +} +EXPORT_SYMBOL_GPL(klp_shadow_get); -- 1.8.3.1