From patchwork Tue Nov 18 06:19:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wang Nan X-Patchwork-Id: 40990 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-la0-f69.google.com (mail-la0-f69.google.com [209.85.215.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 4BB4424035 for ; Tue, 18 Nov 2014 06:23:27 +0000 (UTC) Received: by mail-la0-f69.google.com with SMTP id gq15sf1636848lab.8 for ; Mon, 17 Nov 2014 22:23:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe:content-type; bh=1PaguKKYHzSnW6Brw2jy6nSWJ3QX/KaBUblilLxdj6g=; b=Gj1Y3T+iETs7S3ukql+QcNq+hidllbfWI4ALZuAWzPW/HI8prsZtvb00v3ZhKreK+Y pIJ6XMnCjub8/Q4tMQKIrWHELP7tlJrwFlhzHgU7S0IC2xdQyW9tGu71jIXH+5O6vevK W04ddyO6tuD2dt+Q6chQy9nW8sa+Cx42CTU1eTp7vbKdNALHYP+ylJMvfxg4FqSrPh3a DIuBI9L+OWIMPjXS3GPrG6AZ5j4ON//9P0zzxAoSjuct+iAGWlJpKZER7fYrc7gf4AiL r0qk2O1dzdfnLhFSG35GIzwg4iAOORk88K+4zmSeC4L9QrxnzO7eVrt4vECbNqOqef9s O3xQ== X-Gm-Message-State: ALoCoQlHRCrOxama3DQe+NZxzswRxhXIdrmuyOei7gjJe1JZkwH9PYp+GMn9MQqDW26pDTtF61Mb X-Received: by 10.112.166.102 with SMTP id zf6mr1879lbb.12.1416291806192; Mon, 17 Nov 2014 22:23:26 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.100 with SMTP id p4ls1192666laj.46.gmail; Mon, 17 Nov 2014 22:23:25 -0800 (PST) X-Received: by 10.112.145.37 with SMTP id sr5mr16623776lbb.76.1416291805651; Mon, 17 Nov 2014 22:23:25 -0800 (PST) Received: from mail-lb0-f182.google.com (mail-lb0-f182.google.com. [209.85.217.182]) by mx.google.com with ESMTPS id c8si46802727lac.96.2014.11.17.22.23.25 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 17 Nov 2014 22:23:25 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.182 as permitted sender) client-ip=209.85.217.182; Received: by mail-lb0-f182.google.com with SMTP id f15so19056732lbj.27 for ; Mon, 17 Nov 2014 22:23:25 -0800 (PST) X-Received: by 10.112.52.37 with SMTP id q5mr33160501lbo.32.1416291805516; Mon, 17 Nov 2014 22:23:25 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.184.201 with SMTP id ew9csp1281355lbc; Mon, 17 Nov 2014 22:23:24 -0800 (PST) X-Received: by 10.70.127.169 with SMTP id nh9mr35051076pdb.115.1416291802977; Mon, 17 Nov 2014 22:23:22 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t1si37140720pdd.185.2014.11.17.22.23.21 for ; Mon, 17 Nov 2014 22:23:22 -0800 (PST) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753382AbaKRGXK (ORCPT + 26 others); Tue, 18 Nov 2014 01:23:10 -0500 Received: from szxga02-in.huawei.com ([119.145.14.65]:7836 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751620AbaKRGXH (ORCPT ); Tue, 18 Nov 2014 01:23:07 -0500 Received: from 172.24.2.119 (EHLO lggeml422-hub.china.huawei.com) ([172.24.2.119]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id CCN16101; Tue, 18 Nov 2014 14:22:36 +0800 (CST) Received: from kernel-host.huawei (10.107.197.247) by lggeml422-hub.china.huawei.com (10.72.61.32) with Microsoft SMTP Server id 14.3.158.1; Tue, 18 Nov 2014 14:22:27 +0800 From: Wang Nan To: , , , , , , , , , CC: , , Subject: [PATCH v2 1/3] ARM: kprobes: introduces checker Date: Tue, 18 Nov 2014 14:19:40 +0800 Message-ID: <1416291582-74982-2-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.4 In-Reply-To: <1416291582-74982-1-git-send-email-wangnan0@huawei.com> References: <1416291582-74982-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.107.197.247] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: wangnan0@huawei.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.182 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch introdces 'checker' to decoding phase, and calls checkers when instruction decoding. This allows further decoding for specific instructions. v1 -> v2: - kprobe checker stubs are introduced in this patch. Signed-off-by: Wang Nan Reviewed-by: Jon Medhurst Reviewed-by: Masami Hiramatsu --- arch/arm/kernel/kprobes-arm.c | 2 ++ arch/arm/kernel/kprobes-thumb.c | 3 +++ arch/arm/kernel/kprobes.c | 6 ++++- arch/arm/kernel/kprobes.h | 7 ++++-- arch/arm/kernel/probes-arm.c | 5 ++-- arch/arm/kernel/probes-arm.h | 3 ++- arch/arm/kernel/probes-thumb.c | 10 ++++---- arch/arm/kernel/probes-thumb.h | 6 +++-- arch/arm/kernel/probes.c | 51 ++++++++++++++++++++++++++++++++++++++++- arch/arm/kernel/probes.h | 11 ++++++++- arch/arm/kernel/uprobes.c | 2 +- 11 files changed, 91 insertions(+), 15 deletions(-) diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index ac300c6..5a81275 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -341,3 +341,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_BRANCH] = {.handler = simulate_bbl}, [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} }; + +const struct decode_checker *kprobes_arm_checkers[] = {NULL}; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 9495d7f..b8ba7d2 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -664,3 +664,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { [PROBES_T32_MUL_ADD_LONG] = { .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, }; + +const struct decode_checker *kprobes_t32_checkers[] = {NULL}; +const struct decode_checker *kprobes_t16_checkers[] = {NULL}; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 6d64420..f114a3f 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) kprobe_decode_insn_t *decode_insn; const union decode_action *actions; int is; + const struct decode_checker **checkers; if (in_exception_text(addr)) return -EINVAL; @@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn = __opcode_thumb32_compose(insn, inst2); decode_insn = thumb32_probes_decode_insn; actions = kprobes_t32_actions; + checkers = kprobes_t32_checkers; } else { decode_insn = thumb16_probes_decode_insn; actions = kprobes_t16_actions; + checkers = kprobes_t16_checkers; } #else /* !CONFIG_THUMB2_KERNEL */ thumb = false; @@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn = __mem_to_opcode_arm(*p->addr); decode_insn = arm_probes_decode_insn; actions = kprobes_arm_actions; + checkers = kprobes_arm_checkers; #endif p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { + switch ((*decode_insn)(insn, &p->ainsn, true, actions, NULL)) { case INSN_REJECTED: /* not supported */ return -EINVAL; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 9a2712e..05f3b40 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -36,16 +36,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_probes_insn *, bool, - const union decode_action *); + const union decode_action *, + const struct decode_checker *[*]); #ifdef CONFIG_THUMB2_KERNEL extern const union decode_action kprobes_t32_actions[]; extern const union decode_action kprobes_t16_actions[]; - +extern const struct decode_checker *kprobes_t32_checkers[]; +extern const struct decode_checker *kprobes_t16_checkers[]; #else /* !CONFIG_THUMB2_KERNEL */ extern const union decode_action kprobes_arm_actions[]; +extern const struct decode_checker *kprobes_arm_checkers[]; #endif diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 8eaef81..125feda 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -725,10 +725,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, */ enum probes_insn __kprobes arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28]; return probes_decode_insn(insn, asi, probes_decode_arm_table, false, - emulate, actions); + emulate, actions, checkers); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index ace6572..8b11ec4 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, struct arch_probes_insn *, bool emulate, - const union decode_action *actions); + const union decode_action *actions, + const struct decode_checker *checkers[]); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index 4131351..a5022b4 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, - emulate, actions); + emulate, actions, checkers); } enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, - emulate, actions); + emulate, actions, checkers); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 7c6f6eb..ccfe3e4 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -89,9 +89,11 @@ extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions); + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]); enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions); + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index a8ab540..02598da 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) }; +static int run_checkers(const struct decode_checker *checkers[], + int action, probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + const struct decode_checker **p; + + if (!checkers) + return INSN_GOOD; + + p = checkers; + while (*p != NULL) { + int retval; + probes_check_t *checker_func = (*p)[action].checker; + + retval = INSN_GOOD; + if (checker_func) + retval = checker_func(insn, asi, h); + if (retval == INSN_REJECTED) + return retval; + p++; + } + return INSN_GOOD; +} + /* * probes_decode_insn operates on data tables in order to decode an ARM * architecture instruction onto which a kprobe has been placed. @@ -388,11 +413,17 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; bool matched = false; + /* + * @insn can be modified by decode_regs. Save its original + * value for checkers. + */ + probes_opcode_t origin_insn = insn; if (emulate) insn = prepare_emulated_insn(insn, asi, thumb); @@ -422,18 +453,36 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, } case DECODE_TYPE_CUSTOM: { + int err; struct decode_custom *d = (struct decode_custom *)h; + int action = d->decoder.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; return actions[d->decoder.action].decoder(insn, asi, h); } case DECODE_TYPE_SIMULATE: { + int err; struct decode_simulate *d = (struct decode_simulate *)h; + int action = d->handler.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; asi->insn_handler = actions[d->handler.action].handler; return INSN_GOOD_NO_SLOT; } case DECODE_TYPE_EMULATE: { + int err; struct decode_emulate *d = (struct decode_emulate *)h; + int action = d->handler.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; if (!emulate) return actions[d->handler.action].decoder(insn, diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index dba9f24..b4bf1f5 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -314,6 +314,14 @@ union decode_action { probes_custom_decode_t *decoder; }; +typedef enum probes_insn (probes_check_t)(probes_opcode_t, + struct arch_probes_insn *, + const struct decode_header *); + +struct decode_checker { + probes_check_t *checker; +}; + #define DECODE_END \ {.bits = DECODE_TYPE_END} @@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none; int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, bool emulate, - const union decode_action *actions); + const union decode_action *actions, + const struct decode_checker **checkers); #endif diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/kernel/uprobes.c index 56adf9c..372585a 100644 --- a/arch/arm/kernel/uprobes.c +++ b/arch/arm/kernel/uprobes.c @@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); ret = arm_probes_decode_insn(insn, &auprobe->asi, false, - uprobes_probes_actions); + uprobes_probes_actions, NULL); switch (ret) { case INSN_REJECTED: return -EINVAL;