292e742220
* add dev-package * modularize some kernel drivers * modernize Makefile to silence some warnings * fix various warnings * add some CVE patches [ci:skip-build]: already built successfully in CI
4437 lines
157 KiB
Diff
4437 lines
157 KiB
Diff
https://github.com/Zennoe/android-cve-checker/tree/master/patches/3.4
|
|
From d3752ba7de67976f5f09a7bb2b74d4298eb32f8b Mon Sep 17 00:00:00 2001
|
|
From: Thomas Schmitz <Zennoe@users.noreply.github.com>
|
|
Date: Mon, 24 Jul 2017 21:22:54 +0200
|
|
Subject: [PATCH] Created 3.4 kernel folder. Added patches
|
|
|
|
All patches listed were written and tested with android_kernel_lge_msm8226.
|
|
---
|
|
patches/3.4/CVE-2015-8943.patch | 59 +
|
|
patches/3.4/CVE-2015-8944.patch | 30 +
|
|
patches/3.4/CVE-2015-8955.patch | 113 +
|
|
patches/3.4/CVE-2016-0774.patch | 60 +
|
|
patches/3.4/CVE-2016-0805.patch | 55 +
|
|
patches/3.4/CVE-2016-2185.patch | 110 +
|
|
patches/3.4/CVE-2016-2187.patch | 48 +
|
|
patches/3.4/CVE-2016-2188.patch | 44 +
|
|
patches/3.4/CVE-2016-2488.patch | 45 +
|
|
patches/3.4/CVE-2016-2544.patch | 36 +
|
|
patches/3.4/CVE-2016-3137.patch | 47 +
|
|
patches/3.4/CVE-2016-3857.patch | 49 +
|
|
patches/3.4/CVE-2016-3867.patch | 348 +++
|
|
patches/3.4/CVE-2016-3903.patch | 39 +
|
|
patches/3.4/CVE-2016-6741.patch | 137 ++
|
|
patches/3.4/CVE-2016-6741_complementary.patch | 29 +
|
|
patches/3.4/CVE-2016-6748.patch | 317 +++
|
|
patches/3.4/CVE-2016-6751.patch | 35 +
|
|
patches/3.4/CVE-2016-6752.patch | 45 +
|
|
patches/3.4/CVE-2016-6753.patch | 29 +
|
|
patches/3.4/CVE-2016-6757.patch | 372 ++++
|
|
patches/3.4/CVE-2016-6791.patch | 86 +
|
|
patches/3.4/CVE-2016-7914.patch | 1873 +++++++++++++++++
|
|
patches/3.4/CVE-2016-8403.patch | 119 ++
|
|
patches/3.4/CVE-2016-8406.patch | 102 +
|
|
25 files changed, 4227 insertions(+)
|
|
create mode 100644 patches/3.4/CVE-2015-8943.patch
|
|
create mode 100644 patches/3.4/CVE-2015-8944.patch
|
|
create mode 100644 patches/3.4/CVE-2015-8955.patch
|
|
create mode 100644 patches/3.4/CVE-2016-0774.patch
|
|
create mode 100644 patches/3.4/CVE-2016-0805.patch
|
|
create mode 100644 patches/3.4/CVE-2016-2185.patch
|
|
create mode 100644 patches/3.4/CVE-2016-2187.patch
|
|
create mode 100644 patches/3.4/CVE-2016-2188.patch
|
|
create mode 100644 patches/3.4/CVE-2016-2488.patch
|
|
create mode 100644 patches/3.4/CVE-2016-2544.patch
|
|
create mode 100644 patches/3.4/CVE-2016-3137.patch
|
|
create mode 100644 patches/3.4/CVE-2016-3857.patch
|
|
create mode 100644 patches/3.4/CVE-2016-3867.patch
|
|
create mode 100644 patches/3.4/CVE-2016-3903.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6741.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6741_complementary.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6748.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6751.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6752.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6753.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6757.patch
|
|
create mode 100644 patches/3.4/CVE-2016-6791.patch
|
|
create mode 100644 patches/3.4/CVE-2016-7914.patch
|
|
create mode 100644 patches/3.4/CVE-2016-8403.patch
|
|
create mode 100644 patches/3.4/CVE-2016-8406.patch
|
|
|
|
diff --git a/patches/3.4/CVE-2015-8943.patch b/patches/3.4/CVE-2015-8943.patch
|
|
new file mode 100644
|
|
index 0000000..a5bb95a
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2015-8943.patch
|
|
@@ -0,0 +1,59 @@
|
|
+From 8ee577ed10d44d5f05e11bb60d9b0d8679bcb614 Mon Sep 17 00:00:00 2001
|
|
+From: Jayant Shekhar <jshekhar@codeaurora.org>
|
|
+Date: Tue, 20 Jan 2015 16:12:43 +0530
|
|
+Subject: [PATCH] msm: mdss: Unmap only when buffer was mapped
|
|
+
|
|
+Currently buffer is unmapped if iommu is attached.
|
|
+This can lead to potential unmap issues if wrong
|
|
+addresses are sent and are tried to unmap without
|
|
+mapping. Hence ensure unmap is done only when
|
|
+buffer is mapped.
|
|
+
|
|
+Change-Id: I6d7f1eb1e951cd314a4c3c35551c87930af5118e
|
|
+Signed-off-by: Jayant Shekhar <jshekhar@codeaurora.org>
|
|
+---
|
|
+ drivers/video/msm/mdss/mdss_mdp.h | 1 +
|
|
+ drivers/video/msm/mdss/mdss_mdp_util.c | 4 +++-
|
|
+ 2 files changed, 4 insertions(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
|
|
+index 00b0cebc04b..6c65a1e62b0 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp.h
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp.h
|
|
+@@ -300,6 +300,7 @@ struct mdss_mdp_img_data {
|
|
+ u32 len;
|
|
+ u32 flags;
|
|
+ int p_need;
|
|
++ bool mapped;
|
|
+ struct file *srcp_file;
|
|
+ struct ion_handle *srcp_ihdl;
|
|
+ };
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
+index 0b1a154a225..d25b1b65cc4 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
+@@ -522,7 +522,7 @@ int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
|
|
+ pr_err("invalid ion client\n");
|
|
+ return -ENOMEM;
|
|
+ } else {
|
|
+- if (is_mdss_iommu_attached()) {
|
|
++ if (data->mapped) {
|
|
+ int domain;
|
|
+ if (data->flags & MDP_SECURE_OVERLAY_SESSION)
|
|
+ domain = MDSS_IOMMU_DOMAIN_SECURE;
|
|
+@@ -535,6 +535,7 @@ int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
|
|
+ msm_ion_unsecure_buffer(iclient,
|
|
+ data->srcp_ihdl);
|
|
+ }
|
|
++ data->mapped = false;
|
|
+ }
|
|
+ ion_free(iclient, data->srcp_ihdl);
|
|
+ data->srcp_ihdl = NULL;
|
|
+@@ -613,6 +614,7 @@ int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data)
|
|
+ if (ret && (domain == MDSS_IOMMU_DOMAIN_SECURE))
|
|
+ msm_ion_unsecure_buffer(iclient,
|
|
+ data->srcp_ihdl);
|
|
++ data->mapped = true;
|
|
+ } else {
|
|
+ ret = ion_phys(iclient, data->srcp_ihdl, start,
|
|
+ (size_t *) len);
|
|
diff --git a/patches/3.4/CVE-2015-8944.patch b/patches/3.4/CVE-2015-8944.patch
|
|
new file mode 100644
|
|
index 0000000..cfffcae
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2015-8944.patch
|
|
@@ -0,0 +1,30 @@
|
|
+From 465a6856bafc2f627753596c60894b0ec40310f2 Mon Sep 17 00:00:00 2001
|
|
+From: Biswajit Paul <biswajitpaul@codeaurora.org>
|
|
+Date: Mon, 9 Feb 2015 15:21:12 -0800
|
|
+Subject: [PATCH] kernel: Restrict permissions of /proc/iomem.
|
|
+
|
|
+The permissions of /proc/iomem currently are -r--r--r--. Everyone can
|
|
+see its content. As iomem contains information about the physical memory
|
|
+content of the device, restrict the information only to root.
|
|
+
|
|
+Change-Id: If0be35c3fac5274151bea87b738a48e6ec0ae891
|
|
+CRs-Fixed: 786116
|
|
+Signed-off-by: Biswajit Paul <biswajitpaul@codeaurora.org>
|
|
+Signed-off-by: Avijit Kanti Das <avijitnsec@codeaurora.org>
|
|
+---
|
|
+ kernel/resource.c | 2 +-
|
|
+ 1 file changed, 1 insertion(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/kernel/resource.c b/kernel/resource.c
|
|
+index 7203c06273a..e9ba0770ec3 100644
|
|
+--- a/kernel/resource.c
|
|
++++ b/kernel/resource.c
|
|
+@@ -142,7 +142,7 @@ static const struct file_operations proc_iomem_operations = {
|
|
+ static int __init ioresources_init(void)
|
|
+ {
|
|
+ proc_create("ioports", 0, NULL, &proc_ioports_operations);
|
|
+- proc_create("iomem", 0, NULL, &proc_iomem_operations);
|
|
++ proc_create("iomem", S_IRUSR, NULL, &proc_iomem_operations);
|
|
+ return 0;
|
|
+ }
|
|
+ __initcall(ioresources_init);
|
|
diff --git a/patches/3.4/CVE-2015-8955.patch b/patches/3.4/CVE-2015-8955.patch
|
|
new file mode 100644
|
|
index 0000000..613ec32
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2015-8955.patch
|
|
@@ -0,0 +1,113 @@
|
|
+From 0bbcfb08a2e3a6d5fe83c1e58fca23d01fd88a21 Mon Sep 17 00:00:00 2001
|
|
+From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
|
|
+Date: Tue, 17 Mar 2015 18:14:58 +0000
|
|
+Subject: [PATCH] ARM: perf: reject groups spanning multiple hardware PMUs
|
|
+
|
|
+The perf core implicitly rejects events spanning multiple HW PMUs, as in
|
|
+these cases the event->ctx will differ. However this validation is
|
|
+performed after pmu::event_init() is called in perf_init_event(), and
|
|
+thus pmu::event_init() may be called with a group leader from a
|
|
+different HW PMU.
|
|
+
|
|
+The ARM PMU driver does not take this fact into account, and when
|
|
+validating groups assumes that it can call to_arm_pmu(event->pmu) for
|
|
+any HW event. When the event in question is from another HW PMU this is
|
|
+wrong, and results in dereferencing garbage.
|
|
+
|
|
+This patch updates the ARM PMU driver to first test for and reject
|
|
+events from other PMUs, moving the to_arm_pmu and related logic after
|
|
+this test. Fixes a crash triggered by perf_fuzzer on Linux-4.0-rc2, with
|
|
+a CCI PMU present:
|
|
+
|
|
+ ---
|
|
+CPU: 0 PID: 1527 Comm: perf_fuzzer Not tainted 4.0.0-rc2 #57
|
|
+Hardware name: ARM-Versatile Express
|
|
+task: bd8484c0 ti: be676000 task.ti: be676000
|
|
+PC is at 0xbf1bbc90
|
|
+LR is at validate_event+0x34/0x5c
|
|
+pc : [<bf1bbc90>] lr : [<80016060>] psr: 00000013
|
|
+...
|
|
+[<80016060>] (validate_event) from [<80016198>] (validate_group+0x28/0x90)
|
|
+[<80016198>] (validate_group) from [<80016398>] (armpmu_event_init+0x150/0x218)
|
|
+[<80016398>] (armpmu_event_init) from [<800882e4>] (perf_try_init_event+0x30/0x48)
|
|
+[<800882e4>] (perf_try_init_event) from [<8008f544>] (perf_init_event+0x5c/0xf4)
|
|
+[<8008f544>] (perf_init_event) from [<8008f8a8>] (perf_event_alloc+0x2cc/0x35c)
|
|
+[<8008f8a8>] (perf_event_alloc) from [<8009015c>] (SyS_perf_event_open+0x498/0xa70)
|
|
+[<8009015c>] (SyS_perf_event_open) from [<8000e420>] (ret_fast_syscall+0x0/0x34)
|
|
+Code: bf1be000 bf1bb380 802a2664 00000000 (00000002)
|
|
+---[ end trace 01aff0ff00926a0a ]---
|
|
+
|
|
+Also cleans up the code to use the arm_pmu only when we know that
|
|
+we are dealing with an arm pmu event.
|
|
+
|
|
+Change-Id: I890a2a685d1ecd462287f19907c3de8bedee2c70
|
|
+Cc: Will Deacon <will.deacon@arm.com>
|
|
+Acked-by: Mark Rutland <mark.rutland@arm.com>
|
|
+Acked-by: Peter Ziljstra (Intel) <peterz@infradead.org>
|
|
+Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
|
|
+Signed-off-by: Will Deacon <will.deacon@arm.com>
|
|
+---
|
|
+ arch/arm/kernel/perf_event.c | 24 ++++++++++++++++++------
|
|
+ 1 file changed, 18 insertions(+), 6 deletions(-)
|
|
+
|
|
+diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
|
|
+index 5989418ca04..15d45df3fd3 100644
|
|
+--- a/arch/arm/kernel/perf_event.c
|
|
++++ b/arch/arm/kernel/perf_event.c
|
|
+@@ -343,19 +343,31 @@ out:
|
|
+ }
|
|
+
|
|
+ static int
|
|
+-validate_event(struct pmu_hw_events *hw_events,
|
|
++validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events,
|
|
+ struct perf_event *event)
|
|
+ {
|
|
+- struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
|
|
++ struct arm_pmu *armpmu;
|
|
+ struct hw_perf_event fake_event = event->hw;
|
|
+ struct pmu *leader_pmu = event->group_leader->pmu;
|
|
+
|
|
+ if (is_software_event(event))
|
|
+ return 1;
|
|
+
|
|
+- if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
|
|
++ /*
|
|
++ * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The
|
|
++ * core perf code won't check that the pmu->ctx == leader->ctx
|
|
++ * until after pmu->event_init(event).
|
|
++ */
|
|
++ if (event->pmu != pmu)
|
|
++ return 0;
|
|
++
|
|
++ if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
|
|
++ return 1;
|
|
++
|
|
++ if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
|
|
+ return 1;
|
|
+
|
|
++ armpmu = to_arm_pmu(event->pmu);
|
|
+ return armpmu->get_event_idx(hw_events, &fake_event) >= 0;
|
|
+ }
|
|
+
|
|
+@@ -373,15 +385,15 @@ validate_group(struct perf_event *event)
|
|
+ memset(fake_used_mask, 0, sizeof(fake_used_mask));
|
|
+ fake_pmu.used_mask = fake_used_mask;
|
|
+
|
|
+- if (!validate_event(&fake_pmu, leader))
|
|
++ if (!validate_event(event->pmu, &fake_pmu, leader))
|
|
+ return -EINVAL;
|
|
+
|
|
+ list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
|
|
+- if (!validate_event(&fake_pmu, sibling))
|
|
++ if (!validate_event(event->pmu, &fake_pmu, sibling))
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+- if (!validate_event(&fake_pmu, event))
|
|
++ if (!validate_event(event->pmu, &fake_pmu, event))
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-0774.patch b/patches/3.4/CVE-2016-0774.patch
|
|
new file mode 100644
|
|
index 0000000..bf2b191
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-0774.patch
|
|
@@ -0,0 +1,60 @@
|
|
+From f6447b2c1c4846d61c8d5cbc9d9586f2408880e4 Mon Sep 17 00:00:00 2001
|
|
+From: Jeff Vander Stoep <jeffv@google.com>
|
|
+Date: Wed, 23 Mar 2016 15:32:14 -0700
|
|
+Subject: [PATCH] pipe: iovec: Fix OOB read in pipe_read()
|
|
+
|
|
+Previous upstream *stable* fix 14f81062 was incomplete.
|
|
+
|
|
+A local process can trigger a system crash with an OOB read on buf.
|
|
+This occurs when the state of buf gets out of sync. After an error in
|
|
+pipe_iov_copy_to_user() read_pipe may exit having updated buf->offset
|
|
+but not buf->len. Upon retrying pipe_read() while in
|
|
+pipe_iov_copy_to_user() *remaining will be larger than the space left
|
|
+after buf->offset e.g. *remaing = PAGE_SIZE, buf->len = PAGE_SIZE,
|
|
+buf->offset = 0x300.
|
|
+
|
|
+This is fixed by not updating the state of buf->offset until after the
|
|
+full copy is completed, similar to how pipe_write() is implemented.
|
|
+
|
|
+For stable kernels < 3.16.
|
|
+
|
|
+Bug: 27721803
|
|
+Change-Id: Iefffbcc6cfd159dba69c31bcd98c6d5c1f21ff2e
|
|
+Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
|
|
+---
|
|
+ fs/pipe.c | 6 ++++--
|
|
+ 1 file changed, 4 insertions(+), 2 deletions(-)
|
|
+
|
|
+diff --git a/fs/pipe.c b/fs/pipe.c
|
|
+index edd1c636bf1..c1ddb284357 100644
|
|
+--- a/fs/pipe.c
|
|
++++ b/fs/pipe.c
|
|
+@@ -395,7 +395,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
+ const struct pipe_buf_operations *ops = buf->ops;
|
|
+ void *addr;
|
|
+ size_t chars = buf->len, remaining;
|
|
+- int error, atomic;
|
|
++ int error, atomic, offset;
|
|
+
|
|
+ if (chars > total_len)
|
|
+ chars = total_len;
|
|
+@@ -409,9 +409,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
+
|
|
+ atomic = !iov_fault_in_pages_write(iov, chars);
|
|
+ remaining = chars;
|
|
++ offset = buf->offset;
|
|
+ redo:
|
|
+ addr = ops->map(pipe, buf, atomic);
|
|
+- error = pipe_iov_copy_to_user(iov, addr, &buf->offset,
|
|
++ error = pipe_iov_copy_to_user(iov, addr, &offset,
|
|
+ &remaining, atomic);
|
|
+ ops->unmap(pipe, buf, addr);
|
|
+ if (unlikely(error)) {
|
|
+@@ -427,6 +428,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
+ break;
|
|
+ }
|
|
+ ret += chars;
|
|
++ buf->offset += chars;
|
|
+ buf->len -= chars;
|
|
+
|
|
+ /* Was it a packet buffer? Clean up and exit */
|
|
diff --git a/patches/3.4/CVE-2016-0805.patch b/patches/3.4/CVE-2016-0805.patch
|
|
new file mode 100644
|
|
index 0000000..bafe826
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-0805.patch
|
|
@@ -0,0 +1,55 @@
|
|
+From 1e7cf1e770aa8693452bb6c7dda7f43bfc026bf7 Mon Sep 17 00:00:00 2001
|
|
+From: Swetha Chikkaboraiah <schikk@codeaurora.org>
|
|
+Date: Wed, 27 Jan 2016 11:46:54 +0530
|
|
+Subject: [PATCH] msm: perf: Protect buffer overflow due to malicious user
|
|
+
|
|
+In function krait_pmu_disable_event, parameter hwc comes from
|
|
+userspace and is untrusted.The function krait_clearpmu is called
|
|
+after the function get_krait_evtinfo.
|
|
+Function get_krait_evtinfo as parameter krait_evt_type variable
|
|
+which is used to extract the groupcode(reg) which is bound to
|
|
+KRAIT_MAX_L1_REG (is 3). After validation,one code path modifies
|
|
+groupcode(reg):If this code path executes, groupcode(reg) can be
|
|
+3,4, 5, or 6. In krait_clearpmu groupcode used to access array
|
|
+krait_functions whose size is 3. Since groupcode can be 3,4,5,6
|
|
+accessing array krait_functions lead to bufferoverlflow.
|
|
+This change will validate groupcode not to exceed 3 .
|
|
+
|
|
+Change-Id: I48c92adda137d8a074b4e1a367a468195a810ca1
|
|
+CRs-fixed: 962450
|
|
+Signed-off-by: Swetha Chikkaboraiah <schikk@codeaurora.org>
|
|
+---
|
|
+ arch/arm/kernel/perf_event_msm_krait.c | 8 ++++----
|
|
+ 1 file changed, 4 insertions(+), 4 deletions(-)
|
|
+
|
|
+diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
|
|
+index 1c338f79bab..3f09c4c0754 100644
|
|
+--- a/arch/arm/kernel/perf_event_msm_krait.c
|
|
++++ b/arch/arm/kernel/perf_event_msm_krait.c
|
|
+@@ -1,5 +1,5 @@
|
|
+ /*
|
|
+- * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved.
|
|
++ * Copyright (c) 2011-2012, 2014,2016 The Linux Foundation. All rights reserved.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 and
|
|
+@@ -219,9 +219,6 @@ static unsigned int get_krait_evtinfo(unsigned int krait_evt_type,
|
|
+ code = (krait_evt_type & 0x00FF0) >> 4;
|
|
+ group = krait_evt_type & 0x0000F;
|
|
+
|
|
+- if ((group > 3) || (reg > krait_max_l1_reg))
|
|
+- return -EINVAL;
|
|
+-
|
|
+ if (prefix != KRAIT_EVT_PREFIX && prefix != KRAIT_VENUMEVT_PREFIX)
|
|
+ return -EINVAL;
|
|
+
|
|
+@@ -232,6 +229,9 @@ static unsigned int get_krait_evtinfo(unsigned int krait_evt_type,
|
|
+ reg += VENUM_BASE_OFFSET;
|
|
+ }
|
|
+
|
|
++ if ((group > 3) || (reg > krait_max_l1_reg))
|
|
++ return -EINVAL;
|
|
++
|
|
+ evtinfo->group_setval = 0x80000000 | (code << (group * 8));
|
|
+ evtinfo->groupcode = reg;
|
|
+ evtinfo->armv7_evt_type = evt_type_base[evt_index][reg] | group;
|
|
diff --git a/patches/3.4/CVE-2016-2185.patch b/patches/3.4/CVE-2016-2185.patch
|
|
new file mode 100644
|
|
index 0000000..3cbd89c
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-2185.patch
|
|
@@ -0,0 +1,110 @@
|
|
+From bc47a8af553b852acaf2622bb54dee5507f11e20 Mon Sep 17 00:00:00 2001
|
|
+From: Vladis Dronov <vdronov@redhat.com>
|
|
+Date: Wed, 23 Mar 2016 11:53:46 -0700
|
|
+Subject: [PATCH] Input: ati_remote2 - fix crashes on detecting device with
|
|
+ invalid descriptor
|
|
+
|
|
+[ Upstream commit 950336ba3e4a1ffd2ca60d29f6ef386dd2c7351d ]
|
|
+
|
|
+The ati_remote2 driver expects at least two interfaces with one
|
|
+endpoint each. If given malicious descriptor that specify one
|
|
+interface or no endpoints, it will crash in the probe function.
|
|
+Ensure there is at least two interfaces and one endpoint for each
|
|
+interface before using it.
|
|
+
|
|
+The full disclosure: http://seclists.org/bugtraq/2016/Mar/90
|
|
+
|
|
+Change-Id: I255a66aad0fac2d6915d1e3bb0834e7137cd0da2
|
|
+Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
|
|
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
|
|
+Cc: stable@vger.kernel.org
|
|
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
|
+Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
|
|
+---
|
|
+ drivers/input/misc/ati_remote2.c | 36 ++++++++++++++++++++++++++++++------
|
|
+ 1 file changed, 30 insertions(+), 6 deletions(-)
|
|
+
|
|
+diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
|
|
+index f63341f20b9..e8c6a4842e9 100644
|
|
+--- a/drivers/input/misc/ati_remote2.c
|
|
++++ b/drivers/input/misc/ati_remote2.c
|
|
+@@ -817,26 +817,49 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
|
|
+
|
|
+ ar2->udev = udev;
|
|
+
|
|
++ /* Sanity check, first interface must have an endpoint */
|
|
++ if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
|
|
++ dev_err(&interface->dev,
|
|
++ "%s(): interface 0 must have an endpoint\n", __func__);
|
|
++ r = -ENODEV;
|
|
++ goto fail1;
|
|
++ }
|
|
+ ar2->intf[0] = interface;
|
|
+ ar2->ep[0] = &alt->endpoint[0].desc;
|
|
+
|
|
++ /* Sanity check, the device must have two interfaces */
|
|
+ ar2->intf[1] = usb_ifnum_to_if(udev, 1);
|
|
++ if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
|
|
++ dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
|
|
++ __func__, udev->actconfig->desc.bNumInterfaces);
|
|
++ r = -ENODEV;
|
|
++ goto fail1;
|
|
++ }
|
|
++
|
|
+ r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
|
|
+ if (r)
|
|
+ goto fail1;
|
|
++
|
|
++ /* Sanity check, second interface must have an endpoint */
|
|
+ alt = ar2->intf[1]->cur_altsetting;
|
|
++ if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
|
|
++ dev_err(&interface->dev,
|
|
++ "%s(): interface 1 must have an endpoint\n", __func__);
|
|
++ r = -ENODEV;
|
|
++ goto fail2;
|
|
++ }
|
|
+ ar2->ep[1] = &alt->endpoint[0].desc;
|
|
+
|
|
+ r = ati_remote2_urb_init(ar2);
|
|
+ if (r)
|
|
+- goto fail2;
|
|
++ goto fail3;
|
|
+
|
|
+ ar2->channel_mask = channel_mask;
|
|
+ ar2->mode_mask = mode_mask;
|
|
+
|
|
+ r = ati_remote2_setup(ar2, ar2->channel_mask);
|
|
+ if (r)
|
|
+- goto fail2;
|
|
++ goto fail3;
|
|
+
|
|
+ usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
|
|
+ strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
|
|
+@@ -845,11 +868,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
|
|
+
|
|
+ r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
|
|
+ if (r)
|
|
+- goto fail2;
|
|
++ goto fail3;
|
|
+
|
|
+ r = ati_remote2_input_init(ar2);
|
|
+ if (r)
|
|
+- goto fail3;
|
|
++ goto fail4;
|
|
+
|
|
+ usb_set_intfdata(interface, ar2);
|
|
+
|
|
+@@ -857,10 +880,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
|
|
+
|
|
+ return 0;
|
|
+
|
|
+- fail3:
|
|
++ fail4:
|
|
+ sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
|
|
+- fail2:
|
|
++ fail3:
|
|
+ ati_remote2_urb_cleanup(ar2);
|
|
++ fail2:
|
|
+ usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
|
|
+ fail1:
|
|
+ kfree(ar2);
|
|
diff --git a/patches/3.4/CVE-2016-2187.patch b/patches/3.4/CVE-2016-2187.patch
|
|
new file mode 100644
|
|
index 0000000..cb9a8ae
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-2187.patch
|
|
@@ -0,0 +1,48 @@
|
|
+From 965ab8894f9fd3e90095492100c78de150af380e Mon Sep 17 00:00:00 2001
|
|
+From: Vladis Dronov <vdronov@redhat.com>
|
|
+Date: Thu, 31 Mar 2016 10:53:42 -0700
|
|
+Subject: [PATCH] Input: gtco - fix crash on detecting device without endpoints
|
|
+
|
|
+commit 162f98dea487206d9ab79fc12ed64700667a894d upstream.
|
|
+
|
|
+The gtco driver expects at least one valid endpoint. If given malicious
|
|
+descriptors that specify 0 for the number of endpoints, it will crash in
|
|
+the probe function. Ensure there is at least one endpoint on the interface
|
|
+before using it.
|
|
+
|
|
+Also let's fix a minor coding style issue.
|
|
+
|
|
+The full correct report of this issue can be found in the public
|
|
+Red Hat Bugzilla:
|
|
+
|
|
+https://bugzilla.redhat.com/show_bug.cgi?id=1283385
|
|
+
|
|
+Change-Id: I8e330f2a3f3f88eb005006dffb163c296aa7d092
|
|
+Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
|
|
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
|
|
+Cc: stable@vger.kernel.org
|
|
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
|
+Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
+---
|
|
+ drivers/input/tablet/gtco.c | 8 ++++++++
|
|
+ 1 file changed, 8 insertions(+)
|
|
+
|
|
+diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
|
|
+index 89a297801dc..f707464eb95 100644
|
|
+--- a/drivers/input/tablet/gtco.c
|
|
++++ b/drivers/input/tablet/gtco.c
|
|
+@@ -866,6 +866,14 @@ static int gtco_probe(struct usb_interface *usbinterface,
|
|
+ goto err_free_buf;
|
|
+ }
|
|
+
|
|
++ /* Sanity check that a device has an endpoint */
|
|
++ if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) {
|
|
++ dev_err(&usbinterface->dev,
|
|
++ "Invalid number of endpoints\n");
|
|
++ error = -EINVAL;
|
|
++ goto err_free_urb;
|
|
++ }
|
|
++
|
|
+ /*
|
|
+ * The endpoint is always altsetting 0, we know this since we know
|
|
+ * this device only has one interrupt endpoint
|
|
diff --git a/patches/3.4/CVE-2016-2188.patch b/patches/3.4/CVE-2016-2188.patch
|
|
new file mode 100644
|
|
index 0000000..7efa0b8
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-2188.patch
|
|
@@ -0,0 +1,44 @@
|
|
+From f653fddb51d77c8fa1bcac0f7df54517dbe60d1a Mon Sep 17 00:00:00 2001
|
|
+From: Johan Hovold <johan@kernel.org>
|
|
+Date: Tue, 7 Mar 2017 16:11:03 +0100
|
|
+Subject: [PATCH] USB: iowarrior: fix NULL-deref at probe
|
|
+
|
|
+commit b7321e81fc369abe353cf094d4f0dc2fe11ab95f upstream.
|
|
+
|
|
+Make sure to check for the required interrupt-in endpoint to avoid
|
|
+dereferencing a NULL-pointer should a malicious device lack such an
|
|
+endpoint.
|
|
+
|
|
+Note that a fairly recent change purported to fix this issue, but added
|
|
+an insufficient test on the number of endpoints only, a test which can
|
|
+now be removed.
|
|
+
|
|
+Fixes: 4ec0ef3a8212 ("USB: iowarrior: fix oops with malicious USB descriptors")
|
|
+Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.")
|
|
+Change-Id: Ica55241dca314561282c0e1f9b91f96a5aaaf145
|
|
+Signed-off-by: Johan Hovold <johan@kernel.org>
|
|
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
+[bwh: Backported to 3.2: adjust context]
|
|
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
+---
|
|
+ drivers/usb/misc/iowarrior.c | 7 +++++++
|
|
+ 1 file changed, 7 insertions(+)
|
|
+
|
|
+diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
|
|
+index 4fd0dc835ae..f76b0bd4e2f 100644
|
|
+--- a/drivers/usb/misc/iowarrior.c
|
|
++++ b/drivers/usb/misc/iowarrior.c
|
|
+@@ -802,6 +802,13 @@ static int iowarrior_probe(struct usb_interface *interface,
|
|
+ /* this one will match for the IOWarrior56 only */
|
|
+ dev->int_out_endpoint = endpoint;
|
|
+ }
|
|
++
|
|
++ if (!dev->int_in_endpoint) {
|
|
++ dev_err(&interface->dev, "no interrupt-in endpoint found\n");
|
|
++ retval = -ENODEV;
|
|
++ goto error;
|
|
++ }
|
|
++
|
|
+ /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
|
|
+ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
|
|
+ if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
|
|
diff --git a/patches/3.4/CVE-2016-2488.patch b/patches/3.4/CVE-2016-2488.patch
|
|
new file mode 100644
|
|
index 0000000..a7b0ade
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-2488.patch
|
|
@@ -0,0 +1,45 @@
|
|
+From f8053f442f036f70de94b8b54d52fcb1163db586 Mon Sep 17 00:00:00 2001
|
|
+From: Suman Mukherjee <sumam@codeaurora.org>
|
|
+Date: Fri, 4 Mar 2016 14:04:21 +0530
|
|
+Subject: [PATCH] Reply More msm: camera: ispif: Validate VFE num input during
|
|
+ reset
|
|
+
|
|
+Userspace supplies the actual number of used VFEs in session to ISPIF.
|
|
+Validate the userspace input value and if found to be invalid, return
|
|
+error.
|
|
+
|
|
+Change-Id: I5379d1f7e6482fc249e155b2df5ba3c8391fdfdd
|
|
+CRs-Fixed: 898074
|
|
+Signed-off-by: Venu Yeshala <vyeshala@codeaurora.org>
|
|
+Signed-off-by: Suman Mukherjee<sumam@codeaurora.org>
|
|
+---
|
|
+ drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c | 9 ++++++++-
|
|
+ 1 file changed, 8 insertions(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
|
|
+index d044c1dae5d..ad3218f7858 100755
|
|
+--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
|
|
++++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
|
|
+@@ -1,4 +1,4 @@
|
|
+-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
|
++/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 and
|
|
+@@ -930,6 +930,13 @@ static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
|
|
+ static int msm_ispif_set_vfe_info(struct ispif_device *ispif,
|
|
+ struct msm_ispif_vfe_info *vfe_info)
|
|
+ {
|
|
++ if (!vfe_info || (vfe_info->num_vfe <= 0) ||
|
|
++ ((uint32_t)(vfe_info->num_vfe) > ispif->hw_num_isps)) {
|
|
++ pr_err("Invalid VFE info: %p %d\n", vfe_info,
|
|
++ (vfe_info ? vfe_info->num_vfe:0));
|
|
++ return -EINVAL;
|
|
++ }
|
|
++
|
|
+ memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info));
|
|
+
|
|
+ return 0;
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-2544.patch b/patches/3.4/CVE-2016-2544.patch
|
|
new file mode 100644
|
|
index 0000000..2ef1742
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-2544.patch
|
|
@@ -0,0 +1,36 @@
|
|
+From 8847127e5945ba541087f95f213c18a41e47e4d8 Mon Sep 17 00:00:00 2001
|
|
+From: Takashi Iwai <tiwai@suse.de>
|
|
+Date: Tue, 12 Jan 2016 15:36:27 +0100
|
|
+Subject: [PATCH] ALSA: seq: Fix race at timer setup and close
|
|
+
|
|
+ALSA sequencer code has an open race between the timer setup ioctl and
|
|
+the close of the client. This was triggered by syzkaller fuzzer, and
|
|
+a use-after-free was caught there as a result.
|
|
+
|
|
+This patch papers over it by adding a proper queue->timer_mutex lock
|
|
+around the timer-related calls in the relevant code path.
|
|
+
|
|
+Change-Id: I4348466b871fb5c1f8ff425bc1f4d8e41e4efe0b
|
|
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
|
|
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
|
|
+Cc: <stable@vger.kernel.org>
|
|
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
+---
|
|
+ sound/core/seq/seq_queue.c | 2 ++
|
|
+ 1 file changed, 2 insertions(+)
|
|
+
|
|
+diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
|
|
+index f9077361c11..4c9aa462de9 100644
|
|
+--- a/sound/core/seq/seq_queue.c
|
|
++++ b/sound/core/seq/seq_queue.c
|
|
+@@ -144,8 +144,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
|
|
+ static void queue_delete(struct snd_seq_queue *q)
|
|
+ {
|
|
+ /* stop and release the timer */
|
|
++ mutex_lock(&q->timer_mutex);
|
|
+ snd_seq_timer_stop(q->timer);
|
|
+ snd_seq_timer_close(q);
|
|
++ mutex_unlock(&q->timer_mutex);
|
|
+ /* wait until access free */
|
|
+ snd_use_lock_sync(&q->use_lock);
|
|
+ /* release resources... */
|
|
diff --git a/patches/3.4/CVE-2016-3137.patch b/patches/3.4/CVE-2016-3137.patch
|
|
new file mode 100644
|
|
index 0000000..879db1e
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-3137.patch
|
|
@@ -0,0 +1,47 @@
|
|
+From 2fed1a09bbb4b2c3862b36812f2c441573057b77 Mon Sep 17 00:00:00 2001
|
|
+From: Oliver Neukum <oneukum@suse.com>
|
|
+Date: Thu, 31 Mar 2016 12:04:25 -0400
|
|
+Subject: [PATCH] USB: cypress_m8: add endpoint sanity check
|
|
+
|
|
+An attack using missing endpoints exists.
|
|
+
|
|
+CVE-2016-3137
|
|
+
|
|
+Change-Id: Ic4fa75a7133dd7b66c91622dec84776c08ae21c3
|
|
+Signed-off-by: Oliver Neukum <ONeukum@suse.com>
|
|
+CC: stable@vger.kernel.org
|
|
+Signed-off-by: Johan Hovold <johan@kernel.org>
|
|
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
+---
|
|
+ drivers/usb/serial/cypress_m8.c | 11 +++++------
|
|
+ 1 file changed, 5 insertions(+), 6 deletions(-)
|
|
+
|
|
+diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
|
|
+index b1b846752c4..ce0aea593f2 100644
|
|
+--- a/drivers/usb/serial/cypress_m8.c
|
|
++++ b/drivers/usb/serial/cypress_m8.c
|
|
+@@ -464,6 +464,11 @@ static int generic_startup(struct usb_serial *serial)
|
|
+
|
|
+ dbg("%s - port %d", __func__, port->number);
|
|
+
|
|
++ if (!port->interrupt_out_urb || !port->interrupt_in_urb) {
|
|
++ dev_err(&port->dev, "required endpoint is missing\n");
|
|
++ return -ENODEV;
|
|
++ }
|
|
++
|
|
+ priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+@@ -633,12 +638,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|
+ cypress_set_termios(tty, port, &priv->tmp_termios);
|
|
+
|
|
+ /* setup the port and start reading from the device */
|
|
+- if (!port->interrupt_in_urb) {
|
|
+- dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
|
|
+- __func__);
|
|
+- return -1;
|
|
+- }
|
|
+-
|
|
+ usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
|
|
+ usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
|
|
+ port->interrupt_in_urb->transfer_buffer,
|
|
diff --git a/patches/3.4/CVE-2016-3857.patch b/patches/3.4/CVE-2016-3857.patch
|
|
new file mode 100644
|
|
index 0000000..51c4722
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-3857.patch
|
|
@@ -0,0 +1,49 @@
|
|
+From 9342db9d6bd7a4acfe2233a93012c87c575109db Mon Sep 17 00:00:00 2001
|
|
+From: Dave Weinstein <olorin@google.com>
|
|
+Date: Thu, 28 Jul 2016 11:55:41 -0700
|
|
+Subject: [PATCH] arm: oabi compat: add missing access checks
|
|
+
|
|
+commit 7de249964f5578e67b99699c5f0b405738d820a2 upstream.
|
|
+
|
|
+Add access checks to sys_oabi_epoll_wait() and sys_oabi_semtimedop().
|
|
+This fixes CVE-2016-3857, a local privilege escalation under
|
|
+CONFIG_OABI_COMPAT.
|
|
+
|
|
+Change-Id: I5ed5fef80c63274b8162bc1fb3ec1c07625e472f
|
|
+Reported-by: Chiachih Wu <wuchiachih@gmail.com>
|
|
+Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
+Reviewed-by: Nicolas Pitre <nico@linaro.org>
|
|
+Signed-off-by: Dave Weinstein <olorin@google.com>
|
|
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
+---
|
|
+ arch/arm/kernel/sys_oabi-compat.c | 8 +++++++-
|
|
+ 1 file changed, 7 insertions(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
|
|
+index af0aaebf4de..32884a6006c 100644
|
|
+--- a/arch/arm/kernel/sys_oabi-compat.c
|
|
++++ b/arch/arm/kernel/sys_oabi-compat.c
|
|
+@@ -275,8 +275,12 @@ asmlinkage long sys_oabi_epoll_wait(int epfd,
|
|
+ mm_segment_t fs;
|
|
+ long ret, err, i;
|
|
+
|
|
+- if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
|
|
++ if (maxevents <= 0 ||
|
|
++ maxevents > (INT_MAX/sizeof(*kbuf)) ||
|
|
++ maxevents > (INT_MAX/sizeof(*events)))
|
|
+ return -EINVAL;
|
|
++ if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents))
|
|
++ return -EFAULT;
|
|
+ kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
|
|
+ if (!kbuf)
|
|
+ return -ENOMEM;
|
|
+@@ -313,6 +317,8 @@ asmlinkage long sys_oabi_semtimedop(int semid,
|
|
+
|
|
+ if (nsops < 1 || nsops > SEMOPM)
|
|
+ return -EINVAL;
|
|
++ if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops))
|
|
++ return -EFAULT;
|
|
+ sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
|
|
+ if (!sops)
|
|
+ return -ENOMEM;
|
|
diff --git a/patches/3.4/CVE-2016-3867.patch b/patches/3.4/CVE-2016-3867.patch
|
|
new file mode 100644
|
|
index 0000000..6cd42a5
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-3867.patch
|
|
@@ -0,0 +1,348 @@
|
|
+From c3764128586df342167d184c3085bb8f6d7bbdcb Mon Sep 17 00:00:00 2001
|
|
+From: Skylar Chang <chiaweic@codeaurora.org>
|
|
+Date: Fri, 8 Jul 2016 16:20:33 -0700
|
|
+Subject: [PATCH] msm: ipa: fix potential race condition ioctls
|
|
+
|
|
+There are numerous potential race condition
|
|
+ioctls in the IPA driver. The fix is to add
|
|
+check wherever it copies arguments from
|
|
+user-space memory and process.
|
|
+
|
|
+Change-Id: I5a440f89153518507acdf5dad42625503732e59a
|
|
+Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
|
|
+---
|
|
+ drivers/platform/msm/ipa/ipa.c | 160 +++++++++++++++++++++++++++++++++--------
|
|
+ 1 file changed, 131 insertions(+), 29 deletions(-)
|
|
+
|
|
+diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
|
|
+index c93ec5fb8a1..4cbff8787c2 100644
|
|
+--- a/drivers/platform/msm/ipa/ipa.c
|
|
++++ b/drivers/platform/msm/ipa/ipa.c
|
|
+@@ -188,6 +188,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ struct ipa_ioc_v4_nat_del nat_del;
|
|
+ struct ipa_ioc_rm_dependency rm_depend;
|
|
+ size_t sz;
|
|
++ int pre_entry;
|
|
+
|
|
+ IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
|
|
+
|
|
+@@ -236,11 +237,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_nat_dma_cmd *)header)->entries;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_nat_dma_cmd) +
|
|
+- ((struct ipa_ioc_nat_dma_cmd *)header)->entries *
|
|
+- sizeof(struct ipa_ioc_nat_dma_one);
|
|
++ pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -251,7 +252,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_nat_dma_cmd *)param)->entries,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_nat_dma_cmd((struct ipa_ioc_nat_dma_cmd *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -276,10 +285,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_add_hdr) +
|
|
+- ((struct ipa_ioc_add_hdr *)header)->num_hdrs *
|
|
+- sizeof(struct ipa_hdr_add);
|
|
++ pre_entry * sizeof(struct ipa_hdr_add);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -289,6 +299,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_add_hdr((struct ipa_ioc_add_hdr *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -305,10 +324,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_del_hdr *)header)->num_hdls;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_del_hdr) +
|
|
+- ((struct ipa_ioc_del_hdr *)header)->num_hdls *
|
|
+- sizeof(struct ipa_hdr_del);
|
|
++ pre_entry * sizeof(struct ipa_hdr_del);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -318,6 +338,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_del_hdr *)param)->num_hdls,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_del_hdr((struct ipa_ioc_del_hdr *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -334,10 +363,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_add_rt_rule) +
|
|
+- ((struct ipa_ioc_add_rt_rule *)header)->num_rules *
|
|
+- sizeof(struct ipa_rt_rule_add);
|
|
++ pre_entry * sizeof(struct ipa_rt_rule_add);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -347,6 +377,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_add_rt_rule *)param)->
|
|
++ num_rules,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -363,10 +403,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_del_rt_rule) +
|
|
+- ((struct ipa_ioc_del_rt_rule *)header)->num_hdls *
|
|
+- sizeof(struct ipa_rt_rule_del);
|
|
++ pre_entry * sizeof(struct ipa_rt_rule_del);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -376,6 +417,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -392,10 +442,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_add_flt_rule) +
|
|
+- ((struct ipa_ioc_add_flt_rule *)header)->num_rules *
|
|
+- sizeof(struct ipa_flt_rule_add);
|
|
++ pre_entry * sizeof(struct ipa_flt_rule_add);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -405,6 +456,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_add_flt_rule *)param)->
|
|
++ num_rules,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -421,10 +482,11 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
|
|
+ pyld_sz =
|
|
+ sizeof(struct ipa_ioc_del_flt_rule) +
|
|
+- ((struct ipa_ioc_del_flt_rule *)header)->num_hdls *
|
|
+- sizeof(struct ipa_flt_rule_del);
|
|
++ pre_entry * sizeof(struct ipa_flt_rule_del);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -434,6 +496,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_del_flt_rule *)param)->
|
|
++ num_hdls,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+@@ -544,15 +616,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
+- if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
|
|
+- > IPA_NUM_PROPS_MAX) {
|
|
++ if (((struct ipa_ioc_query_intf_tx_props *)
|
|
++ header)->num_tx_props > IPA_NUM_PROPS_MAX) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
+- pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
|
|
+- header)->num_tx_props *
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_query_intf_tx_props *)
|
|
++ header)->num_tx_props;
|
|
++ pyld_sz = sz + pre_entry *
|
|
+ sizeof(struct ipa_ioc_tx_intf_prop);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+@@ -563,6 +635,16 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
|
|
++ param)->num_tx_props
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_query_intf_tx_props *)
|
|
++ param)->num_tx_props, pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_query_intf_tx_props(
|
|
+ (struct ipa_ioc_query_intf_tx_props *)param)) {
|
|
+ retval = -1;
|
|
+@@ -579,15 +661,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
+- if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
|
|
+- > IPA_NUM_PROPS_MAX) {
|
|
++ if (((struct ipa_ioc_query_intf_rx_props *)
|
|
++ header)->num_rx_props > IPA_NUM_PROPS_MAX) {
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+-
|
|
+- pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
|
|
+- header)->num_rx_props *
|
|
++ pre_entry =
|
|
++ ((struct ipa_ioc_query_intf_rx_props *)
|
|
++ header)->num_rx_props;
|
|
++ pyld_sz = sz + pre_entry *
|
|
+ sizeof(struct ipa_ioc_rx_intf_prop);
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+@@ -598,6 +680,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
|
|
++ param)->num_rx_props != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_ioc_query_intf_rx_props *)
|
|
++ param)->num_rx_props, pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_query_intf_rx_props(
|
|
+ (struct ipa_ioc_query_intf_rx_props *)param)) {
|
|
+ retval = -1;
|
|
+@@ -614,8 +705,10 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ pre_entry =
|
|
++ ((struct ipa_msg_meta *)header)->msg_len;
|
|
+ pyld_sz = sizeof(struct ipa_msg_meta) +
|
|
+- ((struct ipa_msg_meta *)header)->msg_len;
|
|
++ pre_entry;
|
|
+ param = kzalloc(pyld_sz, GFP_KERNEL);
|
|
+ if (!param) {
|
|
+ retval = -ENOMEM;
|
|
+@@ -625,6 +718,15 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
+ retval = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
++ /* add check in case user-space module compromised */
|
|
++ if (unlikely(((struct ipa_msg_meta *)param)->msg_len
|
|
++ != pre_entry)) {
|
|
++ IPAERR("current %d pre %d\n",
|
|
++ ((struct ipa_msg_meta *)param)->msg_len,
|
|
++ pre_entry);
|
|
++ retval = -EFAULT;
|
|
++ break;
|
|
++ }
|
|
+ if (ipa_pull_msg((struct ipa_msg_meta *)param,
|
|
+ (char *)param + sizeof(struct ipa_msg_meta),
|
|
+ ((struct ipa_msg_meta *)param)->msg_len) !=
|
|
diff --git a/patches/3.4/CVE-2016-3903.patch b/patches/3.4/CVE-2016-3903.patch
|
|
new file mode 100644
|
|
index 0000000..ee2ed0b
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-3903.patch
|
|
@@ -0,0 +1,39 @@
|
|
+From ac83977f276a0d2484219523b5713ae3748ff84f Mon Sep 17 00:00:00 2001
|
|
+From: VijayaKumar T M <vtmuni@codeaurora.org>
|
|
+Date: Mon, 25 Jul 2016 11:53:19 +0530
|
|
+Subject: [PATCH] msm: camera: sensor: Fix use after free condition
|
|
+
|
|
+Add a check to return value before calling csid config which will
|
|
+otherwise lead to use after free scenario.
|
|
+
|
|
+CRs-Fixed: 1040857
|
|
+Change-Id: I4f4d9e38eeb537875e0d01de0e99913a44dd3f3f
|
|
+Signed-off-by: VijayaKumar T M <vtmuni@codeaurora.org>
|
|
+---
|
|
+ drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c | 6 +++++-
|
|
+ 1 file changed, 5 insertions(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
|
|
+index 3b015b9c46b..2641b38ac57 100644
|
|
+--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
|
|
++++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
|
|
+@@ -457,7 +457,7 @@ static long msm_csid_cmd(struct csid_device *csid_dev, void *arg)
|
|
+ break;
|
|
+ }
|
|
+ if (csid_params.lut_params.num_cid < 1 ||
|
|
+- csid_params.lut_params.num_cid > 16) {
|
|
++ csid_params.lut_params.num_cid > MAX_CID) {
|
|
+ pr_err("%s: %d num_cid outside range\n",
|
|
+ __func__, __LINE__);
|
|
+ rc = -EINVAL;
|
|
+@@ -485,6 +485,10 @@ static long msm_csid_cmd(struct csid_device *csid_dev, void *arg)
|
|
+ }
|
|
+ csid_params.lut_params.vc_cfg[i] = vc_cfg;
|
|
+ }
|
|
++ if (rc < 0) {
|
|
++ pr_err("%s:%d failed\n", __func__, __LINE__);
|
|
++ break;
|
|
++ }
|
|
+ rc = msm_csid_config(csid_dev, &csid_params);
|
|
+ for (i--; i >= 0; i--)
|
|
+ kfree(csid_params.lut_params.vc_cfg[i]);
|
|
diff --git a/patches/3.4/CVE-2016-6741.patch b/patches/3.4/CVE-2016-6741.patch
|
|
new file mode 100644
|
|
index 0000000..48b2979
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6741.patch
|
|
@@ -0,0 +1,137 @@
|
|
+From 80a1d9978c11f76bbe6d2e622bf2ded18f27e34f Mon Sep 17 00:00:00 2001
|
|
+From: VijayaKumar T M <vtmuni@codeaurora.org>
|
|
+Date: Wed, 7 Sep 2016 12:53:43 +0530
|
|
+Subject: msm: camera: Restructure data handling to be more robust
|
|
+
|
|
+Use dynamic array allocation instead of static array to
|
|
+prevent stack overflow.
|
|
+User-supplied number of bytes may result in integer overflow.
|
|
+To fix this we check that the num_byte isn't above 8K size.
|
|
+
|
|
+CRs-Fixed: 1060554
|
|
+Change-Id: I9b05b846e5cc3a62b1a0a67be529f09abc764796
|
|
+Signed-off-by: VijayaKumar T M <vtmuni@codeaurora.org>
|
|
+---
|
|
+ .../msm/camera_v2/sensor/io/msm_camera_cci_i2c.c | 6 ++++
|
|
+ .../msm/camera_v2/sensor/io/msm_camera_qup_i2c.c | 39 ++++++++++++++++++++--
|
|
+ 2 files changed, 43 insertions(+), 2 deletions(-)
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
|
|
+index 07b7e32..f970233 100644
|
|
+--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
|
|
++++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
|
|
+@@ -71,6 +71,12 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
|
|
+ || num_byte == 0)
|
|
+ return rc;
|
|
+
|
|
++ if (num_byte > I2C_REG_DATA_MAX) {
|
|
++ pr_err("%s: Error num_byte:0x%x exceeds 8K max supported:0x%x\n",
|
|
++ __func__, num_byte, I2C_REG_DATA_MAX);
|
|
++ return rc;
|
|
++ }
|
|
++
|
|
+ buf = kzalloc(num_byte, GFP_KERNEL);
|
|
+ if (!buf) {
|
|
+ pr_err("%s:%d no memory\n", __func__, __LINE__);
|
|
+diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
|
|
+index ee0e9ba..5fd11eb 100644
|
|
+--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
|
|
++++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
|
|
+@@ -102,7 +102,7 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
|
|
+ enum msm_camera_i2c_data_type data_type)
|
|
+ {
|
|
+ int32_t rc = -EFAULT;
|
|
+- unsigned char buf[client->addr_type+data_type];
|
|
++ unsigned char *buf = NULL;
|
|
+
|
|
+ if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
|
|
+ && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|
|
+@@ -110,6 +110,17 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
|
|
+ && data_type != MSM_CAMERA_I2C_WORD_DATA))
|
|
+ return rc;
|
|
+
|
|
++ if (client->addr_type > UINT_MAX - data_type) {
|
|
++ pr_err("%s: integer overflow prevented\n", __func__);
|
|
++ return rc;
|
|
++ }
|
|
++
|
|
++ buf = kzalloc(client->addr_type+data_type, GFP_KERNEL);
|
|
++ if (!buf) {
|
|
++ pr_err("%s:%d no memory\n", __func__, __LINE__);
|
|
++ return -ENOMEM;
|
|
++ }
|
|
++
|
|
+ if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
|
|
+ buf[0] = addr;
|
|
+ } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
|
|
+@@ -119,6 +130,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
|
|
+ rc = msm_camera_qup_i2c_rxdata(client, buf, data_type);
|
|
+ if (rc < 0) {
|
|
+ S_I2C_DBG("%s fail\n", __func__);
|
|
++ kfree(buf);
|
|
++ buf = NULL;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+@@ -128,6 +141,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
|
|
+ *data = buf[0] << 8 | buf[1];
|
|
+
|
|
+ S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
|
|
++ kfree(buf);
|
|
++ buf = NULL;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+@@ -135,7 +150,7 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
|
|
+ uint32_t addr, uint8_t *data, uint32_t num_byte)
|
|
+ {
|
|
+ int32_t rc = -EFAULT;
|
|
+- unsigned char buf[client->addr_type+num_byte];
|
|
++ unsigned char *buf = NULL;
|
|
+ int i;
|
|
+
|
|
+ if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
|
|
+@@ -143,6 +158,22 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
|
|
+ || num_byte == 0)
|
|
+ return rc;
|
|
+
|
|
++ if (num_byte > I2C_REG_DATA_MAX) {
|
|
++ pr_err("%s: Error num_byte:0x%x exceeds 8K max supported:0x%x\n",
|
|
++ __func__, num_byte, I2C_REG_DATA_MAX);
|
|
++ return rc;
|
|
++ }
|
|
++ if (client->addr_type > UINT_MAX - num_byte) {
|
|
++ pr_err("%s: integer overflow prevented\n", __func__);
|
|
++ return rc;
|
|
++ }
|
|
++
|
|
++ buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL);
|
|
++ if (!buf) {
|
|
++ pr_err("%s:%d no memory\n", __func__, __LINE__);
|
|
++ return -ENOMEM;
|
|
++ }
|
|
++
|
|
+ if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
|
|
+ buf[0] = addr;
|
|
+ } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
|
|
+@@ -152,6 +183,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
|
|
+ rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte);
|
|
+ if (rc < 0) {
|
|
+ S_I2C_DBG("%s fail\n", __func__);
|
|
++ kfree(buf);
|
|
++ buf = NULL;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+@@ -161,6 +194,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
|
|
+ S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]);
|
|
+ S_I2C_DBG("Data: 0x%x\n", data[i]);
|
|
+ }
|
|
++ kfree(buf);
|
|
++ buf = NULL;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+--
|
|
+cgit v1.1
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-6741_complementary.patch b/patches/3.4/CVE-2016-6741_complementary.patch
|
|
new file mode 100644
|
|
index 0000000..5692c1f
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6741_complementary.patch
|
|
@@ -0,0 +1,29 @@
|
|
+From 024cca18bbc49ebbb4c9a09a86056dc68e971523 Mon Sep 17 00:00:00 2001
|
|
+From: Zennoe <agrar.pfurtz@gmail.com>
|
|
+Date: Mon, 24 Jul 2017 16:42:58 +0200
|
|
+Subject: [PATCH] Add I2C_REG_DATA_MAX for size param validation
|
|
+
|
|
+Patch partially based on https://review.lineageos.org/c/180786/
|
|
+
|
|
+This patch solves a compile issue occuring whenever CVE-2016-6741 is applied.
|
|
+
|
|
+Change-Id: I5495e41ffc2e186c3321ff2990ca4679c00432ca
|
|
+---
|
|
+ include/media/msm_cam_sensor.h | 1 +
|
|
+ 1 file changed, 1 insertion(+)
|
|
+
|
|
+diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
|
|
+index cfc39439b048..376fefd01055 100644
|
|
+--- a/include/media/msm_cam_sensor.h
|
|
++++ b/include/media/msm_cam_sensor.h
|
|
+@@ -10,6 +10,7 @@
|
|
+
|
|
+ #define I2C_SEQ_REG_SETTING_MAX 5
|
|
+ #define I2C_SEQ_REG_DATA_MAX 20
|
|
++#define I2C_REG_DATA_MAX (8*1024)
|
|
+ #define MAX_CID 16
|
|
+
|
|
+ #define I2C_USER_REG_DATA_MAX 1024
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-6748.patch b/patches/3.4/CVE-2016-6748.patch
|
|
new file mode 100644
|
|
index 0000000..ff0540a
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6748.patch
|
|
@@ -0,0 +1,317 @@
|
|
+From 2bc4d10037c2ab20c6a0c9b3d2251da10ec563d8 Mon Sep 17 00:00:00 2001
|
|
+From: Abdulla Anam <abdullahanam@codeaurora.org>
|
|
+Date: Fri, 3 Jun 2016 17:39:42 +0530
|
|
+Subject: [PATCH] msm: vidc: use %pK instead of %p which respects kptr_restrict
|
|
+ sysctl
|
|
+
|
|
+Hide kernel pointers from unprivileged ussers by using %pK format-
|
|
+specifier instead of %p. This respects the kptr_restrict sysctl
|
|
+setting which is by default on. So by default %pK will print zeroes
|
|
+as address. echo 1 to kptr_restrict to print proper kernel addresses.
|
|
+
|
|
+Change-Id: I79cea5a9f30510079e9127fa6f757a5daca7a96c
|
|
+CRs-Fixed: 987018
|
|
+Signed-off-by: Abdulla Anam <abdullahanam@codeaurora.org>
|
|
+Signed-off-by: Bikshapathi Kothapeta <bkotha@codeaurora.org>
|
|
+---
|
|
+ drivers/media/platform/msm/vidc/hfi_response_handler.c | 6 +++---
|
|
+ drivers/media/platform/msm/vidc/msm_v4l2_vidc.c | 2 +-
|
|
+ drivers/media/platform/msm/vidc/msm_vdec.c | 2 +-
|
|
+ drivers/media/platform/msm/vidc/msm_venc.c | 2 +-
|
|
+ drivers/media/platform/msm/vidc/msm_vidc_common.c | 10 +++++-----
|
|
+ drivers/media/platform/msm/vidc/msm_vidc_debug.c | 2 +-
|
|
+ drivers/media/platform/msm/vidc/q6_hfi.c | 17 ++++++++---------
|
|
+ drivers/media/platform/msm/vidc/venus_hfi.c | 18 +++++++++---------
|
|
+ drivers/media/platform/msm/vidc/vidc_hfi.c | 2 +-
|
|
+ 9 files changed, 30 insertions(+), 31 deletions(-)
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
|
|
+index 032cca4535e..c45ed5f2391 100644
|
|
+--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
|
|
++++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
|
|
+@@ -659,7 +659,7 @@ static void hfi_process_sess_get_prop_buf_req(
|
|
+ dprintk(VIDC_DBG, "Entered ");
|
|
+ if (!prop) {
|
|
+ dprintk(VIDC_ERR,
|
|
+- "hal_process_sess_get_prop_buf_req:bad_prop: %p",
|
|
++ "hal_process_sess_get_prop_buf_req:bad_prop: %pK",
|
|
+ prop);
|
|
+ return;
|
|
+ }
|
|
+@@ -836,8 +836,8 @@ static void hfi_process_session_init_done(
|
|
+ } else {
|
|
+ sess_close = (struct hal_session *)pkt->session_id;
|
|
+ if (sess_close) {
|
|
+- dprintk(VIDC_WARN,
|
|
+- "Sess init failed: 0x%x, 0x%p",
|
|
++ dprintk(VIDC_INFO,
|
|
++ "Sess init failed: Deleting session: 0x%x 0x%pK",
|
|
+ sess_close->session_id, sess_close);
|
|
+ }
|
|
+ }
|
|
+diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
|
|
+index 58015186abb..83bea1dd79c 100644
|
|
+--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
|
|
++++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
|
|
+@@ -516,7 +516,7 @@ static int __devexit msm_vidc_remove(struct platform_device *pdev)
|
|
+ struct msm_vidc_core *core;
|
|
+
|
|
+ if (!pdev) {
|
|
+- dprintk(VIDC_ERR, "%s invalid input %p", __func__, pdev);
|
|
++ dprintk(VIDC_ERR, "%s invalid input %pK", __func__, pdev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ core = pdev->dev.platform_data;
|
|
+diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
|
|
+index b98364c73ff..97300ce81ec 100644
|
|
+--- a/drivers/media/platform/msm/vidc/msm_vdec.c
|
|
++++ b/drivers/media/platform/msm/vidc/msm_vdec.c
|
|
+@@ -938,7 +938,7 @@ int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
|
|
+ fps = fps - 1;
|
|
+
|
|
+ if (inst->prop.fps != fps) {
|
|
+- dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
|
|
++ dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
|
|
+ inst, inst->prop.fps, fps);
|
|
+ inst->prop.fps = fps;
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
|
|
+index 8c685c02d90..d92f79a3dd5 100644
|
|
+--- a/drivers/media/platform/msm/vidc/msm_venc.c
|
|
++++ b/drivers/media/platform/msm/vidc/msm_venc.c
|
|
+@@ -2574,7 +2574,7 @@ int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
|
|
+ fps = fps - 1;
|
|
+
|
|
+ if (inst->prop.fps != fps) {
|
|
+- dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
|
|
++ dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
|
|
+ inst, inst->prop.fps, fps);
|
|
+ inst->prop.fps = fps;
|
|
+ frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
|
|
+diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
|
|
+index f563d3b6592..024500963d5 100644
|
|
+--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
|
|
++++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
|
|
+@@ -410,7 +410,7 @@ static int signal_session_msg_receipt(enum command_response cmd,
|
|
+ struct msm_vidc_inst *inst)
|
|
+ {
|
|
+ if (!inst) {
|
|
+- dprintk(VIDC_ERR, "Invalid(%p) instance id\n", inst);
|
|
++ dprintk(VIDC_ERR, "Invalid(%pK) instance id\n", inst);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
|
|
+@@ -1029,7 +1029,7 @@ static void handle_session_close(enum command_response cmd, void *data)
|
|
+ hdev = inst->core->device;
|
|
+ mutex_lock(&inst->lock);
|
|
+ if (inst->session) {
|
|
+- dprintk(VIDC_DBG, "cleaning up inst: 0x%p", inst);
|
|
++ dprintk(VIDC_DBG, "cleaning up inst: 0x%pK", inst);
|
|
+ call_hfi_op(hdev, session_clean,
|
|
+ (void *) inst->session);
|
|
+ }
|
|
+@@ -1406,7 +1406,7 @@ static void handle_fbd(enum command_response cmd, void *data)
|
|
+
|
|
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
|
|
+ dprintk(VIDC_DBG,
|
|
+- "extradata: userptr = %p; bytesused = %d; length = %d\n",
|
|
++ "extradata: userptr = %pK; bytesused = %d; length = %d\n",
|
|
+ (u8 *)vb->v4l2_planes[extra_idx].m.userptr,
|
|
+ vb->v4l2_planes[extra_idx].bytesused,
|
|
+ vb->v4l2_planes[extra_idx].length);
|
|
+@@ -2555,7 +2555,7 @@ int msm_comm_qbuf(struct vb2_buffer *vb)
|
|
+ }
|
|
+ hdev = core->device;
|
|
+ if (!hdev) {
|
|
+- dprintk(VIDC_ERR, "Invalid input: %p", hdev);
|
|
++ dprintk(VIDC_ERR, "Invalid input: %pK", hdev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+@@ -3191,7 +3191,7 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
|
|
+ }
|
|
+ hdev = core->device;
|
|
+ if (!hdev) {
|
|
+- dprintk(VIDC_ERR, "Invalid device pointer = %p", hdev);
|
|
++ dprintk(VIDC_ERR, "Invalid device pointer = %pK", hdev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
|
|
+index ee91513546d..a805bbd2f5f 100644
|
|
+--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
|
|
++++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
|
|
+@@ -316,7 +316,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
|
|
+ dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst);
|
|
+ goto failed_create_dir;
|
|
+ }
|
|
+- snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
|
|
++ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst);
|
|
+ dir = debugfs_create_dir(debugfs_name, parent);
|
|
+ if (!dir) {
|
|
+ dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
|
|
+diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
|
|
+index 4bc534cdfae..9b2cb985f54 100644
|
|
+--- a/drivers/media/platform/msm/vidc/q6_hfi.c
|
|
++++ b/drivers/media/platform/msm/vidc/q6_hfi.c
|
|
+@@ -200,7 +200,7 @@ static int q6_hfi_register_iommu_domains(struct q6_hfi_device *device)
|
|
+ struct iommu_info *iommu_map;
|
|
+
|
|
+ if (!device || !device->res) {
|
|
+- dprintk(VIDC_ERR, "Invalid parameter: %p", device);
|
|
++ dprintk(VIDC_ERR, "Invalid parameter: %pK", device);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+@@ -218,7 +218,7 @@ static int q6_hfi_register_iommu_domains(struct q6_hfi_device *device)
|
|
+ domain = iommu_group_get_iommudata(iommu_map->group);
|
|
+ if (IS_ERR_OR_NULL(domain)) {
|
|
+ dprintk(VIDC_ERR,
|
|
+- "Failed to get domain data for group %p",
|
|
++ "Failed to get domain data for group %pK",
|
|
+ iommu_map->group);
|
|
+ rc = -EINVAL;
|
|
+ goto fail_group;
|
|
+@@ -226,7 +226,7 @@ static int q6_hfi_register_iommu_domains(struct q6_hfi_device *device)
|
|
+ iommu_map->domain = msm_find_domain_no(domain);
|
|
+ if (iommu_map->domain < 0) {
|
|
+ dprintk(VIDC_ERR,
|
|
+- "Failed to get domain index for domain %p",
|
|
++ "Failed to get domain index for domain %pK",
|
|
+ domain);
|
|
+ rc = -EINVAL;
|
|
+ goto fail_group;
|
|
+@@ -252,7 +252,7 @@ static void q6_hfi_deregister_iommu_domains(struct q6_hfi_device *device)
|
|
+ int i = 0;
|
|
+
|
|
+ if (!device || !device->res) {
|
|
+- dprintk(VIDC_ERR, "Invalid parameter: %p", device);
|
|
++ dprintk(VIDC_ERR, "Invalid parameter: %pK", device);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+@@ -1206,7 +1206,7 @@ static int q6_hfi_iommu_attach(struct q6_hfi_device *device)
|
|
+ struct iommu_info *iommu_map;
|
|
+
|
|
+ if (!device || !device->res) {
|
|
+- dprintk(VIDC_ERR, "Invalid parameter: %p", device);
|
|
++ dprintk(VIDC_ERR, "Invalid parameter: %pK", device);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+@@ -1221,7 +1221,7 @@ static int q6_hfi_iommu_attach(struct q6_hfi_device *device)
|
|
+ rc = IS_ERR(domain) ? PTR_ERR(domain) : -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+- dprintk(VIDC_DBG, "Attaching domain(id:%d) %p to group %p",
|
|
++ dprintk(VIDC_DBG, "Attaching domain(id:%d) %pK to group %pK",
|
|
+ iommu_map->domain, domain, group);
|
|
+ rc = iommu_attach_group(domain, group);
|
|
+ if (rc) {
|
|
+@@ -1252,7 +1252,7 @@ static void q6_hfi_iommu_detach(struct q6_hfi_device *device)
|
|
+ int i;
|
|
+
|
|
+ if (!device || !device->res) {
|
|
+- dprintk(VIDC_ERR, "Invalid parameter: %p", device);
|
|
++ dprintk(VIDC_ERR, "Invalid parameter: %pK", device);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+@@ -1380,7 +1380,7 @@ int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
|
|
+ int rc = 0;
|
|
+
|
|
+ if (!hdev || !res || !callback) {
|
|
+- dprintk(VIDC_ERR, "Invalid params: %p %p %p",
|
|
++ dprintk(VIDC_ERR, "Invalid params: %pK %pK %pK",
|
|
+ hdev, res, callback);
|
|
+ rc = -EINVAL;
|
|
+ goto err_hfi_init;
|
|
+@@ -1398,4 +1398,3 @@ int q6_hfi_initialize(struct hfi_device *hdev, u32 device_id,
|
|
+ err_hfi_init:
|
|
+ return rc;
|
|
+ }
|
|
+-
|
|
+diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
|
|
+index 0de42aef364..8b445c2dec3 100644
|
|
+--- a/drivers/media/platform/msm/vidc/venus_hfi.c
|
|
++++ b/drivers/media/platform/msm/vidc/venus_hfi.c
|
|
+@@ -662,7 +662,7 @@ static int venus_hfi_unvote_bus(void *dev,
|
|
+ struct venus_hfi_device *device = dev;
|
|
+
|
|
+ if (!device) {
|
|
+- dprintk(VIDC_ERR, "%s invalid device handle %p",
|
|
++ dprintk(VIDC_ERR, "%s invalid device handle %pK",
|
|
+ __func__, device);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+@@ -759,7 +759,7 @@ static int venus_hfi_scale_bus(void *dev, int load,
|
|
+ int bus_vector = 0;
|
|
+
|
|
+ if (!device) {
|
|
+- dprintk(VIDC_ERR, "%s invalid device handle %p",
|
|
++ dprintk(VIDC_ERR, "%s invalid device handle %pK",
|
|
+ __func__, device);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+@@ -1068,9 +1068,10 @@ ocmem_alloc_failed:
|
|
+ static int __unset_free_ocmem(struct venus_hfi_device *device)
|
|
+ {
|
|
+ int rc = 0;
|
|
+- if (!device || !device->res) {
|
|
+- dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
|
|
+- __func__, device);
|
|
++
|
|
++ if (!device) {
|
|
++ dprintk(VIDC_ERR, "%s invalid device handle %pK",
|
|
++ __func__, device);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+@@ -2466,7 +2467,7 @@ static int venus_hfi_session_clean(void *session)
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ sess_close = session;
|
|
+- dprintk(VIDC_DBG, "deleted the session: 0x%p",
|
|
++ dprintk(VIDC_DBG, "deleted the session: 0x%pK",
|
|
+ sess_close);
|
|
+ mutex_lock(&((struct venus_hfi_device *)
|
|
+ sess_close->device)->session_lock);
|
|
+@@ -3351,7 +3352,7 @@ static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
|
|
+ domain = iommu_group_get_iommudata(iommu_map->group);
|
|
+ if (!domain) {
|
|
+ dprintk(VIDC_ERR,
|
|
+- "Failed to get domain data for group %p",
|
|
++ "Failed to get domain data for group %pK",
|
|
+ iommu_map->group);
|
|
+ rc = -EINVAL;
|
|
+ goto fail_group;
|
|
+@@ -3359,7 +3360,7 @@ static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
|
|
+ iommu_map->domain = msm_find_domain_no(domain);
|
|
+ if (iommu_map->domain < 0) {
|
|
+ dprintk(VIDC_ERR,
|
|
+- "Failed to get domain index for domain %p",
|
|
++ "Failed to get domain index for domain %pK",
|
|
+ domain);
|
|
+ rc = -EINVAL;
|
|
+ goto fail_group;
|
|
+@@ -4021,4 +4022,3 @@ int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
|
|
+ err_venus_hfi_init:
|
|
+ return rc;
|
|
+ }
|
|
+-
|
|
+diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.c b/drivers/media/platform/msm/vidc/vidc_hfi.c
|
|
+index ef0de370eb0..a9e87a03720 100644
|
|
+--- a/drivers/media/platform/msm/vidc/vidc_hfi.c
|
|
++++ b/drivers/media/platform/msm/vidc/vidc_hfi.c
|
|
+@@ -61,7 +61,7 @@ void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
|
|
+ struct hfi_device *hdev)
|
|
+ {
|
|
+ if (!hdev) {
|
|
+- dprintk(VIDC_ERR, "%s invalid device %p", __func__, hdev);
|
|
++ dprintk(VIDC_ERR, "%s invalid device %pK", __func__, hdev);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-6751.patch b/patches/3.4/CVE-2016-6751.patch
|
|
new file mode 100644
|
|
index 0000000..efe4e5d
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6751.patch
|
|
@@ -0,0 +1,35 @@
|
|
+From 88c6ce04b9a9b010d27ca89ed80df1f3f6063e94 Mon Sep 17 00:00:00 2001
|
|
+From: vivek mehta <mvivek@codeaurora.org>
|
|
+Date: Mon, 12 Sep 2016 17:27:06 -0700
|
|
+Subject: [PATCH] ASoC: msm: initialize the params array before using it
|
|
+
|
|
+The params array is used without initialization, which may cause
|
|
+security issues. Initialize it as all zero after the definition.
|
|
+
|
|
+bug: 30902162
|
|
+Change-Id: If462fe3d82f139d72547f82dc7eb564f83cb35bf
|
|
+Signed-off-by: vivek mehta <mvivek@codeaurora.org>
|
|
+---
|
|
+ sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c | 2 ++
|
|
+ 1 file changed, 2 insertions(+)
|
|
+
|
|
+diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
|
|
+index 3091f4b0449..5b171aebea4 100755
|
|
+--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
|
|
++++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
|
|
+@@ -1031,6 +1031,7 @@ static int msm_compr_ioctl(struct snd_pcm_substream *substream,
|
|
+ struct snd_dec_ddp *ddp =
|
|
+ &compr->info.codec_param.codec.options.ddp;
|
|
+ uint32_t params_length = 0;
|
|
++ memset(params_value, 0, MAX_AC3_PARAM_SIZE);
|
|
+ /* check integer overflow */
|
|
+ if (ddp->params_length > UINT_MAX/sizeof(int)) {
|
|
+ pr_err("%s: Integer overflow ddp->params_length %d\n",
|
|
+@@ -1075,6 +1076,7 @@ static int msm_compr_ioctl(struct snd_pcm_substream *substream,
|
|
+ struct snd_dec_ddp *ddp =
|
|
+ &compr->info.codec_param.codec.options.ddp;
|
|
+ uint32_t params_length = 0;
|
|
++ memset(params_value, 0, MAX_AC3_PARAM_SIZE);
|
|
+ /* check integer overflow */
|
|
+ if (ddp->params_length > UINT_MAX/sizeof(int)) {
|
|
+ pr_err("%s: Integer overflow ddp->params_length %d\n",
|
|
diff --git a/patches/3.4/CVE-2016-6752.patch b/patches/3.4/CVE-2016-6752.patch
|
|
new file mode 100644
|
|
index 0000000..dc5a8c9
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6752.patch
|
|
@@ -0,0 +1,45 @@
|
|
+From 1890c5c24fb7190e56819efefb1cf232da884cc9 Mon Sep 17 00:00:00 2001
|
|
+From: Mallikarjuna Reddy Amireddy <mamire@codeaurora.org>
|
|
+Date: Thu, 15 Sep 2016 10:44:55 -0700
|
|
+Subject: [PATCH] qseecom: Change format specifier %p to %pK
|
|
+
|
|
+Format specifier %p can leak kernel addresses while not valuing the
|
|
+kptr_restrict system settings. When kptr_restrict is set to (1), kernel
|
|
+pointers printed using the %pK format specifier will be replaced with
|
|
+0's.
|
|
+So that %pK will not leak kernel pointers to unprivileged users.
|
|
+So change the format specifier from %p to %pK.
|
|
+
|
|
+Debugging Note : &pK prints only Zeros as address. if you need actual
|
|
+address information, pls echo 0 to kptr_restrict.
|
|
+$ echo 0 > /proc/sys/kernel/kptr_restrict
|
|
+
|
|
+Bug: 31498159
|
|
+Change-Id: I0baf2be2d5a476e2e4267f20b99d0ddf5492469e
|
|
+Signed-off-by: Mallikarjuna Reddy Amireddy <mamire@codeaurora.org>
|
|
+---
|
|
+ drivers/misc/qseecom.c | 4 ++--
|
|
+ 1 file changed, 2 insertions(+), 2 deletions(-)
|
|
+
|
|
+diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
|
|
+index d589e688184..933066d59ca 100644
|
|
+--- a/drivers/misc/qseecom.c
|
|
++++ b/drivers/misc/qseecom.c
|
|
+@@ -1208,7 +1208,7 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
|
+ void *req_buf = NULL;
|
|
+
|
|
+ if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
|
|
+- pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
|
|
++ pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
|
|
+ req_ptr, send_svc_ireq_ptr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+@@ -2412,7 +2412,7 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+- pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
|
|
++ pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%pK\n",
|
|
+ req.resp_len, req.resp_buf);
|
|
+ return ret;
|
|
+ }
|
|
diff --git a/patches/3.4/CVE-2016-6753.patch b/patches/3.4/CVE-2016-6753.patch
|
|
new file mode 100644
|
|
index 0000000..cb01e0b
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6753.patch
|
|
@@ -0,0 +1,29 @@
|
|
+From 3d30b6e2e53449b082274d63468adac992fa9e67 Mon Sep 17 00:00:00 2001
|
|
+From: Nick Desaulniers <ndesaulniers@google.com>
|
|
+Date: Mon, 12 Sep 2016 15:47:42 -0700
|
|
+Subject: [PATCH] cgroup: prefer %pK to %p
|
|
+
|
|
+Prevents leaking kernel pointers when using kptr_restrict.
|
|
+
|
|
+Bug: 30149174
|
|
+Change-Id: I0fa3cd8d4a0d9ea76d085bba6020f1eda073c09b
|
|
+Git-repo: https://android.googlesource.com/kernel/msm.git
|
|
+Git-commit: 505e48f32f1321ed7cf80d49dd5f31b16da445a8
|
|
+Signed-off-by: Srinivasa Rao Kuppala <srkupp@codeaurora.org>
|
|
+---
|
|
+ kernel/cgroup.c | 2 +-
|
|
+ 1 file changed, 1 insertion(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/kernel/cgroup.c b/kernel/cgroup.c
|
|
+index efd8fd20db5..ea66800836d 100644
|
|
+--- a/kernel/cgroup.c
|
|
++++ b/kernel/cgroup.c
|
|
+@@ -5222,7 +5222,7 @@ static int cgroup_css_links_read(struct cgroup *cont,
|
|
+ struct css_set *cg = link->cg;
|
|
+ struct task_struct *task;
|
|
+ int count = 0;
|
|
+- seq_printf(seq, "css_set %p\n", cg);
|
|
++ seq_printf(seq, "css_set %pK\n", cg);
|
|
+ list_for_each_entry(task, &cg->tasks, cg_list) {
|
|
+ if (count++ > MAX_TASKS_SHOWN_PER_CSS) {
|
|
+ seq_puts(seq, " ...\n");
|
|
diff --git a/patches/3.4/CVE-2016-6757.patch b/patches/3.4/CVE-2016-6757.patch
|
|
new file mode 100644
|
|
index 0000000..d2e90e6
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6757.patch
|
|
@@ -0,0 +1,372 @@
|
|
+From 4d863740cd461007657124a0b6be8287ac5dd335 Mon Sep 17 00:00:00 2001
|
|
+From: Abhijit Kulkarni <kabhijit@codeaurora.org>
|
|
+Date: Wed, 15 Jun 2016 10:30:50 -0700
|
|
+Subject: [PATCH] msm: mdss: hide kernel addresses from unprevileged users
|
|
+
|
|
+for printing kernel pointers which should be hidden from unprivileged
|
|
+users, use %pK which evaluates whether kptr_restrict is set.
|
|
+
|
|
+Change-Id: I383bd64c8278f26c237bd189435e91843103000b
|
|
+CRs-Fixed: 987021
|
|
+Signed-off-by: Abhijit Kulkarni <kabhijit@codeaurora.org>
|
|
+Signed-off-by: Nirmal Abraham <nabrah@codeaurora.org>
|
|
+---
|
|
+ drivers/video/msm/mdss/mdp3.c | 14 +++++++-------
|
|
+ drivers/video/msm/mdss/mdss_dsi.c | 8 ++++----
|
|
+ drivers/video/msm/mdss/mdss_dsi_host.c | 2 +-
|
|
+ drivers/video/msm/mdss/mdss_dsi_panel.c | 8 +++++---
|
|
+ drivers/video/msm/mdss/mdss_fb.c | 6 +++---
|
|
+ drivers/video/msm/mdss/mdss_hdmi_tx.c | 2 +-
|
|
+ drivers/video/msm/mdss/mdss_hdmi_util.c | 2 +-
|
|
+ drivers/video/msm/mdss/mdss_mdp.c | 8 ++++----
|
|
+ drivers/video/msm/mdss/mdss_mdp_intf_cmd.c | 5 ++---
|
|
+ drivers/video/msm/mdss/mdss_mdp_intf_video.c | 6 +++---
|
|
+ drivers/video/msm/mdss/mdss_mdp_util.c | 4 ++--
|
|
+ drivers/video/msm/mdss/mdss_mdp_wb.c | 4 ++--
|
|
+ 12 files changed, 35 insertions(+), 34 deletions(-)
|
|
+
|
|
+diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
|
|
+index 4eca6b5ba17c..b2ef1bddcc79 100644
|
|
+--- a/drivers/video/msm/mdss/mdp3.c
|
|
++++ b/drivers/video/msm/mdss/mdp3.c
|
|
+@@ -954,7 +954,7 @@ static int mdp3_res_init(void)
|
|
+
|
|
+ mdp3_res->ion_client = msm_ion_client_create(-1, mdp3_res->pdev->name);
|
|
+ if (IS_ERR_OR_NULL(mdp3_res->ion_client)) {
|
|
+- pr_err("msm_ion_client_create() return error (%p)\n",
|
|
++ pr_err("msm_ion_client_create() return error (%pK)\n",
|
|
+ mdp3_res->ion_client);
|
|
+ mdp3_res->ion_client = NULL;
|
|
+ return -EINVAL;
|
|
+@@ -1382,7 +1382,7 @@ void mdp3_unmap_iommu(struct ion_client *client, struct ion_handle *handle)
|
|
+ mutex_lock(&mdp3_res->iommu_lock);
|
|
+ meta = mdp3_iommu_meta_lookup(table);
|
|
+ if (!meta) {
|
|
+- WARN(1, "%s: buffer was never mapped for %p\n", __func__,
|
|
++ WARN(1, "%s: buffer was never mapped for %pK\n", __func__,
|
|
+ handle);
|
|
+ mutex_unlock(&mdp3_res->iommu_lock);
|
|
+ goto out;
|
|
+@@ -1410,7 +1410,7 @@ static void mdp3_iommu_meta_add(struct mdp3_iommu_meta *meta)
|
|
+ } else if (meta->table > entry->table) {
|
|
+ p = &(*p)->rb_right;
|
|
+ } else {
|
|
+- pr_err("%s: handle %p already exists\n", __func__,
|
|
++ pr_err("%s: handle %pK already exists\n", __func__,
|
|
+ entry->handle);
|
|
+ BUG();
|
|
+ }
|
|
+@@ -1471,7 +1471,7 @@ static int mdp3_iommu_map_iommu(struct mdp3_iommu_meta *meta,
|
|
+ ret = iommu_map_range(domain, meta->iova_addr + padding,
|
|
+ table->sgl, size, prot);
|
|
+ if (ret) {
|
|
+- pr_err("%s: could not map %lx in domain %p\n",
|
|
++ pr_err("%s: could not map %lx in domain %pK\n",
|
|
+ __func__, meta->iova_addr, domain);
|
|
+ unmap_size = padding;
|
|
+ goto out2;
|
|
+@@ -1596,12 +1596,12 @@ int mdp3_self_map_iommu(struct ion_client *client, struct ion_handle *handle,
|
|
+ }
|
|
+ } else {
|
|
+ if (iommu_meta->flags != iommu_flags) {
|
|
+- pr_err("%s: handle %p is already mapped with diff flag\n",
|
|
++ pr_err("%s: handle %pK is already mapped with diff flag\n",
|
|
+ __func__, handle);
|
|
+ ret = -EINVAL;
|
|
+ goto out_unlock;
|
|
+ } else if (iommu_meta->mapped_size != iova_length) {
|
|
+- pr_err("%s: handle %p is already mapped with diff len\n",
|
|
++ pr_err("%s: handle %pK is already mapped with diff len\n",
|
|
+ __func__, handle);
|
|
+ ret = -EINVAL;
|
|
+ goto out_unlock;
|
|
+@@ -1719,7 +1719,7 @@ done:
|
|
+ data->addr += img->offset;
|
|
+ data->len -= img->offset;
|
|
+
|
|
+- pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
|
|
++ pr_debug("mem=%d ihdl=%pK buf=0x%x len=0x%x\n", img->memory_id,
|
|
+ data->srcp_ihdl, data->addr, data->len);
|
|
+ } else {
|
|
+ mdp3_put_img(data, client);
|
|
+diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
|
|
+index e0bbc41913af..8d4f1dc7e1f7 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_dsi.c
|
|
++++ b/drivers/video/msm/mdss/mdss_dsi.c
|
|
+@@ -591,7 +591,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata)
|
|
+
|
|
+ mutex_lock(&ctrl_pdata->mutex);
|
|
+ panel_info = &ctrl_pdata->panel_data.panel_info;
|
|
+- printk("%s+: ctrl=%p ndx=%d\n", __func__,
|
|
++ pr_info("%s+: ctrl=%pK ndx=%d\n", __func__,
|
|
+ ctrl_pdata, ctrl_pdata->ndx);
|
|
+
|
|
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
|
|
+@@ -946,7 +946,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
|
|
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
+ panel_data);
|
|
+
|
|
+- pr_info("%s+: ctrl=%p ndx=%d\n",
|
|
++ pr_info("%s+: ctrl=%pK ndx=%d\n",
|
|
+ __func__, ctrl_pdata, ctrl_pdata->ndx);
|
|
+
|
|
+ pinfo = &pdata->panel_info;
|
|
+@@ -1307,7 +1307,7 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
|
|
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
+ panel_data);
|
|
+
|
|
+- pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
|
|
++ pr_debug("%s+: ctrl=%pK ndx=%d\n", __func__,
|
|
+ ctrl_pdata, ctrl_pdata->ndx);
|
|
+
|
|
+ WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT),
|
|
+@@ -1832,7 +1832,7 @@ int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode,
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+- pr_info("%s: ctrl_base=%p ctrl_size=%x phy_base=%p phy_size=%x\n",
|
|
++ pr_info("%s: ctrl_base=%pK ctrl_size=%x phy_base=%pK phy_size=%x\n",
|
|
+ __func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base,
|
|
+ ctrl->phy_io.len);
|
|
+
|
|
+diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
|
|
+index 8856d0177001..3f3ef84fe9ed 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_dsi_host.c
|
|
++++ b/drivers/video/msm/mdss/mdss_dsi_host.c
|
|
+@@ -91,7 +91,7 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
|
|
+ if (mdss_register_irq(ctrl->dsi_hw))
|
|
+ pr_err("%s: mdss_register_irq failed.\n", __func__);
|
|
+
|
|
+- pr_debug("%s: ndx=%d base=%p\n", __func__, ctrl->ndx, ctrl->ctrl_base);
|
|
++ pr_debug("%s: ndx=%d base=%pK\n", __func__, ctrl->ndx, ctrl->ctrl_base);
|
|
+
|
|
+ init_completion(&ctrl->dma_comp);
|
|
+ init_completion(&ctrl->mdp_comp);
|
|
+diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
|
|
+index 9e032fa54ee5..ec02e38d306f 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
|
|
++++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
|
|
+@@ -520,7 +520,7 @@ static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata)
|
|
+ panel_data);
|
|
+ mipi = &pdata->panel_info.mipi;
|
|
+
|
|
+- pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
++ pr_debug("%s: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
+
|
|
+ caset[1] = (((pdata->panel_info.roi_x) & 0xFF00) >> 8);
|
|
+ caset[2] = (((pdata->panel_info.roi_x) & 0xFF));
|
|
+@@ -1170,7 +1170,8 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
|
|
+ ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
+ panel_data);
|
|
+
|
|
+- pr_info("%s+: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
++
|
|
++ pr_info("%s+: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
+
|
|
+ mipi = &pdata->panel_info.mipi;
|
|
+
|
|
+@@ -1224,7 +1225,8 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
|
|
+ ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
|
+ panel_data);
|
|
+
|
|
+- pr_info("%s+: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
++
|
|
++ pr_info("%s+: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx);
|
|
+
|
|
+ mipi = &pdata->panel_info.mipi;
|
|
+
|
|
+diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
|
|
+index dd593078fcda..aafcd435eb21 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_fb.c
|
|
++++ b/drivers/video/msm/mdss/mdss_fb.c
|
|
+@@ -1655,8 +1655,8 @@ int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size)
|
|
+ goto fb_mmap_failed;
|
|
+ }
|
|
+
|
|
+- pr_debug("alloc 0x%zuB vaddr = %p (%pa iova) for fb%d\n", fb_size,
|
|
+- vaddr, &mfd->iova, mfd->index);
|
|
++ pr_info("alloc 0x%xB vaddr = %pK (%pa iova) for fb%d\n", fb_size, vaddr,
|
|
++ &mfd->iova, mfd->index);
|
|
+
|
|
+ mfd->fbi->screen_base = (char *) vaddr;
|
|
+ mfd->fbi->fix.smem_start = (unsigned int) mfd->iova;
|
|
+@@ -1747,7 +1747,7 @@ static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
|
|
+
|
|
+ __mdss_fb_set_page_protection(vma, mfd);
|
|
+
|
|
+- pr_debug("vma=%p, addr=%x len=%ld",
|
|
++ pr_debug("vma=%pK, addr=%x len=%ld",
|
|
+ vma, (unsigned int)addr, len);
|
|
+ pr_cont("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
|
|
+ (unsigned int)vma->vm_start,
|
|
+diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
|
|
+index 1bf389ae1d6e..4681ac1fde2e 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
|
|
++++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
|
|
+@@ -838,7 +838,7 @@ static int hdmi_tx_sysfs_create(struct hdmi_tx_ctrl *hdmi_ctrl,
|
|
+ return rc;
|
|
+ }
|
|
+ hdmi_ctrl->kobj = &fbi->dev->kobj;
|
|
+- DEV_DBG("%s: sysfs group %p\n", __func__, hdmi_ctrl->kobj);
|
|
++ DEV_DBG("%s: sysfs group %pK\n", __func__, hdmi_ctrl->kobj);
|
|
+
|
|
+ return 0;
|
|
+ } /* hdmi_tx_sysfs_create */
|
|
+diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
|
|
+index 6f6c805122d1..a583a00e16ec 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
|
|
++++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
|
|
+@@ -178,7 +178,7 @@ static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data,
|
|
+ return;
|
|
+ }
|
|
+
|
|
+- DEV_DBG("%s: buf=%p, d_len=0x%x, d_addr=0x%x, no_align=%d\n",
|
|
++ DEV_DBG("%s: buf=%pK, d_len=0x%x, d_addr=0x%x, no_align=%d\n",
|
|
+ caller, ddc_data->data_buf, ddc_data->data_len,
|
|
+ ddc_data->dev_addr, ddc_data->no_align);
|
|
+ DEV_DBG("%s: offset=0x%x, req_len=0x%x, retry=%d, what=%s\n",
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
|
|
+index d3ba05523019..914b64a79033 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp.c
|
|
+@@ -217,7 +217,7 @@ int mdss_register_irq(struct mdss_hw *hw)
|
|
+ if (!mdss_irq_handlers[hw->hw_ndx])
|
|
+ mdss_irq_handlers[hw->hw_ndx] = hw;
|
|
+ else
|
|
+- pr_err("panel %d's irq at %p is already registered\n",
|
|
++ pr_err("panel %d's irq at %pK is already registered\n",
|
|
+ hw->hw_ndx, hw->irq_handler);
|
|
+ spin_unlock_irqrestore(&mdss_lock, irq_flags);
|
|
+
|
|
+@@ -1107,7 +1107,7 @@ static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
|
|
+
|
|
+ mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
|
|
+ if (IS_ERR_OR_NULL(mdata->iclient)) {
|
|
+- pr_err("msm_ion_client_create() return error (%p)\n",
|
|
++ pr_err("msm_ion_client_create() return error (%pK)\n",
|
|
+ mdata->iclient);
|
|
+ mdata->iclient = NULL;
|
|
+ }
|
|
+@@ -1578,7 +1578,7 @@ static int mdss_mdp_parse_bootarg(struct platform_device *pdev)
|
|
+ cmd_len = strlen(cmd_line);
|
|
+ disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len);
|
|
+ if (!disp_idx) {
|
|
+- pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n",
|
|
++ pr_err("%s:%d:cmdline panel not set disp_idx=[%pK]\n",
|
|
+ __func__, __LINE__, disp_idx);
|
|
+ memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
|
|
+ *intf_type = MDSS_PANEL_INTF_INVALID;
|
|
+@@ -1598,7 +1598,7 @@ static int mdss_mdp_parse_bootarg(struct platform_device *pdev)
|
|
+ }
|
|
+
|
|
+ if (end_idx <= disp_idx) {
|
|
+- pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n",
|
|
++ pr_err("%s:%d:cmdline pan incorrect end=[%pK] disp=[%pK]\n",
|
|
+ __func__, __LINE__, end_idx, disp_idx);
|
|
+ memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
|
|
+ *intf_type = MDSS_PANEL_INTF_INVALID;
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
|
|
+index 93db1875d53a..2e37cc9391d6 100755
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
|
|
+@@ -527,7 +527,7 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
|
|
+ ctx->rdptr_enabled, ctl->roi_bkup.w,
|
|
+ ctl->roi_bkup.h);
|
|
+
|
|
+- pr_debug("%s: intf_num=%d ctx=%p koff_cnt=%d\n", __func__,
|
|
++ pr_debug("%s: intf_num=%d ctx=%pK koff_cnt=%d\n", __func__,
|
|
+ ctl->intf_num, ctx, atomic_read(&ctx->koff_cnt));
|
|
+
|
|
+ rc = wait_event_timeout(ctx->pp_waitq,
|
|
+@@ -829,7 +829,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
|
|
+ ctx->recovery.fxn = mdss_mdp_cmd_underflow_recovery;
|
|
+ ctx->recovery.data = ctx;
|
|
+
|
|
+- pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
|
|
++ pr_debug("%s: ctx=%pK num=%d mixer=%d\n", __func__,
|
|
+ ctx, ctx->pp_num, mixer->num);
|
|
+ MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
|
|
+ ctx->rdptr_enabled);
|
|
+@@ -857,4 +857,3 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+-
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
|
|
+index 5ba83487db66..295ebcb6a853 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
|
|
+@@ -115,7 +115,7 @@ int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ head[i].base = mdata->mdp_base + offsets[i];
|
|
+- pr_debug("adding Video Intf #%d offset=0x%x virt=%p\n", i,
|
|
++ pr_debug("adding Video Intf #%d offset=0x%x virt=%pK\n", i,
|
|
+ offsets[i], head[i].base);
|
|
+ head[i].ref_cnt = 0;
|
|
+ head[i].intf_num = i + MDSS_MDP_INTF0;
|
|
+@@ -783,7 +783,7 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
|
|
+ i = ctl->intf_num - MDSS_MDP_INTF0;
|
|
+ if (i < mdata->nintf) {
|
|
+ ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) + i;
|
|
+- pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
|
|
++ pr_debug("video Intf #%d base=%pK", ctx->intf_num, ctx->base);
|
|
+ } else {
|
|
+ pr_err("Invalid intf number: %d\n", ctl->intf_num);
|
|
+ ret = -EINVAL;
|
|
+@@ -856,7 +856,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
|
|
+ pr_err("Intf %d already in use\n", ctl->intf_num);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+- pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
|
|
++ pr_debug("video Intf #%d base=%pK", ctx->intf_num, ctx->base);
|
|
+ ctx->ref_cnt++;
|
|
+ } else {
|
|
+ pr_err("Invalid intf number: %d\n", ctl->intf_num);
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
+index 0b1a154a225c..50e9d9b620c0 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp_util.c
|
|
+@@ -517,7 +517,7 @@ int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
|
|
+ pr_debug("pmem buf=0x%x\n", data->addr);
|
|
+ data->srcp_file = NULL;
|
|
+ } else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
|
|
+- pr_debug("ion hdl=%p buf=0x%x\n", data->srcp_ihdl, data->addr);
|
|
++ pr_debug("ion hdl=%pK buf=0x%x\n", data->srcp_ihdl, data->addr);
|
|
+ if (!iclient) {
|
|
+ pr_err("invalid ion client\n");
|
|
+ return -ENOMEM;
|
|
+@@ -635,7 +635,7 @@ int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data)
|
|
+ data->addr += img->offset;
|
|
+ data->len -= img->offset;
|
|
+
|
|
+- pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
|
|
++ pr_debug("mem=%d ihdl=%pK buf=0x%x len=0x%x\n", img->memory_id,
|
|
+ data->srcp_ihdl, data->addr, data->len);
|
|
+ } else {
|
|
+ mdss_mdp_put_img(data);
|
|
+diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
|
|
+index a87b0abca8e1..7296d0401e1d 100644
|
|
+--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
|
|
++++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
|
|
+@@ -94,7 +94,7 @@ struct mdss_mdp_data *mdss_mdp_wb_debug_buffer(struct msm_fb_data_type *mfd)
|
|
+ ihdl = ion_alloc(iclient, img_size, SZ_4K,
|
|
+ ION_HEAP(ION_SF_HEAP_ID), 0);
|
|
+ if (IS_ERR_OR_NULL(ihdl)) {
|
|
+- pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
|
|
++ pr_err("unable to alloc fbmem from ion (%pK)\n", ihdl);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+@@ -114,7 +114,7 @@ struct mdss_mdp_data *mdss_mdp_wb_debug_buffer(struct msm_fb_data_type *mfd)
|
|
+ img->len = img_size;
|
|
+ }
|
|
+
|
|
+- pr_debug("ihdl=%p virt=%p phys=0x%lx iova=0x%x size=%u\n",
|
|
++ pr_debug("ihdl=%pK virt=%pK phys=0x%lx iova=0x%x size=%u\n",
|
|
+ ihdl, videomemory, mdss_wb_mem, img->addr, img_size);
|
|
+ }
|
|
+ return &mdss_wb_buffer;
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-6791.patch b/patches/3.4/CVE-2016-6791.patch
|
|
new file mode 100644
|
|
index 0000000..4e4ce3a
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-6791.patch
|
|
@@ -0,0 +1,86 @@
|
|
+From 15cfe5f68912235f7fc7a0071106db4e0e854a36 Mon Sep 17 00:00:00 2001
|
|
+From: Walter Yang <yandongy@codeaurora.org>
|
|
+Date: Wed, 28 Sep 2016 20:11:23 +0800
|
|
+Subject: [PATCH] ASoC: msm: lock read/write when add/free audio ion memory
|
|
+
|
|
+As read/write get access to ion memory region as well, it's
|
|
+necessary to lock them when ion memory is about to be added/freed
|
|
+to avoid racing cases.
|
|
+
|
|
+CRs-Fixed: 1071809
|
|
+Change-Id: I436ead23c93384961b38ca99b9312a40c50ad03a
|
|
+Signed-off-by: Walter Yang <yandongy@codeaurora.org>
|
|
+[joel: backport from 3.10]
|
|
+Fixes: CVE-2016-6791
|
|
+Fixes: CVE-2016-8391
|
|
+Signed-off-by: Joel Stanley <joel@jms.id.au>
|
|
+---
|
|
+ arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c | 24 +++++++++++++++++++-----
|
|
+ 1 file changed, 19 insertions(+), 5 deletions(-)
|
|
+
|
|
+diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
|
|
+index b996d29b5f0..fca16673ece 100644
|
|
+--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
|
|
++++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
|
|
+@@ -1,6 +1,6 @@
|
|
+ /* Copyright (C) 2008 Google, Inc.
|
|
+ * Copyright (C) 2008 HTC Corporation
|
|
+- * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
|
|
++ * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
|
|
+ *
|
|
+ * This software is licensed under the terms of the GNU General Public
|
|
+ * License version 2, as published by the Free Software Foundation, and
|
|
+@@ -562,6 +562,8 @@ int audio_aio_release(struct inode *inode, struct file *file)
|
|
+ struct q6audio_aio *audio = file->private_data;
|
|
+ pr_debug("%s[%p]\n", __func__, audio);
|
|
+ mutex_lock(&audio->lock);
|
|
++ mutex_lock(&audio->read_lock);
|
|
++ mutex_lock(&audio->write_lock);
|
|
+ audio->wflush = 1;
|
|
+ if (audio->enabled)
|
|
+ audio_aio_flush(audio);
|
|
+@@ -576,6 +578,8 @@ int audio_aio_release(struct inode *inode, struct file *file)
|
|
+ wake_up(&audio->event_wait);
|
|
+ audio_aio_reset_event_queue(audio);
|
|
+ q6asm_audio_client_free(audio->ac);
|
|
++ mutex_unlock(&audio->write_lock);
|
|
++ mutex_unlock(&audio->read_lock);
|
|
+ mutex_unlock(&audio->lock);
|
|
+ mutex_destroy(&audio->lock);
|
|
+ mutex_destroy(&audio->read_lock);
|
|
+@@ -1347,10 +1351,15 @@ long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
+ struct msm_audio_ion_info info;
|
|
+ pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
|
|
+ mutex_lock(&audio->lock);
|
|
+- if (copy_from_user(&info, (void *)arg, sizeof(info)))
|
|
++ if (copy_from_user(&info, (void *)arg, sizeof(info))) {
|
|
+ rc = -EFAULT;
|
|
+- else
|
|
++ } else {
|
|
++ mutex_lock(&audio->read_lock);
|
|
++ mutex_lock(&audio->write_lock);
|
|
+ rc = audio_aio_ion_add(audio, &info);
|
|
++ mutex_unlock(&audio->write_lock);
|
|
++ mutex_unlock(&audio->read_lock);
|
|
++ }
|
|
+ mutex_unlock(&audio->lock);
|
|
+ break;
|
|
+ }
|
|
+@@ -1358,10 +1367,15 @@ long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
+ struct msm_audio_ion_info info;
|
|
+ mutex_lock(&audio->lock);
|
|
+ pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
|
|
+- if (copy_from_user(&info, (void *)arg, sizeof(info)))
|
|
++ if (copy_from_user(&info, (void *)arg, sizeof(info))) {
|
|
+ rc = -EFAULT;
|
|
+- else
|
|
++ } else {
|
|
++ mutex_lock(&audio->read_lock);
|
|
++ mutex_lock(&audio->write_lock);
|
|
+ rc = audio_aio_ion_remove(audio, &info);
|
|
++ mutex_unlock(&audio->write_lock);
|
|
++ mutex_unlock(&audio->read_lock);
|
|
++ }
|
|
+ mutex_unlock(&audio->lock);
|
|
+ break;
|
|
+ }
|
|
diff --git a/patches/3.4/CVE-2016-7914.patch b/patches/3.4/CVE-2016-7914.patch
|
|
new file mode 100644
|
|
index 0000000..3332710
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-7914.patch
|
|
@@ -0,0 +1,1873 @@
|
|
+From 00381d60c189024036553989440a39c6c6c22d0c Mon Sep 17 00:00:00 2001
|
|
+From: Jerome Marchand <jmarchan@redhat.com>
|
|
+Date: Wed, 6 Apr 2016 14:06:48 +0100
|
|
+Subject: [PATCH] assoc_array: don't call compare_object() on a node
|
|
+
|
|
+[ Upstream commit 8d4a2ec1e0b41b0cf9a0c5cd4511da7f8e4f3de2 ]
|
|
+
|
|
+Changes since V1: fixed the description and added KASan warning.
|
|
+
|
|
+In assoc_array_insert_into_terminal_node(), we call the
|
|
+compare_object() method on all non-empty slots, even when they're
|
|
+not leaves, passing a pointer to an unexpected structure to
|
|
+compare_object(). Currently it causes an out-of-bound read access
|
|
+in keyring_compare_object detected by KASan (see below). The issue
|
|
+is easily reproduced with keyutils testsuite.
|
|
+Only call compare_object() when the slot is a leave.
|
|
+
|
|
+KASan warning:
|
|
+==================================================================
|
|
+BUG: KASAN: slab-out-of-bounds in keyring_compare_object+0x213/0x240 at
|
|
+addr ffff880060a6f838
|
|
+Read of size 8 by task keyctl/1655
|
|
+=============================================================================
|
|
+BUG kmalloc-192 (Not tainted): kasan: bad access detected
|
|
+-----------------------------------------------------------------------------
|
|
+
|
|
+Disabling lock debugging due to kernel taint
|
|
+INFO: Allocated in assoc_array_insert+0xfd0/0x3a60 age=69 cpu=1 pid=1647
|
|
+ ___slab_alloc+0x563/0x5c0
|
|
+ __slab_alloc+0x51/0x90
|
|
+ kmem_cache_alloc_trace+0x263/0x300
|
|
+ assoc_array_insert+0xfd0/0x3a60
|
|
+ __key_link_begin+0xfc/0x270
|
|
+ key_create_or_update+0x459/0xaf0
|
|
+ SyS_add_key+0x1ba/0x350
|
|
+ entry_SYSCALL_64_fastpath+0x12/0x76
|
|
+INFO: Slab 0xffffea0001829b80 objects=16 used=8 fp=0xffff880060a6f550
|
|
+flags=0x3fff8000004080
|
|
+INFO: Object 0xffff880060a6f740 @offset=5952 fp=0xffff880060a6e5d1
|
|
+
|
|
+Bytes b4 ffff880060a6f730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+00 ................
|
|
+Object ffff880060a6f740: d1 e5 a6 60 00 88 ff ff 0e 00 00 00 00 00 00 00
|
|
+ ...`............
|
|
+Object ffff880060a6f750: 02 cf 8e 60 00 88 ff ff 02 c0 8e 60 00 88 ff ff
|
|
+ ...`.......`....
|
|
+Object ffff880060a6f760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7d0: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+Object ffff880060a6f7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
+ ................
|
|
+CPU: 0 PID: 1655 Comm: keyctl Tainted: G B 4.5.0-rc4-kasan+
|
|
+Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
|
|
+ 0000000000000000 000000001b2800b4 ffff880060a179e0 ffffffff81b60491
|
|
+ ffff88006c802900 ffff880060a6f740 ffff880060a17a10 ffffffff815e2969
|
|
+ ffff88006c802900 ffffea0001829b80 ffff880060a6f740 ffff880060a6e650
|
|
+Call Trace:
|
|
+ [<ffffffff81b60491>] dump_stack+0x85/0xc4
|
|
+ [<ffffffff815e2969>] print_trailer+0xf9/0x150
|
|
+ [<ffffffff815e9454>] object_err+0x34/0x40
|
|
+ [<ffffffff815ebe50>] kasan_report_error+0x230/0x550
|
|
+ [<ffffffff819949be>] ? keyring_get_key_chunk+0x13e/0x210
|
|
+ [<ffffffff815ec62d>] __asan_report_load_n_noabort+0x5d/0x70
|
|
+ [<ffffffff81994cc3>] ? keyring_compare_object+0x213/0x240
|
|
+ [<ffffffff81994cc3>] keyring_compare_object+0x213/0x240
|
|
+ [<ffffffff81bc238c>] assoc_array_insert+0x86c/0x3a60
|
|
+ [<ffffffff81bc1b20>] ? assoc_array_cancel_edit+0x70/0x70
|
|
+ [<ffffffff8199797d>] ? __key_link_begin+0x20d/0x270
|
|
+ [<ffffffff8199786c>] __key_link_begin+0xfc/0x270
|
|
+ [<ffffffff81993389>] key_create_or_update+0x459/0xaf0
|
|
+ [<ffffffff8128ce0d>] ? trace_hardirqs_on+0xd/0x10
|
|
+ [<ffffffff81992f30>] ? key_type_lookup+0xc0/0xc0
|
|
+ [<ffffffff8199e19d>] ? lookup_user_key+0x13d/0xcd0
|
|
+ [<ffffffff81534763>] ? memdup_user+0x53/0x80
|
|
+ [<ffffffff819983ea>] SyS_add_key+0x1ba/0x350
|
|
+ [<ffffffff81998230>] ? key_get_type_from_user.constprop.6+0xa0/0xa0
|
|
+ [<ffffffff828bcf4e>] ? retint_user+0x18/0x23
|
|
+ [<ffffffff8128cc7e>] ? trace_hardirqs_on_caller+0x3fe/0x580
|
|
+ [<ffffffff81004017>] ? trace_hardirqs_on_thunk+0x17/0x19
|
|
+ [<ffffffff828bc432>] entry_SYSCALL_64_fastpath+0x12/0x76
|
|
+Memory state around the buggy address:
|
|
+ ffff880060a6f700: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00
|
|
+ ffff880060a6f780: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc
|
|
+>ffff880060a6f800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
+ ^
|
|
+ ffff880060a6f880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
+ ffff880060a6f900: fc fc fc fc fc fc 00 00 00 00 00 00 00 00 00 00
|
|
+==================================================================
|
|
+
|
|
+Change-Id: Iea1f0396558b1856b9855ef2765e331565570e17
|
|
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
|
|
+Signed-off-by: David Howells <dhowells@redhat.com>
|
|
+cc: stable@vger.kernel.org
|
|
+Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
|
|
+---
|
|
+ lib/assoc_array.c | 1750 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
+ 1 file changed, 1750 insertions(+)
|
|
+ create mode 100644 lib/assoc_array.c
|
|
+
|
|
+diff --git a/lib/assoc_array.c b/lib/assoc_array.c
|
|
+new file mode 100644
|
|
+index 000000000000..03a77f4740c1
|
|
+--- /dev/null
|
|
++++ b/lib/assoc_array.c
|
|
+@@ -0,0 +1,1750 @@
|
|
++/* Generic associative array implementation.
|
|
++ *
|
|
++ * See Documentation/assoc_array.txt for information.
|
|
++ *
|
|
++ * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
|
|
++ * Written by David Howells (dhowells@redhat.com)
|
|
++ *
|
|
++ * This program is free software; you can redistribute it and/or
|
|
++ * modify it under the terms of the GNU General Public Licence
|
|
++ * as published by the Free Software Foundation; either version
|
|
++ * 2 of the Licence, or (at your option) any later version.
|
|
++ */
|
|
++//#define DEBUG
|
|
++#include <linux/slab.h>
|
|
++#include <linux/err.h>
|
|
++#include <linux/assoc_array_priv.h>
|
|
++
|
|
++/*
|
|
++ * Iterate over an associative array. The caller must hold the RCU read lock
|
|
++ * or better.
|
|
++ */
|
|
++static int assoc_array_subtree_iterate(const struct assoc_array_ptr *root,
|
|
++ const struct assoc_array_ptr *stop,
|
|
++ int (*iterator)(const void *leaf,
|
|
++ void *iterator_data),
|
|
++ void *iterator_data)
|
|
++{
|
|
++ const struct assoc_array_shortcut *shortcut;
|
|
++ const struct assoc_array_node *node;
|
|
++ const struct assoc_array_ptr *cursor, *ptr, *parent;
|
|
++ unsigned long has_meta;
|
|
++ int slot, ret;
|
|
++
|
|
++ cursor = root;
|
|
++
|
|
++begin_node:
|
|
++ if (assoc_array_ptr_is_shortcut(cursor)) {
|
|
++ /* Descend through a shortcut */
|
|
++ shortcut = assoc_array_ptr_to_shortcut(cursor);
|
|
++ smp_read_barrier_depends();
|
|
++ cursor = ACCESS_ONCE(shortcut->next_node);
|
|
++ }
|
|
++
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ smp_read_barrier_depends();
|
|
++ slot = 0;
|
|
++
|
|
++ /* We perform two passes of each node.
|
|
++ *
|
|
++ * The first pass does all the leaves in this node. This means we
|
|
++ * don't miss any leaves if the node is split up by insertion whilst
|
|
++ * we're iterating over the branches rooted here (we may, however, see
|
|
++ * some leaves twice).
|
|
++ */
|
|
++ has_meta = 0;
|
|
++ for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = ACCESS_ONCE(node->slots[slot]);
|
|
++ has_meta |= (unsigned long)ptr;
|
|
++ if (ptr && assoc_array_ptr_is_leaf(ptr)) {
|
|
++ /* We need a barrier between the read of the pointer
|
|
++ * and dereferencing the pointer - but only if we are
|
|
++ * actually going to dereference it.
|
|
++ */
|
|
++ smp_read_barrier_depends();
|
|
++
|
|
++ /* Invoke the callback */
|
|
++ ret = iterator(assoc_array_ptr_to_leaf(ptr),
|
|
++ iterator_data);
|
|
++ if (ret)
|
|
++ return ret;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ /* The second pass attends to all the metadata pointers. If we follow
|
|
++ * one of these we may find that we don't come back here, but rather go
|
|
++ * back to a replacement node with the leaves in a different layout.
|
|
++ *
|
|
++ * We are guaranteed to make progress, however, as the slot number for
|
|
++ * a particular portion of the key space cannot change - and we
|
|
++ * continue at the back pointer + 1.
|
|
++ */
|
|
++ if (!(has_meta & ASSOC_ARRAY_PTR_META_TYPE))
|
|
++ goto finished_node;
|
|
++ slot = 0;
|
|
++
|
|
++continue_node:
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ smp_read_barrier_depends();
|
|
++
|
|
++ for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = ACCESS_ONCE(node->slots[slot]);
|
|
++ if (assoc_array_ptr_is_meta(ptr)) {
|
|
++ cursor = ptr;
|
|
++ goto begin_node;
|
|
++ }
|
|
++ }
|
|
++
|
|
++finished_node:
|
|
++ /* Move up to the parent (may need to skip back over a shortcut) */
|
|
++ parent = ACCESS_ONCE(node->back_pointer);
|
|
++ slot = node->parent_slot;
|
|
++ if (parent == stop)
|
|
++ return 0;
|
|
++
|
|
++ if (assoc_array_ptr_is_shortcut(parent)) {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(parent);
|
|
++ smp_read_barrier_depends();
|
|
++ cursor = parent;
|
|
++ parent = ACCESS_ONCE(shortcut->back_pointer);
|
|
++ slot = shortcut->parent_slot;
|
|
++ if (parent == stop)
|
|
++ return 0;
|
|
++ }
|
|
++
|
|
++ /* Ascend to next slot in parent node */
|
|
++ cursor = parent;
|
|
++ slot++;
|
|
++ goto continue_node;
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_iterate - Pass all objects in the array to a callback
|
|
++ * @array: The array to iterate over.
|
|
++ * @iterator: The callback function.
|
|
++ * @iterator_data: Private data for the callback function.
|
|
++ *
|
|
++ * Iterate over all the objects in an associative array. Each one will be
|
|
++ * presented to the iterator function.
|
|
++ *
|
|
++ * If the array is being modified concurrently with the iteration then it is
|
|
++ * possible that some objects in the array will be passed to the iterator
|
|
++ * callback more than once - though every object should be passed at least
|
|
++ * once. If this is undesirable then the caller must lock against modification
|
|
++ * for the duration of this function.
|
|
++ *
|
|
++ * The function will return 0 if no objects were in the array or else it will
|
|
++ * return the result of the last iterator function called. Iteration stops
|
|
++ * immediately if any call to the iteration function results in a non-zero
|
|
++ * return.
|
|
++ *
|
|
++ * The caller should hold the RCU read lock or better if concurrent
|
|
++ * modification is possible.
|
|
++ */
|
|
++int assoc_array_iterate(const struct assoc_array *array,
|
|
++ int (*iterator)(const void *object,
|
|
++ void *iterator_data),
|
|
++ void *iterator_data)
|
|
++{
|
|
++ struct assoc_array_ptr *root = ACCESS_ONCE(array->root);
|
|
++
|
|
++ if (!root)
|
|
++ return 0;
|
|
++ return assoc_array_subtree_iterate(root, NULL, iterator, iterator_data);
|
|
++}
|
|
++
|
|
++enum assoc_array_walk_status {
|
|
++ assoc_array_walk_tree_empty,
|
|
++ assoc_array_walk_found_terminal_node,
|
|
++ assoc_array_walk_found_wrong_shortcut,
|
|
++};
|
|
++
|
|
++struct assoc_array_walk_result {
|
|
++ struct {
|
|
++ struct assoc_array_node *node; /* Node in which leaf might be found */
|
|
++ int level;
|
|
++ int slot;
|
|
++ } terminal_node;
|
|
++ struct {
|
|
++ struct assoc_array_shortcut *shortcut;
|
|
++ int level;
|
|
++ int sc_level;
|
|
++ unsigned long sc_segments;
|
|
++ unsigned long dissimilarity;
|
|
++ } wrong_shortcut;
|
|
++};
|
|
++
|
|
++/*
|
|
++ * Navigate through the internal tree looking for the closest node to the key.
|
|
++ */
|
|
++static enum assoc_array_walk_status
|
|
++assoc_array_walk(const struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ const void *index_key,
|
|
++ struct assoc_array_walk_result *result)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut;
|
|
++ struct assoc_array_node *node;
|
|
++ struct assoc_array_ptr *cursor, *ptr;
|
|
++ unsigned long sc_segments, dissimilarity;
|
|
++ unsigned long segments;
|
|
++ int level, sc_level, next_sc_level;
|
|
++ int slot;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ cursor = ACCESS_ONCE(array->root);
|
|
++ if (!cursor)
|
|
++ return assoc_array_walk_tree_empty;
|
|
++
|
|
++ level = 0;
|
|
++
|
|
++ /* Use segments from the key for the new leaf to navigate through the
|
|
++ * internal tree, skipping through nodes and shortcuts that are on
|
|
++ * route to the destination. Eventually we'll come to a slot that is
|
|
++ * either empty or contains a leaf at which point we've found a node in
|
|
++ * which the leaf we're looking for might be found or into which it
|
|
++ * should be inserted.
|
|
++ */
|
|
++jumped:
|
|
++ segments = ops->get_key_chunk(index_key, level);
|
|
++ pr_devel("segments[%d]: %lx\n", level, segments);
|
|
++
|
|
++ if (assoc_array_ptr_is_shortcut(cursor))
|
|
++ goto follow_shortcut;
|
|
++
|
|
++consider_node:
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ smp_read_barrier_depends();
|
|
++
|
|
++ slot = segments >> (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
|
|
++ slot &= ASSOC_ARRAY_FAN_MASK;
|
|
++ ptr = ACCESS_ONCE(node->slots[slot]);
|
|
++
|
|
++ pr_devel("consider slot %x [ix=%d type=%lu]\n",
|
|
++ slot, level, (unsigned long)ptr & 3);
|
|
++
|
|
++ if (!assoc_array_ptr_is_meta(ptr)) {
|
|
++ /* The node doesn't have a node/shortcut pointer in the slot
|
|
++ * corresponding to the index key that we have to follow.
|
|
++ */
|
|
++ result->terminal_node.node = node;
|
|
++ result->terminal_node.level = level;
|
|
++ result->terminal_node.slot = slot;
|
|
++ pr_devel("<--%s() = terminal_node\n", __func__);
|
|
++ return assoc_array_walk_found_terminal_node;
|
|
++ }
|
|
++
|
|
++ if (assoc_array_ptr_is_node(ptr)) {
|
|
++ /* There is a pointer to a node in the slot corresponding to
|
|
++ * this index key segment, so we need to follow it.
|
|
++ */
|
|
++ cursor = ptr;
|
|
++ level += ASSOC_ARRAY_LEVEL_STEP;
|
|
++ if ((level & ASSOC_ARRAY_KEY_CHUNK_MASK) != 0)
|
|
++ goto consider_node;
|
|
++ goto jumped;
|
|
++ }
|
|
++
|
|
++ /* There is a shortcut in the slot corresponding to the index key
|
|
++ * segment. We follow the shortcut if its partial index key matches
|
|
++ * this leaf's. Otherwise we need to split the shortcut.
|
|
++ */
|
|
++ cursor = ptr;
|
|
++follow_shortcut:
|
|
++ shortcut = assoc_array_ptr_to_shortcut(cursor);
|
|
++ smp_read_barrier_depends();
|
|
++ pr_devel("shortcut to %d\n", shortcut->skip_to_level);
|
|
++ sc_level = level + ASSOC_ARRAY_LEVEL_STEP;
|
|
++ BUG_ON(sc_level > shortcut->skip_to_level);
|
|
++
|
|
++ do {
|
|
++ /* Check the leaf against the shortcut's index key a word at a
|
|
++ * time, trimming the final word (the shortcut stores the index
|
|
++ * key completely from the root to the shortcut's target).
|
|
++ */
|
|
++ if ((sc_level & ASSOC_ARRAY_KEY_CHUNK_MASK) == 0)
|
|
++ segments = ops->get_key_chunk(index_key, sc_level);
|
|
++
|
|
++ sc_segments = shortcut->index_key[sc_level >> ASSOC_ARRAY_KEY_CHUNK_SHIFT];
|
|
++ dissimilarity = segments ^ sc_segments;
|
|
++
|
|
++ if (round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > shortcut->skip_to_level) {
|
|
++ /* Trim segments that are beyond the shortcut */
|
|
++ int shift = shortcut->skip_to_level & ASSOC_ARRAY_KEY_CHUNK_MASK;
|
|
++ dissimilarity &= ~(ULONG_MAX << shift);
|
|
++ next_sc_level = shortcut->skip_to_level;
|
|
++ } else {
|
|
++ next_sc_level = sc_level + ASSOC_ARRAY_KEY_CHUNK_SIZE;
|
|
++ next_sc_level = round_down(next_sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++ }
|
|
++
|
|
++ if (dissimilarity != 0) {
|
|
++ /* This shortcut points elsewhere */
|
|
++ result->wrong_shortcut.shortcut = shortcut;
|
|
++ result->wrong_shortcut.level = level;
|
|
++ result->wrong_shortcut.sc_level = sc_level;
|
|
++ result->wrong_shortcut.sc_segments = sc_segments;
|
|
++ result->wrong_shortcut.dissimilarity = dissimilarity;
|
|
++ return assoc_array_walk_found_wrong_shortcut;
|
|
++ }
|
|
++
|
|
++ sc_level = next_sc_level;
|
|
++ } while (sc_level < shortcut->skip_to_level);
|
|
++
|
|
++ /* The shortcut matches the leaf's index to this point. */
|
|
++ cursor = ACCESS_ONCE(shortcut->next_node);
|
|
++ if (((level ^ sc_level) & ~ASSOC_ARRAY_KEY_CHUNK_MASK) != 0) {
|
|
++ level = sc_level;
|
|
++ goto jumped;
|
|
++ } else {
|
|
++ level = sc_level;
|
|
++ goto consider_node;
|
|
++ }
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_find - Find an object by index key
|
|
++ * @array: The associative array to search.
|
|
++ * @ops: The operations to use.
|
|
++ * @index_key: The key to the object.
|
|
++ *
|
|
++ * Find an object in an associative array by walking through the internal tree
|
|
++ * to the node that should contain the object and then searching the leaves
|
|
++ * there. NULL is returned if the requested object was not found in the array.
|
|
++ *
|
|
++ * The caller must hold the RCU read lock or better.
|
|
++ */
|
|
++void *assoc_array_find(const struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ const void *index_key)
|
|
++{
|
|
++ struct assoc_array_walk_result result;
|
|
++ const struct assoc_array_node *node;
|
|
++ const struct assoc_array_ptr *ptr;
|
|
++ const void *leaf;
|
|
++ int slot;
|
|
++
|
|
++ if (assoc_array_walk(array, ops, index_key, &result) !=
|
|
++ assoc_array_walk_found_terminal_node)
|
|
++ return NULL;
|
|
++
|
|
++ node = result.terminal_node.node;
|
|
++ smp_read_barrier_depends();
|
|
++
|
|
++ /* If the target key is available to us, it's has to be pointed to by
|
|
++ * the terminal node.
|
|
++ */
|
|
++ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = ACCESS_ONCE(node->slots[slot]);
|
|
++ if (ptr && assoc_array_ptr_is_leaf(ptr)) {
|
|
++ /* We need a barrier between the read of the pointer
|
|
++ * and dereferencing the pointer - but only if we are
|
|
++ * actually going to dereference it.
|
|
++ */
|
|
++ leaf = assoc_array_ptr_to_leaf(ptr);
|
|
++ smp_read_barrier_depends();
|
|
++ if (ops->compare_object(leaf, index_key))
|
|
++ return (void *)leaf;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ return NULL;
|
|
++}
|
|
++
|
|
++/*
|
|
++ * Destructively iterate over an associative array. The caller must prevent
|
|
++ * other simultaneous accesses.
|
|
++ */
|
|
++static void assoc_array_destroy_subtree(struct assoc_array_ptr *root,
|
|
++ const struct assoc_array_ops *ops)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut;
|
|
++ struct assoc_array_node *node;
|
|
++ struct assoc_array_ptr *cursor, *parent = NULL;
|
|
++ int slot = -1;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ cursor = root;
|
|
++ if (!cursor) {
|
|
++ pr_devel("empty\n");
|
|
++ return;
|
|
++ }
|
|
++
|
|
++move_to_meta:
|
|
++ if (assoc_array_ptr_is_shortcut(cursor)) {
|
|
++ /* Descend through a shortcut */
|
|
++ pr_devel("[%d] shortcut\n", slot);
|
|
++ BUG_ON(!assoc_array_ptr_is_shortcut(cursor));
|
|
++ shortcut = assoc_array_ptr_to_shortcut(cursor);
|
|
++ BUG_ON(shortcut->back_pointer != parent);
|
|
++ BUG_ON(slot != -1 && shortcut->parent_slot != slot);
|
|
++ parent = cursor;
|
|
++ cursor = shortcut->next_node;
|
|
++ slot = -1;
|
|
++ BUG_ON(!assoc_array_ptr_is_node(cursor));
|
|
++ }
|
|
++
|
|
++ pr_devel("[%d] node\n", slot);
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ BUG_ON(node->back_pointer != parent);
|
|
++ BUG_ON(slot != -1 && node->parent_slot != slot);
|
|
++ slot = 0;
|
|
++
|
|
++continue_node:
|
|
++ pr_devel("Node %p [back=%p]\n", node, node->back_pointer);
|
|
++ for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ struct assoc_array_ptr *ptr = node->slots[slot];
|
|
++ if (!ptr)
|
|
++ continue;
|
|
++ if (assoc_array_ptr_is_meta(ptr)) {
|
|
++ parent = cursor;
|
|
++ cursor = ptr;
|
|
++ goto move_to_meta;
|
|
++ }
|
|
++
|
|
++ if (ops) {
|
|
++ pr_devel("[%d] free leaf\n", slot);
|
|
++ ops->free_object(assoc_array_ptr_to_leaf(ptr));
|
|
++ }
|
|
++ }
|
|
++
|
|
++ parent = node->back_pointer;
|
|
++ slot = node->parent_slot;
|
|
++ pr_devel("free node\n");
|
|
++ kfree(node);
|
|
++ if (!parent)
|
|
++ return; /* Done */
|
|
++
|
|
++ /* Move back up to the parent (may need to free a shortcut on
|
|
++ * the way up) */
|
|
++ if (assoc_array_ptr_is_shortcut(parent)) {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(parent);
|
|
++ BUG_ON(shortcut->next_node != cursor);
|
|
++ cursor = parent;
|
|
++ parent = shortcut->back_pointer;
|
|
++ slot = shortcut->parent_slot;
|
|
++ pr_devel("free shortcut\n");
|
|
++ kfree(shortcut);
|
|
++ if (!parent)
|
|
++ return;
|
|
++
|
|
++ BUG_ON(!assoc_array_ptr_is_node(parent));
|
|
++ }
|
|
++
|
|
++ /* Ascend to next slot in parent node */
|
|
++ pr_devel("ascend to %p[%d]\n", parent, slot);
|
|
++ cursor = parent;
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ slot++;
|
|
++ goto continue_node;
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_destroy - Destroy an associative array
|
|
++ * @array: The array to destroy.
|
|
++ * @ops: The operations to use.
|
|
++ *
|
|
++ * Discard all metadata and free all objects in an associative array. The
|
|
++ * array will be empty and ready to use again upon completion. This function
|
|
++ * cannot fail.
|
|
++ *
|
|
++ * The caller must prevent all other accesses whilst this takes place as no
|
|
++ * attempt is made to adjust pointers gracefully to permit RCU readlock-holding
|
|
++ * accesses to continue. On the other hand, no memory allocation is required.
|
|
++ */
|
|
++void assoc_array_destroy(struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops)
|
|
++{
|
|
++ assoc_array_destroy_subtree(array->root, ops);
|
|
++ array->root = NULL;
|
|
++}
|
|
++
|
|
++/*
|
|
++ * Handle insertion into an empty tree.
|
|
++ */
|
|
++static bool assoc_array_insert_in_empty_tree(struct assoc_array_edit *edit)
|
|
++{
|
|
++ struct assoc_array_node *new_n0;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n0)
|
|
++ return false;
|
|
++
|
|
++ edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
|
|
++ edit->leaf_p = &new_n0->slots[0];
|
|
++ edit->adjust_count_on = new_n0;
|
|
++ edit->set[0].ptr = &edit->array->root;
|
|
++ edit->set[0].to = assoc_array_node_to_ptr(new_n0);
|
|
++
|
|
++ pr_devel("<--%s() = ok [no root]\n", __func__);
|
|
++ return true;
|
|
++}
|
|
++
|
|
++/*
|
|
++ * Handle insertion into a terminal node.
|
|
++ */
|
|
++static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ const void *index_key,
|
|
++ struct assoc_array_walk_result *result)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut, *new_s0;
|
|
++ struct assoc_array_node *node, *new_n0, *new_n1, *side;
|
|
++ struct assoc_array_ptr *ptr;
|
|
++ unsigned long dissimilarity, base_seg, blank;
|
|
++ size_t keylen;
|
|
++ bool have_meta;
|
|
++ int level, diff;
|
|
++ int slot, next_slot, free_slot, i, j;
|
|
++
|
|
++ node = result->terminal_node.node;
|
|
++ level = result->terminal_node.level;
|
|
++ edit->segment_cache[ASSOC_ARRAY_FAN_OUT] = result->terminal_node.slot;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ /* We arrived at a node which doesn't have an onward node or shortcut
|
|
++ * pointer that we have to follow. This means that (a) the leaf we
|
|
++ * want must go here (either by insertion or replacement) or (b) we
|
|
++ * need to split this node and insert in one of the fragments.
|
|
++ */
|
|
++ free_slot = -1;
|
|
++
|
|
++ /* Firstly, we have to check the leaves in this node to see if there's
|
|
++ * a matching one we should replace in place.
|
|
++ */
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ ptr = node->slots[i];
|
|
++ if (!ptr) {
|
|
++ free_slot = i;
|
|
++ continue;
|
|
++ }
|
|
++ if (assoc_array_ptr_is_leaf(ptr) &&
|
|
++ ops->compare_object(assoc_array_ptr_to_leaf(ptr),
|
|
++ index_key)) {
|
|
++ pr_devel("replace in slot %d\n", i);
|
|
++ edit->leaf_p = &node->slots[i];
|
|
++ edit->dead_leaf = node->slots[i];
|
|
++ pr_devel("<--%s() = ok [replace]\n", __func__);
|
|
++ return true;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ /* If there is a free slot in this node then we can just insert the
|
|
++ * leaf here.
|
|
++ */
|
|
++ if (free_slot >= 0) {
|
|
++ pr_devel("insert in free slot %d\n", free_slot);
|
|
++ edit->leaf_p = &node->slots[free_slot];
|
|
++ edit->adjust_count_on = node;
|
|
++ pr_devel("<--%s() = ok [insert]\n", __func__);
|
|
++ return true;
|
|
++ }
|
|
++
|
|
++ /* The node has no spare slots - so we're either going to have to split
|
|
++ * it or insert another node before it.
|
|
++ *
|
|
++ * Whatever, we're going to need at least two new nodes - so allocate
|
|
++ * those now. We may also need a new shortcut, but we deal with that
|
|
++ * when we need it.
|
|
++ */
|
|
++ new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n0)
|
|
++ return false;
|
|
++ edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n1 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n1)
|
|
++ return false;
|
|
++ edit->new_meta[1] = assoc_array_node_to_ptr(new_n1);
|
|
++
|
|
++ /* We need to find out how similar the leaves are. */
|
|
++ pr_devel("no spare slots\n");
|
|
++ have_meta = false;
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ ptr = node->slots[i];
|
|
++ if (assoc_array_ptr_is_meta(ptr)) {
|
|
++ edit->segment_cache[i] = 0xff;
|
|
++ have_meta = true;
|
|
++ continue;
|
|
++ }
|
|
++ base_seg = ops->get_object_key_chunk(
|
|
++ assoc_array_ptr_to_leaf(ptr), level);
|
|
++ base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
|
|
++ edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
|
|
++ }
|
|
++
|
|
++ if (have_meta) {
|
|
++ pr_devel("have meta\n");
|
|
++ goto split_node;
|
|
++ }
|
|
++
|
|
++ /* The node contains only leaves */
|
|
++ dissimilarity = 0;
|
|
++ base_seg = edit->segment_cache[0];
|
|
++ for (i = 1; i < ASSOC_ARRAY_FAN_OUT; i++)
|
|
++ dissimilarity |= edit->segment_cache[i] ^ base_seg;
|
|
++
|
|
++ pr_devel("only leaves; dissimilarity=%lx\n", dissimilarity);
|
|
++
|
|
++ if ((dissimilarity & ASSOC_ARRAY_FAN_MASK) == 0) {
|
|
++ /* The old leaves all cluster in the same slot. We will need
|
|
++ * to insert a shortcut if the new node wants to cluster with them.
|
|
++ */
|
|
++ if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0)
|
|
++ goto all_leaves_cluster_together;
|
|
++
|
|
++ /* Otherwise we can just insert a new node ahead of the old
|
|
++ * one.
|
|
++ */
|
|
++ goto present_leaves_cluster_but_not_new_leaf;
|
|
++ }
|
|
++
|
|
++split_node:
|
|
++ pr_devel("split node\n");
|
|
++
|
|
++ /* We need to split the current node; we know that the node doesn't
|
|
++ * simply contain a full set of leaves that cluster together (it
|
|
++ * contains meta pointers and/or non-clustering leaves).
|
|
++ *
|
|
++ * We need to expel at least two leaves out of a set consisting of the
|
|
++ * leaves in the node and the new leaf.
|
|
++ *
|
|
++ * We need a new node (n0) to replace the current one and a new node to
|
|
++ * take the expelled nodes (n1).
|
|
++ */
|
|
++ edit->set[0].to = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n0->back_pointer = node->back_pointer;
|
|
++ new_n0->parent_slot = node->parent_slot;
|
|
++ new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n1->parent_slot = -1; /* Need to calculate this */
|
|
++
|
|
++do_split_node:
|
|
++ pr_devel("do_split_node\n");
|
|
++
|
|
++ new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
|
|
++ new_n1->nr_leaves_on_branch = 0;
|
|
++
|
|
++ /* Begin by finding two matching leaves. There have to be at least two
|
|
++ * that match - even if there are meta pointers - because any leaf that
|
|
++ * would match a slot with a meta pointer in it must be somewhere
|
|
++ * behind that meta pointer and cannot be here. Further, given N
|
|
++ * remaining leaf slots, we now have N+1 leaves to go in them.
|
|
++ */
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ slot = edit->segment_cache[i];
|
|
++ if (slot != 0xff)
|
|
++ for (j = i + 1; j < ASSOC_ARRAY_FAN_OUT + 1; j++)
|
|
++ if (edit->segment_cache[j] == slot)
|
|
++ goto found_slot_for_multiple_occupancy;
|
|
++ }
|
|
++found_slot_for_multiple_occupancy:
|
|
++ pr_devel("same slot: %x %x [%02x]\n", i, j, slot);
|
|
++ BUG_ON(i >= ASSOC_ARRAY_FAN_OUT);
|
|
++ BUG_ON(j >= ASSOC_ARRAY_FAN_OUT + 1);
|
|
++ BUG_ON(slot >= ASSOC_ARRAY_FAN_OUT);
|
|
++
|
|
++ new_n1->parent_slot = slot;
|
|
++
|
|
++ /* Metadata pointers cannot change slot */
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++)
|
|
++ if (assoc_array_ptr_is_meta(node->slots[i]))
|
|
++ new_n0->slots[i] = node->slots[i];
|
|
++ else
|
|
++ new_n0->slots[i] = NULL;
|
|
++ BUG_ON(new_n0->slots[slot] != NULL);
|
|
++ new_n0->slots[slot] = assoc_array_node_to_ptr(new_n1);
|
|
++
|
|
++ /* Filter the leaf pointers between the new nodes */
|
|
++ free_slot = -1;
|
|
++ next_slot = 0;
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ if (assoc_array_ptr_is_meta(node->slots[i]))
|
|
++ continue;
|
|
++ if (edit->segment_cache[i] == slot) {
|
|
++ new_n1->slots[next_slot++] = node->slots[i];
|
|
++ new_n1->nr_leaves_on_branch++;
|
|
++ } else {
|
|
++ do {
|
|
++ free_slot++;
|
|
++ } while (new_n0->slots[free_slot] != NULL);
|
|
++ new_n0->slots[free_slot] = node->slots[i];
|
|
++ }
|
|
++ }
|
|
++
|
|
++ pr_devel("filtered: f=%x n=%x\n", free_slot, next_slot);
|
|
++
|
|
++ if (edit->segment_cache[ASSOC_ARRAY_FAN_OUT] != slot) {
|
|
++ do {
|
|
++ free_slot++;
|
|
++ } while (new_n0->slots[free_slot] != NULL);
|
|
++ edit->leaf_p = &new_n0->slots[free_slot];
|
|
++ edit->adjust_count_on = new_n0;
|
|
++ } else {
|
|
++ edit->leaf_p = &new_n1->slots[next_slot++];
|
|
++ edit->adjust_count_on = new_n1;
|
|
++ }
|
|
++
|
|
++ BUG_ON(next_slot <= 1);
|
|
++
|
|
++ edit->set_backpointers_to = assoc_array_node_to_ptr(new_n0);
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ if (edit->segment_cache[i] == 0xff) {
|
|
++ ptr = node->slots[i];
|
|
++ BUG_ON(assoc_array_ptr_is_leaf(ptr));
|
|
++ if (assoc_array_ptr_is_node(ptr)) {
|
|
++ side = assoc_array_ptr_to_node(ptr);
|
|
++ edit->set_backpointers[i] = &side->back_pointer;
|
|
++ } else {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(ptr);
|
|
++ edit->set_backpointers[i] = &shortcut->back_pointer;
|
|
++ }
|
|
++ }
|
|
++ }
|
|
++
|
|
++ ptr = node->back_pointer;
|
|
++ if (!ptr)
|
|
++ edit->set[0].ptr = &edit->array->root;
|
|
++ else if (assoc_array_ptr_is_node(ptr))
|
|
++ edit->set[0].ptr = &assoc_array_ptr_to_node(ptr)->slots[node->parent_slot];
|
|
++ else
|
|
++ edit->set[0].ptr = &assoc_array_ptr_to_shortcut(ptr)->next_node;
|
|
++ edit->excised_meta[0] = assoc_array_node_to_ptr(node);
|
|
++ pr_devel("<--%s() = ok [split node]\n", __func__);
|
|
++ return true;
|
|
++
|
|
++present_leaves_cluster_but_not_new_leaf:
|
|
++ /* All the old leaves cluster in the same slot, but the new leaf wants
|
|
++ * to go into a different slot, so we create a new node to hold the new
|
|
++ * leaf and a pointer to a new node holding all the old leaves.
|
|
++ */
|
|
++ pr_devel("present leaves cluster but not new leaf\n");
|
|
++
|
|
++ new_n0->back_pointer = node->back_pointer;
|
|
++ new_n0->parent_slot = node->parent_slot;
|
|
++ new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
|
|
++ new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n1->parent_slot = edit->segment_cache[0];
|
|
++ new_n1->nr_leaves_on_branch = node->nr_leaves_on_branch;
|
|
++ edit->adjust_count_on = new_n0;
|
|
++
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++)
|
|
++ new_n1->slots[i] = node->slots[i];
|
|
++
|
|
++ new_n0->slots[edit->segment_cache[0]] = assoc_array_node_to_ptr(new_n0);
|
|
++ edit->leaf_p = &new_n0->slots[edit->segment_cache[ASSOC_ARRAY_FAN_OUT]];
|
|
++
|
|
++ edit->set[0].ptr = &assoc_array_ptr_to_node(node->back_pointer)->slots[node->parent_slot];
|
|
++ edit->set[0].to = assoc_array_node_to_ptr(new_n0);
|
|
++ edit->excised_meta[0] = assoc_array_node_to_ptr(node);
|
|
++ pr_devel("<--%s() = ok [insert node before]\n", __func__);
|
|
++ return true;
|
|
++
|
|
++all_leaves_cluster_together:
|
|
++ /* All the leaves, new and old, want to cluster together in this node
|
|
++ * in the same slot, so we have to replace this node with a shortcut to
|
|
++ * skip over the identical parts of the key and then place a pair of
|
|
++ * nodes, one inside the other, at the end of the shortcut and
|
|
++ * distribute the keys between them.
|
|
++ *
|
|
++ * Firstly we need to work out where the leaves start diverging as a
|
|
++ * bit position into their keys so that we know how big the shortcut
|
|
++ * needs to be.
|
|
++ *
|
|
++ * We only need to make a single pass of N of the N+1 leaves because if
|
|
++ * any keys differ between themselves at bit X then at least one of
|
|
++ * them must also differ with the base key at bit X or before.
|
|
++ */
|
|
++ pr_devel("all leaves cluster together\n");
|
|
++ diff = INT_MAX;
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ int x = ops->diff_objects(assoc_array_ptr_to_leaf(node->slots[i]),
|
|
++ index_key);
|
|
++ if (x < diff) {
|
|
++ BUG_ON(x < 0);
|
|
++ diff = x;
|
|
++ }
|
|
++ }
|
|
++ BUG_ON(diff == INT_MAX);
|
|
++ BUG_ON(diff < level + ASSOC_ARRAY_LEVEL_STEP);
|
|
++
|
|
++ keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++ keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
|
|
++
|
|
++ new_s0 = kzalloc(sizeof(struct assoc_array_shortcut) +
|
|
++ keylen * sizeof(unsigned long), GFP_KERNEL);
|
|
++ if (!new_s0)
|
|
++ return false;
|
|
++ edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s0);
|
|
++
|
|
++ edit->set[0].to = assoc_array_shortcut_to_ptr(new_s0);
|
|
++ new_s0->back_pointer = node->back_pointer;
|
|
++ new_s0->parent_slot = node->parent_slot;
|
|
++ new_s0->next_node = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n0->back_pointer = assoc_array_shortcut_to_ptr(new_s0);
|
|
++ new_n0->parent_slot = 0;
|
|
++ new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n1->parent_slot = -1; /* Need to calculate this */
|
|
++
|
|
++ new_s0->skip_to_level = level = diff & ~ASSOC_ARRAY_LEVEL_STEP_MASK;
|
|
++ pr_devel("skip_to_level = %d [diff %d]\n", level, diff);
|
|
++ BUG_ON(level <= 0);
|
|
++
|
|
++ for (i = 0; i < keylen; i++)
|
|
++ new_s0->index_key[i] =
|
|
++ ops->get_key_chunk(index_key, i * ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++
|
|
++ blank = ULONG_MAX << (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
|
|
++ pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, level, blank);
|
|
++ new_s0->index_key[keylen - 1] &= ~blank;
|
|
++
|
|
++ /* This now reduces to a node splitting exercise for which we'll need
|
|
++ * to regenerate the disparity table.
|
|
++ */
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ ptr = node->slots[i];
|
|
++ base_seg = ops->get_object_key_chunk(assoc_array_ptr_to_leaf(ptr),
|
|
++ level);
|
|
++ base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
|
|
++ edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
|
|
++ }
|
|
++
|
|
++ base_seg = ops->get_key_chunk(index_key, level);
|
|
++ base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
|
|
++ edit->segment_cache[ASSOC_ARRAY_FAN_OUT] = base_seg & ASSOC_ARRAY_FAN_MASK;
|
|
++ goto do_split_node;
|
|
++}
|
|
++
|
|
++/*
|
|
++ * Handle insertion into the middle of a shortcut.
|
|
++ */
|
|
++static bool assoc_array_insert_mid_shortcut(struct assoc_array_edit *edit,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ struct assoc_array_walk_result *result)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut, *new_s0, *new_s1;
|
|
++ struct assoc_array_node *node, *new_n0, *side;
|
|
++ unsigned long sc_segments, dissimilarity, blank;
|
|
++ size_t keylen;
|
|
++ int level, sc_level, diff;
|
|
++ int sc_slot;
|
|
++
|
|
++ shortcut = result->wrong_shortcut.shortcut;
|
|
++ level = result->wrong_shortcut.level;
|
|
++ sc_level = result->wrong_shortcut.sc_level;
|
|
++ sc_segments = result->wrong_shortcut.sc_segments;
|
|
++ dissimilarity = result->wrong_shortcut.dissimilarity;
|
|
++
|
|
++ pr_devel("-->%s(ix=%d dis=%lx scix=%d)\n",
|
|
++ __func__, level, dissimilarity, sc_level);
|
|
++
|
|
++ /* We need to split a shortcut and insert a node between the two
|
|
++ * pieces. Zero-length pieces will be dispensed with entirely.
|
|
++ *
|
|
++ * First of all, we need to find out in which level the first
|
|
++ * difference was.
|
|
++ */
|
|
++ diff = __ffs(dissimilarity);
|
|
++ diff &= ~ASSOC_ARRAY_LEVEL_STEP_MASK;
|
|
++ diff += sc_level & ~ASSOC_ARRAY_KEY_CHUNK_MASK;
|
|
++ pr_devel("diff=%d\n", diff);
|
|
++
|
|
++ if (!shortcut->back_pointer) {
|
|
++ edit->set[0].ptr = &edit->array->root;
|
|
++ } else if (assoc_array_ptr_is_node(shortcut->back_pointer)) {
|
|
++ node = assoc_array_ptr_to_node(shortcut->back_pointer);
|
|
++ edit->set[0].ptr = &node->slots[shortcut->parent_slot];
|
|
++ } else {
|
|
++ BUG();
|
|
++ }
|
|
++
|
|
++ edit->excised_meta[0] = assoc_array_shortcut_to_ptr(shortcut);
|
|
++
|
|
++ /* Create a new node now since we're going to need it anyway */
|
|
++ new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n0)
|
|
++ return false;
|
|
++ edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
|
|
++ edit->adjust_count_on = new_n0;
|
|
++
|
|
++ /* Insert a new shortcut before the new node if this segment isn't of
|
|
++ * zero length - otherwise we just connect the new node directly to the
|
|
++ * parent.
|
|
++ */
|
|
++ level += ASSOC_ARRAY_LEVEL_STEP;
|
|
++ if (diff > level) {
|
|
++ pr_devel("pre-shortcut %d...%d\n", level, diff);
|
|
++ keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++ keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
|
|
++
|
|
++ new_s0 = kzalloc(sizeof(struct assoc_array_shortcut) +
|
|
++ keylen * sizeof(unsigned long), GFP_KERNEL);
|
|
++ if (!new_s0)
|
|
++ return false;
|
|
++ edit->new_meta[1] = assoc_array_shortcut_to_ptr(new_s0);
|
|
++ edit->set[0].to = assoc_array_shortcut_to_ptr(new_s0);
|
|
++ new_s0->back_pointer = shortcut->back_pointer;
|
|
++ new_s0->parent_slot = shortcut->parent_slot;
|
|
++ new_s0->next_node = assoc_array_node_to_ptr(new_n0);
|
|
++ new_s0->skip_to_level = diff;
|
|
++
|
|
++ new_n0->back_pointer = assoc_array_shortcut_to_ptr(new_s0);
|
|
++ new_n0->parent_slot = 0;
|
|
++
|
|
++ memcpy(new_s0->index_key, shortcut->index_key,
|
|
++ keylen * sizeof(unsigned long));
|
|
++
|
|
++ blank = ULONG_MAX << (diff & ASSOC_ARRAY_KEY_CHUNK_MASK);
|
|
++ pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, diff, blank);
|
|
++ new_s0->index_key[keylen - 1] &= ~blank;
|
|
++ } else {
|
|
++ pr_devel("no pre-shortcut\n");
|
|
++ edit->set[0].to = assoc_array_node_to_ptr(new_n0);
|
|
++ new_n0->back_pointer = shortcut->back_pointer;
|
|
++ new_n0->parent_slot = shortcut->parent_slot;
|
|
++ }
|
|
++
|
|
++ side = assoc_array_ptr_to_node(shortcut->next_node);
|
|
++ new_n0->nr_leaves_on_branch = side->nr_leaves_on_branch;
|
|
++
|
|
++ /* We need to know which slot in the new node is going to take a
|
|
++ * metadata pointer.
|
|
++ */
|
|
++ sc_slot = sc_segments >> (diff & ASSOC_ARRAY_KEY_CHUNK_MASK);
|
|
++ sc_slot &= ASSOC_ARRAY_FAN_MASK;
|
|
++
|
|
++ pr_devel("new slot %lx >> %d -> %d\n",
|
|
++ sc_segments, diff & ASSOC_ARRAY_KEY_CHUNK_MASK, sc_slot);
|
|
++
|
|
++ /* Determine whether we need to follow the new node with a replacement
|
|
++ * for the current shortcut. We could in theory reuse the current
|
|
++ * shortcut if its parent slot number doesn't change - but that's a
|
|
++ * 1-in-16 chance so not worth expending the code upon.
|
|
++ */
|
|
++ level = diff + ASSOC_ARRAY_LEVEL_STEP;
|
|
++ if (level < shortcut->skip_to_level) {
|
|
++ pr_devel("post-shortcut %d...%d\n", level, shortcut->skip_to_level);
|
|
++ keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++ keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
|
|
++
|
|
++ new_s1 = kzalloc(sizeof(struct assoc_array_shortcut) +
|
|
++ keylen * sizeof(unsigned long), GFP_KERNEL);
|
|
++ if (!new_s1)
|
|
++ return false;
|
|
++ edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s1);
|
|
++
|
|
++ new_s1->back_pointer = assoc_array_node_to_ptr(new_n0);
|
|
++ new_s1->parent_slot = sc_slot;
|
|
++ new_s1->next_node = shortcut->next_node;
|
|
++ new_s1->skip_to_level = shortcut->skip_to_level;
|
|
++
|
|
++ new_n0->slots[sc_slot] = assoc_array_shortcut_to_ptr(new_s1);
|
|
++
|
|
++ memcpy(new_s1->index_key, shortcut->index_key,
|
|
++ keylen * sizeof(unsigned long));
|
|
++
|
|
++ edit->set[1].ptr = &side->back_pointer;
|
|
++ edit->set[1].to = assoc_array_shortcut_to_ptr(new_s1);
|
|
++ } else {
|
|
++ pr_devel("no post-shortcut\n");
|
|
++
|
|
++ /* We don't have to replace the pointed-to node as long as we
|
|
++ * use memory barriers to make sure the parent slot number is
|
|
++ * changed before the back pointer (the parent slot number is
|
|
++ * irrelevant to the old parent shortcut).
|
|
++ */
|
|
++ new_n0->slots[sc_slot] = shortcut->next_node;
|
|
++ edit->set_parent_slot[0].p = &side->parent_slot;
|
|
++ edit->set_parent_slot[0].to = sc_slot;
|
|
++ edit->set[1].ptr = &side->back_pointer;
|
|
++ edit->set[1].to = assoc_array_node_to_ptr(new_n0);
|
|
++ }
|
|
++
|
|
++ /* Install the new leaf in a spare slot in the new node. */
|
|
++ if (sc_slot == 0)
|
|
++ edit->leaf_p = &new_n0->slots[1];
|
|
++ else
|
|
++ edit->leaf_p = &new_n0->slots[0];
|
|
++
|
|
++ pr_devel("<--%s() = ok [split shortcut]\n", __func__);
|
|
++ return edit;
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_insert - Script insertion of an object into an associative array
|
|
++ * @array: The array to insert into.
|
|
++ * @ops: The operations to use.
|
|
++ * @index_key: The key to insert at.
|
|
++ * @object: The object to insert.
|
|
++ *
|
|
++ * Precalculate and preallocate a script for the insertion or replacement of an
|
|
++ * object in an associative array. This results in an edit script that can
|
|
++ * either be applied or cancelled.
|
|
++ *
|
|
++ * The function returns a pointer to an edit script or -ENOMEM.
|
|
++ *
|
|
++ * The caller should lock against other modifications and must continue to hold
|
|
++ * the lock until assoc_array_apply_edit() has been called.
|
|
++ *
|
|
++ * Accesses to the tree may take place concurrently with this function,
|
|
++ * provided they hold the RCU read lock.
|
|
++ */
|
|
++struct assoc_array_edit *assoc_array_insert(struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ const void *index_key,
|
|
++ void *object)
|
|
++{
|
|
++ struct assoc_array_walk_result result;
|
|
++ struct assoc_array_edit *edit;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ /* The leaf pointer we're given must not have the bottom bit set as we
|
|
++ * use those for type-marking the pointer. NULL pointers are also not
|
|
++ * allowed as they indicate an empty slot but we have to allow them
|
|
++ * here as they can be updated later.
|
|
++ */
|
|
++ BUG_ON(assoc_array_ptr_is_meta(object));
|
|
++
|
|
++ edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
|
|
++ if (!edit)
|
|
++ return ERR_PTR(-ENOMEM);
|
|
++ edit->array = array;
|
|
++ edit->ops = ops;
|
|
++ edit->leaf = assoc_array_leaf_to_ptr(object);
|
|
++ edit->adjust_count_by = 1;
|
|
++
|
|
++ switch (assoc_array_walk(array, ops, index_key, &result)) {
|
|
++ case assoc_array_walk_tree_empty:
|
|
++ /* Allocate a root node if there isn't one yet */
|
|
++ if (!assoc_array_insert_in_empty_tree(edit))
|
|
++ goto enomem;
|
|
++ return edit;
|
|
++
|
|
++ case assoc_array_walk_found_terminal_node:
|
|
++ /* We found a node that doesn't have a node/shortcut pointer in
|
|
++ * the slot corresponding to the index key that we have to
|
|
++ * follow.
|
|
++ */
|
|
++ if (!assoc_array_insert_into_terminal_node(edit, ops, index_key,
|
|
++ &result))
|
|
++ goto enomem;
|
|
++ return edit;
|
|
++
|
|
++ case assoc_array_walk_found_wrong_shortcut:
|
|
++ /* We found a shortcut that didn't match our key in a slot we
|
|
++ * needed to follow.
|
|
++ */
|
|
++ if (!assoc_array_insert_mid_shortcut(edit, ops, &result))
|
|
++ goto enomem;
|
|
++ return edit;
|
|
++ }
|
|
++
|
|
++enomem:
|
|
++ /* Clean up after an out of memory error */
|
|
++ pr_devel("enomem\n");
|
|
++ assoc_array_cancel_edit(edit);
|
|
++ return ERR_PTR(-ENOMEM);
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_insert_set_object - Set the new object pointer in an edit script
|
|
++ * @edit: The edit script to modify.
|
|
++ * @object: The object pointer to set.
|
|
++ *
|
|
++ * Change the object to be inserted in an edit script. The object pointed to
|
|
++ * by the old object is not freed. This must be done prior to applying the
|
|
++ * script.
|
|
++ */
|
|
++void assoc_array_insert_set_object(struct assoc_array_edit *edit, void *object)
|
|
++{
|
|
++ BUG_ON(!object);
|
|
++ edit->leaf = assoc_array_leaf_to_ptr(object);
|
|
++}
|
|
++
|
|
++struct assoc_array_delete_collapse_context {
|
|
++ struct assoc_array_node *node;
|
|
++ const void *skip_leaf;
|
|
++ int slot;
|
|
++};
|
|
++
|
|
++/*
|
|
++ * Subtree collapse to node iterator.
|
|
++ */
|
|
++static int assoc_array_delete_collapse_iterator(const void *leaf,
|
|
++ void *iterator_data)
|
|
++{
|
|
++ struct assoc_array_delete_collapse_context *collapse = iterator_data;
|
|
++
|
|
++ if (leaf == collapse->skip_leaf)
|
|
++ return 0;
|
|
++
|
|
++ BUG_ON(collapse->slot >= ASSOC_ARRAY_FAN_OUT);
|
|
++
|
|
++ collapse->node->slots[collapse->slot++] = assoc_array_leaf_to_ptr(leaf);
|
|
++ return 0;
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_delete - Script deletion of an object from an associative array
|
|
++ * @array: The array to search.
|
|
++ * @ops: The operations to use.
|
|
++ * @index_key: The key to the object.
|
|
++ *
|
|
++ * Precalculate and preallocate a script for the deletion of an object from an
|
|
++ * associative array. This results in an edit script that can either be
|
|
++ * applied or cancelled.
|
|
++ *
|
|
++ * The function returns a pointer to an edit script if the object was found,
|
|
++ * NULL if the object was not found or -ENOMEM.
|
|
++ *
|
|
++ * The caller should lock against other modifications and must continue to hold
|
|
++ * the lock until assoc_array_apply_edit() has been called.
|
|
++ *
|
|
++ * Accesses to the tree may take place concurrently with this function,
|
|
++ * provided they hold the RCU read lock.
|
|
++ */
|
|
++struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ const void *index_key)
|
|
++{
|
|
++ struct assoc_array_delete_collapse_context collapse;
|
|
++ struct assoc_array_walk_result result;
|
|
++ struct assoc_array_node *node, *new_n0;
|
|
++ struct assoc_array_edit *edit;
|
|
++ struct assoc_array_ptr *ptr;
|
|
++ bool has_meta;
|
|
++ int slot, i;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
|
|
++ if (!edit)
|
|
++ return ERR_PTR(-ENOMEM);
|
|
++ edit->array = array;
|
|
++ edit->ops = ops;
|
|
++ edit->adjust_count_by = -1;
|
|
++
|
|
++ switch (assoc_array_walk(array, ops, index_key, &result)) {
|
|
++ case assoc_array_walk_found_terminal_node:
|
|
++ /* We found a node that should contain the leaf we've been
|
|
++ * asked to remove - *if* it's in the tree.
|
|
++ */
|
|
++ pr_devel("terminal_node\n");
|
|
++ node = result.terminal_node.node;
|
|
++
|
|
++ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = node->slots[slot];
|
|
++ if (ptr &&
|
|
++ assoc_array_ptr_is_leaf(ptr) &&
|
|
++ ops->compare_object(assoc_array_ptr_to_leaf(ptr),
|
|
++ index_key))
|
|
++ goto found_leaf;
|
|
++ }
|
|
++ case assoc_array_walk_tree_empty:
|
|
++ case assoc_array_walk_found_wrong_shortcut:
|
|
++ default:
|
|
++ assoc_array_cancel_edit(edit);
|
|
++ pr_devel("not found\n");
|
|
++ return NULL;
|
|
++ }
|
|
++
|
|
++found_leaf:
|
|
++ BUG_ON(array->nr_leaves_on_tree <= 0);
|
|
++
|
|
++ /* In the simplest form of deletion we just clear the slot and release
|
|
++ * the leaf after a suitable interval.
|
|
++ */
|
|
++ edit->dead_leaf = node->slots[slot];
|
|
++ edit->set[0].ptr = &node->slots[slot];
|
|
++ edit->set[0].to = NULL;
|
|
++ edit->adjust_count_on = node;
|
|
++
|
|
++ /* If that concludes erasure of the last leaf, then delete the entire
|
|
++ * internal array.
|
|
++ */
|
|
++ if (array->nr_leaves_on_tree == 1) {
|
|
++ edit->set[1].ptr = &array->root;
|
|
++ edit->set[1].to = NULL;
|
|
++ edit->adjust_count_on = NULL;
|
|
++ edit->excised_subtree = array->root;
|
|
++ pr_devel("all gone\n");
|
|
++ return edit;
|
|
++ }
|
|
++
|
|
++ /* However, we'd also like to clear up some metadata blocks if we
|
|
++ * possibly can.
|
|
++ *
|
|
++ * We go for a simple algorithm of: if this node has FAN_OUT or fewer
|
|
++ * leaves in it, then attempt to collapse it - and attempt to
|
|
++ * recursively collapse up the tree.
|
|
++ *
|
|
++ * We could also try and collapse in partially filled subtrees to take
|
|
++ * up space in this node.
|
|
++ */
|
|
++ if (node->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT + 1) {
|
|
++ struct assoc_array_node *parent, *grandparent;
|
|
++ struct assoc_array_ptr *ptr;
|
|
++
|
|
++ /* First of all, we need to know if this node has metadata so
|
|
++ * that we don't try collapsing if all the leaves are already
|
|
++ * here.
|
|
++ */
|
|
++ has_meta = false;
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ ptr = node->slots[i];
|
|
++ if (assoc_array_ptr_is_meta(ptr)) {
|
|
++ has_meta = true;
|
|
++ break;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ pr_devel("leaves: %ld [m=%d]\n",
|
|
++ node->nr_leaves_on_branch - 1, has_meta);
|
|
++
|
|
++ /* Look further up the tree to see if we can collapse this node
|
|
++ * into a more proximal node too.
|
|
++ */
|
|
++ parent = node;
|
|
++ collapse_up:
|
|
++ pr_devel("collapse subtree: %ld\n", parent->nr_leaves_on_branch);
|
|
++
|
|
++ ptr = parent->back_pointer;
|
|
++ if (!ptr)
|
|
++ goto do_collapse;
|
|
++ if (assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ struct assoc_array_shortcut *s = assoc_array_ptr_to_shortcut(ptr);
|
|
++ ptr = s->back_pointer;
|
|
++ if (!ptr)
|
|
++ goto do_collapse;
|
|
++ }
|
|
++
|
|
++ grandparent = assoc_array_ptr_to_node(ptr);
|
|
++ if (grandparent->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT + 1) {
|
|
++ parent = grandparent;
|
|
++ goto collapse_up;
|
|
++ }
|
|
++
|
|
++ do_collapse:
|
|
++ /* There's no point collapsing if the original node has no meta
|
|
++ * pointers to discard and if we didn't merge into one of that
|
|
++ * node's ancestry.
|
|
++ */
|
|
++ if (has_meta || parent != node) {
|
|
++ node = parent;
|
|
++
|
|
++ /* Create a new node to collapse into */
|
|
++ new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n0)
|
|
++ goto enomem;
|
|
++ edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
|
|
++
|
|
++ new_n0->back_pointer = node->back_pointer;
|
|
++ new_n0->parent_slot = node->parent_slot;
|
|
++ new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
|
|
++ edit->adjust_count_on = new_n0;
|
|
++
|
|
++ collapse.node = new_n0;
|
|
++ collapse.skip_leaf = assoc_array_ptr_to_leaf(edit->dead_leaf);
|
|
++ collapse.slot = 0;
|
|
++ assoc_array_subtree_iterate(assoc_array_node_to_ptr(node),
|
|
++ node->back_pointer,
|
|
++ assoc_array_delete_collapse_iterator,
|
|
++ &collapse);
|
|
++ pr_devel("collapsed %d,%lu\n", collapse.slot, new_n0->nr_leaves_on_branch);
|
|
++ BUG_ON(collapse.slot != new_n0->nr_leaves_on_branch - 1);
|
|
++
|
|
++ if (!node->back_pointer) {
|
|
++ edit->set[1].ptr = &array->root;
|
|
++ } else if (assoc_array_ptr_is_leaf(node->back_pointer)) {
|
|
++ BUG();
|
|
++ } else if (assoc_array_ptr_is_node(node->back_pointer)) {
|
|
++ struct assoc_array_node *p =
|
|
++ assoc_array_ptr_to_node(node->back_pointer);
|
|
++ edit->set[1].ptr = &p->slots[node->parent_slot];
|
|
++ } else if (assoc_array_ptr_is_shortcut(node->back_pointer)) {
|
|
++ struct assoc_array_shortcut *s =
|
|
++ assoc_array_ptr_to_shortcut(node->back_pointer);
|
|
++ edit->set[1].ptr = &s->next_node;
|
|
++ }
|
|
++ edit->set[1].to = assoc_array_node_to_ptr(new_n0);
|
|
++ edit->excised_subtree = assoc_array_node_to_ptr(node);
|
|
++ }
|
|
++ }
|
|
++
|
|
++ return edit;
|
|
++
|
|
++enomem:
|
|
++ /* Clean up after an out of memory error */
|
|
++ pr_devel("enomem\n");
|
|
++ assoc_array_cancel_edit(edit);
|
|
++ return ERR_PTR(-ENOMEM);
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_clear - Script deletion of all objects from an associative array
|
|
++ * @array: The array to clear.
|
|
++ * @ops: The operations to use.
|
|
++ *
|
|
++ * Precalculate and preallocate a script for the deletion of all the objects
|
|
++ * from an associative array. This results in an edit script that can either
|
|
++ * be applied or cancelled.
|
|
++ *
|
|
++ * The function returns a pointer to an edit script if there are objects to be
|
|
++ * deleted, NULL if there are no objects in the array or -ENOMEM.
|
|
++ *
|
|
++ * The caller should lock against other modifications and must continue to hold
|
|
++ * the lock until assoc_array_apply_edit() has been called.
|
|
++ *
|
|
++ * Accesses to the tree may take place concurrently with this function,
|
|
++ * provided they hold the RCU read lock.
|
|
++ */
|
|
++struct assoc_array_edit *assoc_array_clear(struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops)
|
|
++{
|
|
++ struct assoc_array_edit *edit;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ if (!array->root)
|
|
++ return NULL;
|
|
++
|
|
++ edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
|
|
++ if (!edit)
|
|
++ return ERR_PTR(-ENOMEM);
|
|
++ edit->array = array;
|
|
++ edit->ops = ops;
|
|
++ edit->set[1].ptr = &array->root;
|
|
++ edit->set[1].to = NULL;
|
|
++ edit->excised_subtree = array->root;
|
|
++ edit->ops_for_excised_subtree = ops;
|
|
++ pr_devel("all gone\n");
|
|
++ return edit;
|
|
++}
|
|
++
|
|
++/*
|
|
++ * Handle the deferred destruction after an applied edit.
|
|
++ */
|
|
++static void assoc_array_rcu_cleanup(struct rcu_head *head)
|
|
++{
|
|
++ struct assoc_array_edit *edit =
|
|
++ container_of(head, struct assoc_array_edit, rcu);
|
|
++ int i;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ if (edit->dead_leaf)
|
|
++ edit->ops->free_object(assoc_array_ptr_to_leaf(edit->dead_leaf));
|
|
++ for (i = 0; i < ARRAY_SIZE(edit->excised_meta); i++)
|
|
++ if (edit->excised_meta[i])
|
|
++ kfree(assoc_array_ptr_to_node(edit->excised_meta[i]));
|
|
++
|
|
++ if (edit->excised_subtree) {
|
|
++ BUG_ON(assoc_array_ptr_is_leaf(edit->excised_subtree));
|
|
++ if (assoc_array_ptr_is_node(edit->excised_subtree)) {
|
|
++ struct assoc_array_node *n =
|
|
++ assoc_array_ptr_to_node(edit->excised_subtree);
|
|
++ n->back_pointer = NULL;
|
|
++ } else {
|
|
++ struct assoc_array_shortcut *s =
|
|
++ assoc_array_ptr_to_shortcut(edit->excised_subtree);
|
|
++ s->back_pointer = NULL;
|
|
++ }
|
|
++ assoc_array_destroy_subtree(edit->excised_subtree,
|
|
++ edit->ops_for_excised_subtree);
|
|
++ }
|
|
++
|
|
++ kfree(edit);
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_apply_edit - Apply an edit script to an associative array
|
|
++ * @edit: The script to apply.
|
|
++ *
|
|
++ * Apply an edit script to an associative array to effect an insertion,
|
|
++ * deletion or clearance. As the edit script includes preallocated memory,
|
|
++ * this is guaranteed not to fail.
|
|
++ *
|
|
++ * The edit script, dead objects and dead metadata will be scheduled for
|
|
++ * destruction after an RCU grace period to permit those doing read-only
|
|
++ * accesses on the array to continue to do so under the RCU read lock whilst
|
|
++ * the edit is taking place.
|
|
++ */
|
|
++void assoc_array_apply_edit(struct assoc_array_edit *edit)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut;
|
|
++ struct assoc_array_node *node;
|
|
++ struct assoc_array_ptr *ptr;
|
|
++ int i;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ smp_wmb();
|
|
++ if (edit->leaf_p)
|
|
++ *edit->leaf_p = edit->leaf;
|
|
++
|
|
++ smp_wmb();
|
|
++ for (i = 0; i < ARRAY_SIZE(edit->set_parent_slot); i++)
|
|
++ if (edit->set_parent_slot[i].p)
|
|
++ *edit->set_parent_slot[i].p = edit->set_parent_slot[i].to;
|
|
++
|
|
++ smp_wmb();
|
|
++ for (i = 0; i < ARRAY_SIZE(edit->set_backpointers); i++)
|
|
++ if (edit->set_backpointers[i])
|
|
++ *edit->set_backpointers[i] = edit->set_backpointers_to;
|
|
++
|
|
++ smp_wmb();
|
|
++ for (i = 0; i < ARRAY_SIZE(edit->set); i++)
|
|
++ if (edit->set[i].ptr)
|
|
++ *edit->set[i].ptr = edit->set[i].to;
|
|
++
|
|
++ if (edit->array->root == NULL) {
|
|
++ edit->array->nr_leaves_on_tree = 0;
|
|
++ } else if (edit->adjust_count_on) {
|
|
++ node = edit->adjust_count_on;
|
|
++ for (;;) {
|
|
++ node->nr_leaves_on_branch += edit->adjust_count_by;
|
|
++
|
|
++ ptr = node->back_pointer;
|
|
++ if (!ptr)
|
|
++ break;
|
|
++ if (assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(ptr);
|
|
++ ptr = shortcut->back_pointer;
|
|
++ if (!ptr)
|
|
++ break;
|
|
++ }
|
|
++ BUG_ON(!assoc_array_ptr_is_node(ptr));
|
|
++ node = assoc_array_ptr_to_node(ptr);
|
|
++ }
|
|
++
|
|
++ edit->array->nr_leaves_on_tree += edit->adjust_count_by;
|
|
++ }
|
|
++
|
|
++ call_rcu(&edit->rcu, assoc_array_rcu_cleanup);
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_cancel_edit - Discard an edit script.
|
|
++ * @edit: The script to discard.
|
|
++ *
|
|
++ * Free an edit script and all the preallocated data it holds without making
|
|
++ * any changes to the associative array it was intended for.
|
|
++ *
|
|
++ * NOTE! In the case of an insertion script, this does _not_ release the leaf
|
|
++ * that was to be inserted. That is left to the caller.
|
|
++ */
|
|
++void assoc_array_cancel_edit(struct assoc_array_edit *edit)
|
|
++{
|
|
++ struct assoc_array_ptr *ptr;
|
|
++ int i;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ /* Clean up after an out of memory error */
|
|
++ for (i = 0; i < ARRAY_SIZE(edit->new_meta); i++) {
|
|
++ ptr = edit->new_meta[i];
|
|
++ if (ptr) {
|
|
++ if (assoc_array_ptr_is_node(ptr))
|
|
++ kfree(assoc_array_ptr_to_node(ptr));
|
|
++ else
|
|
++ kfree(assoc_array_ptr_to_shortcut(ptr));
|
|
++ }
|
|
++ }
|
|
++ kfree(edit);
|
|
++}
|
|
++
|
|
++/**
|
|
++ * assoc_array_gc - Garbage collect an associative array.
|
|
++ * @array: The array to clean.
|
|
++ * @ops: The operations to use.
|
|
++ * @iterator: A callback function to pass judgement on each object.
|
|
++ * @iterator_data: Private data for the callback function.
|
|
++ *
|
|
++ * Collect garbage from an associative array and pack down the internal tree to
|
|
++ * save memory.
|
|
++ *
|
|
++ * The iterator function is asked to pass judgement upon each object in the
|
|
++ * array. If it returns false, the object is discard and if it returns true,
|
|
++ * the object is kept. If it returns true, it must increment the object's
|
|
++ * usage count (or whatever it needs to do to retain it) before returning.
|
|
++ *
|
|
++ * This function returns 0 if successful or -ENOMEM if out of memory. In the
|
|
++ * latter case, the array is not changed.
|
|
++ *
|
|
++ * The caller should lock against other modifications and must continue to hold
|
|
++ * the lock until assoc_array_apply_edit() has been called.
|
|
++ *
|
|
++ * Accesses to the tree may take place concurrently with this function,
|
|
++ * provided they hold the RCU read lock.
|
|
++ */
|
|
++int assoc_array_gc(struct assoc_array *array,
|
|
++ const struct assoc_array_ops *ops,
|
|
++ bool (*iterator)(void *object, void *iterator_data),
|
|
++ void *iterator_data)
|
|
++{
|
|
++ struct assoc_array_shortcut *shortcut, *new_s;
|
|
++ struct assoc_array_node *node, *new_n;
|
|
++ struct assoc_array_edit *edit;
|
|
++ struct assoc_array_ptr *cursor, *ptr;
|
|
++ struct assoc_array_ptr *new_root, *new_parent, **new_ptr_pp;
|
|
++ unsigned long nr_leaves_on_tree;
|
|
++ int keylen, slot, nr_free, next_slot, i;
|
|
++
|
|
++ pr_devel("-->%s()\n", __func__);
|
|
++
|
|
++ if (!array->root)
|
|
++ return 0;
|
|
++
|
|
++ edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
|
|
++ if (!edit)
|
|
++ return -ENOMEM;
|
|
++ edit->array = array;
|
|
++ edit->ops = ops;
|
|
++ edit->ops_for_excised_subtree = ops;
|
|
++ edit->set[0].ptr = &array->root;
|
|
++ edit->excised_subtree = array->root;
|
|
++
|
|
++ new_root = new_parent = NULL;
|
|
++ new_ptr_pp = &new_root;
|
|
++ cursor = array->root;
|
|
++
|
|
++descend:
|
|
++ /* If this point is a shortcut, then we need to duplicate it and
|
|
++ * advance the target cursor.
|
|
++ */
|
|
++ if (assoc_array_ptr_is_shortcut(cursor)) {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(cursor);
|
|
++ keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
|
|
++ keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
|
|
++ new_s = kmalloc(sizeof(struct assoc_array_shortcut) +
|
|
++ keylen * sizeof(unsigned long), GFP_KERNEL);
|
|
++ if (!new_s)
|
|
++ goto enomem;
|
|
++ pr_devel("dup shortcut %p -> %p\n", shortcut, new_s);
|
|
++ memcpy(new_s, shortcut, (sizeof(struct assoc_array_shortcut) +
|
|
++ keylen * sizeof(unsigned long)));
|
|
++ new_s->back_pointer = new_parent;
|
|
++ new_s->parent_slot = shortcut->parent_slot;
|
|
++ *new_ptr_pp = new_parent = assoc_array_shortcut_to_ptr(new_s);
|
|
++ new_ptr_pp = &new_s->next_node;
|
|
++ cursor = shortcut->next_node;
|
|
++ }
|
|
++
|
|
++ /* Duplicate the node at this position */
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ new_n = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
|
|
++ if (!new_n)
|
|
++ goto enomem;
|
|
++ pr_devel("dup node %p -> %p\n", node, new_n);
|
|
++ new_n->back_pointer = new_parent;
|
|
++ new_n->parent_slot = node->parent_slot;
|
|
++ *new_ptr_pp = new_parent = assoc_array_node_to_ptr(new_n);
|
|
++ new_ptr_pp = NULL;
|
|
++ slot = 0;
|
|
++
|
|
++continue_node:
|
|
++ /* Filter across any leaves and gc any subtrees */
|
|
++ for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = node->slots[slot];
|
|
++ if (!ptr)
|
|
++ continue;
|
|
++
|
|
++ if (assoc_array_ptr_is_leaf(ptr)) {
|
|
++ if (iterator(assoc_array_ptr_to_leaf(ptr),
|
|
++ iterator_data))
|
|
++ /* The iterator will have done any reference
|
|
++ * counting on the object for us.
|
|
++ */
|
|
++ new_n->slots[slot] = ptr;
|
|
++ continue;
|
|
++ }
|
|
++
|
|
++ new_ptr_pp = &new_n->slots[slot];
|
|
++ cursor = ptr;
|
|
++ goto descend;
|
|
++ }
|
|
++
|
|
++ pr_devel("-- compress node %p --\n", new_n);
|
|
++
|
|
++ /* Count up the number of empty slots in this node and work out the
|
|
++ * subtree leaf count.
|
|
++ */
|
|
++ new_n->nr_leaves_on_branch = 0;
|
|
++ nr_free = 0;
|
|
++ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ ptr = new_n->slots[slot];
|
|
++ if (!ptr)
|
|
++ nr_free++;
|
|
++ else if (assoc_array_ptr_is_leaf(ptr))
|
|
++ new_n->nr_leaves_on_branch++;
|
|
++ }
|
|
++ pr_devel("free=%d, leaves=%lu\n", nr_free, new_n->nr_leaves_on_branch);
|
|
++
|
|
++ /* See what we can fold in */
|
|
++ next_slot = 0;
|
|
++ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
|
++ struct assoc_array_shortcut *s;
|
|
++ struct assoc_array_node *child;
|
|
++
|
|
++ ptr = new_n->slots[slot];
|
|
++ if (!ptr || assoc_array_ptr_is_leaf(ptr))
|
|
++ continue;
|
|
++
|
|
++ s = NULL;
|
|
++ if (assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ s = assoc_array_ptr_to_shortcut(ptr);
|
|
++ ptr = s->next_node;
|
|
++ }
|
|
++
|
|
++ child = assoc_array_ptr_to_node(ptr);
|
|
++ new_n->nr_leaves_on_branch += child->nr_leaves_on_branch;
|
|
++
|
|
++ if (child->nr_leaves_on_branch <= nr_free + 1) {
|
|
++ /* Fold the child node into this one */
|
|
++ pr_devel("[%d] fold node %lu/%d [nx %d]\n",
|
|
++ slot, child->nr_leaves_on_branch, nr_free + 1,
|
|
++ next_slot);
|
|
++
|
|
++ /* We would already have reaped an intervening shortcut
|
|
++ * on the way back up the tree.
|
|
++ */
|
|
++ BUG_ON(s);
|
|
++
|
|
++ new_n->slots[slot] = NULL;
|
|
++ nr_free++;
|
|
++ if (slot < next_slot)
|
|
++ next_slot = slot;
|
|
++ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
|
|
++ struct assoc_array_ptr *p = child->slots[i];
|
|
++ if (!p)
|
|
++ continue;
|
|
++ BUG_ON(assoc_array_ptr_is_meta(p));
|
|
++ while (new_n->slots[next_slot])
|
|
++ next_slot++;
|
|
++ BUG_ON(next_slot >= ASSOC_ARRAY_FAN_OUT);
|
|
++ new_n->slots[next_slot++] = p;
|
|
++ nr_free--;
|
|
++ }
|
|
++ kfree(child);
|
|
++ } else {
|
|
++ pr_devel("[%d] retain node %lu/%d [nx %d]\n",
|
|
++ slot, child->nr_leaves_on_branch, nr_free + 1,
|
|
++ next_slot);
|
|
++ }
|
|
++ }
|
|
++
|
|
++ pr_devel("after: %lu\n", new_n->nr_leaves_on_branch);
|
|
++
|
|
++ nr_leaves_on_tree = new_n->nr_leaves_on_branch;
|
|
++
|
|
++ /* Excise this node if it is singly occupied by a shortcut */
|
|
++ if (nr_free == ASSOC_ARRAY_FAN_OUT - 1) {
|
|
++ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++)
|
|
++ if ((ptr = new_n->slots[slot]))
|
|
++ break;
|
|
++
|
|
++ if (assoc_array_ptr_is_meta(ptr) &&
|
|
++ assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ pr_devel("excise node %p with 1 shortcut\n", new_n);
|
|
++ new_s = assoc_array_ptr_to_shortcut(ptr);
|
|
++ new_parent = new_n->back_pointer;
|
|
++ slot = new_n->parent_slot;
|
|
++ kfree(new_n);
|
|
++ if (!new_parent) {
|
|
++ new_s->back_pointer = NULL;
|
|
++ new_s->parent_slot = 0;
|
|
++ new_root = ptr;
|
|
++ goto gc_complete;
|
|
++ }
|
|
++
|
|
++ if (assoc_array_ptr_is_shortcut(new_parent)) {
|
|
++ /* We can discard any preceding shortcut also */
|
|
++ struct assoc_array_shortcut *s =
|
|
++ assoc_array_ptr_to_shortcut(new_parent);
|
|
++
|
|
++ pr_devel("excise preceding shortcut\n");
|
|
++
|
|
++ new_parent = new_s->back_pointer = s->back_pointer;
|
|
++ slot = new_s->parent_slot = s->parent_slot;
|
|
++ kfree(s);
|
|
++ if (!new_parent) {
|
|
++ new_s->back_pointer = NULL;
|
|
++ new_s->parent_slot = 0;
|
|
++ new_root = ptr;
|
|
++ goto gc_complete;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ new_s->back_pointer = new_parent;
|
|
++ new_s->parent_slot = slot;
|
|
++ new_n = assoc_array_ptr_to_node(new_parent);
|
|
++ new_n->slots[slot] = ptr;
|
|
++ goto ascend_old_tree;
|
|
++ }
|
|
++ }
|
|
++
|
|
++ /* Excise any shortcuts we might encounter that point to nodes that
|
|
++ * only contain leaves.
|
|
++ */
|
|
++ ptr = new_n->back_pointer;
|
|
++ if (!ptr)
|
|
++ goto gc_complete;
|
|
++
|
|
++ if (assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ new_s = assoc_array_ptr_to_shortcut(ptr);
|
|
++ new_parent = new_s->back_pointer;
|
|
++ slot = new_s->parent_slot;
|
|
++
|
|
++ if (new_n->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT) {
|
|
++ struct assoc_array_node *n;
|
|
++
|
|
++ pr_devel("excise shortcut\n");
|
|
++ new_n->back_pointer = new_parent;
|
|
++ new_n->parent_slot = slot;
|
|
++ kfree(new_s);
|
|
++ if (!new_parent) {
|
|
++ new_root = assoc_array_node_to_ptr(new_n);
|
|
++ goto gc_complete;
|
|
++ }
|
|
++
|
|
++ n = assoc_array_ptr_to_node(new_parent);
|
|
++ n->slots[slot] = assoc_array_node_to_ptr(new_n);
|
|
++ }
|
|
++ } else {
|
|
++ new_parent = ptr;
|
|
++ }
|
|
++ new_n = assoc_array_ptr_to_node(new_parent);
|
|
++
|
|
++ascend_old_tree:
|
|
++ ptr = node->back_pointer;
|
|
++ if (assoc_array_ptr_is_shortcut(ptr)) {
|
|
++ shortcut = assoc_array_ptr_to_shortcut(ptr);
|
|
++ slot = shortcut->parent_slot;
|
|
++ cursor = shortcut->back_pointer;
|
|
++ if (!cursor)
|
|
++ goto gc_complete;
|
|
++ } else {
|
|
++ slot = node->parent_slot;
|
|
++ cursor = ptr;
|
|
++ }
|
|
++ BUG_ON(!cursor);
|
|
++ node = assoc_array_ptr_to_node(cursor);
|
|
++ slot++;
|
|
++ goto continue_node;
|
|
++
|
|
++gc_complete:
|
|
++ edit->set[0].to = new_root;
|
|
++ assoc_array_apply_edit(edit);
|
|
++ array->nr_leaves_on_tree = nr_leaves_on_tree;
|
|
++ return 0;
|
|
++
|
|
++enomem:
|
|
++ pr_devel("enomem\n");
|
|
++ assoc_array_destroy_subtree(new_root, edit->ops);
|
|
++ kfree(edit);
|
|
++ return -ENOMEM;
|
|
++}
|
|
+--
|
|
+2.13.3
|
|
+
|
|
diff --git a/patches/3.4/CVE-2016-8403.patch b/patches/3.4/CVE-2016-8403.patch
|
|
new file mode 100644
|
|
index 0000000..1e44fd2
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-8403.patch
|
|
@@ -0,0 +1,119 @@
|
|
+From cbecea4e18e5e31a007f0d3f39be549535083f72 Mon Sep 17 00:00:00 2001
|
|
+From: Min Chong <mchong@google.com>
|
|
+Date: Tue, 11 Oct 2016 17:12:00 -0700
|
|
+Subject: [PATCH] usb: diag: change %p to %pK in debug messages
|
|
+
|
|
+The format specifier %p can leak kernel addresses
|
|
+while not valuing the kptr_restrict system settings.
|
|
+Use %pK instead of %p, which also evaluates whether
|
|
+kptr_restrict is set.
|
|
+
|
|
+Bug: 31495348
|
|
+Change-Id: I7392c2b444794234ebd685735566e7b4fa09c409
|
|
+Signed-off-by: Min Chong <mchong@google.com>
|
|
+---
|
|
+ drivers/usb/gadget/u_data_hsic.c | 22 +++++++++++-----------
|
|
+ 1 file changed, 11 insertions(+), 11 deletions(-)
|
|
+
|
|
+diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
|
|
+index 92653dbb8b8..df45994479c 100644
|
|
+--- a/drivers/usb/gadget/u_data_hsic.c
|
|
++++ b/drivers/usb/gadget/u_data_hsic.c
|
|
+@@ -150,7 +150,7 @@ static int ghsic_data_alloc_requests(struct usb_ep *ep, struct list_head *head,
|
|
+ struct usb_request *req;
|
|
+ unsigned long flags;
|
|
+
|
|
+- pr_debug("%s: ep:%s head:%p num:%d cb:%p", __func__,
|
|
++ pr_debug("%s: ep:%s head:%pK num:%d cb:%pK", __func__,
|
|
+ ep->name, head, num, cb);
|
|
+
|
|
+ for (i = 0; i < num; i++) {
|
|
+@@ -266,7 +266,7 @@ static int ghsic_data_receive(void *p, void *data, size_t len)
|
|
+ return -ENOTCONN;
|
|
+ }
|
|
+
|
|
+- pr_debug("%s: p:%p#%d skb_len:%d\n", __func__,
|
|
++ pr_debug("%s: p:%pK#%d skb_len:%d\n", __func__,
|
|
+ port, port->port_num, skb->len);
|
|
+
|
|
+ spin_lock_irqsave(&port->tx_lock, flags);
|
|
+@@ -310,7 +310,7 @@ static void ghsic_data_write_tomdm(struct work_struct *w)
|
|
+ }
|
|
+
|
|
+ while ((skb = __skb_dequeue(&port->rx_skb_q))) {
|
|
+- pr_debug("%s: port:%p tom:%lu pno:%d\n", __func__,
|
|
++ pr_debug("%s: port:%pK tom:%lu pno:%d\n", __func__,
|
|
+ port, port->to_modem, port->port_num);
|
|
+
|
|
+ info = (struct timestamp_info *)skb->cb;
|
|
+@@ -418,7 +418,7 @@ static void ghsic_data_start_rx(struct gdata_port *port)
|
|
+ struct timestamp_info *info;
|
|
+ unsigned int created;
|
|
+
|
|
+- pr_debug("%s: port:%p\n", __func__, port);
|
|
++ pr_debug("%s: port:%pK\n", __func__, port);
|
|
+ if (!port)
|
|
+ return;
|
|
+
|
|
+@@ -475,7 +475,7 @@ static void ghsic_data_start_io(struct gdata_port *port)
|
|
+ struct usb_ep *ep_out, *ep_in;
|
|
+ int ret;
|
|
+
|
|
+- pr_debug("%s: port:%p\n", __func__, port);
|
|
++ pr_debug("%s: port:%pK\n", __func__, port);
|
|
+
|
|
+ if (!port)
|
|
+ return;
|
|
+@@ -527,7 +527,7 @@ static void ghsic_data_connect_w(struct work_struct *w)
|
|
+ !test_bit(CH_READY, &port->bridge_sts))
|
|
+ return;
|
|
+
|
|
+- pr_debug("%s: port:%p\n", __func__, port);
|
|
++ pr_debug("%s: port:%pK\n", __func__, port);
|
|
+
|
|
+ ret = data_bridge_open(&port->brdg);
|
|
+ if (ret) {
|
|
+@@ -725,7 +725,7 @@ static int ghsic_data_port_alloc(unsigned port_num, enum gadget_type gtype)
|
|
+
|
|
+ platform_driver_register(pdrv);
|
|
+
|
|
+- pr_debug("%s: port:%p portno:%d\n", __func__, port, port_num);
|
|
++ pr_debug("%s: port:%pK portno:%d\n", __func__, port, port_num);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+@@ -834,14 +834,14 @@ int ghsic_data_connect(void *gptr, int port_num)
|
|
+
|
|
+ ret = usb_ep_enable(port->in);
|
|
+ if (ret) {
|
|
+- pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
|
|
++ pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK",
|
|
+ __func__, port->in);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ ret = usb_ep_enable(port->out);
|
|
+ if (ret) {
|
|
+- pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
|
|
++ pr_err("%s: usb_ep_enable failed eptype:OUT ep:%pK",
|
|
+ __func__, port->out);
|
|
+ usb_ep_disable(port->in);
|
|
+ goto fail;
|
|
+@@ -917,7 +917,7 @@ static void dbg_timestamp(char *event, struct sk_buff * skb)
|
|
+ write_lock_irqsave(&dbg_data.lck, flags);
|
|
+
|
|
+ scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
|
|
+- "%p %u[%s] %u %u %u %u %u %u\n",
|
|
++ "%pK %u[%s] %u %u %u %u %u %u\n",
|
|
+ skb, skb->len, event, info->created, info->rx_queued,
|
|
+ info->rx_done, info->rx_done_sent, info->tx_queued,
|
|
+ get_timestamp());
|
|
+@@ -991,7 +991,7 @@ static ssize_t ghsic_data_read_stats(struct file *file,
|
|
+ spin_lock_irqsave(&port->rx_lock, flags);
|
|
+ temp += scnprintf(buf + temp, DEBUG_DATA_BUF_SIZE - temp,
|
|
+ "\nName: %s\n"
|
|
+- "#PORT:%d port#: %p\n"
|
|
++ "#PORT:%d port#: %pK\n"
|
|
+ "data_ch_open: %d\n"
|
|
+ "data_ch_ready: %d\n"
|
|
+ "\n******UL INFO*****\n\n"
|
|
diff --git a/patches/3.4/CVE-2016-8406.patch b/patches/3.4/CVE-2016-8406.patch
|
|
new file mode 100644
|
|
index 0000000..1ef8451
|
|
--- /dev/null
|
|
+++ b/patches/3.4/CVE-2016-8406.patch
|
|
@@ -0,0 +1,102 @@
|
|
+From d7a15270ad80aff21d09aaea9c0e98e03e541b50 Mon Sep 17 00:00:00 2001
|
|
+From: Min Chong <mchong@google.com>
|
|
+Date: Thu, 13 Oct 2016 17:15:35 -0700
|
|
+Subject: [PATCH] netfilter: Change %p to %pK in debug messages
|
|
+
|
|
+The format specifier %p can leak kernel addresses
|
|
+while not valuing the kptr_restrict system settings.
|
|
+Use %pK instead of %p, which also evaluates whether
|
|
+kptr_restrict is set.
|
|
+
|
|
+Bug: 31796940
|
|
+Change-Id: Ia2946d6b493126d68281f97778faf578247f088e
|
|
+Signed-off-by: Min Chong <mchong@google.com>
|
|
+---
|
|
+ net/netfilter/nf_conntrack_core.c | 20 ++++++++++----------
|
|
+ 1 file changed, 10 insertions(+), 10 deletions(-)
|
|
+
|
|
+diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
|
|
+index 1c118edd4b794..d9b86c2e96e24 100644
|
|
+--- a/net/netfilter/nf_conntrack_core.c
|
|
++++ b/net/netfilter/nf_conntrack_core.c
|
|
+@@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
|
|
+ static void
|
|
+ clean_from_lists(struct nf_conn *ct)
|
|
+ {
|
|
+- pr_debug("clean_from_lists(%p)\n", ct);
|
|
++ pr_debug("clean_from_lists(%pK)\n", ct);
|
|
+ hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
|
|
+ hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode);
|
|
+
|
|
+@@ -203,7 +203,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
|
+ struct net *net = nf_ct_net(ct);
|
|
+ struct nf_conntrack_l4proto *l4proto;
|
|
+
|
|
+- pr_debug("destroy_conntrack(%p)\n", ct);
|
|
++ pr_debug("destroy_conntrack(%pK)\n", ct);
|
|
+ NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
|
|
+ NF_CT_ASSERT(!timer_pending(&ct->timeout));
|
|
+
|
|
+@@ -234,7 +234,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
|
+ if (ct->master)
|
|
+ nf_ct_put(ct->master);
|
|
+
|
|
+- pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct);
|
|
++ pr_debug("destroy_conntrack: returning ct=%pK to slab\n", ct);
|
|
+ nf_conntrack_free(ct);
|
|
+ }
|
|
+
|
|
+@@ -496,7 +496,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
|
|
+ /* No external references means no one else could have
|
|
+ confirmed us. */
|
|
+ NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
|
|
+- pr_debug("Confirming conntrack %p\n", ct);
|
|
++ pr_debug("Confirming conntrack %pK\n", ct);
|
|
+
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
+
|
|
+@@ -826,7 +826,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
+ exp = nf_ct_find_expectation(net, zone, tuple);
|
|
+ if (exp) {
|
|
+- pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
|
|
++ pr_debug("conntrack: expectation arrives ct=%pK exp=%pK\n",
|
|
+ ct, exp);
|
|
+ /* Welcome, Mr. Bond. We've been expecting you... */
|
|
+ __set_bit(IPS_EXPECTED_BIT, &ct->status);
|
|
+@@ -916,14 +916,14 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
|
|
+ } else {
|
|
+ /* Once we've had two way comms, always ESTABLISHED. */
|
|
+ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
|
|
+- pr_debug("nf_conntrack_in: normal packet for %p\n", ct);
|
|
++ pr_debug("nf_conntrack_in: normal packet for %pK\n", ct);
|
|
+ *ctinfo = IP_CT_ESTABLISHED;
|
|
+ } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
|
|
+- pr_debug("nf_conntrack_in: related packet for %p\n",
|
|
++ pr_debug("nf_conntrack_in: related packet for %pK\n",
|
|
+ ct);
|
|
+ *ctinfo = IP_CT_RELATED;
|
|
+ } else {
|
|
+- pr_debug("nf_conntrack_in: new packet for %p\n", ct);
|
|
++ pr_debug("nf_conntrack_in: new packet for %pK\n", ct);
|
|
+ *ctinfo = IP_CT_NEW;
|
|
+ }
|
|
+ *set_reply = 0;
|
|
+@@ -1065,7 +1065,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
|
|
+ /* Should be unconfirmed, so not in hash table yet */
|
|
+ NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
|
|
+
|
|
+- pr_debug("Altering reply tuple of %p to ", ct);
|
|
++ pr_debug("Altering reply tuple of %pK to ", ct);
|
|
+ nf_ct_dump_tuple(newreply);
|
|
+
|
|
+ ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
|
|
+@@ -1640,7 +1640,7 @@ int nf_conntrack_init_net(struct net *net)
|
|
+ goto err_stat;
|
|
+ }
|
|
+
|
|
+- net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net);
|
|
++ net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%pK", net);
|
|
+ if (!net->ct.slabname) {
|
|
+ ret = -ENOMEM;
|
|
+ goto err_slabname;
|