In some architectural corner cases, AT instructions can generate an
exception, which KVM is not really ready to handle properly.
Teach the code to handle this situation gracefully.
This is a backport of the respective upstream patches to v5.4(.61).
James prepared these already, but we were lacking the upstream commit ID.
I am sending this on his behalf, since he is off this week.
The last two of the patches were tagged Cc: stable already, but did
not apply cleanly, hence this specific backport.
Cheers,
Andre.
James Morse (3):
KVM: arm64: Add kvm_extable for vaxoricism code
KVM: arm64: Survive synchronous exceptions caused by AT instructions
KVM: arm64: Set HCR_EL2.PTW to prevent AT taking synchronous exception
arch/arm64/include/asm/kvm_arm.h | 3 +-
arch/arm64/include/asm/kvm_asm.h | 43 +++++++++++++++++++++
arch/arm64/kernel/vmlinux.lds.S | 8 ++++
arch/arm64/kvm/hyp/entry.S | 15 +++++---
arch/arm64/kvm/hyp/hyp-entry.S | 65 ++++++++++++++++++++------------
arch/arm64/kvm/hyp/switch.c | 39 +++++++++++++++++--
6 files changed, 138 insertions(+), 35 deletions(-)
--
2.17.1
Hi
[This is an automated email]
This commit has been processed because it contains a -stable tag.
The stable tag indicates that it's relevant for the following trees: all
The bot has tested the following trees: v5.8.5, v5.4.61, v4.19.142, v4.14.195, v4.9.234, v4.4.234.
v5.8.5: Build OK!
v5.4.61: Build OK!
v4.19.142: Failed to apply! Possible dependencies:
2932c8b05056 ("mm, memory_hotplug: be more verbose for memory offline failures")
5557c766abad ("mm, memory_hotplug: cleanup memory offline path")
7960509329c2 ("mm, memory_hotplug: print reason for the offlining failure")
7c2ee349cf79 ("memblock: rename __free_pages_bootmem to memblock_free_pages")
9b7ea46a82b3 ("mm/hotplug: fix offline undo_isolate_page_range()")
a9cd410a3d29 ("mm/page_alloc.c: memory hotplug: free pages as higher order")
bb8965bd82fd ("mm, memory_hotplug: deobfuscate migration part of offlining")
d381c54760dc ("mm: only report isolation failures when offlining memory")
v4.14.195: Failed to apply! Possible dependencies:
1b7176aea0a9 ("memory hotplug: fix comments when adding section")
24e6d5a59ac7 ("mm: pass the vmem_altmap to arch_add_memory and __add_pages")
2f47a91f4dab ("mm: deferred_init_memmap improvements")
381eab4a6ee8 ("mm/memory_hotplug: fix online/offline_pages called w.o. mem_hotplug_lock")
7960509329c2 ("mm, memory_hotplug: print reason for the offlining failure")
7b73d978a5d0 ("mm: pass the vmem_altmap to vmemmap_populate")
80b1f41c0957 ("mm: split deferred_init_range into initializing and freeing parts")
9bb5a391f9a5 ("mm, memory_hotplug: fix memmap initialization")
b9ff036082cd ("mm/memory_hotplug.c: make add_memory_resource use __try_online_node")
bb8965bd82fd ("mm, memory_hotplug: deobfuscate migration part of offlining")
d0dc12e86b31 ("mm/memory_hotplug: optimize memory hotplug")
e8b098fc5747 ("mm: kernel-doc: add missing parameter descriptions")
f7f99100d8d9 ("mm: stop zeroing memory during allocation in vmemmap")
v4.9.234: Failed to apply! Possible dependencies:
1b862aecfbd4 ("mm, memory_hotplug: get rid of is_zone_device_section")
381eab4a6ee8 ("mm/memory_hotplug: fix online/offline_pages called w.o. mem_hotplug_lock")
385386cff4c6 ("mm: vmstat: move slab statistics from zone to node counters")
438cc81a41e8 ("powerpc/pseries: Automatically resize HPT for memory hot add/remove")
72675e131eb4 ("mm, memory_hotplug: drop zone from build_all_zonelists")
7960509329c2 ("mm, memory_hotplug: print reason for the offlining failure")
88ed365ea227 ("mm: don't steal highatomic pageblock")
a6ffdc07847e ("mm: use is_migrate_highatomic() to simplify the code")
b93e0f329e24 ("mm, memory_hotplug: get rid of zonelists_mutex")
bb8965bd82fd ("mm, memory_hotplug: deobfuscate migration part of offlining")
c8f9565716e3 ("mm, memory_hotplug: use node instead of zone in can_online_high_movable")
f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded memory to zones until online")
v4.4.234: Failed to apply! Possible dependencies:
0caeef63e6d2 ("libnvdimm: Add a poison list and export badblocks")
0e749e54244e ("dax: increase granularity of dax_clear_blocks() operations")
1b862aecfbd4 ("mm, memory_hotplug: get rid of is_zone_device_section")
260ae3f7db61 ("mm: skip memory block registration for ZONE_DEVICE")
34c0fd540e79 ("mm, dax, pmem: introduce pfn_t")
381eab4a6ee8 ("mm/memory_hotplug: fix online/offline_pages called w.o. mem_hotplug_lock")
4a65429457a5 ("s390/mm: fix zone calculation in arch_add_memory()")
4b94ffdc4163 ("x86, mm: introduce vmem_altmap to augment vmemmap_populate()")
7960509329c2 ("mm, memory_hotplug: print reason for the offlining failure")
87ba05dff351 ("libnvdimm: don't fail init for full badblocks list")
ad9a8bde2cb1 ("libnvdimm, pmem: move definition of nvdimm_namespace_add_poison to nd.h")
b95f5f4391fa ("libnvdimm: convert to statically allocated badblocks")
bb8965bd82fd ("mm, memory_hotplug: deobfuscate migration part of offlining")
f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded memory to zones until online")
NOTE: The patch will not be queued to stable trees until it is upstream.
How should we proceed with this patch?
--
Thanks
Sasha
Commit ca399c96e96e changes gfs2_log_flush to not withdraw the
filesystem while holding the log flush lock, but it fails to check if
the filesystem needs to be withdrawn once the log flush lock has been
released. Likewise, commit f05b86db314d depends on gfs2_log_flush to
trigger for delayed withdraws. Add that and clean up the code flow
somewhat.
In gfs2_put_super, add a check for delayed withdraws that have been
missed to prevent these kinds of bugs in the future.
Fixes: ca399c96e96e ("gfs2: flesh out delayed withdraw for gfs2_log_flush")
Fixes: f05b86db314d ("gfs2: Prepare to withdraw as soon as an IO error occurs in log write")
Cc: stable(a)vger.kernel.org # v5.7+
Signed-off-by: Andreas Gruenbacher <agruenba(a)redhat.com>
---
fs/gfs2/log.c | 61 +++++++++++++++++++++++++------------------------
fs/gfs2/super.c | 2 ++
fs/gfs2/util.h | 10 ++++++++
3 files changed, 43 insertions(+), 30 deletions(-)
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 3763c9ff1406..93032feb5159 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -954,10 +954,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
goto out;
/* Log might have been flushed while we waited for the flush lock */
- if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) {
- up_write(&sdp->sd_log_flush_lock);
- return;
- }
+ if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags))
+ goto out;
trace_gfs2_log_flush(sdp, 1, flags);
if (flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN)
@@ -971,25 +969,25 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (unlikely (state == SFS_FROZEN))
if (gfs2_assert_withdraw_delayed(sdp,
!tr->tr_num_buf_new && !tr->tr_num_databuf_new))
- goto out;
+ goto out_withdraw;
}
if (unlikely(state == SFS_FROZEN))
if (gfs2_assert_withdraw_delayed(sdp, !sdp->sd_log_num_revoke))
- goto out;
+ goto out_withdraw;
if (gfs2_assert_withdraw_delayed(sdp,
sdp->sd_log_num_revoke == sdp->sd_log_committed_revoke))
- goto out;
+ goto out_withdraw;
gfs2_ordered_write(sdp);
if (gfs2_withdrawn(sdp))
- goto out;
+ goto out_withdraw;
lops_before_commit(sdp, tr);
if (gfs2_withdrawn(sdp))
- goto out;
+ goto out_withdraw;
gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE);
if (gfs2_withdrawn(sdp))
- goto out;
+ goto out_withdraw;
if (sdp->sd_log_head != sdp->sd_log_flush_head) {
log_flush_wait(sdp);
@@ -1000,7 +998,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
log_write_header(sdp, flags);
}
if (gfs2_withdrawn(sdp))
- goto out;
+ goto out_withdraw;
lops_after_commit(sdp, tr);
gfs2_log_lock(sdp);
@@ -1020,7 +1018,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (!sdp->sd_log_idle) {
empty_ail1_list(sdp);
if (gfs2_withdrawn(sdp))
- goto out;
+ goto out_withdraw;
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
trace_gfs2_log_blocks(sdp, -1);
log_write_header(sdp, flags);
@@ -1033,27 +1031,30 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
}
-out:
- if (gfs2_withdrawn(sdp)) {
- trans_drain(tr);
- /**
- * If the tr_list is empty, we're withdrawing during a log
- * flush that targets a transaction, but the transaction was
- * never queued onto any of the ail lists. Here we add it to
- * ail1 just so that ail_drain() will find and free it.
- */
- spin_lock(&sdp->sd_ail_lock);
- if (tr && list_empty(&tr->tr_list))
- list_add(&tr->tr_list, &sdp->sd_ail1_list);
- spin_unlock(&sdp->sd_ail_lock);
- ail_drain(sdp); /* frees all transactions */
- tr = NULL;
- }
-
+out_end:
trace_gfs2_log_flush(sdp, 0, flags);
+out:
up_write(&sdp->sd_log_flush_lock);
-
gfs2_trans_free(sdp, tr);
+ if (gfs2_withdrawing(sdp))
+ gfs2_withdraw(sdp);
+ return;
+
+out_withdraw:
+ trans_drain(tr);
+ /**
+ * If the tr_list is empty, we're withdrawing during a log
+ * flush that targets a transaction, but the transaction was
+ * never queued onto any of the ail lists. Here we add it to
+ * ail1 just so that ail_drain() will find and free it.
+ */
+ spin_lock(&sdp->sd_ail_lock);
+ if (tr && list_empty(&tr->tr_list))
+ list_add(&tr->tr_list, &sdp->sd_ail1_list);
+ spin_unlock(&sdp->sd_ail_lock);
+ ail_drain(sdp); /* frees all transactions */
+ tr = NULL;
+ goto out_end;
}
/**
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 9f4d9e7be839..19add2da1013 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -702,6 +702,8 @@ static void gfs2_put_super(struct super_block *sb)
if (error)
gfs2_io_error(sdp);
}
+ WARN_ON(gfs2_withdrawing(sdp));
+
/* At this point, we're through modifying the disk */
/* Release stuff */
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index 6d9157efe16c..d7562981b3a0 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -205,6 +205,16 @@ static inline bool gfs2_withdrawn(struct gfs2_sbd *sdp)
test_bit(SDF_WITHDRAWING, &sdp->sd_flags);
}
+/**
+ * gfs2_withdrawing - check if a withdraw is pending
+ * @sdp: the superblock
+ */
+static inline bool gfs2_withdrawing(struct gfs2_sbd *sdp)
+{
+ return test_bit(SDF_WITHDRAWING, &sdp->sd_flags) &&
+ !test_bit(SDF_WITHDRAWN, &sdp->sd_flags);
+}
+
#define gfs2_tune_get(sdp, field) \
gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
--
2.26.2
Hi,
please pick up the following patches for 5.4.
Those are build time optimizations for kernel/gen_kheaders.sh, and - by
removing bashisms - dropping the dependency to /bin/bash.
In addition, this enables build time improvements across the tree by optionally
allowing to use alternative implementations for various compression tools, e.g.
GZIP=pigz.
The documentation-only change is not strictly necessary, but keeps
kernel/gen_kheaders.sh in sync with mainline.
Cheers,
Matthias
Cc: Denis Efremov <efremov(a)linux.com>
Cc: Masahiro Yamada <yamada.masahiro(a)socionext.com>
Cc: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Denis Efremov (1):
kbuild: add variables for compression tools
Masahiro Yamada (5):
kheaders: remove unneeded 'cat' command piped to 'head' / 'tail'
kheaders: optimize md5sum calculation for in-tree builds
kheaders: optimize header copy for in-tree builds
kheaders: remove the last bashism to allow sh to run it
kheaders: explain why include/config/autoconf.h is excluded from
md5sum
Makefile | 25 +++++++++++-
arch/arm/boot/deflate_xip_data.sh | 2 +-
arch/ia64/Makefile | 2 +-
arch/m68k/Makefile | 8 ++--
arch/parisc/Makefile | 2 +-
kernel/Makefile | 2 +-
kernel/gen_kheaders.sh | 66 ++++++++++++++++++-------------
scripts/Makefile.lib | 12 +++---
scripts/Makefile.package | 8 ++--
scripts/package/buildtar | 6 +--
scripts/xz_wrap.sh | 2 +-
11 files changed, 83 insertions(+), 52 deletions(-)
--
2.28.0.297.g1956fa8f8d-goog
Tegra210/Tegra186/Tegra194 has incorrectly enabled
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK from the beginning of their support.
Tegra210 and later SDMMC hardware default uses sdmmc_legacy_tm (TMCLK)
all the time for hardware data timeout instead of SDCLK and this TMCLK
need to be kept enabled by Tegra sdmmc driver.
This series includes manual backport patches to fix this for stable
kernel #4.19
Sowjanya Komatineni (7):
sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra210
sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra186
dt-bindings: mmc: tegra: Add tmclk for Tegra210 and Tegra186
arm64: tegra: Add missing timeout clock to Tegra210 SDMMC
arm64: tegra: Add missing timeout clock to Tegra186 SDMMC nodes
arm64: tegra: Add missing timeout clock to Tegra194 SDMMC nodes
sdhci: tegra: Add missing TMCLK for data timeout
.../bindings/mmc/nvidia,tegra20-sdhci.txt | 23 +++++++++-
arch/arm64/boot/dts/nvidia/tegra186.dtsi | 20 +++++----
arch/arm64/boot/dts/nvidia/tegra194.dtsi | 15 ++++---
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 28 ++++++------
drivers/mmc/host/sdhci-tegra.c | 50 +++++++++++++++++++++-
5 files changed, 106 insertions(+), 30 deletions(-)
--
2.7.4
When EVM_ALLOW_METADATA_WRITES is set, EVM allows any operation on
metadata. Its main purpose is to allow users to freely set metadata when
they are protected by a portable signature, until the HMAC key is loaded.
However, IMA is not notified about metadata changes and, after the first
appraisal, always allows access to the files without checking metadata
again.
This patch checks in evm_reset_status() if EVM_ALLOW_METADATA WRITES is
enabled and if it is, sets the IMA_CHANGE_XATTR/ATTR bits depending on the
operation performed. At the next appraisal, metadata are revalidated.
This patch also adds a call to evm_reset_status() in
evm_inode_post_setattr() so that EVM won't return the cached status the
next time appraisal is performed.
Cc: stable(a)vger.kernel.org # 4.16.x
Fixes: ae1ba1676b88e ("EVM: Allow userland to permit modification of EVM-protected metadata")
Signed-off-by: Roberto Sassu <roberto.sassu(a)huawei.com>
---
security/integrity/evm/evm_main.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 41cc6a4aaaab..d4d918183094 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -478,13 +478,17 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
return evm_protect_xattr(dentry, xattr_name, NULL, 0);
}
-static void evm_reset_status(struct inode *inode)
+static void evm_reset_status(struct inode *inode, int bit)
{
struct integrity_iint_cache *iint;
iint = integrity_iint_find(inode);
- if (iint)
+ if (iint) {
+ if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
+ set_bit(bit, &iint->atomic_flags);
+
iint->evm_status = INTEGRITY_UNKNOWN;
+ }
}
/**
@@ -507,7 +511,7 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
&& !posix_xattr_acl(xattr_name)))
return;
- evm_reset_status(dentry->d_inode);
+ evm_reset_status(dentry->d_inode, IMA_CHANGE_XATTR);
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
@@ -527,7 +531,7 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
return;
- evm_reset_status(dentry->d_inode);
+ evm_reset_status(dentry->d_inode, IMA_CHANGE_XATTR);
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
@@ -600,6 +604,8 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
if (!evm_key_loaded())
return;
+ evm_reset_status(dentry->d_inode, IMA_CHANGE_ATTR);
+
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
}
--
2.17.1
From: Nick Desaulniers <ndesaulniers(a)google.com>
Basically, consider .text.{hot|unlikely|unknown}.* part of .text, too.
When compiling with profiling information (collected via PGO
instrumentations or AutoFDO sampling), Clang will separate code into
.text.hot, .text.unlikely, or .text.unknown sections based on profiling
information. After D79600 (clang-11), these sections will have a
trailing `.` suffix, ie. .text.hot., .text.unlikely., .text.unknown..
When using -ffunction-sections together with profiling infomation,
either explicitly (FGKASLR) or implicitly (LTO), code may be placed in
sections following the convention:
.text.hot.<foo>, .text.unlikely.<bar>, .text.unknown.<baz>
where <foo>, <bar>, and <baz> are functions. (This produces one section
per function; we generally try to merge these all back via linker script
so that we don't have 50k sections).
For the above cases, we need to teach our linker scripts that such
sections might exist and that we'd explicitly like them grouped
together, otherwise we can wind up with code outside of the
_stext/_etext boundaries that might not be mapped properly for some
architectures, resulting in boot failures.
If the linker script is not told about possible input sections, then
where the section is placed as output is a heuristic-laiden mess that's
non-portable between linkers (ie. BFD and LLD), and has resulted in many
hard to debug bugs. Kees Cook is working on cleaning this up by adding
--orphan-handling=warn linker flag used in ARCH=powerpc to additional
architectures. In the case of linker scripts, borrowing from the Zen of
Python: explicit is better than implicit.
Also, ld.bfd's internal linker script considers .text.hot AND
.text.hot.* to be part of .text, as well as .text.unlikely and
.text.unlikely.*. I didn't see support for .text.unknown.*, and didn't
see Clang producing such code in our kernel builds, but I see code in
LLVM that can produce such section names if profiling information is
missing. That may point to a larger issue with generating or collecting
profiles, but I would much rather be safe and explicit than have to
debug yet another issue related to orphan section placement.
Reported-by: Jian Cai <jiancai(a)google.com>
Suggested-by: Fāng-ruì Sòng <maskray(a)google.com>
Tested-by: Luis Lozano <llozano(a)google.com>
Tested-by: Manoj Gupta <manojgupta(a)google.com>
Acked-by: Kees Cook <keescook(a)chromium.org>
Cc: stable(a)vger.kernel.org
Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=add44f8d5c5c0…
Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=1de778ed23ce7…
Link: https://reviews.llvm.org/D79600
Link: https://bugs.chromium.org/p/chromium/issues/detail?id=1084760
Debugged-by: Luis Lozano <llozano(a)google.com>
Signed-off-by: Nick Desaulniers <ndesaulniers(a)google.com>
Signed-off-by: Kees Cook <keescook(a)chromium.org>
---
include/asm-generic/vmlinux.lds.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 98d013dcc11a..91dcfb91ac45 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -581,7 +581,10 @@
*/
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
- *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \
+ *(.text.hot .text.hot.*) \
+ *(TEXT_MAIN .text.fixup) \
+ *(.text.unlikely .text.unlikely.*) \
+ *(.text.unknown .text.unknown.*) \
NOINSTR_TEXT \
*(.text..refcount) \
*(.ref.text) \
--
2.25.1
In some architectural corner cases, AT instructions can generate an
exception, which KVM is not really ready to handle properly.
Teach the code to handle this situation gracefully.
This is a backport of the respective upstream patches to v5.8(.5).
James prepared and tested these already, but we were lacking the upstream
commit ID so far.
I am sending this on his behalf, since he is off this week.
The last two of the originally three patches were tagged Cc: stable
already, but 2/3 did not apply cleanly, hence this specific backport.
3/3 has already been added to stable-queue, so I am dropping it from
this post.
Cheers,
Andre.
James Morse (2):
KVM: arm64: Add kvm_extable for vaxoricism code
KVM: arm64: Survive synchronous exceptions caused by AT instructions
arch/arm64/include/asm/kvm_asm.h | 43 +++++++++++++++++++++
arch/arm64/kernel/vmlinux.lds.S | 8 ++++
arch/arm64/kvm/hyp/entry.S | 15 +++++---
arch/arm64/kvm/hyp/hyp-entry.S | 65 ++++++++++++++++++++------------
arch/arm64/kvm/hyp/switch.c | 39 +++++++++++++++++--
5 files changed, 136 insertions(+), 34 deletions(-)
--
2.17.1
When calling into hid_map_usage(), the passed event code is
blindly stored as is, even if it doesn't fit in the associated bitmap.
This event code can come from a variety of sources, including devices
masquerading as input devices, only a bit more "programmable".
Instead of taking the event code at face value, check that it actually
fits the corresponding bitmap, and if it doesn't:
- spit out a warning so that we know which device is acting up
- NULLify the bitmap pointer so that we catch unexpected uses
Code paths that can make use of untrusted inputs can now check
that the mapping was indeed correct and bail out if not.
Cc: stable(a)vger.kernel.org
Signed-off-by: Marc Zyngier <maz(a)kernel.org>
---
* From v3:
- Drop totally unrelated mfd/syscon change from the patch
* From v2:
- Don't prematurely narrow the event code so that hid_map_usage()
catches illegal values beyond the 16bit limit.
* From v1:
- Dropped the input.c changes, and turned hid_map_usage() into
the validation primitive.
- Handle mapping failures in hidinput_configure_usage() and
mt_touch_input_mapping() (on top of hid_map_usage_clear() which
was already handled)
drivers/hid/hid-input.c | 4 ++++
drivers/hid/hid-multitouch.c | 2 ++
include/linux/hid.h | 42 +++++++++++++++++++++++++-----------
3 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index b8eabf206e74..88e19996427e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
mapped:
+ /* Mapping failed, bail out */
+ if (!bit)
+ return;
+
if (device->driver->input_mapped &&
device->driver->input_mapped(device, hidinput, field, usage,
&bit, &max) < 0) {
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3f94b4954225..e3152155c4b8 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
+ if (!*bit)
+ return -1;
input_set_capability(hi->input, EV_KEY, code);
return 1;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 875f71132b14..c7044a14200e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) {
* @max: maximal valid usage->code to consider later (out parameter)
* @type: input event type (EV_KEY, EV_REL, ...)
* @c: code which corresponds to this usage and type
+ *
+ * The value pointed to by @bit will be set to NULL if either @type is
+ * an unhandled event type, or if @c is out of range for @type. This
+ * can be used as an error condition.
*/
static inline void hid_map_usage(struct hid_input *hidinput,
struct hid_usage *usage, unsigned long **bit, int *max,
- __u8 type, __u16 c)
+ __u8 type, unsigned int c)
{
struct input_dev *input = hidinput->input;
-
- usage->type = type;
- usage->code = c;
+ unsigned long *bmap = NULL;
+ unsigned int limit = 0;
switch (type) {
case EV_ABS:
- *bit = input->absbit;
- *max = ABS_MAX;
+ bmap = input->absbit;
+ limit = ABS_MAX;
break;
case EV_REL:
- *bit = input->relbit;
- *max = REL_MAX;
+ bmap = input->relbit;
+ limit = REL_MAX;
break;
case EV_KEY:
- *bit = input->keybit;
- *max = KEY_MAX;
+ bmap = input->keybit;
+ limit = KEY_MAX;
break;
case EV_LED:
- *bit = input->ledbit;
- *max = LED_MAX;
+ bmap = input->ledbit;
+ limit = LED_MAX;
break;
}
+
+ if (unlikely(c > limit || !bmap)) {
+ pr_warn_ratelimited("%s: Invalid code %d type %d\n",
+ input->name, c, type);
+ *bit = NULL;
+ return;
+ }
+
+ usage->type = type;
+ usage->code = c;
+ *max = limit;
+ *bit = bmap;
}
/**
@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
__u8 type, __u16 c)
{
hid_map_usage(hidinput, usage, bit, max, type, c);
- clear_bit(c, *bit);
+ if (*bit)
+ clear_bit(usage->code, *bit);
}
/**
--
2.27.0