3.18.119-stable review
Greg Kroah-Hartman
maintainerPATCH 2/15 root dentries need RCU-delayed freeing
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
commit 90bad5e05bcdb0308cfa3d3a60f5c0b9c8e2efb3 upstream.
Since mountpoint crossing can happen without leaving lazy mode, root dentries do need the same protection against having their memory freed without RCU delay as everything else in the tree.
It's partially hidden by RCU delay between detaching from the mount tree and dropping the vfsmount reference, but the starting point of pathwalk can be on an already detached mount, in which case umount-caused RCU delay has already passed by the time the lazy pathwalk grabs rcu_read_lock(). If the starting point happens to be at the root of that vfsmount *and* that vfsmount covers the entire filesystem, we get trouble.
--- fs/dcache.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/dcache.c +4 -2
@@ -1848,10 +1848,12 @@ struct dentry *d_make_root(struct inodestatic const struct qstr name =QSTR_INIT ("/" ,1 ); res =__d_alloc (root_inode->i_sb, &name); -if (res) +if (res) { + res->d_flags |=DCACHE_RCUACCESS ;d_instantiate (res, root_inode); -else + }else {iput (root_inode); + } }return res; }
Greg Kroah-Hartman
maintainerPATCH 4/15 fix __legitimize_mnt()/mntput() race
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
commit 119e1ef80ecfe0d1deb6378d4ab41f5b71519de1 upstream.
__legitimize_mnt() has two problems - one is that in case of success the check of mount_lock is not ordered wrt preceding increment of refcount, making it possible to have successful __legitimize_mnt() on one CPU just before the otherwise final mntpu() on another, with __legitimize_mnt() not seeing mntput() taking the lock and mntput() not seeing the increment done by __legitimize_mnt(). Solved by a pair of barriers.
Another is that failure of __legitimize_mnt() on the second read_seqretry() leaves us with reference that'll need to be dropped by caller; however, if that races with final mntput() we can end up with caller dropping rcu_read_lock() and doing mntput() to release that reference - with the first mntput() having freed the damn thing just as rcu_read_lock() had been dropped. Solution: in "do mntput() yourself" failure case grab mount_lock, check if MNT_DOOMED has been set by racing final mntput() that has missed our increment and if it has - undo the increment and treat that as "failure, caller doesn't need to drop anything" case.
It's not easy to hit - the final mntput() has to come right after the first read_seqretry() in __legitimize_mnt() *and* manage to miss the increment done by __legitimize_mnt() before the second read_seqretry() in there. The things that are almost impossible to hit on bare hardware are not impossible on SMP KVM, though...
--- fs/namespace.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
fs/namespace.c +14 -0
@@ -590,12 +590,21 @@ bool legitimize_mnt(struct vfsmount *basreturn true; mnt =real_mount (bastard);mnt_add_count (mnt,1 ); +smp_mb ();// see mntput_no_expire() if (likely (!read_seqretry (&mount_lock, seq)))return true;if (bastard->mnt_flags &MNT_SYNC_UMOUNT ) {mnt_add_count (mnt,-1 );return false; } +lock_mount_hash (); +if (unlikely (bastard->mnt_flags &MNT_DOOMED )) { +mnt_add_count (mnt,-1 ); +unlock_mount_hash (); +return true; + } +unlock_mount_hash (); +rcu_read_unlock ();mntput (bastard);rcu_read_lock ();
@@ -1064,6 +1073,11 @@ static void mntput_no_expire(struct mounreturn ; }lock_mount_hash (); +/* +* make sure that if __legitimize_mnt() has not seen us grab +* mount_lock, we'll see their refcount increment here. +*/ +smp_mb ();mnt_add_count (mnt,-1 );if (mnt_get_count (mnt)) {rcu_read_unlock ();
Greg Kroah-Hartman
maintainerPATCH 5/15 ARM: dts: imx6sx: fix irq for pcie bridge
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleksij Rempel <[email protected]>
commit 1bcfe0564044be578841744faea1c2f46adc8178 upstream.
Use the correct IRQ line for the MSI controller in the PCIe host controller. Apparently a different IRQ line is used compared to other i.MX6 variants. Without this change MSI IRQs aren't properly propagated to the upstream interrupt controller.
--- arch/arm/boot/dts/imx6sx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/imx6sx.dtsi +1 -1
@@ -1202,7 +1202,7 @@ /* non-prefetchable memory */ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; num-lanes = <1>; - interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, <&clks IMX6SX_CLK_PCIE_AXI>, <&clks IMX6SX_CLK_LVDS1_OUT>,
Greg Kroah-Hartman
maintainerPATCH 6/15 kprobes/x86: Fix %p uses in error messages
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <[email protected]>
commit 0ea063306eecf300fcf06d2f5917474b580f666f upstream.
Remove all %p uses in error messages in kprobes/x86.
--- arch/x86/kernel/kprobes/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/kprobes/core.c +1 -3
@@ -365,7 +365,6 @@ int __copy_instruction(u8 *dest, u8 *src newdisp = (u8 *) src + (s64 ) insn.displacement.value - (u8 *) dest;if ((s64 ) (s32 ) newdisp != newdisp) {pr_err ("Kprobes error: new displacement does not fit into s32 (%llx)\n" , newdisp); -pr_err ("\tSrc: %p, Dest: %p, old disp: %x\n" , src, dest, insn.displacement.value);return 0 ; } disp = (u8 *) dest +insn_offset_displacement (&insn);
@@ -568,8 +567,7 @@ static int reenter_kprobe(struct kprobe* Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */ -printk (KERN_WARNING "Unrecoverable kprobe detected at %p.\n" , - p->addr); +pr_err ("Unrecoverable kprobe detected.\n" );dump_kprobe (p);BUG ();default :
Greg Kroah-Hartman
maintainerPATCH 13/15 crypto: blkcipher - fix crash flushing dcache in error path
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 0868def3e4100591e7a1fdbf3eed1439cc8f7ca3 upstream.
Like the skcipher_walk case:
scatterwalk_done() is only meant to be called after a nonzero number of bytes have been processed, since scatterwalk_pagedone() will flush the dcache of the *previous* page. But in the error case of blkcipher_walk_done(), e.g. if the input wasn't an integer number of blocks, scatterwalk_done() was actually called after advancing 0 bytes. This caused a crash ("BUG: unable to handle kernel paging request") during '!PageSlab(page)' on architectures like arm and arm64 that define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, provided that the input was page-aligned as in that case walk->offset == 0.
Fix it by reorganizing blkcipher_walk_done() to skip the scatterwalk_advance() and scatterwalk_done() if an error has occurred.
This bug was found by syzkaller fuzzing.
Reproducer, assuming ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
struct sockaddr_alg addr = {
.salg_type = "skcipher",
.salg_name = "ecb(aes-generic)",
};
char buffer[4096] __attribute__((aligned(4096))) = { 0 };
int fd;
fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(fd, (void *)&addr, sizeof(addr));
setsockopt(fd, SOL_ALG, ALG_SET_KEY, buffer, 16);
fd = accept(fd, NULL, NULL);
write(fd, buffer, 15);
read(fd, buffer, 15);
}--- crypto/blkcipher.c | 54 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-)
crypto/blkcipher.c +26 -28
@@ -70,19 +70,18 @@ static inline u8 *blkcipher_get_spot(u8return max (start, end_page); } -static inline unsigned int blkcipher_done_slow (struct blkcipher_walk *walk, -unsigned int bsize) +static inline void blkcipher_done_slow (struct blkcipher_walk *walk, +unsigned int bsize) {u8 *addr; addr = (u8 *)ALIGN ((unsigned long )walk->buffer, walk->alignmask +1 ); addr =blkcipher_get_spot (addr, bsize);scatterwalk_copychunks (addr, &walk->out, bsize,1 ); -return bsize; } -static inline unsigned int blkcipher_done_fast (struct blkcipher_walk *walk, -unsigned int n) +static inline void blkcipher_done_fast (struct blkcipher_walk *walk, +unsigned int n) {if (walk->flags &BLKCIPHER_WALK_COPY ) {blkcipher_map_dst (walk);
@@ -96,49 +95,48 @@ static inline unsigned int blkcipher_donscatterwalk_advance (&walk->in, n);scatterwalk_advance (&walk->out, n); - -return n; }int blkcipher_walk_done (struct blkcipher_desc *desc,struct blkcipher_walk *walk,int err) { -unsigned int nbytes =0 ; +unsigned int n;/* bytes processed */ +bool more; -if (likely (err >=0 )) { -unsigned int n = walk->nbytes - err; +if (unlikely (err <0 )) + goto finish; -if (likely (!(walk->flags &BLKCIPHER_WALK_SLOW ))) - n =blkcipher_done_fast (walk, n); -else if (WARN_ON (err)) { + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total !=0 ); + +if (likely (!(walk->flags &BLKCIPHER_WALK_SLOW ))) { +blkcipher_done_fast (walk, n); + }else { +if (WARN_ON (err)) { +/* unexpected case; didn't process all bytes */ err = -EINVAL ; - goto err; - }else - n =blkcipher_done_slow (walk, n); - - nbytes = walk->total - n; - err =0 ; + goto finish; + } +blkcipher_done_slow (walk, n); } -scatterwalk_done (&walk->in,0 , nbytes); -scatterwalk_done (&walk->out,1 , nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; +scatterwalk_done (&walk->in,0 , more); +scatterwalk_done (&walk->out,1 , more); -if (nbytes) { +if (more) {crypto_yield (desc->flags);return blkcipher_walk_next (desc, walk); } - + err =0 ; +finish: + walk->nbytes =0 ;if (walk->iv != desc->info)memcpy (desc->info, walk->iv, walk->ivsize);if (walk->buffer != walk->page)kfree (walk->buffer);if (walk->page)free_page ((unsigned long )walk->page); -return err; }EXPORT_SYMBOL_GPL (blkcipher_walk_done);
Greg Kroah-Hartman
maintainerPATCH 14/15 crypto: ablkcipher - fix crash flushing dcache in error path
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 318abdfbe708aaaa652c79fb500e9bd60521f9dc upstream.
Like the skcipher_walk and blkcipher_walk cases:
scatterwalk_done() is only meant to be called after a nonzero number of bytes have been processed, since scatterwalk_pagedone() will flush the dcache of the *previous* page. But in the error case of ablkcipher_walk_done(), e.g. if the input wasn't an integer number of blocks, scatterwalk_done() was actually called after advancing 0 bytes. This caused a crash ("BUG: unable to handle kernel paging request") during '!PageSlab(page)' on architectures like arm and arm64 that define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, provided that the input was page-aligned as in that case walk->offset == 0.
Fix it by reorganizing ablkcipher_walk_done() to skip the scatterwalk_advance() and scatterwalk_done() if an error has occurred.
--- crypto/ablkcipher.c | 57 +++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 31 deletions(-)
crypto/ablkcipher.c +26 -31
@@ -72,11 +72,9 @@ static inline u8 *ablkcipher_get_spot(u8return max (start, end_page); } -static inline unsigned int ablkcipher_done_slow (struct ablkcipher_walk *walk, -unsigned int bsize) +static inline void ablkcipher_done_slow (struct ablkcipher_walk *walk, +unsigned int n) { -unsigned int n = bsize; -for (;;) {unsigned int len_this_page =scatterwalk_pagelen (&walk->out);
@@ -88,17 +86,13 @@ static inline unsigned int ablkcipher_do n -= len_this_page;scatterwalk_start (&walk->out,scatterwalk_sg_next (walk->out.sg)); } - -return bsize; } -static inline unsigned int ablkcipher_done_fast (struct ablkcipher_walk *walk, -unsigned int n) +static inline void ablkcipher_done_fast (struct ablkcipher_walk *walk, +unsigned int n) {scatterwalk_advance (&walk->in, n);scatterwalk_advance (&walk->out, n); - -return n; } static int ablkcipher_walk_next(struct ablkcipher_request *req,
@@ -108,39 +102,40 @@ int ablkcipher_walk_done(struct ablkciph struct ablkcipher_walk *walk, int err) {struct crypto_tfm *tfm = req->base.tfm; -unsigned int nbytes =0 ; +unsigned int n;/* bytes processed */ +bool more; -if (likely (err >=0 )) { -unsigned int n = walk->nbytes - err; +if (unlikely (err <0 )) + goto finish; -if (likely (!(walk->flags &ABLKCIPHER_WALK_SLOW ))) - n =ablkcipher_done_fast (walk, n); -else if (WARN_ON (err)) { + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total !=0 ); + +if (likely (!(walk->flags &ABLKCIPHER_WALK_SLOW ))) { +ablkcipher_done_fast (walk, n); + }else { +if (WARN_ON (err)) { +/* unexpected case; didn't process all bytes */ err = -EINVAL ; - goto err; - }else - n =ablkcipher_done_slow (walk, n); - - nbytes = walk->total - n; - err =0 ; + goto finish; + } +ablkcipher_done_slow (walk, n); } -scatterwalk_done (&walk->in,0 , nbytes); -scatterwalk_done (&walk->out,1 , nbytes); +scatterwalk_done (&walk->in,0 , more); +scatterwalk_done (&walk->out,1 , more); -err: - walk->total = nbytes; - walk->nbytes = nbytes; - -if (nbytes) { +if (more) {crypto_yield (req->base.flags);return ablkcipher_walk_next (req, walk); } - + err =0 ; +finish: + walk->nbytes =0 ;if (walk->iv != req->info)memcpy (req->info, walk->iv, tfm->crt_ablkcipher.ivsize);kfree (walk->iv_buffer); -return err; }EXPORT_SYMBOL_GPL (ablkcipher_walk_done);
Greg Kroah-Hartman
maintainerPATCH 15/15 Bluetooth: hidp: buffer overflow in hidp_process_report
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Salyzyn <[email protected]>
commit 7992c18810e568b95c869b227137a2215702a805 upstream.
CVE-2018-9363
The buffer length is unsigned at all layers, but gets cast to int and checked in hidp_process_report and can lead to a buffer overflow. Switch len parameter to unsigned int to resolve issue.
This affects 3.18 and newer kernels.
--- net/bluetooth/hidp/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/hidp/core.c +2 -2
@@ -416,8 +416,8 @@ static void hidp_del_timer(struct hidp_sdel_timer (&session->timer); } -static void hidp_process_report (struct hidp_session *session, -int type,const u8 *data,int len,int intr) +static void hidp_process_report (struct hidp_session *session,int type, +const u8 *data,unsigned int len,int intr) {if (len >HID_MAX_BUFFER_SIZE ) len =HID_MAX_BUFFER_SIZE ;
Greg Kroah-Hartman
maintainercover 3.18.119-stable review
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v3.x/stable-review/patch-3.18.119-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-3.18.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 3.18.119-rc1
Mark Salyzyn <[email protected]>
Bluetooth: hidp: buffer overflow in hidp_process_report
Eric Biggers <[email protected]>
crypto: ablkcipher - fix crash flushing dcache in error path
Eric Biggers <[email protected]>
crypto: blkcipher - fix crash flushing dcache in error path
Eric Biggers <[email protected]>
crypto: vmac - separate tfm and request context
Eric Biggers <[email protected]>
crypto: vmac - require a block cipher with 128-bit block size
Randy Dunlap <[email protected]>
kbuild: verify that $DEPMOD is installed
Liwei Song <[email protected]>
i2c: ismt: fix wrong device address when unmap the data buffer
Andrey Ryabinin <[email protected]>
mm: slub: fix format mismatches in slab_err() callers
Erick Reyes <[email protected]>
ALSA: info: Check for integer overflow in snd_info_entry_write()
Masami Hiramatsu <[email protected]>
kprobes/x86: Fix %p uses in error messages
Oleksij Rempel <[email protected]>
ARM: dts: imx6sx: fix irq for pcie bridge
Al Viro <[email protected]>
fix __legitimize_mnt()/mntput() race
Al Viro <[email protected]>
fix mntput/mntput race
Al Viro <[email protected]>
root dentries need RCU-delayed freeing
Juergen Gross <[email protected]>
xen/netfront: don't cache skb_shinfo()
-------------
Diffstat:
Documentation/Changes | 17 +- Makefile | 4 +- arch/arm/boot/dts/imx6sx.dtsi | 2 +- arch/x86/kernel/kprobes/core.c | 4 +- crypto/ablkcipher.c | 57 +++--- crypto/blkcipher.c | 54 +++--- crypto/vmac.c | 412 ++++++++++++++++++----------------------- drivers/i2c/busses/i2c-ismt.c | 2 +- drivers/net/xen-netfront.c | 8 +- fs/dcache.c | 6 +- fs/namespace.c | 28 ++- include/crypto/vmac.h | 63 ------- mm/slub.c | 6 +- net/bluetooth/hidp/core.c | 4 +- scripts/depmod.sh | 8 +- sound/core/info.c | 4 +- 16 files changed, 297 insertions(+), 382 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 1/15 xen/netfront: dont cache skb_shinfo()
3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Juergen Gross <[email protected]>
commit d472b3a6cf63cd31cae1ed61930f07e6cd6671b5 upstream.
skb_shinfo() can change when calling __pskb_pull_tail(): Don't cache its return value.
--- drivers/net/xen-netfront.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/xen-netfront.c +4 -4
@@ -903,7 +903,6 @@ static RING_IDX xennet_fill_frags(structstruct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = queue->rx.rsp_cons;struct sk_buff *nskb;
@@ -912,15 +911,16 @@ static RING_IDX xennet_fill_frags(structRING_GET_RESPONSE (&queue->rx, ++cons);skb_frag_t *nfrag = &skb_shinfo (nskb)->frags[0 ]; -if (shinfo->nr_frags ==MAX_SKB_FRAGS ) { +if (skb_shinfo (skb)->nr_frags ==MAX_SKB_FRAGS ) {unsigned int pull_to =NETFRONT_SKB_CB (skb)->pull_to;BUG_ON (pull_to <=skb_headlen (skb));__pskb_pull_tail (skb, pull_to -skb_headlen (skb)); } -BUG_ON (shinfo->nr_frags >=MAX_SKB_FRAGS ); +BUG_ON (skb_shinfo (skb)->nr_frags >=MAX_SKB_FRAGS ); -skb_add_rx_frag (skb, shinfo->nr_frags,skb_frag_page (nfrag), +skb_add_rx_frag (skb,skb_shinfo (skb)->nr_frags, +skb_frag_page (nfrag), rx->offset, rx->status,PAGE_SIZE );skb_shinfo (nskb)->nr_frags =0 ;
Greg Kroah-Hartman
maintainerPATCH 10/15 kbuild: verify that $DEPMOD is installed
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Randy Dunlap <[email protected]>
commit 934193a654c1f4d0643ddbf4b2529b508cae926e upstream.
Verify that 'depmod' ($DEPMOD) is installed. This is a partial revert of commit 620c231c7a7f ("kbuild: do not check for ancient modutils tools").
Also update Documentation/process/changes.rst to refer to kmod instead of module-init-tools.
Fixes kernel bugzilla #198965:
https://bugzilla.kernel.org/show_bug.cgi?id=198965
--- Documentation/Changes | 17 ++++++----------- scripts/depmod.sh | 8 +++++++- 2 files changed, 13 insertions(+), 12 deletions(-)
Documentation/Changes +6 -11
@@ -25,7 +25,7 @@ o Gnu C 3.2 o Gnu make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version -o module-init-tools 0.9.10 # depmod -V +o kmod 13 # depmod -V o e2fsprogs 1.41.4 # e2fsck -V o jfsutils 1.1.3 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V
@@ -119,12 +119,6 @@ is not build with CONFIG_KALLSYMS and yo reproduce the Oops with that option, then you can still decode that Oops with ksymoops. -Module-Init-Tools ------------------ - -A new module loader is now in the kernel that requires module-init-tools -to use. It is backward compatible with the 2.4.x series kernels. - Mkinitrd --------
@@ -302,14 +296,15 @@ Util-linux ---------- o <ftp://ftp.kernel.org/pub/linux/utils/util-linux/> +Kmod +---- +o <https://www.kernel.org/pub/linux/utils/kernel/kmod/> +o <https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git> + Ksymoops -------- o <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4/> -Module-Init-Tools ------------------ -o <ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/> - Mkinitrd -------- o <https://code.launchpad.net/initrd-tools/main>
scripts/depmod.sh +7 -1
@@ -10,10 +10,16 @@ DEPMOD=$1 KERNELRELEASE=$2 SYMBOL_PREFIX=$3 -if ! test -r System.map -a -x "$DEPMOD"; then +if ! test -r System.map ; then exit 0 fi +if [ -z $(command -v $DEPMOD) ]; then + echo "'make modules_install' requires $DEPMOD. Please install it." >&2 + echo "This is probably in the kmod package." >&2 + exit 1 +fi + # older versions of depmod don't support -P <symbol-prefix> # support was added in module-init-tools 3.13 if test -n "$SYMBOL_PREFIX"; then
Greg Kroah-Hartman
maintainerPATCH 11/15 crypto: vmac - require a block cipher with 128-bit block size
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 73bf20ef3df262026c3470241ae4ac8196943ffa upstream.
The VMAC template assumes the block cipher has a 128-bit block size, but it failed to check for that. Thus it was possible to instantiate it using a 64-bit block size cipher, e.g. "vmac(cast5)", causing uninitialized memory to be used.
Add the needed check when instantiating the template.
--- crypto/vmac.c | 4 ++++ 1 file changed, 4 insertions(+)
crypto/vmac.c +4 -0
@@ -655,6 +655,10 @@ static int vmac_create(struct crypto_temif (IS_ERR (alg))return PTR_ERR (alg); + err = -EINVAL ; +if (alg->cra_blocksize !=16 ) + goto out_put_alg; + inst =shash_alloc_instance ("vmac" , alg); err =PTR_ERR (inst);if (IS_ERR (inst))
Greg Kroah-Hartman
maintainerPATCH 12/15 crypto: vmac - separate tfm and request context
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit bb29648102335586e9a66289a1d98a0cb392b6e5 upstream.
syzbot reported a crash in vmac_final() when multiple threads concurrently use the same "vmac(aes)" transform through AF_ALG. The bug is pretty fundamental: the VMAC template doesn't separate per-request state from per-tfm (per-key) state like the other hash algorithms do, but rather stores it all in the tfm context. That's wrong.
Also, vmac_final() incorrectly zeroes most of the state including the derived keys and cached pseudorandom pad. Therefore, only the first VMAC invocation with a given key calculates the correct digest.
Fix these bugs by splitting the per-tfm state from the per-request state and using the proper init/update/final sequencing for requests.
Reproducer for the crash:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int fd;
struct sockaddr_alg addr = {
.salg_type = "hash",
.salg_name = "vmac(aes)",
};
char buf[256] = { 0 };
fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(fd, (void *)&addr, sizeof(addr));
setsockopt(fd, SOL_ALG, ALG_SET_KEY, buf, 16);
fork();
fd = accept(fd, NULL, NULL);
for (;;)
write(fd, buf, 256);
}The immediate cause of the crash is that vmac_ctx_t.partial_size exceeds VMAC_NHBYTES, causing vmac_final() to memset() a negative length.
--- crypto/vmac.c | 414 ++++++++++++++++++++++---------------------------- include/crypto/vmac.h | 63 ------- 2 files changed, 184 insertions(+), 293 deletions(-)
crypto/vmac.c +184 -230
@@ -1,6 +1,10 @@/* -* Modified to interface to the Linux kernel +* VMAC: Message Authentication Code using Universal Hashing +* +* Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01 +* * Copyright (c) 2009, Intel Corporation. +* Copyright (c) 2018, Google Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License,
@@ -16,14 +20,15 @@* Place - Suite 330, Boston, MA 02111-1307 USA. */ -/* -------------------------------------------------------------------------- -* VMAC and VHASH Implementation by Ted Krovetz ([email protected]) and Wei Dai. -* This implementation is herby placed in the public domain. -* The authors offers no warranty. Use at your own risk. -* Please send bug reports to the authors. -* Last modified: 17 APR 08, 1700 PDT -* ----------------------------------------------------------------------- */ +/* +* Derived from: +* VMAC and VHASH Implementation by Ted Krovetz ([email protected]) and Wei Dai. +* This implementation is herby placed in the public domain. +* The authors offers no warranty. Use at your own risk. +* Last modified: 17 APR 08, 1700 PDT +*/ +#include <asm/unaligned.h> #include <linux/init.h> #include <linux/types.h> #include <linux/crypto.h>
@@ -31,10 +36,36 @@#include <linux/scatterlist.h> #include <asm/byteorder.h> #include <crypto/scatterwalk.h> -#include <crypto/vmac.h> #include <crypto/internal/hash.h> /* +* User definable settings. +*/ +#define VMAC_TAG_LEN 64 +#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ +#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) +#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ + +/* per-transform (per-key) context */ +struct vmac_tfm_ctx { +struct crypto_cipher *cipher; +u64 nhkey[(VMAC_NHBYTES /8 )+2 *(VMAC_TAG_LEN /64 -1 )]; +u64 polykey[2 *VMAC_TAG_LEN /64 ]; +u64 l3key[2 *VMAC_TAG_LEN /64 ]; +}; + +/* per-request context */ +struct vmac_desc_ctx { +union { +u8 partial[VMAC_NHBYTES ];/* partial block */ +__le64 partial_words[VMAC_NHBYTES /8 ]; + }; +unsigned int partial_size;/* size of the partial block */ +bool first_block_processed; +u64 polytmp[2 *VMAC_TAG_LEN /64 ];/* running total of L2-hash */ +}; + +/* * Constants and masks */ #define UINT64_C (x) x##ULL
@@ -318,13 +349,6 @@ static void poly_step_func(u64 *ahi, u64 } while (0)#endif -static void vhash_abort (struct vmac_ctx *ctx) -{ - ctx->polytmp[0 ] = ctx->polykey[0 ] ; - ctx->polytmp[1 ] = ctx->polykey[1 ] ; - ctx->first_block_processed =0 ; -} -static u64 l3hash (u64 p1,u64 p2,u64 k1,u64 k2,u64 len) {u64 rh, rl, t, z =0 ;
@@ -364,280 +388,209 @@ static u64 l3hash(u64 p1, u64 p2, u64 k1return rl; } -static void vhash_update (const unsigned char *m, -unsigned int mbytes,/* Pos multiple of VMAC_NHBYTES */ -struct vmac_ctx *ctx) -{ -u64 rh, rl, *mptr; -const u64 *kptr = (u64 *)ctx->nhkey; -int i; -u64 ch, cl; -u64 pkh = ctx->polykey[0 ]; -u64 pkl = ctx->polykey[1 ]; - -if (!mbytes) -return ; - -BUG_ON (mbytes %VMAC_NHBYTES ); +/* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */ +static void vhash_blocks (const struct vmac_tfm_ctx *tctx, +struct vmac_desc_ctx *dctx, +const __le64 *mptr,unsigned int blocks) +{ +const u64 *kptr = tctx->nhkey; +const u64 pkh = tctx->polykey[0 ]; +const u64 pkl = tctx->polykey[1 ]; +u64 ch = dctx->polytmp[0 ]; +u64 cl = dctx->polytmp[1 ]; +u64 rh, rl; - mptr = (u64 *)m; - i = mbytes /VMAC_NHBYTES ;/* Must be non-zero */ - - ch = ctx->polytmp[0 ]; - cl = ctx->polytmp[1 ]; - -if (!ctx->first_block_processed) { - ctx->first_block_processed =1 ; +if (!dctx->first_block_processed) { + dctx->first_block_processed = true;nh_vmac_nhbytes (mptr, kptr,VMAC_NHBYTES /8 , rh, rl); rh &= m62;ADD128 (ch, cl, rh, rl); mptr += (VMAC_NHBYTES /sizeof (u64)); - i--; + blocks--; } -while (i--) { +while (blocks--) {nh_vmac_nhbytes (mptr, kptr,VMAC_NHBYTES /8 , rh, rl); rh &= m62;poly_step (ch, cl, pkh, pkl, rh, rl); mptr += (VMAC_NHBYTES /sizeof (u64)); } - ctx->polytmp[0 ] = ch; - ctx->polytmp[1 ] = cl; + dctx->polytmp[0 ] = ch; + dctx->polytmp[1 ] = cl; } -static u64 vhash (unsigned char m[],unsigned int mbytes, -u64 *tagl,struct vmac_ctx *ctx) +static int vmac_setkey (struct crypto_shash *tfm, +const u8 *key,unsigned int keylen) { -u64 rh, rl, *mptr; -const u64 *kptr = (u64 *)ctx->nhkey; -int i, remaining; -u64 ch, cl; -u64 pkh = ctx->polykey[0 ]; -u64 pkl = ctx->polykey[1 ]; - - mptr = (u64 *)m; - i = mbytes /VMAC_NHBYTES ; - remaining = mbytes %VMAC_NHBYTES ; - -if (ctx->first_block_processed) { - ch = ctx->polytmp[0 ]; - cl = ctx->polytmp[1 ]; - }else if (i) { -nh_vmac_nhbytes (mptr, kptr,VMAC_NHBYTES /8 , ch, cl); - ch &= m62; -ADD128 (ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES /sizeof (u64)); - i--; - }else if (remaining) { -nh_16 (mptr, kptr,2 *((remaining+15 )/16 ), ch, cl); - ch &= m62; -ADD128 (ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES /sizeof (u64)); - goto do_l3; - }else {/* Empty String */ - ch = pkh; cl = pkl; - goto do_l3; - } - -while (i--) { -nh_vmac_nhbytes (mptr, kptr,VMAC_NHBYTES /8 , rh, rl); - rh &= m62; -poly_step (ch, cl, pkh, pkl, rh, rl); - mptr += (VMAC_NHBYTES /sizeof (u64)); - } -if (remaining) { -nh_16 (mptr, kptr,2 *((remaining+15 )/16 ), rh, rl); - rh &= m62; -poly_step (ch, cl, pkh, pkl, rh, rl); - } - -do_l3: -vhash_abort (ctx); - remaining *=8 ; -return l3hash (ch, cl, ctx->l3key[0 ], ctx->l3key[1 ], remaining); -} - -static u64 vmac (unsigned char m[],unsigned int mbytes, -const unsigned char n[16 ],u64 *tagl, -struct vmac_ctx_t *ctx) -{ -u64 *in_n, *out_p; -u64 p, h; -int i; - - in_n = ctx->__vmac_ctx.cached_nonce; - out_p = ctx->__vmac_ctx.cached_aes; - - i = n[15 ] &1 ; -if ((*(u64 *)(n+8 ) != in_n[1 ]) || (*(u64 *)(n) != in_n[0 ])) { - in_n[0 ] = *(u64 *)(n); - in_n[1 ] = *(u64 *)(n+8 ); - ((unsigned char *)in_n)[15 ] &=0xFE ; -crypto_cipher_encrypt_one (ctx->child, - (unsigned char *)out_p, (unsigned char *)in_n); +struct vmac_tfm_ctx *tctx =crypto_shash_ctx (tfm); +__be64 out[2 ]; +u8 in[16 ] = {0 }; +unsigned int i; +int err; - ((unsigned char *)in_n)[15 ] |= (unsigned char )(1 -i); +if (keylen !=VMAC_KEY_LEN ) { +crypto_shash_set_flags (tfm,CRYPTO_TFM_RES_BAD_KEY_LEN ); +return -EINVAL ; } - p =be64_to_cpup (out_p + i); - h =vhash (m, mbytes, (u64 *)0 , &ctx->__vmac_ctx); -return le64_to_cpu (p + h); -} - -static int vmac_set_key (unsigned char user_key[],struct vmac_ctx_t *ctx) -{ -u64 in[2 ] = {0 }, out[2 ]; -unsigned i; -int err =0 ; - err =crypto_cipher_setkey (ctx->child, user_key,VMAC_KEY_LEN ); + err =crypto_cipher_setkey (tctx->cipher, key, keylen);if (err)return err;/* Fill nh key */ - ((unsigned char *)in)[0 ] =0x80 ; -for (i =0 ; i <sizeof (ctx->__vmac_ctx.nhkey)/8 ; i +=2 ) { -crypto_cipher_encrypt_one (ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.nhkey[i] =be64_to_cpup (out); - ctx->__vmac_ctx.nhkey[i+1 ] =be64_to_cpup (out+1 ); - ((unsigned char *)in)[15 ] +=1 ; + in[0 ] =0x80 ; +for (i =0 ; i <ARRAY_SIZE (tctx->nhkey); i +=2 ) { +crypto_cipher_encrypt_one (tctx->cipher, (u8 *)out, in); + tctx->nhkey[i] =be64_to_cpu (out[0 ]); + tctx->nhkey[i+1 ] =be64_to_cpu (out[1 ]); + in[15 ]++; }/* Fill poly key */ - ((unsigned char *)in)[0 ] =0xC0 ; - in[1 ] =0 ; -for (i =0 ; i <sizeof (ctx->__vmac_ctx.polykey)/8 ; i +=2 ) { -crypto_cipher_encrypt_one (ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.polytmp[i] = - ctx->__vmac_ctx.polykey[i] = -be64_to_cpup (out) & mpoly; - ctx->__vmac_ctx.polytmp[i+1 ] = - ctx->__vmac_ctx.polykey[i+1 ] = -be64_to_cpup (out+1 ) & mpoly; - ((unsigned char *)in)[15 ] +=1 ; + in[0 ] =0xC0 ; + in[15 ] =0 ; +for (i =0 ; i <ARRAY_SIZE (tctx->polykey); i +=2 ) { +crypto_cipher_encrypt_one (tctx->cipher, (u8 *)out, in); + tctx->polykey[i] =be64_to_cpu (out[0 ]) & mpoly; + tctx->polykey[i+1 ] =be64_to_cpu (out[1 ]) & mpoly; + in[15 ]++; }/* Fill ip key */ - ((unsigned char *)in)[0 ] =0xE0 ; - in[1 ] =0 ; -for (i =0 ; i <sizeof (ctx->__vmac_ctx.l3key)/8 ; i +=2 ) { + in[0 ] =0xE0 ; + in[15 ] =0 ; +for (i =0 ; i <ARRAY_SIZE (tctx->l3key); i +=2 ) {do { -crypto_cipher_encrypt_one (ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.l3key[i] =be64_to_cpup (out); - ctx->__vmac_ctx.l3key[i+1 ] =be64_to_cpup (out+1 ); - ((unsigned char *)in)[15 ] +=1 ; - }while (ctx->__vmac_ctx.l3key[i] >= p64 - || ctx->__vmac_ctx.l3key[i+1 ] >= p64); +crypto_cipher_encrypt_one (tctx->cipher, (u8 *)out, in); + tctx->l3key[i] =be64_to_cpu (out[0 ]); + tctx->l3key[i+1 ] =be64_to_cpu (out[1 ]); + in[15 ]++; + }while (tctx->l3key[i] >= p64 || tctx->l3key[i+1 ] >= p64); } -/* Invalidate nonce/aes cache and reset other elements */ - ctx->__vmac_ctx.cached_nonce[0 ] = (u64)-1 ;/* Ensure illegal nonce */ - ctx->__vmac_ctx.cached_nonce[1 ] = (u64 )0 ;/* Ensure illegal nonce */ - ctx->__vmac_ctx.first_block_processed =0 ; - -return err; +return 0 ; } -static int vmac_setkey (struct crypto_shash *parent, -const u8 *key,unsigned int keylen) +static int vmac_init (struct shash_desc *desc) { -struct vmac_ctx_t *ctx =crypto_shash_ctx (parent); +const struct vmac_tfm_ctx *tctx =crypto_shash_ctx (desc->tfm); +struct vmac_desc_ctx *dctx =shash_desc_ctx (desc); -if (keylen !=VMAC_KEY_LEN ) { -crypto_shash_set_flags (parent,CRYPTO_TFM_RES_BAD_KEY_LEN ); -return -EINVAL ; - } - -return vmac_set_key ((u8 *)key, ctx); -} - -static int vmac_init (struct shash_desc *pdesc) -{ + dctx->partial_size =0 ; + dctx->first_block_processed = false; +memcpy (dctx->polytmp, tctx->polykey,sizeof (dctx->polytmp));return 0 ; } -static int vmac_update (struct shash_desc *pdesc,const u8 *p, -unsigned int len) +static int vmac_update (struct shash_desc *desc,const u8 *p,unsigned int len) { -struct crypto_shash *parent = pdesc->tfm; -struct vmac_ctx_t *ctx =crypto_shash_ctx (parent); -int expand; -int min; - - expand =VMAC_NHBYTES - ctx->partial_size >0 ? -VMAC_NHBYTES - ctx->partial_size :0 ; - - min = len < expand ? len : expand; - -memcpy (ctx->partial + ctx->partial_size, p, min); - ctx->partial_size += min; - -if (len < expand) -return 0 ; - -vhash_update (ctx->partial,VMAC_NHBYTES , &ctx->__vmac_ctx); - ctx->partial_size =0 ; - - len -= expand; - p += expand; - -if (len %VMAC_NHBYTES ) { -memcpy (ctx->partial, p + len - (len %VMAC_NHBYTES ), - len %VMAC_NHBYTES ); - ctx->partial_size = len %VMAC_NHBYTES ; +const struct vmac_tfm_ctx *tctx =crypto_shash_ctx (desc->tfm); +struct vmac_desc_ctx *dctx =shash_desc_ctx (desc); +unsigned int n; + +if (dctx->partial_size) { + n =min (len,VMAC_NHBYTES - dctx->partial_size); +memcpy (&dctx->partial[dctx->partial_size], p, n); + dctx->partial_size += n; + p += n; + len -= n; +if (dctx->partial_size ==VMAC_NHBYTES ) { +vhash_blocks (tctx, dctx, dctx->partial_words,1 ); + dctx->partial_size =0 ; + } + } + +if (len >=VMAC_NHBYTES ) { + n =round_down (len,VMAC_NHBYTES ); +/* TODO: 'p' may be misaligned here */ +vhash_blocks (tctx, dctx, (const __le64 *)p, n /VMAC_NHBYTES ); + p += n; + len -= n; + } + +if (len) { +memcpy (dctx->partial, p, len); + dctx->partial_size = len; } -vhash_update (p, len - len %VMAC_NHBYTES , &ctx->__vmac_ctx); -return 0 ; } -static int vmac_final (struct shash_desc *pdesc,u8 *out) +static u64 vhash_final (const struct vmac_tfm_ctx *tctx, +struct vmac_desc_ctx *dctx) { -struct crypto_shash *parent = pdesc->tfm; -struct vmac_ctx_t *ctx =crypto_shash_ctx (parent); -vmac_t mac; -u8 nonce[16 ] = {}; - -/* vmac() ends up accessing outside the array bounds that -* we specify. In appears to access up to the next 2-word -* boundary. We'll just be uber cautious and zero the -* unwritten bytes in the buffer. -*/ -if (ctx->partial_size) { -memset (ctx->partial + ctx->partial_size,0 , -VMAC_NHBYTES - ctx->partial_size); - } - mac =vmac (ctx->partial, ctx->partial_size, nonce,NULL , ctx); -memcpy (out, &mac,sizeof (vmac_t)); -memzero_explicit (&mac,sizeof (vmac_t)); -memset (&ctx->__vmac_ctx,0 ,sizeof (struct vmac_ctx )); - ctx->partial_size =0 ; +unsigned int partial = dctx->partial_size; +u64 ch = dctx->polytmp[0 ]; +u64 cl = dctx->polytmp[1 ]; + +/* L1 and L2-hash the final block if needed */ +if (partial) { +/* Zero-pad to next 128-bit boundary */ +unsigned int n =round_up (partial,16 ); +u64 rh, rl; + +memset (&dctx->partial[partial],0 , n - partial); +nh_16 (dctx->partial_words, tctx->nhkey, n /8 , rh, rl); + rh &= m62; +if (dctx->first_block_processed) +poly_step (ch, cl, tctx->polykey[0 ], tctx->polykey[1 ], + rh, rl); +else +ADD128 (ch, cl, rh, rl); + } + +/* L3-hash the 128-bit output of L2-hash */ +return l3hash (ch, cl, tctx->l3key[0 ], tctx->l3key[1 ], partial *8 ); +} + +static int vmac_final (struct shash_desc *desc,u8 *out) +{ +const struct vmac_tfm_ctx *tctx =crypto_shash_ctx (desc->tfm); +struct vmac_desc_ctx *dctx =shash_desc_ctx (desc); +static const u8 nonce[16 ] = {};/* TODO: this is insecure */ +union { +u8 bytes[16 ]; +__be64 pads[2 ]; + } block; +int index; +u64 hash, pad; + +/* Finish calculating the VHASH of the message */ + hash =vhash_final (tctx, dctx); + +/* Generate pseudorandom pad by encrypting the nonce */ +memcpy (&block, nonce,16 ); + index = block.bytes[15 ] &1 ; + block.bytes[15 ] &= ~1 ; +crypto_cipher_encrypt_one (tctx->cipher, block.bytes, block.bytes); + pad =be64_to_cpu (block.pads[index]); + +/* The VMAC is the sum of VHASH and the pseudorandom pad */ +put_unaligned_le64 (hash + pad, out);return 0 ; }static int vmac_init_tfm (struct crypto_tfm *tfm) { -struct crypto_cipher *cipher; -struct crypto_instance *inst = (void *)tfm->__crt_alg; +struct crypto_instance *inst =crypto_tfm_alg_instance (tfm);struct crypto_spawn *spawn =crypto_instance_ctx (inst); -struct vmac_ctx_t *ctx =crypto_tfm_ctx (tfm); +struct vmac_tfm_ctx *tctx =crypto_tfm_ctx (tfm); +struct crypto_cipher *cipher; cipher =crypto_spawn_cipher (spawn);if (IS_ERR (cipher))return PTR_ERR (cipher); - ctx->child = cipher; + tctx->cipher = cipher;return 0 ; }static void vmac_exit_tfm (struct crypto_tfm *tfm) { -struct vmac_ctx_t *ctx =crypto_tfm_ctx (tfm); -crypto_free_cipher (ctx->child); +struct vmac_tfm_ctx *tctx =crypto_tfm_ctx (tfm); + +crypto_free_cipher (tctx->cipher); }static int vmac_create (struct crypto_template *tmpl,struct rtattr **tb)
@@ -674,11 +627,12 @@ static int vmac_create(struct crypto_tem inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; - inst->alg.digestsize =sizeof (vmac_t); - inst->alg.base.cra_ctxsize =sizeof (struct vmac_ctx_t ); + inst->alg.base.cra_ctxsize =sizeof (struct vmac_tfm_ctx ); inst->alg.base.cra_init = vmac_init_tfm; inst->alg.base.cra_exit = vmac_exit_tfm; + inst->alg.descsize =sizeof (struct vmac_desc_ctx ); + inst->alg.digestsize =VMAC_TAG_LEN /8 ; inst->alg.init = vmac_init; inst->alg.update = vmac_update; inst->alg.final = vmac_final;
include/crypto/vmac.h deleted +0 -63
63 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 3/15 fix mntput/mntput race
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
commit 9ea0a46ca2c318fcc449c1e6b62a7230a17888f1 upstream.
mntput_no_expire() does the calculation of total refcount under mount_lock; unfortunately, the decrement (as well as all increments) are done outside of it, leading to false positives in the "are we dropping the last reference" test. Consider the following situation:
* mnt is a lazy-umounted mount, kept alive by two opened files. One
of those files gets closed. Total refcount of mnt is 2. On CPU 42 mntput(mnt) (called from __fput()) drops one reference, decrementing component
* After it has looked at component #0, the process on CPU 0 doesmntget(), incrementing component #0, gets preempted and gets to run again - on CPU 69. There it does mntput(), which drops the reference (component #69) and proceeds to spin on mount_lock.
* On CPU 42 our first mntput() finishes counting. It observes the
decrement of component #69, but not the increment of component #0. As the result, the total it gets is not 1 as it should've been - it's 0. At which point we decide that vfsmount needs to be killed and proceed to free it and shut the filesystem down. However, there's still another opened file on that filesystem, with reference to (now freed) vfsmount, etc. and we are screwed.
It's not a wide race, but it can be reproduced with artificial slowdown of the mnt_get_count() loop, and it should be easier to hit on SMP KVM setups.
Fix consists of moving the refcount decrement under mount_lock; the tricky part is that we want (and can) keep the fast case (i.e. mount that still has non-NULL ->mnt_ns) entirely out of mount_lock. All places that zero mnt->mnt_ns are dropping some reference to mnt and they call synchronize_rcu() before that mntput(). IOW, if mntput() observes (under rcu_read_lock()) a non-NULL ->mnt_ns, it is guaranteed that there is another reference yet to be dropped.
--- fs/namespace.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/namespace.c +12 -2
@@ -1049,12 +1049,22 @@ static DECLARE_DELAYED_WORK(delayed_mntpstatic void mntput_no_expire (struct mount *mnt) {rcu_read_lock (); -mnt_add_count (mnt,-1 ); -if (likely (mnt->mnt_ns)) {/* shouldn't be the last one */ +if (likely (READ_ONCE (mnt->mnt_ns))) { +/* +* Since we don't do lock_mount_hash() here, +* ->mnt_ns can change under us. However, if it's +* non-NULL, then there's a reference that won't +* be dropped until after an RCU delay done after +* turning ->mnt_ns NULL. So if we observe it +* non-NULL under rcu_read_lock(), the reference +* we are dropping is not the final one. +*/ +mnt_add_count (mnt,-1 );rcu_read_unlock ();return ; }lock_mount_hash (); +mnt_add_count (mnt,-1 );if (mnt_get_count (mnt)) {rcu_read_unlock ();unlock_mount_hash ();
Greg Kroah-Hartman
maintainerPATCH 7/15 ALSA: info: Check for integer overflow in snd_info_entry_write()
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erick Reyes <[email protected]>
Commit 4adb7bcbcb69 ("ALSA: core: Use seq_file for text proc file reads") heavily refactored ALSA procfs and fixed the overflow as a side-effect, so this fix only applies to kernels < 4.2 and there is no upstream equivalent
snd_info_entry_write() resizes the buffer with an unsigned long size argument that gets truncated because resize_info_buffer() takes the size parameter as an unsigned int. On 64-bit kernels, this causes the following copy_to_user() to write out-of-bounds if (pos + count) can't be represented by an unsigned int.
--- sound/core/info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/core/info.c +3 -1
@@ -253,6 +253,7 @@ static ssize_t snd_info_entry_write(strustruct snd_info_buffer *buf;ssize_t size =0 ;loff_t pos; +unsigned long realloc_size; data = file->private_data;if (snd_BUG_ON (!data))
@@ -261,7 +262,8 @@ static ssize_t snd_info_entry_write(stru pos = *offset;if (pos <0 || (long ) pos != pos || (ssize_t ) count <0 )return -EIO ; -if ((unsigned long ) pos + (unsigned long ) count < (unsigned long ) pos) + realloc_size = (unsigned long ) pos + (unsigned long ) count; +if (realloc_size < (unsigned long ) pos || realloc_size >UINT_MAX )return -EIO ;switch (entry->content) {case SNDRV_INFO_CONTENT_TEXT :
Greg Kroah-Hartman
maintainerPATCH 8/15 mm: slub: fix format mismatches in slab_err() callers
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrey Ryabinin <[email protected]>
commit f6edde9cbe0634e4391b6e421a609ca3f57f6c38 upstream.
Adding __printf(3, 4) to slab_err exposed following:
mm/slub.c: In function `check_slab':
mm/slub.c:852:4: warning: format %u' expects argument of type unsigned int', but argument 4 has type `const char *' [-Wformat=]
s->name, page->objects, maxobj);
^
mm/slub.c:852:4: warning: too many arguments for format [-Wformat-extra-args]
mm/slub.c:857:4: warning: format `%u' expects argument of type `unsigned int', but argument 4 has type `const char *' [-Wformat=]
s->name, page->inuse, page->objects);
^ mm/slub.c:857:4: warning: too many arguments for format [-Wformat-extra-args]
mm/slub.c: In function `on_freelist':
mm/slub.c:905:4: warning: format %d' expects argument of type int', but argument 5 has type `long unsigned int' [-Wformat=]
"should be %d", page->objects, max_objects);
Fix first two warnings by removing redundant s->name.
Fix the last by changing type of max_object from unsigned long to int.
--- mm/slub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
mm/slub.c +3 -3
@@ -849,12 +849,12 @@ static int check_slab(struct kmem_cache maxobj =order_objects (compound_order (page), s->size, s->reserved);if (page->objects > maxobj) {slab_err (s, page,"objects %u > max %u" , - s->name, page->objects, maxobj); + page->objects, maxobj);return 0 ; }if (page->inuse > page->objects) {slab_err (s, page,"inuse %u > max %u" , - s->name, page->inuse, page->objects); + page->inuse, page->objects);return 0 ; }/* Slab_pad_check fixes things up after itself */
@@ -871,7 +871,7 @@ static int on_freelist(struct kmem_cacheint nr =0 ;void *fp;void *object =NULL ; -unsigned long max_objects; +int max_objects; fp = page->freelist;while (fp && nr <= page->objects) {
Greg Kroah-Hartman
maintainerPATCH 9/15 i2c: ismt: fix wrong device address when unmap the data buffer
In reply to Greg Kroah-Hartman3.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liwei Song <[email protected]>
commit 17e83549e199d89aace7788a9f11c108671eecf5 upstream.
Fix the following kernel bug:
kernel BUG at drivers/iommu/intel-iommu.c:3260!
invalid opcode: 0000 [#5] PREEMPT SMP
Hardware name: Intel Corp. Harcuvar/Server, BIOS HAVLCRB0.X64.0013.D39.1608311820 08/31/2016 task: ffff880175389950 ti: ffff880176bec000 task.ti: ffff880176bec000 RIP: 0010:[<ffffffff8150a83b>] [<ffffffff8150a83b>] intel_unmap+0x25b/0x260 RSP: 0018:ffff880176bef5e8 EFLAGS: 00010296 RAX: 0000000000000024 RBX: ffff8800773c7c88 RCX: 000000000000ce04 RDX: 0000000080000000 RSI: 0000000000000000 RDI: 0000000000000009 RBP: ffff880176bef638 R08: 0000000000000010 R09: 0000000000000004 R10: ffff880175389c78 R11: 0000000000000a4f R12: ffff8800773c7868 R13: 00000000ffffac88 R14: ffff8800773c7818 R15: 0000000000000001 FS: 00007fef21258700(0000) GS:ffff88017b5c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000066d6d8 CR3: 000000007118c000 CR4: 00000000003406e0 Stack: 00000000ffffac88 ffffffff8199867f ffff880176bef5f8 ffff880100000030 ffff880176bef668 ffff8800773c7c88 ffff880178288098 ffff8800772c0010 ffff8800773c7818 0000000000000001 ffff880176bef648 ffffffff8150a86e Call Trace: [<ffffffff8199867f>] ? printk+0x46/0x48 [<ffffffff8150a86e>] intel_unmap_page+0xe/0x10 [<ffffffffa039d99b>] ismt_access+0x27b/0x8fa [i2c_ismt] [<ffffffff81554420>] ? __pm_runtime_suspend+0xa0/0xa0 [<ffffffff815544a0>] ? pm_suspend_timer_fn+0x80/0x80 [<ffffffff81554420>] ? __pm_runtime_suspend+0xa0/0xa0 [<ffffffff815544a0>] ? pm_suspend_timer_fn+0x80/0x80 [<ffffffff8143dfd0>] ? pci_bus_read_dev_vendor_id+0xf0/0xf0 [<ffffffff8172b36c>] i2c_smbus_xfer+0xec/0x4b0 [<ffffffff810aa4d5>] ? vprintk_emit+0x345/0x530 [<ffffffffa038936b>] i2cdev_ioctl_smbus+0x12b/0x240 [i2c_dev] [<ffffffff810aa829>] ? vprintk_default+0x29/0x40 [<ffffffffa0389b33>] i2cdev_ioctl+0x63/0x1ec [i2c_dev] [<ffffffff811b04c8>] do_vfs_ioctl+0x328/0x5d0 [<ffffffff8119d8ec>] ? vfs_write+0x11c/0x190 [<ffffffff8109d449>] ? rt_up_read+0x19/0x20 [<ffffffff811b07f1>] SyS_ioctl+0x81/0xa0 [<ffffffff819a351b>] system_call_fastpath+0x16/0x6e
This happen When run "i2cdetect -y 0" detect SMBus iSMT adapter.
After finished I2C block read/write, when unmap the data buffer, a wrong device address was pass to dma_unmap_single().
To fix this, give dma_unmap_single() the "dev" parameter, just like what dma_map_single() does, then unmap can find the right devices.
--- drivers/i2c/busses/i2c-ismt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-ismt.c +1 -1
@@ -587,7 +587,7 @@ static int ismt_access(struct i2c_adapte/* unmap the data buffer */ if (dma_size !=0 ) -dma_unmap_single (&adap->dev, dma_addr, dma_size, dma_direction); +dma_unmap_single (dev, dma_addr, dma_size, dma_direction);if (unlikely (!ret)) {dev_err (dev,"completion wait timed out\n" );
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v3.x/stable-review/patch-3.18.119-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-3.18.y
and the diffstat can be found below.thanks,
greg k-h
Merged, compiled with -Werror, and installed onto my Pixel XL.
No initial issues noticed in dmesg or general usage.
Thanks!
Nathan
Greg Kroah-Hartman
maintainerQuoted 15 lines · Nathan Chancellor
Quoted 14 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v3.x/stable-review/patch-3.18.119-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-3.18.y
and the diffstat can be found below.
Quoted 8 lines
Quoted 4 lines
thanks,
greg k-h
Merged, compiled with -Werror, and installed onto my Pixel XL.
No initial issues noticed in dmesg or general usage.
Thanks for testing two of these and letting me know.
greg k-h
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
Quoted 6 lines
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v3.x/stable-review/patch-3.18.119-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git
linux-3.18.y
and the diffstat can be found below.
Merged cleanly and compiled with -Werror, All good on the OnePlus 3T. Thanks for the update!
Signature · 1 line
Harsh Shandilya, PRJKT Development LLC
Greg Kroah-Hartman
maintainerQuoted 9 lines · Harsh 'Shandilya
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
Quoted 7 lines
Quoted 6 lines
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v3.x/stable-review/patch-3.18.119-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git
linux-3.18.y
and the diffstat can be found below.Merged cleanly and compiled with -Werror, All good on the OnePlus 3T. Thanks for the update!
Wonderful, thanks for testing and letting me know.
greg k-h
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 3.18.119 release. There are 15 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Aug 18 17:16:20 UTC 2018. Anything received after that time might be too late.
Build results:
total: 138 pass: 138 fail: 0 Qemu test results: total: 207 pass: 207 fail: 0
Details are available at http://kerneltests.org/builders/.
Guenter