pmaports/device/linux-oppo-find-7a/0004_3.4_android_CVE_d3752ba7de67976f5f09a7bb2b74d4298eb32f8b.patch
Tito Ragusa 292e742220
oppo-find-7a: linux: various improvements (!580)
* 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
2019-08-31 15:30:38 +02:00

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;