3.16.61-rc1 review
Subsystems (10)
PATCH 151/366 MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tokunori Ikegami <[email protected]>
commit 2a027b47dba6b77ab8c8e47b589ae9bbc5ac6175 upstream.
The erratum and workaround are described by BCM5300X-ES300-RDS.pdf as below.
R10: PCIe Transactions Periodically Fail
Description: The BCM5300X PCIe does not maintain transaction ordering.
This may cause PCIe transaction failure.
Fix Comment: Add a dummy PCIe configuration read after a PCIe
configuration write to ensure PCIe configuration access ordering. Set ES bit of CP0 configu7 register to enable sync function so that the sync instruction is functional.
Resolution: hndpci.c: extpci_write_config()
hndmips.c: si_mips_init()
mipsinc.h CONF7_ES
This is fixed by the CFE MIPS bcmsi chipset driver also for BCM47XX. Also the dummy PCIe configuration read is already implemented in the Linux BCMA driver.
Enable ExternalSync in Config7 when CONFIG_BCMA_DRIVER_PCI_HOSTMODE=y too so that the sync instruction is externalised.
Patchwork: https://patchwork.linux-mips.org/patch/19461/
--- arch/mips/bcm47xx/setup.c | 6 ++++++ arch/mips/include/asm/mipsregs.h | 3 +++ 2 files changed, 9 insertions(+)
arch/mips/bcm47xx/setup.c +6 -0
@@ -253,6 +253,12 @@ static int __init bcm47xx_cpu_fixes(void*/ if (bcm47xx_bus.bcma.bus.chipinfo.id ==BCMA_CHIP_ID_BCM4706 ) cpu_wait =NULL ; + +/* +* BCM47XX Erratum "R10: PCIe Transactions Periodically Fail" +* Enable ExternalSync for sync instruction to take effect +*/ +set_c0_config7 (MIPS_CONF7_ES );break ;#endif }
arch/mips/include/asm/mipsregs.h +3 -0
@@ -674,6 +674,8 @@#define MIPS_CONF7_WII (_ULCAST_(1) << 31)#define MIPS_CONF7_RPS (_ULCAST_(1) << 2) +/* ExternalSync */ +#define MIPS_CONF7_ES (_ULCAST_(1) << 8)#define MIPS_CONF7_IAR (_ULCAST_(1) << 10)#define MIPS_CONF7_AR (_ULCAST_(1) << 16)
@@ -1817,6 +1819,7 @@ __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) +__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap)
Re: [PATCH 3.16 151/366] MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum
Quoted 1 line · Ben Hutchings
3.16.61-rc1 review patch. If anyone has any objections, please let me know.
Nack. This patch has caused a regression and had to be reverted. Please check upstream repository for a revert (search git log for 2a027b47dba6).
Re: [PATCH 3.16 151/366] MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum
Quoted 6 lines · Rafał Miłecki
Quoted 1 line · Ben Hutchings
3.16.61-rc1 review patch. If anyone has any objections, please let me know.
Nack. This patch has caused a regression and had to be reverted. Please check upstream repository for a revert (search git log for
2a027b47dba6).
I've dropped this from the queue, thanks.
Ben.
Signature · 3 lines
Ben Hutchings Time is nature's way of making sure that everything doesn't happen at once.
PATCH 152/366 mtd: rawnand: mxc: set spare area size register explicitly
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
commit 3f77f244d8ec28e3a0a81240ffac7d626390060c upstream.
The v21 version of the NAND flash controller contains a Spare Area Size Register (SPAS) at offset 0x10. Its setting defaults to the maximum spare area size of 218 bytes. The size that is set in this register is used by the controller when it calculates the ECC bytes internally in hardware.
Usually, this register is updated from settings in the IIM fuses when the system is booting from NAND flash. For other boot media, however, the SPAS register remains at the default setting, which may not work for the particular flash chip on the board. The same goes for flash chips whose configuration cannot be set in the IIM fuses (e.g. chips with 2k sector size and 128 bytes spare area size can't be configured in the IIM fuses on imx25 systems).
Set the SPAS register explicitly during the preset operation. Derive the register value from mtd->oobsize that was detected during probe by decoding the flash chip's ID bytes.
While at it, rename the define for the spare area register's offset to NFC_V21_RSLTSPARE_AREA. The register at offset 0x10 on v1 controllers is different from the register on v21 controllers.
--- drivers/mtd/nand/mxc_nand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mtd/nand/mxc_nand.c +4 -1
@@ -49,7 +49,7 @@#define NFC_V1_V2_CONFIG (host->regs + 0x0a)#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e) -#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10) +#define NFC_V21_RSLTSPARE_AREA (host->regs + 0x10)#define NFC_V1_V2_WRPROT (host->regs + 0x12)#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
@@ -958,6 +958,9 @@ static void preset_v2(struct mtd_info *mwritew (config1,NFC_V1_V2_CONFIG1 );/* preset operation */ +/* spare area size in 16-bit half-words */ +writew (mtd->oobsize /2 ,NFC_V21_RSLTSPARE_AREA ); +/* Unlock the internal RAM Buffer */ writew (0x2 ,NFC_V1_V2_CONFIG );
PATCH 153/366 powerpc/e500mc: Set assembler machine type to e500mc
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Michael Jeanson <[email protected]>
commit 69a8405999aa1c489de4b8d349468f0c2b83f093 upstream.
In binutils 2.26 a new opcode for the "wait" instruction was added for the POWER9 and has precedence over the one specific to the e500mc. Commit ebf714ff3756 ("powerpc/e500mc: Add support for the wait instruction in e500_idle") uses this instruction specifically on the e500mc to work around an erratum.
This results in an invalid instruction in idle_e500 when we build for the e500mc on bintutils >= 2.26 with the default assembler machine type.
Since multiplatform between e500 and non-e500 is not supported, set the assembler machine type globaly when CONFIG_PPC_E500MC=y.
--- arch/powerpc/Makefile | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/Makefile +1 -0
@@ -205,6 +205,7 @@ endif cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_ALTIVEC) += -Wa,-maltivec cpu-as-$(CONFIG_E200) += -Wa,-me200 +cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc) KBUILD_AFLAGS += $(cpu-as-y) KBUILD_CFLAGS += $(cpu-as-y)
PATCH 154/366 xfrm_user: prevent leaking 2 bytes of kernel memory
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 45c180bc29babbedd6b8c01b975780ef44d9d09c upstream.
struct xfrm_userpolicy_type has two holes, so we should not use C99 style initializer.
KMSAN report:
BUG: KMSAN: kernel-infoleak in copyout lib/iov_iter.c:140 [inline] BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x1b14/0x2800 lib/iov_iter.c:571 CPU: 1 PID: 4520 Comm: syz-executor841 Not tainted 4.17.0+ #5 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:113 kmsan_report+0x188/0x2a0 mm/kmsan/kmsan.c:1117 kmsan_internal_check_memory+0x138/0x1f0 mm/kmsan/kmsan.c:1211 kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1253 copyout lib/iov_iter.c:140 [inline] _copy_to_iter+0x1b14/0x2800 lib/iov_iter.c:571 copy_to_iter include/linux/uio.h:106 [inline] skb_copy_datagram_iter+0x422/0xfa0 net/core/datagram.c:431 skb_copy_datagram_msg include/linux/skbuff.h:3268 [inline] netlink_recvmsg+0x6f1/0x1900 net/netlink/af_netlink.c:1959 sock_recvmsg_nosec net/socket.c:802 [inline] sock_recvmsg+0x1d6/0x230 net/socket.c:809 ___sys_recvmsg+0x3fe/0x810 net/socket.c:2279 __sys_recvmmsg+0x58e/0xe30 net/socket.c:2391 do_sys_recvmmsg+0x2a6/0x3e0 net/socket.c:2472 __do_sys_recvmmsg net/socket.c:2485 [inline] __se_sys_recvmmsg net/socket.c:2481 [inline] __x64_sys_recvmmsg+0x15d/0x1c0 net/socket.c:2481 do_syscall_64+0x15b/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x446ce9 RSP: 002b:00007fc307918db8 EFLAGS: 00000293 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000006dbc24 RCX: 0000000000446ce9 RDX: 000000000000000a RSI: 0000000020005040 RDI: 0000000000000003 RBP: 00000000006dbc20 R08: 0000000020004e40 R09: 0000000000000000 R10: 0000000040000000 R11: 0000000000000293 R12: 0000000000000000 R13: 00007ffc8d2df32f R14: 00007fc3079199c0 R15: 0000000000000001
Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_save_stack mm/kmsan/kmsan.c:294 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:685 kmsan_memcpy_origins+0x11d/0x170 mm/kmsan/kmsan.c:527 __msan_memcpy+0x109/0x160 mm/kmsan/kmsan_instr.c:413 __nla_put lib/nlattr.c:569 [inline] nla_put+0x276/0x340 lib/nlattr.c:627 copy_to_user_policy_type net/xfrm/xfrm_user.c:1678 [inline] dump_one_policy+0xbe1/0x1090 net/xfrm/xfrm_user.c:1708 xfrm_policy_walk+0x45a/0xd00 net/xfrm/xfrm_policy.c:1013 xfrm_dump_policy+0x1c0/0x2a0 net/xfrm/xfrm_user.c:1749 netlink_dump+0x9b5/0x1550 net/netlink/af_netlink.c:2226 __netlink_dump_start+0x1131/0x1270 net/netlink/af_netlink.c:2323 netlink_dump_start include/linux/netlink.h:214 [inline] xfrm_user_rcv_msg+0x8a3/0x9b0 net/xfrm/xfrm_user.c:2577 netlink_rcv_skb+0x37e/0x600 net/netlink/af_netlink.c:2448 xfrm_netlink_rcv+0xb2/0xf0 net/xfrm/xfrm_user.c:2598 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1680/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec8/0x1320 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x15b/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Local variable description: ----upt.i@dump_one_policy Variable was created at: dump_one_policy+0x78/0x1090 net/xfrm/xfrm_user.c:1689 xfrm_policy_walk+0x45a/0xd00 net/xfrm/xfrm_policy.c:1013
Byte 130 of 137 is uninitialized
Memory access starts at ffff88019550407f
--- net/xfrm/xfrm_user.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/xfrm/xfrm_user.c +5 -3
@@ -1515,9 +1515,11 @@ static inline size_t userpolicy_type_att#ifdef CONFIG_XFRM_SUB_POLICY static int copy_to_user_policy_type (u8 type,struct sk_buff *skb) { -struct xfrm_userpolicy_type upt = { - .type = type, - }; +struct xfrm_userpolicy_type upt; + +/* Sadly there are two holes in struct xfrm_userpolicy_type */ +memset (&upt,0 ,sizeof (upt)); + upt.type = type;return nla_put (skb,XFRMA_POLICY_TYPE ,sizeof (upt), &upt); }
PATCH 155/366 scsi: target: Fix truncated PR-in ReadKeys response
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Disseldorp <[email protected]>
commit 63ce3c384db26494615e3c8972bcd419ed71f4c4 upstream.
SPC5r17 states that the contents of the ADDITIONAL LENGTH field are not altered based on the allocation length, so always calculate and pack the full key list length even if the list itself is truncated.
According to Maged:
Yes it fixes the "Storage Spaces Persistent Reservation" test in the Windows 2016 Server Failover Cluster validation suites when having many connections that result in more than 8 registrations. I tested your patch on 4.17 with iblock.
This behaviour can be tested using the libiscsi PrinReadKeys.Truncate test.
--- drivers/target/target_core_pr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/target/target_core_pr.c +10 -12
@@ -3726,18 +3726,16 @@ core_scsi3_pri_read_keys(struct se_cmd ** Check for overflow of 8byte PRI READ_KEYS payload and * next reservation key list descriptor. */ -if ((add_len +8 ) > (cmd->data_length -8 )) -break ; - - buf[off++] = ((pr_reg->pr_res_key >>56 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>48 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>40 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>32 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>24 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>16 ) &0xff ); - buf[off++] = ((pr_reg->pr_res_key >>8 ) &0xff ); - buf[off++] = (pr_reg->pr_res_key &0xff ); - +if (off +8 <= cmd->data_length) { +put_unaligned_be64 (pr_reg->pr_res_key, &buf[off]); + off +=8 ; + } +/* +* SPC5r17: 6.16.2 READ KEYS service action +* The ADDITIONAL LENGTH field indicates the number of bytes in +* the Reservation key list. The contents of the ADDITIONAL +* LENGTH field are not altered based on the allocation length +*/ add_len +=8 ; }spin_unlock (&dev->t10_pr.registration_lock);
PATCH 156/366 MIPS: io: Add barrier after register read in inX()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit 18f3e95b90b28318ef35910d21c39908de672331 upstream.
While a barrier is present in the outX() functions before the register write, a similar barrier is missing in the inX() functions after the register read. This could allow memory accesses following inX() to observe stale data.
This patch is very similar to commit a1cc7034e33d12dc1 ("MIPS: io: Add barrier after register read in readX()"). Because war_io_reorder_wmb() is both used by writeX() and outX(), if readX() need a barrier then so does inX().
Patchwork: https://patchwork.linux-mips.org/patch/19516/
--- arch/mips/include/asm/io.h | 2 ++ 1 file changed, 2 insertions(+)
arch/mips/include/asm/io.h +2 -0
@@ -410,6 +410,8 @@ static inline type pfx##in##bwlq##p(unsi __val = *__addr; \ slow; \ \ +/* prevent prefetching of coherent DMA data prematurely */ \ +rmb (); \ return pfx##ioswab##bwlq(__addr, __val); \ }
PATCH 157/366 udf: Detect incorrect directory size
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit fa65653e575fbd958bdf5fb9c4a71a324e39510d upstream.
Detect when a directory entry is (possibly partially) beyond directory size and return EIO in that case since it means the filesystem is corrupted. Otherwise directory operations can further corrupt the directory and possibly also oops the kernel.
--- fs/udf/directory.c | 3 +++ 1 file changed, 3 insertions(+)
fs/udf/directory.c +3 -0
@@ -151,6 +151,9 @@ struct fileIdentDesc *udf_fileident_read sizeof(struct fileIdentDesc)); } } +/* Got last entry outside of dir size - fs is corrupted! */ +if (*nf_pos > dir->i_size) +return NULL ;return fi; }
PATCH 158/366 x86: Call fixup_exception() before notify_die() in math_error()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Siarhei Liakh <[email protected]>
commit 3ae6295ccb7cf6d344908209701badbbbb503e40 upstream.
fpu__drop() has an explicit fwait which under some conditions can trigger a fixable FPU exception while in kernel. Thus, we should attempt to fixup the exception first, and only call notify_die() if the fixup failed just like in do_general_protection(). The original call sequence incorrectly triggers KDB entry on debug kernels under particular FPU-intensive workloads.
Andy noted, that this makes the whole conditional irq enable thing even more inconsistent, but fixing that it outside the scope of this.
--- arch/x86/kernel/traps.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
arch/x86/kernel/traps.c +8 -6
@@ -556,17 +556,19 @@ static void math_error(struct pt_regs *rchar *str = (trapnr ==X86_TRAP_MF ) ?"fpu exception" :"simd exception" ; -if (notify_die (DIE_TRAP , str, regs, error_code, trapnr,SIGFPE ) ==NOTIFY_STOP ) -return ;conditional_sti (regs);if (!user_mode_vm (regs)) { -if (!fixup_exception (regs)) { - task->thread.error_code = error_code; - task->thread.trap_nr = trapnr; +if (fixup_exception (regs)) +return ; + + task->thread.error_code = error_code; + task->thread.trap_nr = trapnr; + +if (notify_die (DIE_TRAP , str, regs, error_code, + trapnr,SIGFPE ) !=NOTIFY_STOP )die (str, regs, error_code); - }return ; }
PATCH 159/366 x86/speculation: Fix up array_index_nospec_mask() asm constraint
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Williams <[email protected]>
commit be3233fbfcb8f5acb6e3bcd0895c3ef9e100d470 upstream.
Allow the compiler to handle @size as an immediate value or memory directly rather than allocating a register.
--- arch/x86/include/asm/barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/barrier.h +1 -1
@@ -40,7 +40,7 @@ static inline unsigned long array_index_ asm ("cmp %1,%2; sbb %0,%0;" :"=r" (mask) - :"r" (size),"r" (index) + :"g" (size),"r" (index) :"cc" );return mask; }
PATCH 160/366 x86/spectre_v1: Disable compiler optimizations over array_index_mask_nospec()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Williams <[email protected]>
commit eab6870fee877258122a042bfd99ee7908c40280 upstream.
Mark Rutland noticed that GCC optimization passes have the potential to elide necessary invocations of the array_index_mask_nospec() instruction sequence, so mark the asm() volatile.
Mark explains:
"The volatile will inhibit *some* cases where the compiler could lift the
array_index_nospec() call out of a branch, e.g. where there are multiple invocations of array_index_nospec() with the same arguments:
if (idx < foo) {
idx1 = array_idx_nospec(idx, foo)
do_something(idx1);
}
< some other code >
if (idx < foo) {
idx2 = array_idx_nospec(idx, foo);
do_something_else(idx2);
}... since the compiler can determine that the two invocations yield the same result, and reuse the first result (likely the same register as idx was in originally) for the second branch, effectively re-writing the above as:
if (idx < foo) {
idx = array_idx_nospec(idx, foo);
do_something(idx);
}
< some other code >
if (idx < foo) {
do_something_else(idx);
}... if we don't take the first branch, then speculatively take the second, we lose the nospec protection.
There's more info on volatile asm in the GCC docs:
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
"
--- arch/x86/include/asm/barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/barrier.h +1 -1
@@ -38,7 +38,7 @@ static inline unsigned long array_index_ {unsigned long mask; - asm ("cmp %1,%2; sbb %0,%0;" + asmvolatile ("cmp %1,%2; sbb %0,%0;" :"=r" (mask) :"g" (size),"r" (index) :"cc" );
PATCH 161/366 mtd: cfi_cmdset_0002: Use right chip in do_ppb_xxlock()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Joakim Tjernlund <[email protected]>
commit f93aa8c4de307069c270b2d81741961162bead6c upstream.
do_ppb_xxlock() fails to add chip->start when querying for lock status (and chip_ready test), which caused false status reports. Fix that by adding adr += chip->start and adjust call sites accordingly.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +5 -4
@@ -2224,8 +2224,9 @@ static int __maybe_unused do_ppb_xxlock(unsigned long timeo;int ret; + adr += chip->start;mutex_lock (&chip->mutex); - ret =get_chip (map, chip, adr + chip->start,FL_LOCKING ); + ret =get_chip (map, chip, adr,FL_LOCKING );if (ret) {mutex_unlock (&chip->mutex);return ret;
@@ -2243,8 +2244,8 @@ static int __maybe_unused do_ppb_xxlock(if (thunk ==DO_XXLOCK_ONEBLOCK_LOCK ) { chip->state =FL_LOCKING ; -map_write (map,CMD (0xA0 ), chip->start + adr); -map_write (map,CMD (0x00 ), chip->start + adr); +map_write (map,CMD (0xA0 ), adr); +map_write (map,CMD (0x00 ), adr); }else if (thunk ==DO_XXLOCK_ONEBLOCK_UNLOCK ) {/* * Unlocking of one specific sector is not supported, so we
@@ -2282,7 +2283,7 @@ static int __maybe_unused do_ppb_xxlock(map_write (map,CMD (0x00 ), chip->start); chip->state =FL_READY ; -put_chip (map, chip, adr + chip->start); +put_chip (map, chip, adr);mutex_unlock (&chip->mutex);return ret;
PATCH 162/366 mtd: cfi_cmdset_0002: fix SEGV unlocking multiple chips
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Joakim Tjernlund <[email protected]>
commit 5fdfc3dbad099281bf027a353d5786c09408a8e5 upstream.
cfi_ppb_unlock() tries to relock all sectors that were locked before unlocking the whole chip.
This locking used the chip start address + the FULL offset from the first flash chip, thereby forming an illegal address. Fix that by using the chip offset(adr).
--- drivers/mtd/chips/cfi_cmdset_0002.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +3 -3
@@ -2206,7 +2206,7 @@ static int cfi_atmel_unlock(struct mtd_istruct ppb_lock {struct flchip *chip; -loff_t offset; +unsigned long adr;int locked; };
@@ -2342,7 +2342,7 @@ static int __maybe_unused cfi_ppb_unlock*/ if ((adr < ofs) || (adr >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; - sect[sectors].offset = offset; + sect[sectors].adr = adr; sect[sectors].locked =do_ppb_xxlock ( map, &cfi->chips[chipnum], adr,0 ,DO_XXLOCK_ONEBLOCK_GETLOCK );
@@ -2386,7 +2386,7 @@ static int __maybe_unused cfi_ppb_unlock*/ for (i =0 ; i < sectors; i++) {if (sect[i].locked) -do_ppb_xxlock (map, sect[i].chip, sect[i].offset,0 , +do_ppb_xxlock (map, sect[i].chip, sect[i].adr,0 ,DO_XXLOCK_ONEBLOCK_LOCK ); }
PATCH 163/366 xen-netfront: fix locking in connect error path
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Vrabel <[email protected]>
commit db8c8ab61a28d7e3eb86d247b342a853263262c3 upstream.
If no queues could be created when connecting to the backend, one of the error paths would deadlock.
--- drivers/net/xen-netfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/xen-netfront.c +1 -1
@@ -2000,7 +2000,7 @@ abort_transaction_no_dev_fatal: info->queues =NULL ;rtnl_lock ();netif_set_real_num_tx_queues (info->netdev,0 ); -rtnl_lock (); +rtnl_unlock (); out:return err; }
PATCH 164/366 xen-netfront: release per-queue Tx and Rx resource when disconnecting
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Vrabel <[email protected]>
commit a5b5dc3ce4df4f05f4d81c7d3c56a7604b242093 upstream.
Since netfront may reconnect to a backend with a different number of queues, all per-queue Rx and Tx resources (skbs and grant references) should be freed when disconnecting.
Without this fix, the Tx and Rx grant refs are not released and netfront will exhaust them after only a few reconnections. netfront will fail to connect when no free grant references are available.
Since all Rx bufs are freed and reallocated instead of reused this will add some additional delay to the reconnection but this is expected to be small compared to the time taken by any backend hotplug scripts etc.
--- drivers/net/xen-netfront.c | 68 ++++---------------------------------- 1 file changed, 7 insertions(+), 61 deletions(-)
drivers/net/xen-netfront.c +7 -61
@@ -1194,22 +1194,6 @@ static void xennet_release_rx_bufs(strucspin_unlock_bh (&queue->rx_lock); } -static void xennet_uninit (struct net_device *dev) -{ -struct netfront_info *np =netdev_priv (dev); -unsigned int num_queues = dev->real_num_tx_queues; -struct netfront_queue *queue; -unsigned int i; - -for (i =0 ; i < num_queues; ++i) { - queue = &np->queues[i]; -xennet_release_tx_bufs (queue); -xennet_release_rx_bufs (queue); -gnttab_free_grant_references (queue->gref_tx_head); -gnttab_free_grant_references (queue->gref_rx_head); - } -} -static netdev_features_t xennet_fix_features (struct net_device *dev,netdev_features_t features) {
@@ -1311,7 +1295,6 @@ static void xennet_poll_controller(strucstatic const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, - .ndo_uninit = xennet_uninit, .ndo_stop = xennet_close, .ndo_start_xmit = xennet_start_xmit, .ndo_change_mtu = xennet_change_mtu,
@@ -1454,6 +1437,11 @@ static void xennet_disconnect_backend(stif (netif_running (info->netdev))napi_synchronize (&queue->napi); +xennet_release_tx_bufs (queue); +xennet_release_rx_bufs (queue); +gnttab_free_grant_references (queue->gref_tx_head); +gnttab_free_grant_references (queue->gref_rx_head); +/* End access and free the pages */ xennet_end_access (queue->tx_ring_ref, queue->tx.sring);xennet_end_access (queue->rx_ring_ref, queue->rx.sring);
@@ -2009,10 +1997,7 @@ static int xennet_connect(struct net_dev {struct netfront_info *np =netdev_priv (dev);unsigned int num_queues =0 ; -int i, requeue_idx, err; -struct sk_buff *skb; -grant_ref_t ref; -struct xen_netif_rx_request *req; +int err;unsigned int feature_rx_copy;unsigned int j =0 ;struct netfront_queue *queue =NULL ;
@@ -2039,47 +2024,8 @@ static int xennet_connect(struct net_devnetdev_update_features (dev);rtnl_unlock (); -/* By now, the queue structures have been set up */ -for (j =0 ; j < num_queues; ++j) { - queue = &np->queues[j]; - -/* Step 1: Discard all pending TX packet fragments. */ -spin_lock_irq (&queue->tx_lock); -xennet_release_tx_bufs (queue); -spin_unlock_irq (&queue->tx_lock); - -/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ -spin_lock_bh (&queue->rx_lock); - -for (requeue_idx =0 , i =0 ; i <NET_RX_RING_SIZE ; i++) { -skb_frag_t *frag; -const struct page *page; -if (!queue->rx_skbs[i]) -continue ; - - skb = queue->rx_skbs[requeue_idx] =xennet_get_rx_skb (queue, i); - ref = queue->grant_rx_ref[requeue_idx] =xennet_get_rx_ref (queue, i); - req =RING_GET_REQUEST (&queue->rx, requeue_idx); - - frag = &skb_shinfo (skb)->frags[0 ]; - page =skb_frag_page (frag); -gnttab_grant_foreign_access_ref ( - ref, queue->info->xbdev->otherend_id, -pfn_to_mfn (page_to_pfn (page)), -0 ); - req->gref = ref; - req->id = requeue_idx; - - requeue_idx++; - } - - queue->rx.req_prod_pvt = requeue_idx; - -spin_unlock_bh (&queue->rx_lock); - } -/* -* Step 3: All public and private state should now be sane. Get +* All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver * domain a kick because we've probably just requeued some * packets.
PATCH 165/366 xen-netfront: use different locks for Rx and Tx stats
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Vrabel <[email protected]>
commit 900e183301b54f8ca17a86d9835e9569090d182a upstream.
In netfront the Rx and Tx path are independent and use different locks. The Tx lock is held with hard irqs disabled, but Rx lock is held with only BH disabled. Since both sides use the same stats lock, a deadlock may occur.
[ INFO: possible irq lock inversion dependency detected ] 3.16.2 #16 Not tainted
---------------------------------------------------------
swapper/0/0 just changed the state of lock:
(&(&queue->tx_lock)->rlock){-.....}, at: [<c03adec8>]
xennet_tx_interrupt+0x14/0x34
but this lock took another, HARDIRQ-unsafe lock in the past:
(&stat->syncp.seq#2){+.-...}
and interrupts could create inverse lock ordering between them.
other info that might help us debug this:
Possible interrupt unsafe locking scenario: CPU0 CPU1
---- ----
lock(&stat->syncp.seq#2);
local_irq_disable();
lock(&(&queue->tx_lock)->rlock);
lock(&stat->syncp.seq#2);
<Interrupt>
lock(&(&queue->tx_lock)->rlock);Using separate locks for the Rx and Tx stats fixes this deadlock.
--- drivers/net/xen-netfront.c | 71 ++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 29 deletions(-)
drivers/net/xen-netfront.c +42 -29
@@ -86,10 +86,8 @@ struct netfront_cb {#define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)struct netfront_stats { -u64 rx_packets; -u64 tx_packets; -u64 rx_bytes; -u64 tx_bytes; +u64 packets; +u64 bytes;struct u64_stats_sync syncp; };
@@ -165,7 +163,8 @@ struct netfront_info {struct netfront_queue *queues;/* Statistics */ -struct netfront_stats __percpu *stats; +struct netfront_stats __percpu *rx_stats; +struct netfront_stats __percpu *tx_stats;atomic_t rx_gso_checksum_fixup; };
@@ -588,7 +587,7 @@ static int xennet_start_xmit(struct sk_b {unsigned short id;struct netfront_info *np =netdev_priv (dev); -struct netfront_stats *stats =this_cpu_ptr (np->stats); +struct netfront_stats *tx_stats =this_cpu_ptr (np->tx_stats);struct xen_netif_tx_request *tx;char *data = skb->data;RING_IDX i;
@@ -695,10 +694,10 @@ static int xennet_start_xmit(struct sk_bif (notify)notify_remote_via_irq (queue->tx_irq); -u64_stats_update_begin (&stats->syncp); - stats->tx_bytes += skb->len; - stats->tx_packets++; -u64_stats_update_end (&stats->syncp); +u64_stats_update_begin (&tx_stats->syncp); + tx_stats->bytes += skb->len; + tx_stats->packets++; +u64_stats_update_end (&tx_stats->syncp);/* Note: It is not safe to access skb after xennet_tx_buf_gc()! */ xennet_tx_buf_gc (queue);
@@ -954,7 +953,7 @@ static int checksum_setup(struct net_devstatic int handle_incoming_queue (struct netfront_queue *queue,struct sk_buff_head *rxq) { -struct netfront_stats *stats =this_cpu_ptr (queue->info->stats); +struct netfront_stats *rx_stats =this_cpu_ptr (queue->info->rx_stats);int packets_dropped =0 ;struct sk_buff *skb;
@@ -975,10 +974,10 @@ static int handle_incoming_queue(structcontinue ; } -u64_stats_update_begin (&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; -u64_stats_update_end (&stats->syncp); +u64_stats_update_begin (&rx_stats->syncp); + rx_stats->packets++; + rx_stats->bytes += skb->len; +u64_stats_update_end (&rx_stats->syncp);/* Pass it up. */ napi_gro_receive (&queue->napi, skb);
@@ -1113,18 +1112,22 @@ static struct rtnl_link_stats64 *xennet_int cpu;for_each_possible_cpu (cpu) { -struct netfront_stats *stats =per_cpu_ptr (np->stats, cpu); +struct netfront_stats *rx_stats =per_cpu_ptr (np->rx_stats, cpu); +struct netfront_stats *tx_stats =per_cpu_ptr (np->tx_stats, cpu);u64 rx_packets, rx_bytes, tx_packets, tx_bytes;unsigned int start;do { - start =u64_stats_fetch_begin_irq (&stats->syncp); + start =u64_stats_fetch_begin_irq (&tx_stats->syncp); + tx_packets = tx_stats->packets; + tx_bytes = tx_stats->bytes; + }while (u64_stats_fetch_retry_irq (&tx_stats->syncp, start)); - rx_packets = stats->rx_packets; - tx_packets = stats->tx_packets; - rx_bytes = stats->rx_bytes; - tx_bytes = stats->tx_bytes; - }while (u64_stats_fetch_retry_irq (&stats->syncp, start)); +do { + start =u64_stats_fetch_begin_irq (&rx_stats->syncp); + rx_packets = rx_stats->packets; + rx_bytes = rx_stats->bytes; + }while (u64_stats_fetch_retry_irq (&rx_stats->syncp, start)); tot->rx_packets += rx_packets; tot->tx_packets += tx_packets;
@@ -1309,6 +1312,15 @@ static const struct net_device_ops xenne#endif }; +static void xennet_free_netdev (struct net_device *netdev) +{ +struct netfront_info *np =netdev_priv (netdev); + +free_percpu (np->rx_stats); +free_percpu (np->tx_stats); +free_netdev (netdev); +} +static struct net_device *xennet_create_dev (struct xenbus_device *dev) {int err;
@@ -1329,8 +1341,11 @@ static struct net_device *xennet_create_ np->queues =NULL ; err = -ENOMEM ; - np->stats = netdev_alloc_pcpu_stats(struct netfront_stats); -if (np->stats ==NULL ) + np->rx_stats = netdev_alloc_pcpu_stats(struct netfront_stats); +if (np->rx_stats ==NULL ) + goto exit; + np->tx_stats = netdev_alloc_pcpu_stats(struct netfront_stats); +if (np->tx_stats ==NULL ) goto exit; netdev->netdev_ops = &xennet_netdev_ops;
@@ -1359,7 +1374,7 @@ static struct net_device *xennet_create_return netdev; exit: -free_netdev (netdev); +xennet_free_netdev (netdev);return ERR_PTR (err); }
@@ -1401,7 +1416,7 @@ static int netfront_probe(struct xenbus_return 0 ; fail: -free_netdev (netdev); +xennet_free_netdev (netdev);dev_set_drvdata (&dev->dev,NULL );return err; }
@@ -2322,9 +2337,7 @@ static int xennet_remove(struct xenbus_d info->queues =NULL ; } -free_percpu (info->stats); - -free_netdev (info->netdev); +xennet_free_netdev (info->netdev);return 0 ; }
PATCH 166/366 xen-netfront: Use static attribute groups for sysfs entries
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 27b917e54bed7156c2b0249969ace34a5f585626 upstream.
Instead of manual calls of device_create_file() and device_remove_files(), assign the static attribute groups to netdev groups array. This simplifies the code and avoids the possible races.
--- drivers/net/xen-netfront.c | 62 ++++++++++---------------------------- 1 file changed, 16 insertions(+), 46 deletions(-)
drivers/net/xen-netfront.c +16 -46
@@ -228,11 +228,7 @@ static grant_ref_t xennet_get_rx_ref(str }#ifdef CONFIG_SYSFS -static int xennet_sysfs_addif (struct net_device *netdev); -static void xennet_sysfs_delif (struct net_device *netdev); -#else /* !CONFIG_SYSFS */ -#define xennet_sysfs_addif (dev) (0) -#define xennet_sysfs_delif (dev) do { } while (0) +static const struct attribute_group xennet_dev_group;#endif static bool xennet_can_sg (struct net_device *dev)
@@ -1399,20 +1395,15 @@ static int netfront_probe(struct xenbus_ info =netdev_priv (netdev);dev_set_drvdata (&dev->dev, info); - +#ifdef CONFIG_SYSFS + info->netdev->sysfs_groups[0 ] = &xennet_dev_group; +#endif err =register_netdev (info->netdev);if (err) {pr_warn ("%s: register_netdev err=%d\n" , __func__, err); goto fail; } - err =xennet_sysfs_addif (info->netdev); -if (err) { -unregister_netdev (info->netdev); -pr_warn ("%s: add sysfs failed err=%d\n" , __func__, err); - goto fail; - } -return 0 ; fail:
@@ -2278,39 +2269,20 @@ static ssize_t show_rxbuf_cur(struct devreturn sprintf (buf,"0\n" ); } -static struct device_attribute xennet_attrs[] = { -__ATTR (rxbuf_min,S_IRUGO |S_IWUSR , show_rxbuf_min, store_rxbuf_min), -__ATTR (rxbuf_max,S_IRUGO |S_IWUSR , show_rxbuf_max, store_rxbuf_max), -__ATTR (rxbuf_cur,S_IRUGO , show_rxbuf_cur,NULL ), +static DEVICE_ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min); +static DEVICE_ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max); +static DEVICE_ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL); + +static struct attribute *xennet_dev_attrs[] = { + &dev_attr_rxbuf_min.attr, + &dev_attr_rxbuf_max.attr, + &dev_attr_rxbuf_cur.attr, +NULL }; -static int xennet_sysfs_addif (struct net_device *netdev) -{ -int i; -int err; - -for (i =0 ; i <ARRAY_SIZE (xennet_attrs); i++) { - err =device_create_file (&netdev->dev, - &xennet_attrs[i]); -if (err) - goto fail; - } -return 0 ; - - fail: -while (--i >=0 ) -device_remove_file (&netdev->dev, &xennet_attrs[i]); -return err; -} - -static void xennet_sysfs_delif (struct net_device *netdev) -{ -int i; - -for (i =0 ; i <ARRAY_SIZE (xennet_attrs); i++) -device_remove_file (&netdev->dev, &xennet_attrs[i]); -} - +static const struct attribute_group xennet_dev_group = { + .attrs = xennet_dev_attrs +};#endif /* CONFIG_SYSFS */ static const struct xenbus_device_id netfront_ids[] = {
@@ -2328,8 +2300,6 @@ static int xennet_remove(struct xenbus_dxennet_disconnect_backend (info); -xennet_sysfs_delif (info->netdev); -unregister_netdev (info->netdev);if (num_queues) {
PATCH 167/366 xen-netfront: properly destroy queues when removing device
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Vrabel <[email protected]>
commit ad0681185770716523c81b156c44b9804d7b8ed2 upstream.
xennet_remove() freed the queues before freeing the netdevice which results in a use-after-free when free_netdev() tries to delete the napi instances that have already been freed.
Fix this by fully destroy the queues (which includes deleting the napi instances) before freeing the netdevice.
[bwh: Backported to 3.16: I already backported most of this along with
the later commit 74470954857c "xen-netfront: Delete rx_refill_timer in
xennet_disconnect_backend()"; don't move the del_timer_sync() again.]
---
drivers/net/xen-netfront.c +1 -6
@@ -2294,7 +2294,6 @@ static const struct xenbus_device_id netstatic int xennet_remove (struct xenbus_device *dev) {struct netfront_info *info =dev_get_drvdata (&dev->dev); -unsigned int num_queues = info->netdev->real_num_tx_queues;dev_dbg (&dev->dev,"%s\n" , dev->nodename);
@@ -2302,11 +2301,7 @@ static int xennet_remove(struct xenbus_dunregister_netdev (info->netdev); -if (num_queues) { -kfree (info->queues); - info->queues =NULL ; - } - +xennet_destroy_queues (info);xennet_free_netdev (info->netdev);return 0 ;
PATCH 168/366 xen-netfront: Remove the meaningless code
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Li, Liang Z" <[email protected]>
commit 905726c1c5a3ca620ba7d73c78eddfb91de5ce28 upstream.
The function netif_set_real_num_tx_queues() will return -EINVAL if the second parameter < 1, so call this function with the second parameter set to 0 is meaningless.
--- drivers/net/xen-netfront.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/net/xen-netfront.c +0 -7
@@ -1330,10 +1330,6 @@ static struct net_device *xennet_create_ np =netdev_priv (netdev); np->xbdev = dev; -/* No need to use rtnl_lock() before the call below as it -* happens before register_netdev(). -*/ -netif_set_real_num_tx_queues (netdev,0 ); np->queues =NULL ; err = -ENOMEM ;
@@ -1992,9 +1988,6 @@ abort_transaction_no_dev_fatal:xennet_disconnect_backend (info);kfree (info->queues); info->queues =NULL ; -rtnl_lock (); -netif_set_real_num_tx_queues (info->netdev,0 ); -rtnl_unlock (); out:return err; }
PATCH 169/366 net/xen-netfront: only clean up queues if present
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Chas Williams <[email protected]>
commit 9a873c71e91cabf4c10fd9bbd8358c22deaf6c9e upstream.
If you simply load and unload the module without starting the interfaces, the queues are never created and you get a bad pointer dereference.
--- drivers/net/xen-netfront.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/xen-netfront.c +3 -2
@@ -1422,7 +1422,7 @@ static void xennet_disconnect_backend(stnetif_carrier_off (info->netdev); -for (i =0 ; i < num_queues; ++i) { +for (i =0 ; i < num_queues && info->queues; ++i) {struct netfront_queue *queue = &info->queues[i];del_timer_sync (&queue->rx_refill_timer);
@@ -2294,7 +2294,8 @@ static int xennet_remove(struct xenbus_dunregister_netdev (info->netdev); -xennet_destroy_queues (info); +if (info->queues) +xennet_destroy_queues (info);xennet_free_netdev (info->netdev);return 0 ;
PATCH 170/366 xen-netfront: Improve error handling during initialization
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ross Lagerwall <[email protected]>
commit e2e004acc7cbe3c531e752a270a74e95cde3ea48 upstream.
This fixes a crash when running out of grant refs when creating many queues across many netdevs.
* If creating queues fails (i.e. there are no grant refs available), call xenbus_dev_fatal() to ensure that the xenbus device is set to the closed state.
* If no queues are created, don't call xennet_disconnect_backend as netdev->real_num_tx_queues will not have been set correctly.
* If setup_netfront() fails, ensure that all the queues created are cleaned up, not just those that have been set up.
* If any queues were set up and an error occurs, call xennet_destroy_queues() to clean up the napi context.
* If any fatal error occurs, unregister and destroy the netdev to avoid leaving around a half setup network device.
--- drivers/net/xen-netfront.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-)
drivers/net/xen-netfront.c +11 -18
@@ -1879,27 +1879,19 @@ static int talk_to_netback(struct xenbusxennet_destroy_queues (info); err =xennet_create_queues (info, &num_queues); -if (err <0 ) - goto destroy_ring; +if (err <0 ) { +xenbus_dev_fatal (dev, err,"creating queues" ); +kfree (info->queues); + info->queues =NULL ; + goto out; + }/* Create shared ring, alloc event channel -- for each queue */ for (i =0 ; i < num_queues; ++i) { queue = &info->queues[i]; err =setup_netfront (dev, queue, feature_split_evtchn); -if (err) { -/* setup_netfront() will tidy up the current -* queue on error, but we need to clean up -* those already allocated. -*/ -if (i >0 ) { -rtnl_lock (); -netif_set_real_num_tx_queues (info->netdev, i); -rtnl_unlock (); - goto destroy_ring; - }else { - goto out; - } - } +if (err) + goto destroy_ring; } again:
@@ -1986,9 +1978,10 @@ abort_transaction_no_dev_fatal:xenbus_transaction_end (xbt,1 ); destroy_ring:xennet_disconnect_backend (info); -kfree (info->queues); - info->queues =NULL ; +xennet_destroy_queues (info); out: +unregister_netdev (info->netdev); +xennet_free_netdev (info->netdev);return err; }
PATCH 171/366 xen-netfront: avoid crashing on resume after a failure in talk_to_netback()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vitaly Kuznetsov <[email protected]>
commit d86b5672b1adb98b4cdd6fbf0224bbfb03db6e2e upstream.
Unavoidable crashes in netfront_resume() and netback_changed() after a previous fail in talk_to_netback() (e.g. when we fail to read MAC from xenstore) were discovered. The failure path in talk_to_netback() does unregister/free for netdev but we don't reset drvdata and we try accessing it after resume.
Fix the bug by removing the whole xen device completely with device_unregister(), this guarantees we won't have any calls into netfront after a failure.
--- drivers/net/xen-netfront.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/xen-netfront.c +1 -2
@@ -1980,8 +1980,7 @@ abort_transaction_no_dev_fatal:xennet_disconnect_backend (info);xennet_destroy_queues (info); out: -unregister_netdev (info->netdev); -xennet_free_netdev (info->netdev); +device_unregister (&dev->dev);return err; }
PATCH 172/366 xen-netfront: Fix race between device setup and open
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ross Lagerwall <[email protected]>
commit f599c64fdf7d9c108e8717fb04bc41c680120da4 upstream.
When a netfront device is set up it registers a netdev fairly early on, before it has set up the queues and is actually usable. A userspace tool like NetworkManager will immediately try to open it and access its state as soon as it appears. The bug can be reproduced by hotplugging VIFs until the VM runs out of grant refs. It registers the netdev but fails to set up any queues (since there are no more grant refs). In the meantime, NetworkManager opens the device and the kernel crashes trying to access the queues (of which there are none).
Fix this in two ways:
* For initial setup, register the netdev much later, after the queues are setup. This avoids the race entirely.
* During a suspend/resume cycle, the frontend reconnects to the backend and the queues are recreated. It is possible (though highly unlikely) to race with something opening the device and accessing the queues after they have been destroyed but before they have been recreated. Extend the region covered by the rtnl semaphore to protect against this race. There is a possibility that we fail to recreate the queues so check for this in the open function.
--- drivers/net/xen-netfront.c | 46 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-)
drivers/net/xen-netfront.c +24 -22
@@ -369,6 +369,9 @@ static int xennet_open(struct net_deviceunsigned int i =0 ;struct netfront_queue *queue =NULL ; +if (!np->queues) +return -ENODEV ; +for (i =0 ; i < num_queues; ++i) { queue = &np->queues[i];napi_enable (&queue->napi);
@@ -1394,18 +1397,8 @@ static int netfront_probe(struct xenbus_#ifdef CONFIG_SYSFS info->netdev->sysfs_groups[0 ] = &xennet_dev_group;#endif - err =register_netdev (info->netdev); -if (err) { -pr_warn ("%s: register_netdev err=%d\n" , __func__, err); - goto fail; - }return 0 ; - - fail: -xennet_free_netdev (netdev); -dev_set_drvdata (&dev->dev,NULL ); -return err; }static void xennet_end_access (int ref,void *page)
@@ -1779,8 +1772,6 @@ static void xennet_destroy_queues(struct {unsigned int i; -rtnl_lock (); -for (i =0 ; i < info->netdev->real_num_tx_queues; i++) {struct netfront_queue *queue = &info->queues[i];
@@ -1789,8 +1780,6 @@ static void xennet_destroy_queues(structnetif_napi_del (&queue->napi); } -rtnl_unlock (); -kfree (info->queues); info->queues =NULL ; }
@@ -1806,8 +1795,6 @@ static int xennet_create_queues(struct nif (!info->queues)return -ENOMEM ; -rtnl_lock (); -for (i =0 ; i < *num_queues; i++) {struct netfront_queue *queue = &info->queues[i];
@@ -1816,7 +1803,7 @@ static int xennet_create_queues(struct n ret =xennet_init_queue (queue);if (ret <0 ) { -dev_warn (&info->netdev->dev, +dev_warn (&info->xbdev->dev,"only created %d queues\n" , i); *num_queues = i;break ;
@@ -1830,10 +1817,8 @@ static int xennet_create_queues(struct nnetif_set_real_num_tx_queues (info->netdev, *num_queues); -rtnl_unlock (); -if (*num_queues ==0 ) { -dev_err (&info->netdev->dev,"no queues\n" ); +dev_err (&info->xbdev->dev,"no queues\n" );return -EINVAL ; }return 0 ;
@@ -1875,6 +1860,7 @@ static int talk_to_netback(struct xenbus goto out; } +rtnl_lock ();if (info->queues)xennet_destroy_queues (info);
@@ -1885,6 +1871,7 @@ static int talk_to_netback(struct xenbus info->queues =NULL ; goto out; } +rtnl_unlock ();/* Create shared ring, alloc event channel -- for each queue */ for (i =0 ; i < num_queues; ++i) {
@@ -1978,8 +1965,10 @@ abort_transaction_no_dev_fatal:xenbus_transaction_end (xbt,1 ); destroy_ring:xennet_disconnect_backend (info); +rtnl_lock ();xennet_destroy_queues (info); out: +rtnl_unlock ();device_unregister (&dev->dev);return err; }
@@ -2015,6 +2004,15 @@ static int xennet_connect(struct net_devnetdev_update_features (dev);rtnl_unlock (); +if (dev->reg_state ==NETREG_UNINITIALIZED ) { + err =register_netdev (dev); +if (err) { +pr_warn ("%s: register_netdev err=%d\n" , __func__, err); +device_unregister (&np->xbdev->dev); +return err; + } + } +/* * All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver
@@ -2284,10 +2282,14 @@ static int xennet_remove(struct xenbus_dxennet_disconnect_backend (info); -unregister_netdev (info->netdev); +if (info->netdev->reg_state ==NETREG_REGISTERED ) +unregister_netdev (info->netdev); -if (info->queues) +if (info->queues) { +rtnl_lock ();xennet_destroy_queues (info); +rtnl_unlock (); + }xennet_free_netdev (info->netdev);return 0 ;
PATCH 173/366 xen-netfront: Fix mismatched rtnl_unlock
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ross Lagerwall <[email protected]>
commit cb257783c2927b73614b20f915a91ff78aa6f3e8 upstream.
--- drivers/net/xen-netfront.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/xen-netfront.c +2 -1
@@ -1857,7 +1857,7 @@ static int talk_to_netback(struct xenbus err =xen_net_read_mac (dev, info->netdev->dev_addr);if (err) {xenbus_dev_fatal (dev, err,"parsing %s/mac" , dev->nodename); - goto out; + goto out_unlocked; }rtnl_lock ();
@@ -1969,6 +1969,7 @@ abort_transaction_no_dev_fatal:xennet_destroy_queues (info); out:rtnl_unlock (); +out_unlocked:device_unregister (&dev->dev);return err; }
PATCH 174/366 xen-netfront: Update features after registering netdev
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ross Lagerwall <[email protected]>
commit 45c8184c1bed1ca8a7f02918552063a00b909bf5 upstream.
Update the features after calling register_netdev() otherwise the device features are not set up correctly and it not possible to change the MTU of the device. After this change, the features reported by ethtool match the device's features before the commit which introduced the issue and it is possible to change the device's MTU.
--- drivers/net/xen-netfront.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/xen-netfront.c +4 -4
@@ -2001,10 +2001,6 @@ static int xennet_connect(struct net_dev/* talk_to_netback() sets the correct number of queues */ num_queues = dev->real_num_tx_queues; -rtnl_lock (); -netdev_update_features (dev); -rtnl_unlock (); -if (dev->reg_state ==NETREG_UNINITIALIZED ) { err =register_netdev (dev);if (err) {
@@ -2014,6 +2010,10 @@ static int xennet_connect(struct net_dev } } +rtnl_lock (); +netdev_update_features (dev); +rtnl_unlock (); +/* * All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver
PATCH 175/366 mtd: cfi_cmdset_0002: Fix unlocking requests crossing a chip boudary
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Joakim Tjernlund <[email protected]>
commit 0cd8116f172eed018907303dbff5c112690eeb91 upstream.
The "sector is in requested range" test used to determine whether sectors should be re-locked or not is done on a variable that is reset everytime we cross a chip boundary, which can lead to some blocks being re-locked while the caller expect them to be unlocked.
Fix the check to make sure this cannot happen.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/chips/cfi_cmdset_0002.c +1 -1
@@ -2340,7 +2340,7 @@ static int __maybe_unused cfi_ppb_unlock* sectors shall be unlocked, so lets keep their locking * status at "unlocked" (locked=0) for the final re-locking. */ -if ((adr < ofs) || (adr >= (ofs + len))) { +if ((offset < ofs) || (offset >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; sect[sectors].adr = adr; sect[sectors].locked = do_ppb_xxlock(
PATCH 176/366 Input: elantech - report the middle button of the touchpad
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ulrik De Bie <[email protected]>
commit f386474e12a560e005ec7899e78f51f6bdc3cf41 upstream.
In the past, no elantech was known with 3 touchpad mouse buttons. Fujitsu H730 is the first known elantech with a middle button. This commit enables this middle button. For backwards compatibility, the Fujitsu is detected via DMI, and only for this one 3 buttons will be announced.
--- drivers/input/mouse/elantech.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
drivers/input/mouse/elantech.c +19 -0
@@ -500,6 +500,7 @@ static void elantech_input_sync_v4(struc }else {input_report_key (dev,BTN_LEFT , packet[0 ] &0x01 );input_report_key (dev,BTN_RIGHT , packet[0 ] &0x02 ); +input_report_key (dev,BTN_MIDDLE , packet[0 ] &0x04 ); }input_mt_report_pointer_emulation (dev, true);
@@ -1064,6 +1065,22 @@ static void elantech_set_buttonpad_prop( }/* +* Some hw_version 4 models do have a middle button +*/ +static const struct dmi_system_id elantech_dmi_has_middle_button[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) + { +/* Fujitsu H730 has a middle button */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"FUJITSU" ), +DMI_MATCH (DMI_PRODUCT_NAME ,"CELSIUS H730" ), + }, + }, +#endif + { } +}; + +/* * Set the appropriate event bits for the input subsystem */ static int elantech_set_input_params (struct psmouse *psmouse)
@@ -1082,6 +1099,8 @@ static int elantech_set_input_params(str__clear_bit (EV_REL , dev->evbit);__set_bit (BTN_LEFT , dev->keybit); +if (dmi_check_system (elantech_dmi_has_middle_button)) +__set_bit (BTN_MIDDLE , dev->keybit);__set_bit (BTN_RIGHT , dev->keybit);__set_bit (BTN_TOUCH , dev->keybit);
PATCH 177/366 Input: elantech - enable middle button of touchpads on ThinkPad P52
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Aaron Ma <[email protected]>
commit 24bb555e6e46d96e2a954aa0295029a81cc9bbaa upstream.
PNPID is better way to identify the type of touchpads. Enable middle button support on 2 types of touchpads on Lenovo P52.
--- drivers/input/mouse/elantech.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/input/mouse/elantech.c +8 -1
@@ -1080,6 +1080,12 @@ static const struct dmi_system_id elante { } }; +static const char *const middle_button_pnp_ids[] = { +"LEN2131" ,/* ThinkPad P52 w/ NFC */ +"LEN2132" ,/* ThinkPad P52 */ +NULL +}; +/* * Set the appropriate event bits for the input subsystem */
@@ -1099,7 +1105,8 @@ static int elantech_set_input_params(str__clear_bit (EV_REL , dev->evbit);__set_bit (BTN_LEFT , dev->keybit); -if (dmi_check_system (elantech_dmi_has_middle_button)) +if (dmi_check_system (elantech_dmi_has_middle_button) || +psmouse_matches_pnp_id (psmouse, middle_button_pnp_ids))__set_bit (BTN_MIDDLE , dev->keybit);__set_bit (BTN_RIGHT , dev->keybit);
PATCH 178/366 Input: elantech - fix V4 report decoding for module with middle key
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: ??? <[email protected]>
commit e0ae2519ca004a628fa55aeef969c37edce522d3 upstream.
Some touchpad has middle key and it will be indicated in bit 2 of packet[0]. We need to fix V4 formation's byte mask to prevent error decoding.
--- drivers/input/mouse/elantech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/mouse/elantech.c +1 -1
@@ -737,7 +737,7 @@ static int elantech_packet_check_v4(struif (etd->crc_enabled) sanity_check = ((packet[3 ] &0x08 ) ==0x00 );else - sanity_check = ((packet[0 ] &0x0c ) ==0x04 && + sanity_check = ((packet[0 ] &0x08 ) ==0x00 && (packet[3 ] &0x1c ) ==0x10 );if (!sanity_check)
PATCH 179/366 xen: Remove unnecessary BUG_ON from __unbind_from_irq()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Boris Ostrovsky <[email protected]>
commit eef04c7b3786ff0c9cb1019278b6c6c2ea0ad4ff upstream.
Commit 910f8befdf5b ("xen/pirq: fix error path cleanup when binding MSIs") fixed a couple of errors in error cleanup path of xen_bind_pirq_msi_to_irq(). This cleanup allowed a call to __unbind_from_irq() with an unbound irq, which would result in triggering the BUG_ON there.
Since there is really no reason for the BUG_ON (xen_free_irq() can operate on unbound irqs) we can remove it.
--- drivers/xen/events/events_base.c | 2 -- 1 file changed, 2 deletions(-)
drivers/xen/events/events_base.c +0 -2
@@ -636,8 +636,6 @@ static void __unbind_from_irq(unsigned ixen_irq_info_cleanup (info); } -BUG_ON (info_for_irq (irq)->type ==IRQT_UNBOUND ); -xen_free_irq (irq); }
PATCH 180/366 mtd: cfi_cmdset_0002: Avoid walking all chips when unlocking.
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Joakim Tjernlund <[email protected]>
commit f1ce87f6080b1dda7e7b1eda3da332add19d87b9 upstream.
cfi_ppb_unlock() walks all flash chips when unlocking sectors, avoid walking chips unaffected by the unlock operation.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/mtd/chips/cfi_cmdset_0002.c +2 -0
@@ -2356,6 +2356,8 @@ static int __maybe_unused cfi_ppb_unlock i++;if (adr >> cfi->chipshift) { +if (offset >= (ofs + len)) +break ; adr =0 ; chipnum++;
PATCH 181/366 ALSA: hda/realtek - Add a quirk for FSC ESPRIMO U9210
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 275ec0cb946cb75ac8977f662e608fce92f8b8a8 upstream.
Fujitsu Seimens ESPRIMO Mobile U9210 requires the same fixup as H270 for the correct pin configs.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200107
--- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+)
sound/pci/hda/patch_realtek.c +1 -0
@@ -2496,6 +2496,7 @@ static const struct snd_pci_quirk alc262SND_PCI_QUIRK (0x10cf ,0x1397 ,"Fujitsu Lifebook S7110" ,ALC262_FIXUP_FSC_S7110 ),SND_PCI_QUIRK (0x10cf ,0x142d ,"Fujitsu Lifebook E8410" ,ALC262_FIXUP_BENQ ),SND_PCI_QUIRK (0x10f1 ,0x2915 ,"Tyan Thunder n6650W" ,ALC262_FIXUP_TYAN ), +SND_PCI_QUIRK (0x1734 ,0x1141 ,"FSC ESPRIMO U9210" ,ALC262_FIXUP_FSC_H270 ),SND_PCI_QUIRK (0x1734 ,0x1147 ,"FSC Celsius H270" ,ALC262_FIXUP_FSC_H270 ),SND_PCI_QUIRK (0x17aa ,0x384e ,"Lenovo 3000" ,ALC262_FIXUP_LENOVO_3000 ), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
PATCH 182/366 x86/mce: Do not overwrite MCi_STATUS in mce_no_way_out()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Borislav Petkov <[email protected]>
commit 1f74c8a64798e2c488f86efc97e308b85fb7d7aa upstream.
mce_no_way_out() does a quick check during #MC to see whether some of the MCEs logged would require the kernel to panic immediately. And it passes a struct mce where MCi_STATUS gets written.
However, after having saved a valid status value, the next iteration of the loop which goes over the MCA banks on the CPU, overwrites the valid status value because we're using struct mce as storage instead of a temporary variable.
Which leads to MCE records with an empty status value:
mce: [Hardware Error]: CPU 0: Machine Check Exception: 6 Bank 0: 0000000000000000
mce: [Hardware Error]: RIP 10:<ffffffffbd42fbd7> {trigger_mce+0x7/0x10}
In order to prevent the loss of the status register value, return immediately when severity is a panic one so that we can panic immediately with the first fatal MCE logged. This is also the intention of this function and not to noodle over the banks while a fatal MCE is already logged.
Tony: read the rest of the MCA bank to populate the struct mce fully.
--- arch/x86/kernel/cpu/mcheck/mce.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +10 -8
@@ -666,23 +666,25 @@ EXPORT_SYMBOL_GPL(machine_check_poll);static int mce_no_way_out (struct mce *m,char **msg,unsigned long *validp,struct pt_regs *regs) { -int i, ret =0 ;char *tmp; +int i;for (i =0 ; i < mca_cfg.banks; i++) { m->status =mce_rdmsrl (MSR_IA32_MCx_STATUS (i)); -if (m->status &MCI_STATUS_VAL ) { -__set_bit (i, validp); -if (quirk_no_way_out) -quirk_no_way_out (i, m, regs); - } +if (!(m->status &MCI_STATUS_VAL )) +continue ; + +__set_bit (i, validp); +if (quirk_no_way_out) +quirk_no_way_out (i, m, regs);if (mce_severity (m, mca_cfg.tolerant, &tmp) >=MCE_PANIC_SEVERITY ) { +mce_read_aux (m, i); *msg = tmp; - ret =1 ; +return 1 ; } } -return ret; +return 0 ; }/*
PATCH 183/366 time: Make sure jiffies_to_msecs() preserves non-zero time periods
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
commit abcbcb80cd09cd40f2089d912764e315459b71f7 upstream.
For the common cases where 1000 is a multiple of HZ, or HZ is a multiple of 1000, jiffies_to_msecs() never returns zero when passed a non-zero time period.
However, if HZ > 1000 and not an integer multiple of 1000 (e.g. 1024 or 1200, as used on alpha and DECstation), jiffies_to_msecs() may return zero for small non-zero time periods. This may break code that relies on receiving back a non-zero value.
jiffies_to_usecs() does not need such a fix: one jiffy can only be less than one µs if HZ > 1000000, and such large values of HZ are already rejected at build time, twice:
- include/linux/jiffies.h does #error if HZ >= 12288,
- kernel/time/time.c has BUILD_BUG_ON(HZ > USEC_PER_SEC).
Broken since forever.
--- kernel/time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/time.c +4 -2
@@ -28,6 +28,7 @@*/ #include <linux/export.h> +#include <linux/kernel.h> #include <linux/timex.h> #include <linux/capability.h> #include <linux/timekeeper_internal.h>
@@ -253,9 +254,10 @@ unsigned int jiffies_to_msecs(const unsireturn (j + (HZ /MSEC_PER_SEC ) -1 )/(HZ /MSEC_PER_SEC );#else # if BITS_PER_LONG ==32 -return (HZ_TO_MSEC_MUL32 * j) >>HZ_TO_MSEC_SHR32 ; +return (HZ_TO_MSEC_MUL32 * j + (1ULL <<HZ_TO_MSEC_SHR32 ) -1 ) >> +HZ_TO_MSEC_SHR32 ;# else -return (j *HZ_TO_MSEC_NUM ) /HZ_TO_MSEC_DEN ; +return DIV_ROUND_UP (j *HZ_TO_MSEC_NUM ,HZ_TO_MSEC_DEN );# endif #endif }
PATCH 184/366 vhost_net: validate sock before trying to put its fd
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jason Wang <[email protected]>
commit b8f1f65882f07913157c44673af7ec0b308d03eb upstream.
Sock will be NULL if we pass -1 to vhost_net_set_backend(), but when we meet errors during ubuf allocation, the code does not check for NULL before calling sockfd_put(), this will lead NULL dereferencing. Fixing by checking sock pointer before.
--- drivers/vhost/net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/vhost/net.c +2 -1
@@ -983,7 +983,8 @@ err_used:if (ubufs)vhost_net_ubuf_put_wait_and_free (ubufs); err_ubufs: -sockfd_put (sock); +if (sock) +sockfd_put (sock); err_vq:mutex_unlock (&vq->mutex); err:
PATCH 185/366 ipv6: mcast: fix unsolicited report interval after receiving querys
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu <[email protected]>
commit 6c6da92808442908287fae8ebb0ca041a52469f4 upstream.
After recieving MLD querys, we update idev->mc_maxdelay with max_delay from query header. This make the later unsolicited reports have the same interval with mc_maxdelay, which means we may send unsolicited reports with long interval time instead of default configured interval time.
Also as we will not call ipv6_mc_reset() after device up. This issue will be there even after leave the group and join other groups.
--- net/ipv6/mcast.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/ipv6/mcast.c +6 -3
@@ -2058,7 +2058,8 @@ void ipv6_mc_dad_complete(struct inet6_dmld_send_initial_cr (idev); idev->mc_dad_count--;if (idev->mc_dad_count) -mld_dad_start_timer (idev, idev->mc_maxdelay); +mld_dad_start_timer (idev, +unsolicited_report_interval (idev)); } }
@@ -2070,7 +2071,8 @@ static void mld_dad_timer_expire(unsigneif (idev->mc_dad_count) { idev->mc_dad_count--;if (idev->mc_dad_count) -mld_dad_start_timer (idev, idev->mc_maxdelay); +mld_dad_start_timer (idev, +unsolicited_report_interval (idev)); }in6_dev_put (idev); }
@@ -2428,7 +2430,8 @@ static void mld_ifc_timer_expire(unsigneif (idev->mc_ifc_count) { idev->mc_ifc_count--;if (idev->mc_ifc_count) -mld_ifc_start_timer (idev, idev->mc_maxdelay); +mld_ifc_start_timer (idev, +unsolicited_report_interval (idev)); }in6_dev_put (idev); }
PATCH 186/366 batman-adv: debugfs, avoid compiling for !DEBUG_FS
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Markus Pargmann <[email protected]>
commit 9bb218828c8f4fa6587af93e248903c96ce469d0 upstream.
Normally the debugfs framework will return error pointer with -ENODEV for function calls when DEBUG_FS is not set.
batman does not notice this error code and continues trying to create debugfs files and executes more code. We can avoid this code execution by disabling compiling debugfs.c when DEBUG_FS is not set.
--- net/batman-adv/Makefile | 2 +- net/batman-adv/debugfs.c | 8 -------- net/batman-adv/debugfs.h | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 9 deletions(-)
net/batman-adv/Makefile +1 -1
@@ -20,7 +20,7 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv.o batman-adv-y += bat_iv_ogm.o batman-adv-y += bitarray.o batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o -batman-adv-y += debugfs.o +batman-adv-$(CONFIG_DEBUG_FS) += debugfs.o batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o batman-adv-y += fragmentation.o batman-adv-y += gateway_client.o
net/batman-adv/debugfs.c +0 -8
@@ -482,11 +482,7 @@ rem_attr:debugfs_remove_recursive (hard_iface->debug_dir); hard_iface->debug_dir =NULL ; out: -#ifdef CONFIG_DEBUG_FS return -ENOMEM ; -#else -return 0 ; -#endif /* CONFIG_DEBUG_FS */ }/**
@@ -541,11 +537,7 @@ rem_attr:debugfs_remove_recursive (bat_priv->debug_dir); bat_priv->debug_dir =NULL ; out: -#ifdef CONFIG_DEBUG_FS return -ENOMEM ; -#else -return 0 ; -#endif /* CONFIG_DEBUG_FS */ }void batadv_debugfs_del_meshif (struct net_device *dev)
net/batman-adv/debugfs.h +34 -0
@@ -20,6 +20,8 @@#define BATADV_DEBUGFS_SUBDIR "batman_adv" +#if IS_ENABLED (CONFIG_DEBUG_FS ) +void batadv_debugfs_init (void );void batadv_debugfs_destroy (void );int batadv_debugfs_add_meshif (struct net_device *dev);
@@ -27,4 +29,36 @@ void batadv_debugfs_del_meshif(struct neint batadv_debugfs_add_hardif (struct batadv_hard_iface *hard_iface);void batadv_debugfs_del_hardif (struct batadv_hard_iface *hard_iface); +#else + +static inline void batadv_debugfs_init (void ) +{ +} + +static inline void batadv_debugfs_destroy (void ) +{ +} + +static inline int batadv_debugfs_add_meshif (struct net_device *dev) +{ +return 0 ; +} + +static inline void batadv_debugfs_del_meshif (struct net_device *dev) +{ +} + +static inline +int batadv_debugfs_add_hardif (struct batadv_hard_iface *hard_iface) +{ +return 0 ; +} + +static inline +void batadv_debugfs_del_hardif (struct batadv_hard_iface *hard_iface) +{ +} + +#endif +#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
PATCH 187/366 batman-adv: Fix debugfs path for renamed hardif
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 36dc621ceca1be3ec885aeade5fdafbbcc452a6d upstream.
batman-adv is creating special debugfs directories in the init net_namespace for each valid hard-interface (net_device). But it is possible to rename a net_device to a completely different name then the original one.
It can therefore happen that a user registers a new net_device which gets the name "wlan0" assigned by default. batman-adv is also adding a new directory under $debugfs/batman-adv/ with the name "wlan0".
The user then decides to rename this device to "wl_pri" and registers a different device. The kernel may now decide to use the name "wlan0" again for this new device. batman-adv will detect it as a valid net_device and tries to create a directory with the name "wlan0" under $debugfs/batman-adv/. But there already exists one with this name under this path and thus this fails. batman-adv will detect a problem and rollback the registering of this device.
batman-adv must therefore take care of renaming the debugfs directories for hard-interfaces whenever it detects such a net_device rename.
--- net/batman-adv/debugfs.c | 20 ++++++++++++++++++++ net/batman-adv/debugfs.h | 6 ++++++ net/batman-adv/hard-interface.c | 3 +++ 3 files changed, 29 insertions(+)
net/batman-adv/debugfs.c +20 -0
@@ -17,6 +17,7 @@#include "main.h" +#include <linux/dcache.h> #include <linux/debugfs.h> #include "debugfs.h"
@@ -486,6 +487,25 @@ out: }/** +* batadv_debugfs_rename_hardif() - Fix debugfs path for renamed hardif +* @hard_iface: hard interface which was renamed +*/ +void batadv_debugfs_rename_hardif (struct batadv_hard_iface *hard_iface) +{ +const char *name = hard_iface->net_dev->name; +struct dentry *dir; +struct dentry *d; + + dir = hard_iface->debug_dir; +if (!dir) +return ; + + d =debugfs_rename (dir->d_parent, dir, dir->d_parent, name); +if (!d) +pr_err ("Can't rename debugfs dir to %s\n" , name); +} + +/** * batadv_debugfs_del_hardif - delete the base directory for a hard interface * in debugfs. * @hard_iface: hard interface which is deleted.
net/batman-adv/debugfs.h +6 -0
@@ -27,6 +27,7 @@ void batadv_debugfs_destroy(void);int batadv_debugfs_add_meshif (struct net_device *dev);void batadv_debugfs_del_meshif (struct net_device *dev);int batadv_debugfs_add_hardif (struct batadv_hard_iface *hard_iface); +void batadv_debugfs_rename_hardif (struct batadv_hard_iface *hard_iface);void batadv_debugfs_del_hardif (struct batadv_hard_iface *hard_iface);#else
@@ -55,6 +56,11 @@ int batadv_debugfs_add_hardif(struct bat }static inline +void batadv_debugfs_rename_hardif (struct batadv_hard_iface *hard_iface) +{ +} + +static inline void batadv_debugfs_del_hardif (struct batadv_hard_iface *hard_iface) { }
net/batman-adv/hard-interface.c +3 -0
@@ -695,6 +695,9 @@ static int batadv_hard_if_event(struct nif (hard_iface == primary_if)batadv_primary_if_update_addr (bat_priv,NULL );break ; +case NETDEV_CHANGENAME : +batadv_debugfs_rename_hardif (hard_iface); +break ;default :break ; }
PATCH 188/366 batman-adv: Fix debugfs path for renamed softif
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 6da7be7d24b2921f8215473ba7552796dff05fe1 upstream.
batman-adv is creating special debugfs directories in the init net_namespace for each created soft-interface (batadv net_device). But it is possible to rename a net_device to a completely different name then the original one.
It can therefore happen that a user registers a new batadv net_device with the name "bat0". batman-adv is then also adding a new directory under $debugfs/batman-adv/ with the name "wlan0".
The user then decides to rename this device to "bat1" and registers a different batadv device with the name "bat0". batman-adv will then try to create a directory with the name "bat0" under $debugfs/batman-adv/ again. But there already exists one with this name under this path and thus this fails. batman-adv will detect a problem and rollback the registering of this device.
batman-adv must therefore take care of renaming the debugfs directories for soft-interfaces whenever it detects such a net_device rename.
--- net/batman-adv/debugfs.c | 20 +++++++++++++++++++ net/batman-adv/debugfs.h | 5 +++++ net/batman-adv/hard-interface.c | 34 +++++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 6 deletions(-)
net/batman-adv/debugfs.c +20 -0
@@ -560,6 +560,26 @@ out:return -ENOMEM ; } +/** +* batadv_debugfs_rename_meshif() - Fix debugfs path for renamed softif +* @dev: net_device which was renamed +*/ +void batadv_debugfs_rename_meshif (struct net_device *dev) +{ +struct batadv_priv *bat_priv =netdev_priv (dev); +const char *name = dev->name; +struct dentry *dir; +struct dentry *d; + + dir = bat_priv->debug_dir; +if (!dir) +return ; + + d =debugfs_rename (dir->d_parent, dir, dir->d_parent, name); +if (!d) +pr_err ("Can't rename debugfs dir to %s\n" , name); +} +void batadv_debugfs_del_meshif (struct net_device *dev) {struct batadv_priv *bat_priv =netdev_priv (dev);
net/batman-adv/debugfs.h +5 -0
@@ -25,6 +25,7 @@void batadv_debugfs_init (void );void batadv_debugfs_destroy (void );int batadv_debugfs_add_meshif (struct net_device *dev); +void batadv_debugfs_rename_meshif (struct net_device *dev);void batadv_debugfs_del_meshif (struct net_device *dev);int batadv_debugfs_add_hardif (struct batadv_hard_iface *hard_iface);void batadv_debugfs_rename_hardif (struct batadv_hard_iface *hard_iface);
@@ -45,6 +46,10 @@ static inline int batadv_debugfs_add_mesreturn 0 ; } +static inline void batadv_debugfs_rename_meshif (struct net_device *dev) +{ +} +static inline void batadv_debugfs_del_meshif (struct net_device *dev) { }
net/batman-adv/hard-interface.c +28 -6
@@ -640,6 +640,32 @@ void batadv_hardif_remove_interfaces(voirtnl_unlock (); } +/** +* batadv_hard_if_event_softif() - Handle events for soft interfaces +* @event: NETDEV_* event to handle +* @net_dev: net_device which generated an event +* +* Return: NOTIFY_* result +*/ +static int batadv_hard_if_event_softif (unsigned long event, +struct net_device *net_dev) +{ +struct batadv_priv *bat_priv; + +switch (event) { +case NETDEV_REGISTER : +batadv_sysfs_add_meshif (net_dev); + bat_priv =netdev_priv (net_dev); +batadv_softif_create_vlan (bat_priv,BATADV_NO_FLAGS ); +break ; +case NETDEV_CHANGENAME : +batadv_debugfs_rename_meshif (net_dev); +break ; + } + +return NOTIFY_DONE ; +} +static int batadv_hard_if_event (struct notifier_block *this,unsigned long event,void *ptr) {
@@ -648,12 +674,8 @@ static int batadv_hard_if_event(struct nstruct batadv_hard_iface *primary_if =NULL ;struct batadv_priv *bat_priv; -if (batadv_softif_is_valid (net_dev) && event ==NETDEV_REGISTER ) { -batadv_sysfs_add_meshif (net_dev); - bat_priv =netdev_priv (net_dev); -batadv_softif_create_vlan (bat_priv,BATADV_NO_FLAGS ); -return NOTIFY_DONE ; - } +if (batadv_softif_is_valid (net_dev)) +return batadv_hard_if_event_softif (event, net_dev); hard_iface =batadv_hardif_get_by_netdev (net_dev);if (!hard_iface && event ==NETDEV_REGISTER )
PATCH 189/366 batman-adv: Avoid storing non-TT-sync flags on singular entries too
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Linus Lüssing <[email protected]>
commit 4a519b83da16927fb98fd32b0f598e639d1f1859 upstream.
Since commit 54e22f265e87 ("batman-adv: fix TT sync flag inconsistencies") TT sync flags and TT non-sync'd flags are supposed to be stored separately.
The previous patch missed to apply this separation on a TT entry with only a single TT orig entry.
This is a minor fix because with only a single TT orig entry the DDoS issue the former patch solves does not apply.
--- net/batman-adv/translation-table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/batman-adv/translation-table.c +2 -1
@@ -1378,7 +1378,8 @@ static bool batadv_tt_global_add(structether_addr_copy (common->addr, tt_addr); common->vid = vid; - common->flags = flags; + common->flags = flags & (~BATADV_TT_SYNC_MASK ); + tt_global_entry->roam_at =0 ;/* node must store current time in case of roaming. This is * needed to purge this entry out on timeout (if nobody claims
PATCH 190/366 batman-adv: unify flags access style in tt global add
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Simon Wunderlich <[email protected]>
commit ad7e2c466d8b0a7056cd248e1df6bb7296e014f7 upstream.
This should slightly improve readability
--- net/batman-adv/translation-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/translation-table.c +1 -1
@@ -1435,7 +1435,7 @@ static bool batadv_tt_global_add(struct* TT_CLIENT_TEMP, therefore they have to be copied in the * client entry */ - tt_global_entry->common.flags |= flags & (~BATADV_TT_SYNC_MASK ); + common->flags |= flags & (~BATADV_TT_SYNC_MASK );/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only * one originator left in the list and we previously received a
PATCH 191/366 batman-adv: Fix multicast TT issues with bogus ROAM flags
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Linus Lüssing <[email protected]>
commit a44ebeff6bbd6ef50db41b4195fca87b21aefd20 upstream.
When a (broken) node wrongly sends multicast TT entries with a ROAM flag then this causes any receiving node to drop all entries for the same multicast MAC address announced by other nodes, leading to packet loss.
Fix this DoS vector by only storing TT sync flags. For multicast TT non-sync'ing flag bits like ROAM are unused so far anyway.
--- net/batman-adv/translation-table.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/batman-adv/translation-table.c +4 -2
@@ -1378,7 +1378,8 @@ static bool batadv_tt_global_add(structether_addr_copy (common->addr, tt_addr); common->vid = vid; - common->flags = flags & (~BATADV_TT_SYNC_MASK ); +if (!is_multicast_ether_addr (common->addr)) + common->flags = flags & (~BATADV_TT_SYNC_MASK ); tt_global_entry->roam_at =0 ;/* node must store current time in case of roaming. This is
@@ -1435,7 +1436,8 @@ static bool batadv_tt_global_add(struct* TT_CLIENT_TEMP, therefore they have to be copied in the * client entry */ - common->flags |= flags & (~BATADV_TT_SYNC_MASK ); +if (!is_multicast_ether_addr (common->addr)) + common->flags |= flags & (~BATADV_TT_SYNC_MASK );/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only * one originator left in the list and we previously received a
PATCH 192/366 xfrm: fix missing dst_release() after policy blocking lbcast and multicast
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tommi Rantala <[email protected]>
commit 8cc88773855f988d6a3bbf102bbd9dd9c828eb81 upstream.
Fix missing dst_release() when local broadcast or multicast traffic is xfrm policy blocked.
For IPv4 this results to dst leak: ip_route_output_flow() allocates dst_entry via __ip_route_output_key() and passes it to xfrm_lookup_route(). xfrm_lookup returns ERR_PTR(-EPERM) that is propagated. The dst that was allocated is never released.
IPv4 local broadcast testcase:
ping -b 192.168.1.255 &
sleep 1
ip xfrm policy add src 0.0.0.0/0 dst 192.168.1.255/32 dir out action block
IPv4 multicast testcase:
ping 224.0.0.1 &
sleep 1
ip xfrm policy add src 0.0.0.0/0 dst 224.0.0.1/32 dir out action block
For IPv6 the missing dst_release() causes trouble e.g. when used in netns:
ip netns add TEST
ip netns exec TEST ip link set lo up
ip link add dummy0 type dummy
ip link set dev dummy0 netns TEST
ip netns exec TEST ip addr add fd00::1111 dev dummy0
ip netns exec TEST ip link set dummy0 up
ip netns exec TEST ping -6 -c 5 ff02::1%dummy0 &
sleep 1
ip netns exec TEST ip xfrm policy add src ::/0 dst ff02::1 dir out action block wait
ip netns del TEST
After netns deletion we see:
[ 258.239097] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 268.279061] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 278.367018] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 288.375259] unregister_netdevice: waiting for lo to become free. Usage count = 2
--- net/xfrm/xfrm_policy.c | 3 +++ 1 file changed, 3 insertions(+)
net/xfrm/xfrm_policy.c +3 -0
@@ -2176,6 +2176,9 @@ struct dst_entry *xfrm_lookup_route(struif (IS_ERR (dst) &&PTR_ERR (dst) == -EREMOTE )return make_blackhole (net, dst_orig->ops->family, dst_orig); +if (IS_ERR (dst)) +dst_release (dst_orig); +return dst; }EXPORT_SYMBOL (xfrm_lookup_route);
PATCH 193/366 ALSA: timer: Fix UBSAN warning at SNDRV_TIMER_IOCTL_NEXT_DEVICE ioctl
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit b41f794f284966fd6ec634111e3b40d241389f96 upstream.
The kernel may spew a WARNING about UBSAN undefined behavior at handling ALSA timer ioctl SNDRV_TIMER_IOCTL_NEXT_DEVICE:
UBSAN: Undefined behaviour in sound/core/timer.c:1524:19 signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x122/0x1c8 lib/dump_stack.c:113 ubsan_epilogue+0x12/0x86 lib/ubsan.c:159 handle_overflow+0x1c2/0x21f lib/ubsan.c:190 __ubsan_handle_add_overflow+0x2a/0x31 lib/ubsan.c:198 snd_timer_user_next_device sound/core/timer.c:1524 [inline] __snd_timer_user_ioctl+0x204d/0x2520 sound/core/timer.c:1939 snd_timer_user_ioctl+0x67/0x95 sound/core/timer.c:1994 ....
It happens only when a value with INT_MAX is passed, as we're incrementing it unconditionally. So the fix is trivial, check the value with INT_MAX. Although the bug itself is fairly harmless, it's better to fix it so that fuzzers won't hit this again later.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200213
--- sound/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/core/timer.c +1 -1
@@ -1476,7 +1476,7 @@ static int snd_timer_user_next_device(st }else {if (id.subdevice <0 ) { id.subdevice =0 ; - }else { + }else if (id.subdevice <INT_MAX ) { id.subdevice++; } }
PATCH 194/366 usb: cdc_acm: Add quirk for Uniden UBC125 scanner
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Houston Yaroschoff <[email protected]>
commit 4a762569a2722b8a48066c7bacf0e1dc67d17fa1 upstream.
Uniden UBC125 radio scanner has USB interface which fails to work with cdc_acm driver:
usb 1-1.5: new full-speed USB device number 4 using xhci_hcd cdc_acm 1-1.5:1.0: Zero length descriptor references
cdc_acm: probe of 1-1.5:1.0 failed with error -22
Adding the NO_UNION_NORMAL quirk for the device fixes the issue:
usb 1-4: new full-speed USB device number 15 using xhci_hcd usb 1-4: New USB device found, idVendor=1965, idProduct=0018 usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-4: Product: UBC125XLT
usb 1-4: Manufacturer: Uniden Corp.
usb 1-4: SerialNumber: 0001
cdc_acm 1-4:1.0: ttyACM0: USB ACM device
lsusb -v of the device:
Bus 001 Device 015: ID 1965:0018 Uniden Corporation Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1965 Uniden Corporation
idProduct 0x0018
bcdDevice 0.01
iManufacturer 1 Uniden Corp.
iProduct 2 UBC125XLT
iSerial 3 0001
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 48
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0 None
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x87 EP 7 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0000
(Bus Powered)
--- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/class/cdc-acm.c +3 -0
@@ -1711,6 +1711,9 @@ static const struct usb_device_id acm_id { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info =SINGLE_RX_URB , }, + { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ },
PATCH 195/366 xfrm: free skb if nlsk pointer is NULL
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit 86126b77dcd551ce223e7293bb55854e3df05646 upstream.
nlmsg_multicast() always frees the skb, so in case we cannot call it we must do that ourselves.
--- net/xfrm/xfrm_user.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
net/xfrm/xfrm_user.c +6 -4
@@ -959,10 +959,12 @@ static inline int xfrm_nlmsg_multicast(s {struct sock *nlsk =rcu_dereference (net->xfrm.nlsk); -if (nlsk) -return nlmsg_multicast (nlsk, skb, pid, group,GFP_ATOMIC ); -else -return -1 ; +if (!nlsk) { +kfree_skb (skb); +return -EPIPE ; + } + +return nlmsg_multicast (nlsk, skb, pid, group,GFP_ATOMIC ); }static inline size_t xfrm_spdinfo_msgsize (void )
PATCH 196/366 staging: android: ion: Return an ERR_PTR in ion_map_kernel
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Laura Abbott <[email protected]>
commit 0a2bc00341dcfcc793c0dbf4f8d43adf60458b05 upstream.
The expected return value from ion_map_kernel is an ERR_PTR. The error path for a vmalloc failure currently just returns NULL, triggering a warning in ion_buffer_kmap_get. Encode the vmalloc failure as an ERR_PTR.
--- drivers/staging/android/ion/ion_heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/android/ion/ion_heap.c +1 -1
@@ -38,7 +38,7 @@ void *ion_heap_map_kernel(struct ion_heastruct page **tmp = pages;if (!pages) -return NULL ; +return ERR_PTR (-ENOMEM );if (buffer->flags &ION_FLAG_CACHED ) pgprot =PAGE_KERNEL ;
PATCH 197/366 X.509: unpack RSA signatureValue field from BIT STRING
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Maciej S. Szmigiero" <[email protected]>
commit b65c32ec5a942ab3ada93a048089a938918aba7f upstream.
The signatureValue field of a X.509 certificate is encoded as a BIT STRING. For RSA signatures this BIT STRING is of so-called primitive subtype, which contains a u8 prefix indicating a count of unused bits in the encoding.
We have to strip this prefix from signature data, just as we already do for key data in x509_extract_key_data() function.
This wasn't noticed earlier because this prefix byte is zero for RSA key sizes divisible by 8. Since BIT STRING is a big-endian encoding adding zero prefixes has no bearing on its value.
The signature length, however was incorrect, which is a problem for RSA implementations that need it to be exactly correct (like AMD CCP).
[bwh: Backported to 3.16:
- x509_certificate::sig is a structure, not a pointer
- public_key_signature::pkey_algo is an enumeration type, not a string]
--- crypto/asymmetric_keys/x509_cert_parser.c | 9 +++++++++ 1 file changed, 9 insertions(+)
crypto/asymmetric_keys/x509_cert_parser.c +9 -0
@@ -205,6 +205,15 @@ int x509_note_signature(void *context, sreturn -EINVAL ; } +if (ctx->cert->sig.pkey_algo ==PKEY_ALGO_RSA ) { +/* Discard the BIT STRING metadata */ +if (vlen <1 || *(const u8 *)value !=0 ) +return -EBADMSG ; + + value++; + vlen--; + } + ctx->cert->raw_sig = value; ctx->cert->raw_sig_size = vlen;return 0 ;
PATCH 198/366 RDMA/uverbs: Protect from attempts to create flows on unsupported QP
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
commit 940efcc8889f0d15567eb07fc9fd69b06e366aa5 upstream.
Flows can be created on UD and RAW_PACKET QP types. Attempts to provide other QP types as an input causes to various unpredictable failures.
The reason is that in order to support all various types (e.g. XRC), we are supposed to use real_qp handle and not qp handle and expect to driver/FW to fail such (XRC) flows. The simpler and safer variant is to ban all QP types except UD and RAW_PACKET, instead of relying on driver/FW.
--- drivers/infiniband/core/uverbs_cmd.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/infiniband/core/uverbs_cmd.c +5 -0
@@ -2740,6 +2740,11 @@ int ib_uverbs_ex_create_flow(struct ib_u goto err_uobj; } +if (qp->qp_type !=IB_QPT_UD && qp->qp_type !=IB_QPT_RAW_PACKET ) { + err = -EINVAL ; + goto err_put; + } + flow_attr =kmalloc (sizeof (*flow_attr) + cmd.flow_attr.size,GFP_KERNEL );if (!flow_attr) { err = -ENOMEM ;
PATCH 199/366 RDMA/uverbs: Fix slab-out-of-bounds in ib_uverbs_ex_create_flow
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
commit 4fae7f170416f970e5655f7e945ce69286b1c4ff upstream.
The check of cmd.flow_attr.size should check into account the size of the reserved field (2 bytes), otherwise user can provide a size which will cause a slab-out-of-bounds warning below.
==================================================================
BUG: KASAN: slab-out-of-bounds in ib_uverbs_ex_create_flow+0x1740/0x1d00 Read of size 2 at addr ffff880068dff1a6 by task syz-executor775/269 CPU: 0 PID: 269 Comm: syz-executor775 Not tainted 4.18.0-rc1+ #245 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0xef/0x17e print_address_description+0x83/0x3b0 kasan_report+0x18d/0x4d0 ib_uverbs_ex_create_flow+0x1740/0x1d00 ib_uverbs_write+0x923/0x1010 __vfs_write+0x10d/0x720 vfs_write+0x1b0/0x550 ksys_write+0xc6/0x1a0 do_syscall_64+0xa7/0x590 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x433899 Code: fd ff 48 81 c4 80 00 00 00 e9 f1 fe ff ff 0f 1f 00 48 89 f8 48 89
f7 48 89 d6 48 89 ca 4d 89 c2 4d
89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b 91 fd ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007ffc2724db58 EFLAGS: 00000217 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000000020006880 RCX: 0000000000433899
RDX: 00000000000000e0 RSI: 0000000020002480 RDI: 0000000000000003
RBP: 00000000006d7018 R08: 00000000004002f8 R09: 00000000004002f8
R10: 00000000004002f8 R11: 0000000000000217 R12: 0000000000000000
R13: 000000000040cd20 R14: 000000000040cdb0 R15: 0000000000000006
Allocated by task 269:
kasan_kmalloc+0xa0/0xd0
__kmalloc+0x1a9/0x510
ib_uverbs_ex_create_flow+0x26c/0x1d00
ib_uverbs_write+0x923/0x1010
__vfs_write+0x10d/0x720
vfs_write+0x1b0/0x550
ksys_write+0xc6/0x1a0
do_syscall_64+0xa7/0x590
entry_SYSCALL_64_after_hwframe+0x49/0xbe
Freed by task 0:
__kasan_slab_free+0x12e/0x180
kfree+0x159/0x630
detach_buf+0x559/0x7a0
virtqueue_get_buf_ctx+0x3cc/0xab0
virtblk_done+0x1eb/0x3d0
vring_interrupt+0x16d/0x2b0
__handle_irq_event_percpu+0x10a/0x980
handle_irq_event_percpu+0x77/0x190
handle_irq_event+0xc6/0x1a0
handle_edge_irq+0x211/0xd80
handle_irq+0x3d/0x60
do_IRQ+0x9b/0x220
The buggy address belongs to the object at ffff880068dff180
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 38 bytes inside of
64-byte region [ffff880068dff180, ffff880068dff1c0)
The buggy address belongs to the page:
page:ffffea0001a37fc0 count:1 mapcount:0 mapping:ffff88006c401780
index:0x0
flags: 0x4000000000000100(slab)
raw: 4000000000000100 ffffea0001a31100 0000001100000011 ffff88006c401780
raw: 0000000000000000 00000000802a002a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff880068dff080: fb fb fb fb fc fc fc fc fb fb fb fb fb fb fb fb
ffff880068dff100: fc fc fc fc fb fb fb fb fb fb fb fb fc fc fc fc
>ffff880068dff180: 00 00 00 00 07 fc fc fc fc fc fc fc fb fb fb fb
^
ffff880068dff200: fb fb fb fb fc fc fc fc 00 00 00 00 00 00 fc fc
ffff880068dff280: fc fc fc fc 00 00 00 00 00 00 00 00 fc fc fc fc
==================================================================--- drivers/infiniband/core/uverbs_cmd.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/infiniband/core/uverbs_cmd.c +12 -10
@@ -2674,8 +2674,8 @@ int ib_uverbs_ex_create_flow(struct ib_ustruct ib_uverbs_flow_attr *kern_flow_attr;struct ib_flow_attr *flow_attr;struct ib_qp *qp; +struct ib_uverbs_flow_spec_hdr *kern_spec;int err =0 ; -void *kern_spec;void *ib_spec;int i;
@@ -2717,8 +2717,8 @@ int ib_uverbs_ex_create_flow(struct ib_uif (!kern_flow_attr)return -ENOMEM ; -memcpy (kern_flow_attr, &cmd.flow_attr,sizeof (*kern_flow_attr)); - err =ib_copy_from_udata (kern_flow_attr +1 , ucore, + *kern_flow_attr = cmd.flow_attr; + err =ib_copy_from_udata (&kern_flow_attr->flow_specs, ucore, cmd.flow_attr.size);if (err) goto err_free_attr;
@@ -2758,19 +2758,21 @@ int ib_uverbs_ex_create_flow(struct ib_u flow_attr->flags = kern_flow_attr->flags; flow_attr->size =sizeof (*flow_attr); - kern_spec = kern_flow_attr +1 ; + kern_spec = kern_flow_attr->flow_specs; ib_spec = flow_attr +1 ;for (i =0 ; i < flow_attr->num_of_specs && - cmd.flow_attr.size > offsetof(struct ib_uverbs_flow_spec , reserved) && - cmd.flow_attr.size >= - ((struct ib_uverbs_flow_spec *)kern_spec)->size; i++) { - err =kern_spec_to_ib_spec (kern_spec, ib_spec); + cmd.flow_attr.size >sizeof (*kern_spec) && + cmd.flow_attr.size >= kern_spec->size; + i++) { + err =kern_spec_to_ib_spec ( + (struct ib_uverbs_flow_spec *)kern_spec, + ib_spec);if (err) goto err_free; flow_attr->size += ((union ib_flow_spec *) ib_spec)->size; - cmd.flow_attr.size -= ((struct ib_uverbs_flow_spec *)kern_spec)->size; - kern_spec += ((struct ib_uverbs_flow_spec *) kern_spec)->size; + cmd.flow_attr.size -= kern_spec->size; + kern_spec = ((void *)kern_spec) + kern_spec->size; ib_spec += ((union ib_flow_spec *) ib_spec)->size; }if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
PATCH 200/366 netfilter: nf_log: don't hold nf_log_mutex during user access
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit ce00bf07cc95a57cd20b208e02b3c2604e532ae8 upstream.
The old code would indefinitely block other users of nf_log_mutex if a userspace access in proc_dostring() blocked e.g. due to a userfaultfd region. Fix it by moving proc_dostring() out of the locked region.
This is a followup to commit 266d07cb1c9a ("netfilter: nf_log: fix sleeping function called from invalid context"), which changed this code from using rcu_read_lock() to taking nf_log_mutex.
--- net/netfilter/nf_log.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/netfilter/nf_log.c +6 -3
@@ -273,15 +273,18 @@ static int nf_log_proc_dostring(struct crcu_assign_pointer (net->nf.nf_loggers[tindex], logger);mutex_unlock (&nf_log_mutex); }else { +struct ctl_table tmp = *table; + + tmp.data = buf;mutex_lock (&nf_log_mutex); logger =rcu_dereference_protected (net->nf.nf_loggers[tindex],lockdep_is_held (&nf_log_mutex));if (!logger) - table->data ="NONE" ; +strlcpy (buf,"NONE" ,sizeof (buf));else - table->data = logger->name; - r =proc_dostring (table, write, buffer, lenp, ppos); +strlcpy (buf, logger->name,sizeof (buf));mutex_unlock (&nf_log_mutex); + r =proc_dostring (&tmp, write, buffer, lenp, ppos); }return r;
PATCH 201/366 nfsd: silence sparse warning about accessing credentials
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
commit ae4b884fc6316b3190be19448cea24b020c1cad6 upstream.
sparse says:
fs/nfsd/auth.c:31:38: warning: incorrect type in argument 1 (different address spaces)
fs/nfsd/auth.c:31:38: expected struct cred const *cred
fs/nfsd/auth.c:31:38: got struct cred const [noderef] <asn:4>*real_cred
Add a new accessor for the ->real_cred and use that to fetch the pointer. Accessing current->real_cred directly is actually quite safe since we know that they can't go away so this is mostly a cosmetic fixup to silence sparse.
--- fs/nfsd/auth.c | 2 +- include/linux/cred.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
fs/nfsd/auth.c +1 -1
@@ -28,7 +28,7 @@ int nfsd_setuser(struct svc_rqst *rqstp,validate_process_creds ();/* discard any old override before preparing the new set */ -revert_creds (get_cred (current->real_cred)); +revert_creds (get_cred (current_real_cred ())); new =prepare_creds ();if (!new)return -ENOMEM ;
include/linux/cred.h +9 -0
@@ -261,6 +261,15 @@ static inline void put_cred(const structrcu_dereference_protected (current->cred,1 )/** +* current_real_cred - Access the current task's objective credentials +* +* Access the objective credentials of the current task. RCU-safe, +* since nobody else can modify it. + */ +#define current_real_cred () \ + rcu_dereference_protected(current->real_cred, 1) + +/** * __task_cred - Access a task's objective credentials * @task: The task to query *
PATCH 202/366 scsi: sg: mitigate read/write abuse
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 26b5b874aff5659a7e26e5b1997e3df2c41fa7fd upstream.
As Al Viro noted in commit 128394eff343 ("sg_write()/bsg_write() is not fit to be called under KERNEL_DS"), sg improperly accesses userspace memory outside the provided buffer, permitting kernel memory corruption via splice(). But it doesn't just do it on ->write(), also on ->read().
As a band-aid, make sure that the ->read() and ->write() handlers can not be called in weird contexts (kernel context or credentials different from file opener), like for ib_safe_file_access().
If someone needs to use these interfaces from different security contexts, a new interface should be written that goes through the ->ioctl() handler.
I've mostly copypasted ib_safe_file_access() over as sg_safe_file_access() because I couldn't find a good common header - please tell me if you know a better way.
[mkp: s/_safe_/_check_/]
--- drivers/scsi/sg.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-)
drivers/scsi/sg.c +40 -2
@@ -52,6 +52,7 @@ static int sg_version_num = 30534; /* 2#include <linux/blktrace_api.h> #include <linux/mutex.h> #include <linux/ratelimit.h> +#include <linux/cred.h> /* for sg_check_file_access() */ #include "scsi.h" #include <scsi/scsi_dbg.h>
@@ -215,6 +216,33 @@ static void sg_put_dev(Sg_device *sdp);#define SZ_SG_IOVEC sizeof(sg_iovec_t)#define SZ_SG_REQ_INFO sizeof(sg_req_info_t) +/* +* The SCSI interfaces that use read() and write() as an asynchronous variant of +* ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways +* to trigger read() and write() calls from various contexts with elevated +* privileges. This can lead to kernel memory corruption (e.g. if these +* interfaces are called through splice()) and privilege escalation inside +* userspace (e.g. if a process with access to such a device passes a file +* descriptor to a SUID binary as stdin/stdout/stderr). +* +* This function provides protection for the legacy API by restricting the +* calling context. +*/ +static int sg_check_file_access (struct file *filp,const char *caller) +{ +if (filp->f_cred !=current_real_cred ()) { +pr_err_once ("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n" , + caller,task_tgid_vnr (current), current->comm); +return -EPERM ; + } +if (unlikely (segment_eq (get_fs (),KERNEL_DS ))) { +pr_err_once ("%s: process %d (%s) called from kernel context, this is not allowed.\n" , + caller,task_tgid_vnr (current), current->comm); +return -EACCES ; + } +return 0 ; +} +static int sg_allow_access (struct file *filp,unsigned char *cmd) {struct sg_fd *sfp = filp->private_data;
@@ -382,6 +410,14 @@ sg_read(struct file *filp, char __user *struct sg_header *old_hdr =NULL ;int retval =0 ; +/* +* This could cause a response to be stranded. Close the associated +* file descriptor to free up any resources being held. +*/ + retval =sg_check_file_access (filp, __func__); +if (retval) +return retval; +if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))return -ENXIO ; SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n",
@@ -567,9 +603,11 @@ sg_write(struct file *filp, const char _struct sg_header old_hdr;sg_io_hdr_t *hp;unsigned char cmnd[MAX_COMMAND_SIZE ]; +int retval; -if (unlikely (segment_eq (get_fs (),KERNEL_DS ))) -return -EINVAL ; + retval =sg_check_file_access (filp, __func__); +if (retval) +return retval;if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))return -ENXIO ;
PATCH 203/366 block: Fix transfer when chunk sectors exceeds max
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
commit 15bfd21fbc5d35834b9ea383dc458a1f0c9e3434 upstream.
A device may have boundary restrictions where the number of sectors between boundaries exceeds its max transfer size. In this case, we need to cap the max size to the smaller of the two limits.
--- include/linux/blkdev.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/blkdev.h +2 -2
@@ -929,8 +929,8 @@ static inline unsigned int blk_max_size_if (!q->limits.chunk_sectors)return q->limits.max_sectors; -return q->limits.chunk_sectors - - (offset & (q->limits.chunk_sectors -1 )); +return min (q->limits.max_sectors, (unsigned int )(q->limits.chunk_sectors - + (offset & (q->limits.chunk_sectors -1 )))); }static inline unsigned int blk_rq_get_max_sectors (struct request *rq)
PATCH 204/366 net/mlx5: Fix incorrect raw command length parsing
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alex Vesker <[email protected]>
commit 603b7bcff824740500ddfa001d7a7168b0b38542 upstream.
The NULL character was not set correctly for the string containing the command length, this caused failures reading the output of the command due to a random length. The fix is to initialize the output length string.
--- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +1 -3
@@ -1028,7 +1028,7 @@ static ssize_t outlen_write(struct file {struct mlx5_core_dev *dev = filp->private_data;struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; -char outlen_str[8 ]; +char outlen_str[8 ] = {0 };int outlen;void *ptr;int err;
@@ -1043,8 +1043,6 @@ static ssize_t outlen_write(struct fileif (copy_from_user (outlen_str, buf, count))return -EFAULT ; - outlen_str[7 ] =0 ; - err =sscanf (outlen_str,"%d" , &outlen);if (err <0 )return err;
PATCH 205/366 net/mlx5: Fix command interface race in polling mode
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alex Vesker <[email protected]>
commit d412c31dae053bf30a1bc15582a9990df297a660 upstream.
The command interface can work in two modes: Events and Polling. In the general case, each time we invoke a command, a work is queued to handle it.
When working in events, the interrupt handler completes the command execution. On the other hand, when working in polling mode, the work itself completes it.
Due to a bug in the work handler, a command could have been completed by the interrupt handler, while the work handler hasn't finished yet, causing the it to complete once again if the command interface mode was changed from Events to polling after the interrupt handler was called.
mlx5_unload_one()
mlx5_stop_eqs()
// Destroy the EQ before cmd EQ
...cmd_work_handler()
write_doorbell()
--> EVENT_TYPE_CMD
mlx5_cmd_comp_handler() // First free
free_ent(cmd, ent->idx)
complete(&ent->done)
<-- mlx5_stop_eqs //cmd was complete
// move to polling before destroying the last cmd EQ
mlx5_cmd_use_polling()
cmd->mode = POLL;
--> cmd_work_handler (continues)
if (cmd->mode == POLL)
mlx5_cmd_comp_handler() // Double freeThe solution is to store the cmd->mode before writing the doorbell.
--- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +3 -1
@@ -560,6 +560,7 @@ static void cmd_work_handler(struct workstruct mlx5_cmd_layout *lay;struct semaphore *sem;int alloc_ret; +int cmd_mode; sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;down (sem);
@@ -602,6 +603,7 @@ static void cmd_work_handler(struct workset_signature (ent, !cmd->checksum_disabled);dump_command (dev, ent,1 );ktime_get_ts (&ent->ts1); + cmd_mode = cmd->mode;if (ent->callback)schedule_delayed_work (&ent->cb_timeout_work, cb_timeout);
@@ -611,7 +613,7 @@ static void cmd_work_handler(struct workiowrite32be (1 << ent->idx, &dev->iseg->cmd_dbell);mlx5_core_dbg (dev,"write 0x%x to command doorbell\n" ,1 << ent->idx);mmiowb (); -if (cmd->mode ==CMD_MODE_POLLING ) { +if (cmd_mode ==CMD_MODE_POLLING ) {poll_timeout (ent);/* make sure we read the descriptor after ownership is SW */ rmb ();
PATCH 206/366 ARM: dts: da850: Fix interrups property for gpio
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Keerthy <[email protected]>
commit 3eb1b955cd7ed1e621ace856710006c2a8a7f231 upstream.
The intc #interrupt-cells is equal to 1. Currently gpio node has 2 cells per IRQ which is wrong. Remove the additional cell for each of the interrupts.
--- arch/arm/boot/dts/da850.dtsi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
arch/arm/boot/dts/da850.dtsi +1 -5
@@ -261,11 +261,7 @@ compatible = "ti,dm6441-gpio"; gpio-controller; reg = <0x226000 0x1000>; - interrupts = <42 IRQ_TYPE_EDGE_BOTH - 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH - 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH - 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH - 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>; + interrupts = <42 43 44 45 46 47 48 49 50>; ti,ngpio = <144>; ti,davinci-gpio-unbanked = <0>; status = "disabled";
PATCH 207/366 dm thin: handle running out of data space vs concurrent discard
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
commit a685557fbbc3122ed11e8ad3fa63a11ebc5de8c3 upstream.
Discards issued to a DM thin device can complete to userspace (via fstrim) _before_ the metadata changes associated with the discards is reflected in the thinp superblock (e.g. free blocks). As such, if a user constructs a test that loops repeatedly over these steps, block allocation can fail due to discards not having completed yet:
1) fill thin device via filesystem file
2) remove file
3) fstrim
=46rominitial report, here:
https://www.redhat.com/archives/dm-devel/2018-April/msg00022.html
"The root cause of this issue is that dm-thin will first remove mapping and increase corresponding blocks' reference count to prevent them from being reused before DISCARD bios get processed by the underlying layers. However. increasing blocks' reference count could also increase the nr_allocated_this_transaction in struct sm_disk which makes smd->old_ll.nr_allocated + smd->nr_allocated_this_transaction bigger than smd->old_ll.nr_blocks. In this case, alloc_data_block() will never commit metadata to reset the begin pointer of struct sm_disk, because sm_disk_get_nr_free() always return an underflow value."
While there is room for improvement to the space-map accounting that thinp is making use of: the reality is this test is inherently racey and will result in the previous iteration's fstrim's discard(s) completing vs concurrent block allocation, via dd, in the next iteration of the loop.
No amount of space map accounting improvements will be able to allow user's to use a block before a discard of that block has completed.
So the best we can really do is allow DM thinp to gracefully handle such aggressive use of all the pool's data by degrading the pool into out-of-data-space (OODS) mode. We _should_ get that behaviour already (if space map accounting didn't falsely cause alloc_data_block() to believe free space was available).. but short of that we handle the current reality that dm_pool_alloc_data_block() can return -ENOSPC.
--- drivers/md/dm-thin.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/md/dm-thin.c +9 -2
@@ -938,6 +938,8 @@ static void schedule_zero(struct thin_cstatic void set_pool_mode (struct pool *pool,enum pool_mode new_mode); +static void requeue_bios (struct pool *pool); +static void check_for_space (struct pool *pool) {int r;
@@ -950,8 +952,10 @@ static void check_for_space(struct poolif (r)return ; -if (nr_free) +if (nr_free) {set_pool_mode (pool,PM_WRITE ); +requeue_bios (pool); + } }/*
@@ -1028,7 +1032,10 @@ static int alloc_data_block(struct thin_ r =dm_pool_alloc_data_block (pool->pmd, result);if (r) { -metadata_operation_failed (pool,"dm_pool_alloc_data_block" , r); +if (r == -ENOSPC ) +set_pool_mode (pool,PM_OUT_OF_DATA_SPACE ); +else +metadata_operation_failed (pool,"dm_pool_alloc_data_block" , r);return r; }
PATCH 208/366 dmaengine: k3dma: Off by one in k3_of_dma_simple_xlate()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit c4c2b7644cc9a41f17a8cc8904efe3f66ae4c7ed upstream.
The d->chans[] array has d->dma_requests elements so the > should be
Quoted 1 line
= here.
--- drivers/dma/k3dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/k3dma.c +1 -1
@@ -652,7 +652,7 @@ static struct dma_chan *k3_of_dma_simplestruct k3_dma_dev *d = ofdma->of_dma_data;unsigned int request = dma_spec->args[0 ]; -if (request > d->dma_requests) +if (request >= d->dma_requests)return NULL ;return dma_get_slave_channel (&(d->chans[request].vc.chan));
PATCH 209/366 n_tty: Fix stall at n_tty_receive_char_special().
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
commit 3d63b7e4ae0dc5e02d28ddd2fa1f945defc68d81 upstream.
syzbot is reporting stalls at n_tty_receive_char_special() [1]. This is because comparison is not working as expected since ldata->read_head can change at any moment. Mitigate this by explicitly masking with buffer size when checking condition for "while" loops.
[1] https://syzkaller.appspot.com/bug?id=3d7481a346958d9469bebbeb0537d5f056bdd6e8
--- drivers/tty/n_tty.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/tty/n_tty.c +8 -5
@@ -127,6 +127,8 @@ struct n_tty_data {struct mutex output_lock; }; +#define MASK (x) ((x) & (N_TTY_BUF_SIZE - 1)) +static inline size_t read_cnt (struct n_tty_data *ldata) {return ldata->read_head - ldata->read_tail;
@@ -1032,14 +1034,15 @@ static void eraser(unsigned char c, stru } seen_alnums =0 ; -while (ldata->read_head != ldata->canon_head) { +while (MASK (ldata->read_head) !=MASK (ldata->canon_head)) { head = ldata->read_head;/* erase a single possibly multibyte character */ do { head--; c =read_buf (ldata, head); - }while (is_continuation (c, tty) && head != ldata->canon_head); + }while (is_continuation (c, tty) && +MASK (head) !=MASK (ldata->canon_head));/* do not partially erase */ if (is_continuation (c, tty))
@@ -1081,7 +1084,7 @@ static void eraser(unsigned char c, stru* This info is used to go back the correct * number of columns. */ -while (tail != ldata->canon_head) { +while (MASK (tail) !=MASK (ldata->canon_head)) { tail--; c =read_buf (ldata, tail);if (c =='\t' ) {
@@ -1341,7 +1344,7 @@ n_tty_receive_char_special(struct tty_stfinish_erasing (ldata);echo_char (c, tty);echo_char_raw ('\n' , ldata); -while (tail != ldata->read_head) { +while (MASK (tail) !=MASK (ldata->read_head)) {echo_char (read_buf (ldata, tail), tty); tail++; }
@@ -2506,7 +2509,7 @@ static unsigned long inq_canon(struct n_ tail = ldata->read_tail; nr = head - tail;/* Skip EOF-chars.. */ -while (head != tail) { +while (MASK (head) !=MASK (tail)) {if (test_bit (tail & (N_TTY_BUF_SIZE -1 ), ldata->read_flags) &&read_buf (ldata, tail) == __DISABLED_CHAR) nr--;
PATCH 210/366 n_tty: Access echo_* variables carefully.
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
commit ebec3f8f5271139df618ebdf8427e24ba102ba94 upstream.
syzbot is reporting stalls at __process_echoes() [1]. This is because since ldata->echo_commit < ldata->echo_tail becomes true for some reason, the discard loop is serving as almost infinite loop. This patch tries to avoid falling into ldata->echo_commit < ldata->echo_tail situation by making access to echo_* variables more carefully.
Since reset_buffer_flags() is called without output_lock held, it should not touch echo_* variables. And omit a call to reset_buffer_flags() from n_tty_open() by using vzalloc().
Since add_echo_byte() is called without output_lock held, it needs memory barrier between storing into echo_buf[] and incrementing echo_head counter. echo_buf() needs corresponding memory barrier before reading echo_buf[]. Lack of handling the possibility of not-yet-stored multi-byte operation might be the reason of falling into ldata->echo_commit < ldata->echo_tail situation, for if I do WARN_ON(ldata->echo_commit == tail + 1) prior to echo_buf(ldata, tail + 1), the WARN_ON() fires.
Also, explicitly masking with buffer for the former "while" loop, and use ldata->echo_commit > tail for the latter "while" loop.
[1] https://syzkaller.appspot.com/bug?id=17f23b094cd80df750e5b0f8982c521ee6bcbf40
--- drivers/tty/n_tty.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-)
drivers/tty/n_tty.c +24 -18
@@ -146,6 +146,7 @@ static inline unsigned char *read_buf_adstatic inline unsigned char echo_buf (struct n_tty_data *ldata,size_t i) { +smp_rmb ();/* Matches smp_wmb() in add_echo_byte(). */ return ldata->echo_buf[i & (N_TTY_BUF_SIZE -1 )]; }
@@ -347,8 +348,6 @@ static inline void put_tty_queue(unsignestatic void reset_buffer_flags (struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail =0 ; - ldata->echo_head = ldata->echo_tail = ldata->echo_commit =0 ; - ldata->echo_mark =0 ; ldata->line_start =0 ; ldata->erasing =0 ;
@@ -669,13 +668,20 @@ static size_t __process_echoes(struct tt old_space = space =tty_write_room (tty); tail = ldata->echo_tail; -while (ldata->echo_commit != tail) { +while (MASK (ldata->echo_commit) !=MASK (tail)) { c =echo_buf (ldata, tail);if (c ==ECHO_OP_START ) {unsigned char op;int no_space_left =0 ;/* +* Since add_echo_byte() is called without holding +* output_lock, we might see only portion of multi-byte +* operation. +*/ +if (MASK (ldata->echo_commit) ==MASK (tail +1 )) + goto not_yet_stored; +/* * If the buffer byte is the start of a multi-byte * operation, get the next byte, which is either the * op code or a control character value.
@@ -686,6 +692,8 @@ static size_t __process_echoes(struct ttunsigned int num_chars, num_bs;case ECHO_OP_ERASE_TAB : +if (MASK (ldata->echo_commit) ==MASK (tail +2 )) + goto not_yet_stored; num_chars =echo_buf (ldata, tail +2 );/*
@@ -780,7 +788,8 @@ static size_t __process_echoes(struct tt/* If the echo buffer is nearly full (so that the possibility exists * of echo overrun before the next commit), then discard enough * data at the tail to prevent a subsequent overrun */ -while (ldata->echo_commit - tail >=ECHO_DISCARD_WATERMARK ) { +while (ldata->echo_commit > tail && + ldata->echo_commit - tail >=ECHO_DISCARD_WATERMARK ) {if (echo_buf (ldata, tail) ==ECHO_OP_START ) {if (echo_buf (ldata, tail +1 ) ==ECHO_OP_ERASE_TAB ) tail +=3 ;
@@ -790,6 +799,7 @@ static size_t __process_echoes(struct tt tail++; } + not_yet_stored: ldata->echo_tail = tail;return old_space - space; }
@@ -800,6 +810,7 @@ static void commit_echoes(struct tty_strsize_t nr, old, echoed;size_t head; +mutex_lock (&ldata->output_lock); head = ldata->echo_head; ldata->echo_mark = head; old = ldata->echo_commit - ldata->echo_tail;
@@ -808,10 +819,12 @@ static void commit_echoes(struct tty_str* is over the threshold (and try again each time another * block is accumulated) */ nr = head - ldata->echo_tail; -if (nr <ECHO_COMMIT_WATERMARK || (nr %ECHO_BLOCK > old %ECHO_BLOCK )) +if (nr <ECHO_COMMIT_WATERMARK || + (nr %ECHO_BLOCK > old %ECHO_BLOCK )) { +mutex_unlock (&ldata->output_lock);return ; + } -mutex_lock (&ldata->output_lock); ldata->echo_commit = head; echoed =__process_echoes (tty);mutex_unlock (&ldata->output_lock);
@@ -862,7 +875,9 @@ static void flush_echoes(struct tty_strustatic inline void add_echo_byte (unsigned char c,struct n_tty_data *ldata) { - *echo_buf_addr (ldata, ldata->echo_head++) = c; + *echo_buf_addr (ldata, ldata->echo_head) = c; +smp_wmb ();/* Matches smp_rmb() in echo_buf(). */ + ldata->echo_head++; }/**
@@ -1928,31 +1943,22 @@ static int n_tty_open(struct tty_structstruct n_tty_data *ldata;/* Currently a malloc failure here can panic */ - ldata =vmalloc (sizeof (*ldata)); + ldata =vzalloc (sizeof (*ldata));if (!ldata) - goto err; +return -ENOMEM ; ldata->overrun_time = jiffies;mutex_init (&ldata->atomic_read_lock);mutex_init (&ldata->output_lock); tty->disc_data = ldata; -reset_buffer_flags (tty->disc_data); - ldata->column =0 ; - ldata->canon_column =0 ; ldata->minimum_to_wake =1 ; - ldata->num_overrun =0 ; - ldata->no_room =0 ; - ldata->lnext =0 ; tty->closing =0 ;/* indicate buffer work may resume */ clear_bit (TTY_LDISC_HALTED , &tty->flags);n_tty_set_termios (tty,NULL );tty_unthrottle (tty); -return 0 ; -err: -return -ENOMEM ; }static inline int input_available_p (struct tty_struct *tty,int poll)
PATCH 211/366 tty: vt, remove reduntant check
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby <[email protected]>
commit 182846a00f489849c55d113954f0c4a8a286ca39 upstream.
MAX_NR_CONSOLES and MAX_NR_USER_CONSOLES are both 63 since they were introduced in 1.1.54. And since vc_allocate does:
if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
if (!vc_cons[currcons].d) {
if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
return -EPERM;
}the second check is pointless. Remove both the check and the macro MAX_NR_USER_CONSOLES.
--- drivers/tty/vt/vt.c | 4 ---- include/uapi/linux/vt.h | 1 - 2 files changed, 5 deletions(-)
drivers/tty/vt/vt.c +0 -4
@@ -760,10 +760,6 @@ int vc_allocate(unsigned int currcons) /struct vc_data *vc;struct vt_notifier_param param; -/* prevent users from taking too much memory */ -if (currcons >=MAX_NR_USER_CONSOLES && !capable (CAP_SYS_RESOURCE )) -return -EPERM ; -/* due to the granularity of kmalloc, we waste some memory here */ /* the alloc is done in two steps, to optimize the common situation of a 25x80 console (structsize=216, screenbuf_size=4000) */
include/uapi/linux/vt.h +0 -1
@@ -8,7 +8,6 @@*/ #define MIN_NR_CONSOLES 1/* must be at least 1 */ #define MAX_NR_CONSOLES 63/* serial lines start at 64 */ -#define MAX_NR_USER_CONSOLES 63/* must be root to allocate above this */ /* Note: the ioctl VT_GETSTATE does not work for consoles 16 and higher (since it returns a short) */
PATCH 212/366 tty: vt, get rid of weird source code flow
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby <[email protected]>
commit 34902b7f2754e6d890feb0cee34187f1bc75c930 upstream.
Some code in vc_allocate is indented by 4 spaces. It is inside a condition. Invert the condition and move the code to the first indentation level (using \tab). And insert some empty lines to have logical code blocks separated.
Then, instead of freeing in an 'if' false branch, use goto-error label as fail path.
Maybe better to look at this patch with diff -w -b.
--- drivers/tty/vt/vt.c | 70 +++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 31 deletions(-)
drivers/tty/vt/vt.c +40 -32
@@ -752,46 +752,54 @@ static void visual_init(struct vc_data *int vc_allocate (unsigned int currcons)/* return 0 on success */ { +struct vt_notifier_param param; +struct vc_data *vc; +WARN_CONSOLE_UNLOCKED ();if (currcons >=MAX_NR_CONSOLES )return -ENXIO ; -if (!vc_cons[currcons].d) { -struct vc_data *vc; -struct vt_notifier_param param; - -/* due to the granularity of kmalloc, we waste some memory here */ -/* the alloc is done in two steps, to optimize the common situation -of a 25x80 console (structsize=216, screenbuf_size=4000) */ -/* although the numbers above are not valid since long ago, the -point is still up-to-date and the comment still has its value -even if only as a historical artifact. --mj, July 1998 */ - param.vc = vc =kzalloc (sizeof (struct vc_data ),GFP_KERNEL ); -if (!vc) + +if (vc_cons[currcons].d) +return 0 ; + +/* due to the granularity of kmalloc, we waste some memory here */ +/* the alloc is done in two steps, to optimize the common situation +of a 25x80 console (structsize=216, screenbuf_size=4000) */ +/* although the numbers above are not valid since long ago, the +point is still up-to-date and the comment still has its value +even if only as a historical artifact. --mj, July 1998 */ + param.vc = vc =kzalloc (sizeof (struct vc_data ),GFP_KERNEL ); +if (!vc)return -ENOMEM ; - vc_cons[currcons].d = vc; -tty_port_init (&vc->port); -INIT_WORK (&vc_cons[currcons].SAK_work, vc_SAK); -visual_init (vc, currcons,1 ); -if (!*vc->vc_uni_pagedir_loc) + + vc_cons[currcons].d = vc; +tty_port_init (&vc->port); +INIT_WORK (&vc_cons[currcons].SAK_work, vc_SAK); + +visual_init (vc, currcons,1 ); + +if (!*vc->vc_uni_pagedir_loc)con_set_default_unimap (vc); - vc->vc_screenbuf =kmalloc (vc->vc_screenbuf_size,GFP_KERNEL ); -if (!vc->vc_screenbuf) { -kfree (vc); - vc_cons[currcons].d =NULL ; -return -ENOMEM ; - } -/* If no drivers have overridden us and the user didn't pass a -boot option, default to displaying the cursor */ -if (global_cursor_default ==-1 ) - global_cursor_default =1 ; - -vc_init (vc, vc->vc_rows, vc->vc_cols,1 ); -vcs_make_sysfs (currcons); -atomic_notifier_call_chain (&vt_notifier_list,VT_ALLOCATE , ¶m); - } + vc->vc_screenbuf =kmalloc (vc->vc_screenbuf_size,GFP_KERNEL ); +if (!vc->vc_screenbuf) + goto err_free; + +/* If no drivers have overridden us and the user didn't pass a +boot option, default to displaying the cursor */ +if (global_cursor_default ==-1 ) + global_cursor_default =1 ; + +vc_init (vc, vc->vc_rows, vc->vc_cols,1 ); +vcs_make_sysfs (currcons); +atomic_notifier_call_chain (&vt_notifier_list,VT_ALLOCATE , ¶m); +return 0 ; +err_free: +kfree (vc); + vc_cons[currcons].d =NULL ; +return -ENOMEM ; } static inline int resize_screen(struct vc_data *vc, int width, int height,
PATCH 213/366 vt: prevent leaking uninitialized data to userspace via /dev/vcs*
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Potapenko <[email protected]>
commit 21eff69aaaa0e766ca0ce445b477698dc6a9f55a upstream.
KMSAN reported an infoleak when reading from /dev/vcs*:
BUG: KMSAN: kernel-infoleak in vcs_read+0x18ba/0x1cc0 Call Trace: ... kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1253 copy_to_user ./include/linux/uaccess.h:184 vcs_read+0x18ba/0x1cc0 drivers/tty/vt/vc_screen.c:352 __vfs_read+0x1b2/0x9d0 fs/read_write.c:416 vfs_read+0x36c/0x6b0 fs/read_write.c:452 ... Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:189 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:315 __kmalloc+0x13a/0x350 mm/slub.c:3818 kmalloc ./include/linux/slab.h:517 vc_allocate+0x438/0x800 drivers/tty/vt/vt.c:787 con_install+0x8c/0x640 drivers/tty/vt/vt.c:2880 tty_driver_install_tty drivers/tty/tty_io.c:1224 tty_init_dev+0x1b5/0x1020 drivers/tty/tty_io.c:1324 tty_open_by_driver drivers/tty/tty_io.c:1959 tty_open+0x17b4/0x2ed0 drivers/tty/tty_io.c:2007 chrdev_open+0xc25/0xd90 fs/char_dev.c:417 do_dentry_open+0xccc/0x1440 fs/open.c:794 vfs_open+0x1b6/0x2f0 fs/open.c:908 ... Bytes 0-79 of 240 are uninitialized
Consistently allocating |vc_screenbuf| with kzalloc() fixes the problem
--- drivers/tty/vt/vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/tty/vt/vt.c +2 -2
@@ -782,7 +782,7 @@ int vc_allocate(unsigned int currcons) /if (!*vc->vc_uni_pagedir_loc)con_set_default_unimap (vc); - vc->vc_screenbuf =kmalloc (vc->vc_screenbuf_size,GFP_KERNEL ); + vc->vc_screenbuf =kzalloc (vc->vc_screenbuf_size,GFP_KERNEL );if (!vc->vc_screenbuf) goto err_free;
@@ -869,7 +869,7 @@ static int vc_do_resize(struct tty_strucif (new_screen_size > (4 <<20 ))return -EINVAL ; - newscreen =kmalloc (new_screen_size,GFP_USER ); + newscreen =kzalloc (new_screen_size,GFP_USER );if (!newscreen)return -ENOMEM ;
syzbot
syzbotRe: [PATCH 3.16 213/366] vt: prevent leaking uninitialized data to userspace via /dev/vcs*
Can't find the corresponding bug.
Quoted 59 lines
3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Potapenko <[email protected]>
commit
21eff69aaaa0e766ca0ce445b477698dc6a9f55aupstream.KMSAN reported an infoleak when reading from
/dev/vcs*:BUG: KMSAN: kernel-infoleak in vcs_read+0x18ba/0x1cc0 Call Trace: ... kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1253 copy_to_user ./include/linux/uaccess.h:184 vcs_read+0x18ba/0x1cc0 drivers/tty/vt/vc_screen.c:352 __vfs_read+0x1b2/0x9d0 fs/read_write.c:416 vfs_read+0x36c/0x6b0 fs/read_write.c:452 ... Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:189 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:315 __kmalloc+0x13a/0x350 mm/slub.c:3818 kmalloc ./include/linux/slab.h:517 vc_allocate+0x438/0x800 drivers/tty/vt/vt.c:787 con_install+0x8c/0x640 drivers/tty/vt/vt.c:2880 tty_driver_install_tty drivers/tty/tty_io.c:1224 tty_init_dev+0x1b5/0x1020 drivers/tty/tty_io.c:1324 tty_open_by_driver drivers/tty/tty_io.c:1959 tty_open+0x17b4/0x2ed0 drivers/tty/tty_io.c:2007 chrdev_open+0xc25/0xd90 fs/char_dev.c:417 do_dentry_open+0xccc/0x1440 fs/open.c:794 vfs_open+0x1b6/0x2f0 fs/open.c:908 ... Bytes 0-79 of 240 are uninitializedConsistently allocating |vc_screenbuf| with
kzalloc()fixes the problemReported-by [email protected]Signed-off-by Alexander Potapenko <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>Signed-off-by Ben Hutchings <[email protected]>--- drivers/tty/vt/vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)drivers/tty/vt/vt.c +1
-1@@ -782,7 +782,7 @@ int vc_allocate(unsigned int currcons) /if (!*vc->vc_uni_pagedir_loc)con_set_default_unimap (vc); - vc->vc_screenbuf =kmalloc (vc->vc_screenbuf_size,GFP_KERNEL ); + vc->vc_screenbuf =kzalloc (vc->vc_screenbuf_size,GFP_KERNEL );if (!vc->vc_screenbuf) goto err_free;
drivers/tty/vt/vt.c static int vc_do_resize(struct tty_struc · line 874
Quoted 7 lines
drivers/tty/vt/vt.c +1
-1@@ -869,7 +869,7 @@ static int vc_do_resize(struct tty_strucif (new_screen_size > (4 <<20 ))return -EINVAL ; - newscreen =kmalloc (new_screen_size,GFP_USER ); + newscreen =kzalloc (new_screen_size,GFP_USER );if (!newscreen)return -ENOMEM ;
Can't find the corresponding bug.
PATCH 214/366 s390/qeth: don't clobber buffer on async TX completion
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Julian Wiedmann <[email protected]>
commit ce28867fd20c23cd769e78b4d619c4755bf71a1c upstream.
If qeth_qdio_output_handler() detects that a transmit requires async completion, it replaces the pending buffer's metadata object (qeth_qdio_out_buffer) so that this queue buffer can be re-used while the data is pending completion.
Later when the CQ indicates async completion of such a metadata object, qeth_qdio_cq_handler() tries to free any data associated with this object (since HW has now completed the transfer). By calling qeth_clear_output_buffer(), it erronously operates on the queue buffer that _previously_ belonged to this transfer ... but which has been potentially re-used several times by now.
This results in double-free's of the buffer's data, and failing transmits as the buffer descriptor is scrubbed in mid-air.
The correct way of handling this situation is to
1. scrub the queue buffer when it is prepared for re-use, and
2. later obtain the data addresses from the async-completion notifier (ie. the AOB), instead of the queue buffer.
All this only affects qeth devices used for af_iucv HiperTransport.
--- drivers/s390/net/qeth_core.h | 11 +++++++++++ drivers/s390/net/qeth_core_main.c | 22 ++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-)
drivers/s390/net/qeth_core.h +11 -0
@@ -844,6 +844,17 @@ struct qeth_trap_id {/*some helper functions*/ #define QETH_CARD_IFNAME (card) (((card)->dev)? (card)->dev->name : "") +static inline void qeth_scrub_qdio_buffer (struct qdio_buffer *buf, +unsigned int elements) +{ +unsigned int i; + +for (i =0 ; i < elements; i++) +memset (&buf->element[i],0 ,sizeof (struct qdio_buffer_element )); + buf->element[14 ].sflags =0 ; + buf->element[15 ].sflags =0 ; +} +static inline struct qeth_card *CARD_FROM_CDEV (struct ccw_device *cdev) { struct qeth_card *card = dev_get_drvdata(&((struct ccwgroup_device *)
drivers/s390/net/qeth_core_main.c +16 -6
@@ -65,9 +65,6 @@ static void qeth_notify_skbs(struct qethstruct qeth_qdio_out_buffer *buf, enum iucv_tx_notify notification);static void qeth_release_skbs (struct qeth_qdio_out_buffer *buf); -static void qeth_clear_output_buffer (struct qeth_qdio_out_q *queue, -struct qeth_qdio_out_buffer *buf, -enum qeth_qdio_buffer_states newbufstate);static int qeth_init_qdio_out_buf (struct qeth_qdio_out_q *,int );struct workqueue_struct *qeth_wq;
@@ -451,6 +448,7 @@ static inline void qeth_qdio_handle_aob(struct qaob *aob;struct qeth_qdio_out_buffer *buffer;enum iucv_tx_notify notification; +unsigned int i; aob = (struct qaob *)phys_to_virt (phys_aob_addr);QETH_CARD_TEXT (card,5 ,"haob" );
@@ -475,10 +473,18 @@ static inline void qeth_qdio_handle_aob(qeth_notify_skbs (buffer->q, buffer, notification); buffer->aob =NULL ; -qeth_clear_output_buffer (buffer->q, buffer, -QETH_QDIO_BUF_HANDLED_DELAYED ); +/* Free dangling allocations. The attached skbs are handled by +* qeth_cleanup_handled_pending(). +*/ +for (i =0 ; + i < aob->sb_count && i <QETH_MAX_BUFFER_ELEMENTS (card); + i++) { +if (aob->sba[i] && buffer->is_header[i]) +kmem_cache_free (qeth_core_header_cache, + (void *) aob->sba[i]); + } +atomic_set (&buffer->state,QETH_QDIO_BUF_HANDLED_DELAYED ); -/* from here on: do not touch buffer anymore */ qdio_release_aob (aob); }
@@ -3635,6 +3641,10 @@ void qeth_qdio_output_handler(struct ccwQETH_CARD_TEXT (queue->card,5 ,"aob" );QETH_CARD_TEXT_ (queue->card,5 ,"%lx" ,virt_to_phys (buffer->aob)); + +/* prepare the queue slot for re-use: */ +qeth_scrub_qdio_buffer (buffer->buffer, +QETH_MAX_BUFFER_ELEMENTS (card));if (qeth_init_qdio_out_buf (queue, bidx)) {QETH_CARD_TEXT (card,2 ,"outofbuf" );qeth_schedule_recovery (card);
PATCH 215/366 ahci: Disable LPM on Lenovo 50 series laptops with a too old BIOS
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
commit 240630e61870e62e39a97225048f9945848fa5f5 upstream.
There have been several reports of LPM related hard freezes about once a day on multiple Lenovo 50 series models. Strange enough these reports where not disk model specific as LPM issues usually are and some users with the exact same disk + laptop where seeing them while other users where not seeing these issues.
It turns out that enabling LPM triggers a firmware bug somewhere, which has been fixed in later BIOS versions.
This commit adds a new ahci_broken_lpm() function and a new ATA_FLAG_NO_LPM for dealing with this.
The ahci_broken_lpm() function contains DMI match info for the 4 models which are known to be affected by this and the DMI BIOS date field for known good BIOS versions. If the BIOS date is older then the one in the table LPM will be disabled and a warning will be printed.
Note the BIOS dates are for known good versions, some older versions may work too, but we don't know for sure, the table is using dates from BIOS versions for which users have confirmed that upgrading to that version makes the problem go away.
Unfortunately I've been unable to get hold of the reporter who reported that BIOS version 2.35 fixed the problems on the W541 for him. I've been able to verify the DMI_SYS_VENDOR and DMI_PRODUCT_VERSION from an older dmidecode, but I don't know the exact BIOS date as reported in the DMI. Lenovo keeps a changelog with dates in their release notes, but the dates there are the release dates not the build dates which are in DMI. So I've chosen to set the date to which we compare to one day past the release date of the 2.34 BIOS. I plan to fix this with a follow up commit once I've the necessary info.
--- drivers/ata/ahci.c | 59 +++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-core.c | 3 ++ include/linux/libata.h | 1 + 3 files changed, 63 insertions(+)
drivers/ata/ahci.c +59 -0
@@ -1225,6 +1225,59 @@ static bool ahci_broken_suspend(struct preturn strcmp (buf, dmi->driver_data) <0 ; } +static bool ahci_broken_lpm (struct pci_dev *pdev) +{ +static const struct dmi_system_id sysids[] = { +/* Various Lenovo 50 series have LPM issues with older BIOSen */ + { + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad X250" ), + }, + .driver_data ="20180406" ,/* 1.31 */ + }, + { + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad L450" ), + }, + .driver_data ="20180420" ,/* 1.28 */ + }, + { + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad T450s" ), + }, + .driver_data ="20180315" ,/* 1.33 */ + }, + { + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad W541" ), + }, +/* +* Note date based on release notes, 2.35 has been +* reported to be good, but I've been unable to get +* a hold of the reporter to get the DMI BIOS date. +* TODO: fix this. +*/ + .driver_data ="20180310" ,/* 2.35 */ + }, + { }/* terminate list */ + }; +const struct dmi_system_id *dmi =dmi_first_match (sysids); +int year, month, date; +char buf[9 ]; + +if (!dmi) +return false; + +dmi_get_date (DMI_BIOS_DATE , &year, &month, &date); +snprintf (buf,sizeof (buf),"%04d%02d%02d" , year, month, date); + +return strcmp (buf, dmi->driver_data) <0 ; +} +static bool ahci_broken_online (struct pci_dev *pdev) {#define ENCODE_BUSDEVFN (bus, slot, func) \
@@ -1608,6 +1661,12 @@ static int ahci_init_one(struct pci_dev "quirky BIOS, skipping spindown on poweroff\n"); } +if (ahci_broken_lpm (pdev)) { + pi.flags |=ATA_FLAG_NO_LPM ; +dev_warn (&pdev->dev, +"BIOS update required for Link Power Management support\n" ); + } +if (ahci_broken_suspend (pdev)) { hpriv->flags |=AHCI_HFLAG_NO_SUSPEND ; dev_warn(&pdev->dev,
drivers/ata/libata-core.c +3 -0
@@ -2227,6 +2227,9 @@ int ata_dev_configure(struct ata_device (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2) dev->horkage |= ATA_HORKAGE_NOLPM; +if (ap->flags &ATA_FLAG_NO_LPM ) + dev->horkage |=ATA_HORKAGE_NOLPM ; +if (dev->horkage &ATA_HORKAGE_NOLPM ) {ata_dev_warn (dev,"LPM support broken, forcing max_power\n" ); dev->link->ap->target_lpm_policy =ATA_LPM_MAX_POWER ;
include/linux/libata.h +1 -0
@@ -210,6 +210,7 @@ enum {ATA_FLAG_SLAVE_POSS = (1 <<0 ),/* host supports slave dev */ /* (doesn't imply presence) */ ATA_FLAG_SATA = (1 <<1 ), +ATA_FLAG_NO_LPM = (1 <<2 ),/* host not happy with LPM */ ATA_FLAG_NO_ATAPI = (1 <<6 ),/* No ATAPI support */ ATA_FLAG_PIO_DMA = (1 <<7 ),/* PIO cmds via DMA */ ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */
PATCH 216/366 ext4: Fix WARN_ON_ONCE in ext4_commit_super()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Pranay Kr. Srivastava" <[email protected]>
commit 4743f83990614af6adb09ea7aa3c37b78c4031ab upstream.
If there are racing calls to ext4_commit_super() it's possible for another writeback of the superblock to result in the buffer being marked with an error after we check if the buffer is marked as having a write error and the buffer up-to-date flag is set again. If that happens mark_buffer_dirty() can end up throwing a WARN_ON_ONCE.
Fix this by moving this check to write before we call write_buffer_dirty(), and keeping the buffer locked during this whole sequence.
--- fs/ext4/super.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-)
fs/ext4/super.c +16 -14
@@ -4653,20 +4653,6 @@ static int ext4_commit_super(struct supeif (!sbh ||block_device_ejected (sb))return error; -if (buffer_write_io_error (sbh)) { -/* -* Oh, dear. A previous attempt to write the -* superblock failed. This could happen because the -* USB device was yanked out. Or it could happen to -* be a transient write error and maybe the block will -* be remapped. Nothing we can do but to retry the -* write and hope for the best. -*/ -ext4_msg (sb,KERN_ERR ,"previous I/O error to " -"superblock detected" ); -clear_buffer_write_io_error (sbh); -set_buffer_uptodate (sbh); - }/* * If the file system is mounted read-only, don't update the * superblock write time. This avoids updating the superblock
@@ -4695,7 +4681,23 @@ static int ext4_commit_super(struct supe &EXT4_SB(sb)->s_freeinodes_counter));BUFFER_TRACE (sbh,"marking dirty" );ext4_superblock_csum_set (sb); +lock_buffer (sbh); +if (buffer_write_io_error (sbh)) { +/* +* Oh, dear. A previous attempt to write the +* superblock failed. This could happen because the +* USB device was yanked out. Or it could happen to +* be a transient write error and maybe the block will +* be remapped. Nothing we can do but to retry the +* write and hope for the best. +*/ +ext4_msg (sb,KERN_ERR ,"previous I/O error to " +"superblock detected" ); +clear_buffer_write_io_error (sbh); +set_buffer_uptodate (sbh); + }mark_buffer_dirty (sbh); +unlock_buffer (sbh);if (sync) { error =sync_dirty_buffer (sbh);if (error)
PATCH 217/366 ext4: check superblock mapped prior to committing
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jon Derrick <[email protected]>
commit a17712c8e4be4fa5404d20e9cd3b2b21eae7bc56 upstream.
This patch attempts to close a hole leading to a BUG seen with hot removals during writes [1].
A block device (NVME namespace in this test case) is formatted to EXT4 without partitions. It's mounted and write I/O is run to a file, then the device is hot removed from the slot. The superblock attempts to be written to the drive which is no longer present.
The typical chain of events leading to the BUG:ext4_commit_super()
__sync_dirty_buffer()
submit_bh()
submit_bh_wbc()
BUG_ON(!buffer_mapped(bh));This fix checks for the superblock's buffer head being mapped prior to syncing.
[1] https://www.spinics.net/lists/linux-ext4/msg56527.html
--- fs/ext4/super.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ext4/super.c +8 -0
@@ -4653,6 +4653,14 @@ static int ext4_commit_super(struct supeif (!sbh ||block_device_ejected (sb))return error; + +/* +* The superblock bh should be mapped, but it might not be if the +* device was hot-removed. Not much we can do but fail the I/O. +*/ +if (!buffer_mapped (sbh)) +return error; +/* * If the file system is mounted read-only, don't update the * superblock write time. This avoids updating the superblock
PATCH 218/366 sched/fair: Fix bandwidth timer clock drift condition
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Xunlei Pang <[email protected]>
commit 512ac999d2755d2b7109e996a76b6fb8b888631d upstream.
I noticed that cgroup task groups constantly get throttled even if they have low CPU usage, this causes some jitters on the response time to some of our business containers when enabling CPU quotas.
It's very simple to reproduce:
mkdir /sys/fs/cgroup/cpu/test
cd /sys/fs/cgroup/cpu/test
echo 100000 > cpu.cfs_quota_us
echo $$ > tasks
then repeat:
cat cpu.stat | grep nr_throttled # nr_throttled will increase steadily
After some analysis, we found that cfs_rq::runtime_remaining will be cleared by expire_cfs_rq_runtime() due to two equal but stale "cfs_{b|q}->runtime_expires" after period timer is re-armed.
The current condition to judge clock drift in expire_cfs_rq_runtime() is wrong, the two runtime_expires are actually the same when clock drift happens, so this condtion can never hit. The orginal design was correctly done by this commit:
a9cf55b28610 ("sched: Expire invalid runtime")
... but was changed to be the current implementation due to its locking bug.
This patch introduces another way, it adds a new field in both structures cfs_rq and cfs_bandwidth to record the expiration update sequence, and uses them to figure out if clock drift happens (true if they are equal).
[bwh: Backported to 3.16:
- Drop changes to other member types in struct cfs_bandwidth
- Adjust context]
--- kernel/sched/fair.c | 14 ++++++++------ kernel/sched/sched.h | 6 ++++-- 2 files changed, 12 insertions(+), 8 deletions(-)
kernel/sched/fair.c +8 -6
@@ -3143,6 +3143,7 @@ void __refill_cfs_bandwidth_runtime(stru now =sched_clock_cpu (smp_processor_id ()); cfs_b->runtime = cfs_b->quota; cfs_b->runtime_expires = now +ktime_to_ns (cfs_b->period); + cfs_b->expires_seq++; }static inline struct cfs_bandwidth *tg_cfs_bandwidth (struct task_group *tg)
@@ -3165,6 +3166,7 @@ static int assign_cfs_rq_runtime(structstruct task_group *tg = cfs_rq->tg;struct cfs_bandwidth *cfs_b =tg_cfs_bandwidth (tg);u64 amount =0 , min_amount, expires; +int expires_seq;/* note: this is a positive sum as runtime_remaining <= 0 */ min_amount =sched_cfs_bandwidth_slice () - cfs_rq->runtime_remaining;
@@ -3190,6 +3192,7 @@ static int assign_cfs_rq_runtime(struct cfs_b->idle =0 ; } } + expires_seq = cfs_b->expires_seq; expires = cfs_b->runtime_expires;raw_spin_unlock (&cfs_b->lock);
@@ -3199,8 +3202,10 @@ static int assign_cfs_rq_runtime(struct* spread between our sched_clock and the one on which runtime was * issued. */ -if ((s64)(expires - cfs_rq->runtime_expires) >0 ) +if (cfs_rq->expires_seq != expires_seq) { + cfs_rq->expires_seq = expires_seq; cfs_rq->runtime_expires = expires; + }return cfs_rq->runtime_remaining >0 ; }
@@ -3226,12 +3231,9 @@ static void expire_cfs_rq_runtime(struct* has not truly expired. * * Fortunately we can check determine whether this the case by checking -* whether the global deadline has advanced. It is valid to compare -* cfs_b->runtime_expires without any locks since we only care about -* exact equality, so a partial write will still work. +* whether the global deadline(cfs_b->expires_seq) has advanced. */ - -if (cfs_rq->runtime_expires != cfs_b->runtime_expires) { +if (cfs_rq->expires_seq == cfs_b->expires_seq) {/* extend local deadline, drift is bounded above by 2 ticks */ cfs_rq->runtime_expires +=TICK_NSEC ; }else {
kernel/sched/sched.h +2 -0
@@ -186,6 +186,7 @@ struct cfs_bandwidth {u64 quota, runtime;s64 hierarchal_quota;u64 runtime_expires; +int expires_seq;int idle, timer_active;struct hrtimer period_timer, slack_timer;
@@ -375,6 +376,7 @@ struct cfs_rq {#ifdef CONFIG_CFS_BANDWIDTH int runtime_enabled; +int expires_seq;u64 runtime_expires;s64 runtime_remaining;
PATCH 219/366 x86/cpufeatures: Hide AMD-specific speculation flags
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ben Hutchings <[email protected]>
Hide the AMD_{IBRS,IBPB,STIBP} flag from /proc/cpuinfo. This was done upstream as part of commit e7c587da1252 "x86/speculation: Use synthetic bits for IBRS/IBPB/STIBP". I already backported that commit but accidentally dropped this part.
---
arch/x86/include/asm/cpufeature.h +3 -3
@@ -253,9 +253,9 @@#define X86_FEATURE_SPEC_CTRL_SSBD (10*32+31)/* "" Speculative Store Bypass Disable */ /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 11 */ -#define X86_FEATURE_AMD_IBPB (11*32+12)/* Indirect Branch Prediction Barrier */ -#define X86_FEATURE_AMD_IBRS (11*32+14)/* Indirect Branch Restricted Speculation */ -#define X86_FEATURE_AMD_STIBP (11*32+15)/* Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_AMD_IBPB (11*32+12)/* "" Indirect Branch Prediction Barrier */ +#define X86_FEATURE_AMD_IBRS (11*32+14)/* "" Indirect Branch Restricted Speculation */ +#define X86_FEATURE_AMD_STIBP (11*32+15)/* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_VIRT_SSBD (11*32+25)/* Virtualized Speculative Store Bypass Disable */ /*
PATCH 220/366 x86/bugs: Add AMD's variant of SSB_NO
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Rzeszutek Wilk <[email protected]>
commit 24809860012e0130fbafe536709e08a22b3e959e upstream.
The AMD document outlining the SSBD handling 124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf mentions that the CPUID 8000_0008.EBX[26] will mean that the speculative store bypass disable is no longer needed.
A copy of this document is available at:
https://bugzilla.kernel.org/show_bug.cgi?id=199889
[bwh: Backported to 3.16:
- The feature bit is in feature word 11
- Adjust filename, context]
--- arch/x86/include/asm/cpufeature.h | 1 + arch/x86/kernel/cpu/common.c | 3 ++- arch/x86/kvm/cpuid.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-)
arch/x86/include/asm/cpufeature.h +1 -0
@@ -257,6 +257,7 @@#define X86_FEATURE_AMD_IBRS (11*32+14)/* "" Indirect Branch Restricted Speculation */ #define X86_FEATURE_AMD_STIBP (11*32+15)/* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_VIRT_SSBD (11*32+25)/* Virtualized Speculative Store Bypass Disable */ +#define X86_FEATURE_AMD_SSB_NO (11*32+26)/* "" Speculative Store Bypass is fixed in hardware. */ /* * BUG word(s)
arch/x86/kernel/cpu/common.c +2 -1
@@ -865,7 +865,8 @@ static void __init cpu_set_bug_bits(strurdmsrl (MSR_IA32_ARCH_CAPABILITIES , ia32_cap);if (!x86_match_cpu (cpu_no_spec_store_bypass) && - !(ia32_cap &ARCH_CAP_SSB_NO )) + !(ia32_cap &ARCH_CAP_SSB_NO ) && + !cpu_has (c,X86_FEATURE_AMD_SSB_NO ))setup_force_cpu_bug (X86_BUG_SPEC_STORE_BYPASS );if (x86_match_cpu (cpu_no_speculation))
arch/x86/kvm/cpuid.c +1 -1
@@ -302,7 +302,7 @@ static inline int __do_cpuid_ent(struct/* cpuid 0x80000008.ebx */ const u32 kvm_cpuid_8000_0008_ebx_x86_features = -F (AMD_IBPB ) |F (AMD_IBRS ) |F (VIRT_SSBD ); +F (AMD_IBPB ) |F (AMD_IBRS ) |F (VIRT_SSBD ) |F (AMD_SSB_NO );/* cpuid 0xC0000001.edx */ const u32 kvm_supported_word5_x86_features =
PATCH 221/366 x86/bugs: Add AMD's SPEC_CTRL MSR usage
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Rzeszutek Wilk <[email protected]>
commit 6ac2f49edb1ef5446089c7c660017732886d62d6 upstream.
The AMD document outlining the SSBD handling 124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf mentions that if CPUID 8000_0008.EBX[24] is set we should be using the SPEC_CTRL MSR (0x48) over the VIRT SPEC_CTRL MSR (0xC001_011f) for speculative store bypass disable.
This in effect means we should clear the X86_FEATURE_VIRT_SSBD flag so that we would prefer the SPEC_CTRL MSR.
See the document titled:
124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf
A copy of this document is available at
https://bugzilla.kernel.org/show_bug.cgi?id=199889
[bwh: Backported to 3.16:
- The feature bit is in feature word 11
- Update feature test in guest_cpuid_has_spec_ctrl() instead of svm_{get,set}_msr()
- Adjust filenames, context]
---
arch/x86/include/asm/cpufeature.h +1 -0
@@ -256,6 +256,7 @@#define X86_FEATURE_AMD_IBPB (11*32+12)/* "" Indirect Branch Prediction Barrier */ #define X86_FEATURE_AMD_IBRS (11*32+14)/* "" Indirect Branch Restricted Speculation */ #define X86_FEATURE_AMD_STIBP (11*32+15)/* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_AMD_SSBD (11*32+24)/* "" Speculative Store Bypass Disable */ #define X86_FEATURE_VIRT_SSBD (11*32+25)/* Virtualized Speculative Store Bypass Disable */ #define X86_FEATURE_AMD_SSB_NO (11*32+26)/* "" Speculative Store Bypass is fixed in hardware. */
arch/x86/kernel/cpu/bugs.c +7 -5
@@ -570,18 +570,20 @@ static enum ssb_mitigation __init __ssb_if (mode ==SPEC_STORE_BYPASS_DISABLE ) {setup_force_cpu_cap (X86_FEATURE_SPEC_STORE_BYPASS_DISABLE );/* -* Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD uses -* a completely different MSR and bit dependent on family. +* Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD may +* use a completely different MSR and bit dependent on family. */ switch (boot_cpu_data.x86_vendor) {case X86_VENDOR_INTEL : +case X86_VENDOR_AMD : +if (!static_cpu_has (X86_FEATURE_MSR_SPEC_CTRL )) { +x86_amd_ssb_disable (); +break ; + } x86_spec_ctrl_base |=SPEC_CTRL_SSBD ; x86_spec_ctrl_mask |=SPEC_CTRL_SSBD ;wrmsrl (MSR_IA32_SPEC_CTRL , x86_spec_ctrl_base);break ; -case X86_VENDOR_AMD : -x86_amd_ssb_disable (); -break ; } }
arch/x86/kernel/cpu/common.c +6 -0
@@ -716,6 +716,12 @@ static void init_speculation_control(strset_cpu_cap (c,X86_FEATURE_STIBP );set_cpu_cap (c,X86_FEATURE_MSR_SPEC_CTRL ); } + +if (cpu_has (c,X86_FEATURE_AMD_SSBD )) { +set_cpu_cap (c,X86_FEATURE_SSBD ); +set_cpu_cap (c,X86_FEATURE_MSR_SPEC_CTRL ); +clear_cpu_cap (c,X86_FEATURE_VIRT_SSBD ); + } }void get_cpu_cap (struct cpuinfo_x86 *c)
arch/x86/kvm/cpuid.c +8 -2
@@ -302,7 +302,8 @@ static inline int __do_cpuid_ent(struct/* cpuid 0x80000008.ebx */ const u32 kvm_cpuid_8000_0008_ebx_x86_features = -F (AMD_IBPB ) |F (AMD_IBRS ) |F (VIRT_SSBD ) |F (AMD_SSB_NO ); +F (AMD_IBPB ) |F (AMD_IBRS ) |F (AMD_SSBD ) |F (VIRT_SSBD ) | +F (AMD_SSB_NO );/* cpuid 0xC0000001.edx */ const u32 kvm_supported_word5_x86_features =
@@ -536,7 +537,12 @@ static inline int __do_cpuid_ent(struct entry->ebx |=F (VIRT_SSBD ); entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;cpuid_mask (&entry->ebx,11 ); -if (boot_cpu_has (X86_FEATURE_LS_CFG_SSBD )) +/* +* The preference is to use SPEC CTRL MSR instead of the +* VIRT_SPEC MSR. +*/ +if (boot_cpu_has (X86_FEATURE_LS_CFG_SSBD ) && + !boot_cpu_has (X86_FEATURE_AMD_SSBD )) entry->ebx |=F (VIRT_SSBD );break ; }
arch/x86/kvm/cpuid.h +1 -1
@@ -120,7 +120,7 @@ static inline bool guest_cpuid_has_spec_struct kvm_cpuid_entry2 *best; best =kvm_find_cpuid_entry (vcpu,0x80000008 ,0 ); -if (best && (best->ebx &bit (X86_FEATURE_AMD_IBRS ))) +if (best && (best->ebx & (bit (X86_FEATURE_AMD_IBRS |bit (X86_FEATURE_AMD_SSBD )))))return true; best =kvm_find_cpuid_entry (vcpu,7 ,0 );return best && (best->edx & (bit (X86_FEATURE_SPEC_CTRL ) |bit (X86_FEATURE_SPEC_CTRL_SSBD )));
arch/x86/kvm/svm.c +1 -1
@@ -3236,7 +3236,7 @@ static int svm_set_msr(struct kvm_vcpu *return 1 ;/* The STIBP bit doesn't fault even if it's not advertised */ -if (data & ~(SPEC_CTRL_IBRS |SPEC_CTRL_STIBP )) +if (data & ~(SPEC_CTRL_IBRS |SPEC_CTRL_STIBP |SPEC_CTRL_SSBD ))return 1 ; svm->spec_ctrl = data;
PATCH 222/366 x86/bugs: Switch the selection of mitigation from CPU vendor to CPU features
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Rzeszutek Wilk <[email protected]>
commit 108fab4b5c8f12064ef86e02cb0459992affb30f upstream.
Both AMD and Intel can have SPEC_CTRL_MSR for SSBD.
However AMD also has two more other ways of doing it - which are !SPEC_CTRL MSR ways.
--- arch/x86/kernel/cpu/bugs.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/bugs.c +3 -8
@@ -573,17 +573,12 @@ static enum ssb_mitigation __init __ssb_* Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD may * use a completely different MSR and bit dependent on family. */ -switch (boot_cpu_data.x86_vendor) { -case X86_VENDOR_INTEL : -case X86_VENDOR_AMD : -if (!static_cpu_has (X86_FEATURE_MSR_SPEC_CTRL )) { -x86_amd_ssb_disable (); -break ; - } +if (!static_cpu_has (X86_FEATURE_MSR_SPEC_CTRL )) +x86_amd_ssb_disable (); +else { x86_spec_ctrl_base |=SPEC_CTRL_SSBD ; x86_spec_ctrl_mask |=SPEC_CTRL_SSBD ;wrmsrl (MSR_IA32_SPEC_CTRL , x86_spec_ctrl_base); -break ; } }
PATCH 223/366 x86/bugs: Fix the AMD SSBD usage of the SPEC_CTRL MSR
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tom Lendacky <[email protected]>
commit 612bc3b3d4be749f73a513a17d9b3ee1330d3487 upstream.
On AMD, the presence of the MSR_SPEC_CTRL feature does not imply that the SSBD mitigation support should use the SPEC_CTRL MSR. Other features could have caused the MSR_SPEC_CTRL feature to be set, while a different SSBD mitigation option is in place.
Update the SSBD support to check for the actual SSBD features that will use the SPEC_CTRL MSR.
--- arch/x86/kernel/cpu/bugs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/bugs.c +5 -3
@@ -219,7 +219,8 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;/* SSBD controlled in MSR_SPEC_CTRL */ -if (static_cpu_has (X86_FEATURE_SPEC_CTRL_SSBD )) +if (static_cpu_has (X86_FEATURE_SPEC_CTRL_SSBD ) || +static_cpu_has (X86_FEATURE_AMD_SSBD )) hostval |=ssbd_tif_to_spec_ctrl (ti->flags);if (hostval != guestval) {
@@ -573,9 +574,10 @@ static enum ssb_mitigation __init __ssb_* Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD may * use a completely different MSR and bit dependent on family. */ -if (!static_cpu_has (X86_FEATURE_MSR_SPEC_CTRL )) +if (!static_cpu_has (X86_FEATURE_SPEC_CTRL_SSBD ) && + !static_cpu_has (X86_FEATURE_AMD_SSBD )) {x86_amd_ssb_disable (); -else { + }else { x86_spec_ctrl_base |=SPEC_CTRL_SSBD ; x86_spec_ctrl_mask |=SPEC_CTRL_SSBD ;wrmsrl (MSR_IA32_SPEC_CTRL , x86_spec_ctrl_base);
PATCH 224/366 RDMA/uverbs: Don't fail in creation of multiple flows
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
commit fe48aecb4df837540f13b5216f27ddb306aaf4b9 upstream.
The conversion from offsetof() calculations to sizeof() wrongly behaved for missed exact size and in scenario with more than one flow.
In such scenario we got "create flow failed, flow 10: 8 bytes left from uverb cmd" error, which is wrong because the size of kern_spec is exactly 8 bytes, and we were not supposed to fail.
--- drivers/infiniband/core/uverbs_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/core/uverbs_cmd.c +1 -1
@@ -2761,7 +2761,7 @@ int ib_uverbs_ex_create_flow(struct ib_u kern_spec = kern_flow_attr->flow_specs; ib_spec = flow_attr +1 ;for (i =0 ; i < flow_attr->num_of_specs && - cmd.flow_attr.size >sizeof (*kern_spec) && + cmd.flow_attr.size >=sizeof (*kern_spec) && cmd.flow_attr.size >= kern_spec->size; i++) { err = kern_spec_to_ib_spec(
PATCH 225/366 tracing: Fix missing return symbol in function_graph output
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Changbin Du <[email protected]>
commit 1fe4293f4b8de75824935f8d8e9a99c7fc6873da upstream.
The function_graph tracer does not show the interrupt return marker for the leaf entry. On leaf entries, we see an unbalanced interrupt marker (the interrupt was entered, but nevern left).
Before:
1) | SyS_write() {
1) | __fdget_pos() {
1) 0.061 us | __fget_light();
1) 0.289 us | }
1) | vfs_write() {
1) 0.049 us | rw_verify_area();
1) + 15.424 us | __vfs_write();
1) ==========> |
1) 6.003 us | smp_apic_timer_interrupt();
1) 0.055 us | __fsnotify_parent();
1) 0.073 us | fsnotify();
1) + 23.665 us | }
1) + 24.501 us | }After:
0) | SyS_write() {
0) | __fdget_pos() {
0) 0.052 us | __fget_light();
0) 0.328 us | }
0) | vfs_write() {
0) 0.057 us | rw_verify_area();
0) | __vfs_write() {
0) ==========> |
0) 8.548 us | smp_apic_timer_interrupt();
0) <========== |
0) + 36.507 us | } /* __vfs_write */
0) 0.049 us | __fsnotify_parent();
0) 0.066 us | fsnotify();
0) + 50.064 us | }
0) + 50.952 us | }[bwh: Backported to 3.16: Propagate return of TRACE_TYPE_PARTIAL_LINE from
print_graph_irq()]
--- kernel/trace/trace_functions_graph.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
kernel/trace/trace_functions_graph.c +6 -1
@@ -828,6 +828,7 @@ print_graph_entry_leaf(struct trace_iterstruct ftrace_graph_ret *graph_ret;struct ftrace_graph_ent *call;unsigned long long duration; +int cpu = iter->cpu;int ret;int i;
@@ -837,7 +838,6 @@ print_graph_entry_leaf(struct trace_iterif (data) {struct fgraph_cpu_data *cpu_data; -int cpu = iter->cpu; cpu_data =per_cpu_ptr (data->cpu_data, cpu);
@@ -874,6 +874,11 @@ print_graph_entry_leaf(struct trace_iterif (!ret)return TRACE_TYPE_PARTIAL_LINE ; + ret =print_graph_irq (iter, graph_ret->func,TRACE_GRAPH_RET , + cpu, iter->ent->pid, flags); +if (ret ==TRACE_TYPE_PARTIAL_LINE ) +return ret; +return TRACE_TYPE_HANDLED ; }
PATCH 226/366 mm: hugetlb: yield when prepping struct pages
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Cannon Matthews <[email protected]>
commit 520495fe96d74e05db585fc748351e0504d8f40d upstream.
When booting with very large numbers of gigantic (i.e. 1G) pages, the operations in the loop of gather_bootmem_prealloc, and specifically prep_compound_gigantic_page, takes a very long time, and can cause a softlockup if enough pages are requested at boot.
For example booting with 3844 1G pages requires prepping (set_compound_head, init the count) over 1 billion 4K tail pages, which takes considerable time.
Add a cond_resched() to the outer loop in gather_bootmem_prealloc() to prevent this lockup.
Tested: Booted with softlockup_panic=1 hugepagesz=1G hugepages=3844 and no softlockup is reported, and the hugepages are reported as successfully setup.
--- mm/hugetlb.c | 1 + 1 file changed, 1 insertion(+)
mm/hugetlb.c +1 -0
@@ -1546,6 +1546,7 @@ static void __init gather_bootmem_preall*/ if (hstate_is_gigantic (h))adjust_managed_page_count (page,1 << h->order); +cond_resched (); } }
PATCH 227/366 smsc75xx: Add workaround for gigabit link up hardware errata.
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Yuiko Oshino <[email protected]>
commit d461e3da905332189aad546b2ad9adbe6071c7cc upstream.
In certain conditions, the device may not be able to link in gigabit mode. This software workaround ensures that the device will not enter the failure state.
--- drivers/net/usb/smsc75xx.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
drivers/net/usb/smsc75xx.c +62 -0
@@ -81,6 +81,9 @@ static bool turbo_mode = true;module_param (turbo_mode, bool,0644 );MODULE_PARM_DESC (turbo_mode,"Enable multiple frames per Rx transaction" ); +static int smsc75xx_link_ok_nopm (struct usbnet *dev); +static int smsc75xx_phy_gig_workaround (struct usbnet *dev); +static int __must_check __smsc75xx_read_reg (struct usbnet *dev,u32 index,u32 *data,int in_pm) {
@@ -840,6 +843,9 @@ static int smsc75xx_phy_initialize(strucreturn -EIO ; } +/* phy workaround for gig link */ +smsc75xx_phy_gig_workaround (dev); +smsc75xx_mdio_write (dev->net, dev->mii.phy_id,MII_ADVERTISE ,ADVERTISE_ALL |ADVERTISE_CSMA |ADVERTISE_PAUSE_CAP |ADVERTISE_PAUSE_ASYM );
@@ -977,6 +983,62 @@ static int smsc75xx_wait_ready(struct usreturn -EIO ; } +static int smsc75xx_phy_gig_workaround (struct usbnet *dev) +{ +struct mii_if_info *mii = &dev->mii; +int ret =0 , timeout =0 ; +u32 buf, link_up =0 ; + +/* Set the phy in Gig loopback */ +smsc75xx_mdio_write (dev->net, mii->phy_id,MII_BMCR ,0x4040 ); + +/* Wait for the link up */ +do { + link_up =smsc75xx_link_ok_nopm (dev); +usleep_range (10000 ,20000 ); + timeout++; + }while ((!link_up) && (timeout <1000 )); + +if (timeout >=1000 ) { +netdev_warn (dev->net,"Timeout waiting for PHY link up\n" ); +return -EIO ; + } + +/* phy reset */ + ret =smsc75xx_read_reg (dev,PMT_CTL , &buf); +if (ret <0 ) { +netdev_warn (dev->net,"Failed to read PMT_CTL: %d\n" , ret); +return ret; + } + + buf |=PMT_CTL_PHY_RST ; + + ret =smsc75xx_write_reg (dev,PMT_CTL , buf); +if (ret <0 ) { +netdev_warn (dev->net,"Failed to write PMT_CTL: %d\n" , ret); +return ret; + } + + timeout =0 ; +do { +usleep_range (10000 ,20000 ); + ret =smsc75xx_read_reg (dev,PMT_CTL , &buf); +if (ret <0 ) { +netdev_warn (dev->net,"Failed to read PMT_CTL: %d\n" , + ret); +return ret; + } + timeout++; + }while ((buf &PMT_CTL_PHY_RST ) && (timeout <100 )); + +if (timeout >=100 ) { +netdev_warn (dev->net,"timeout waiting for PHY Reset\n" ); +return -EIO ; + } + +return 0 ; +} +static int smsc75xx_reset (struct usbnet *dev) {struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0 ]);
PATCH 228/366 USB: serial: cp210x: add another USB ID for Qivicon ZigBee stick
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Olli Salonen <[email protected]>
commit 367b160fe4717c14a2a978b6f9ffb75a7762d3ed upstream.
There are two versions of the Qivicon Zigbee stick in circulation. This adds the second USB ID to the cp210x driver.
--- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/cp210x.c +1 -0
@@ -145,6 +145,7 @@ static const struct usb_device_id id_tab { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ { USB_DEVICE(0x10C4, 0x89A4) }, /* CESINEL FTBC Flexible Thyristor Bridge Controller */ + { USB_DEVICE(0x10C4, 0x89FB) }, /* Qivicon ZigBee USB Radio Stick */ { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */ { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */
PATCH 229/366 USB: serial: ch341: fix type promotion bug in ch341_control_in()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit e33eab9ded328ccc14308afa51b5be7cbe78d30b upstream.
The "r" variable is an int and "bufsize" is an unsigned int so the comparison is type promoted to unsigned. If usb_control_msg() returns a negative that is treated as a high positive value and the error handling doesn't work.
--- drivers/usb/serial/ch341.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/serial/ch341.c +1 -1
@@ -131,7 +131,7 @@ static int ch341_control_in(struct usb_d r =usb_control_msg (dev,usb_rcvctrlpipe (dev,0 ), request,USB_TYPE_VENDOR |USB_RECIP_DEVICE |USB_DIR_IN , value, index, buf, bufsize,DEFAULT_TIMEOUT ); -if (r < bufsize) { +if (r < (int )bufsize) {if (r >=0 ) { dev_err(&dev->dev, "short control message received (%d < %u)\n",
PATCH 230/366 drm/udl: fix display corruption of the last line
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 99ec9e77511dea55d81729fc80b6c63a61bfa8e0 upstream.
The displaylink hardware has such a peculiarity that it doesn't render a command until next command is received. This produces occasional corruption, such as when setting 22x11 font on the console, only the first line of the cursor will be blinking if the cursor is located at some specific columns.
When we end up with a repeating pixel, the driver has a bug that it leaves one uninitialized byte after the command (and this byte is enough to flush the command and render it - thus it fixes the screen corruption), however whe we end up with a non-repeating pixel, there is no byte appended and this results in temporary screen corruption.
This patch fixes the screen corruption by always appending a byte 0xAF at the end of URB. It also removes the uninitialized byte.
--- drivers/gpu/drm/udl/udl_fb.c | 5 ++++- drivers/gpu/drm/udl/udl_transfer.c | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-)
drivers/gpu/drm/udl/udl_fb.c +4 -1
@@ -234,7 +234,10 @@ int udl_handle_damage(struct udl_framebuif (cmd > (char *) urb->transfer_buffer) {/* Send partial buffer remaining before exiting */ -int len = cmd - (char *) urb->transfer_buffer; +int len; +if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ =0xAF ; + len = cmd - (char *) urb->transfer_buffer; ret =udl_submit_urb (dev, urb, len); bytes_sent += len; }else
drivers/gpu/drm/udl/udl_transfer.c +7 -4
@@ -149,11 +149,11 @@ static void udl_compress_hline16( raw_pixels_count_byte = cmd++;/* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + (min (MAX_CMD_PIXELS +1 , -min ((int )(pixel_end - pixel) / bpp, - (int )(cmd_buffer_end - cmd) /2 ))) * bpp; + cmd_pixel_end = pixel +min3 (MAX_CMD_PIXELS +1UL , + (unsigned long )(pixel_end - pixel) / bpp, + (unsigned long )(cmd_buffer_end -1 - cmd) /2 ) * bpp; -prefetch_range ((void *) pixel, (cmd_pixel_end - pixel) * bpp); +prefetch_range ((void *) pixel, cmd_pixel_end - pixel);while (pixel < cmd_pixel_end) {const u8 *const start = pixel;
@@ -193,6 +193,9 @@ static void udl_compress_hline16(if (pixel > raw_pixel_start) {/* finalize last RAW span */ *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) &0xFF ; + }else { +/* undo unused byte */ + cmd--; } *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) &0xFF ;
PATCH 231/366 cifs: Fix use after free of a mid_q_entry
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lars Persson <[email protected]>
commit 696e420bb2a6624478105651d5368d45b502b324 upstream.
With protocol version 2.0 mounts we have seen crashes with corrupt mid entries. Either the server->pending_mid_q list becomes corrupt with a cyclic reference in one element or a mid object fetched by the demultiplexer thread becomes overwritten during use.
Code review identified a race between the demultiplexer thread and the request issuing thread. The demultiplexer thread seems to be written with the assumption that it is the sole user of the mid object until it calls the mid callback which either wakes the issuer task or deletes the mid.
This assumption is not true because the issuer task can be woken up earlier by a signal. If the demultiplexer thread has proceeded as far as setting the mid_state to MID_RESPONSE_RECEIVED then the issuer thread will happily end up calling cifs_delete_mid while the demultiplexer thread still is using the mid object.
Inserting a delay in the cifs demultiplexer thread widens the race window and makes reproduction of the race very easy:
if (server->large_buf) buf = server->bigbuf;
+ usleep_range(500, 4000);
server->lstrp = jiffies;
To resolve this I think the proper solution involves putting a reference count on the mid object. This patch makes sure that the demultiplexer thread holds a reference until it has finished processing the transaction.
--- fs/cifs/cifsglob.h | 1 + fs/cifs/cifsproto.h | 1 + fs/cifs/connect.c | 8 +++++++- fs/cifs/smb1ops.c | 1 + fs/cifs/smb2ops.c | 1 + fs/cifs/smb2transport.c | 1 + fs/cifs/transport.c | 18 +++++++++++++++++- 7 files changed, 29 insertions(+), 2 deletions(-)
fs/cifs/cifsglob.h +1 -0
@@ -1232,6 +1232,7 @@ typedef void (mid_callback_t)(struct mid/* one of these for every pending CIFS request to the server */ struct mid_q_entry {struct list_head qhead;/* mids waiting on reply from this server */ +struct kref refcount;struct TCP_Server_Info *server;/* server corresponding to this mid */ __u64 mid;/* multiplex id */ __u32 pid;/* process id */
fs/cifs/cifsproto.h +1 -0
@@ -74,6 +74,7 @@ extern struct mid_q_entry *AllocMidQEntr struct TCP_Server_Info *server);extern void DeleteMidQEntry (struct mid_q_entry *midEntry);extern void cifs_delete_mid (struct mid_q_entry *mid); +extern void cifs_mid_q_entry_release (struct mid_q_entry *midEntry);extern void cifs_wake_up_task (struct mid_q_entry *mid); extern int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
fs/cifs/connect.c +6 -1
@@ -903,8 +903,11 @@ cifs_demultiplex_thread(void *p)else length = mid_entry->receive (server, mid_entry); -if (length <0 ) +if (length <0 ) { +if (mid_entry) +cifs_mid_q_entry_release (mid_entry);continue ; + }if (server->large_buf) buf = server->bigbuf;
@@ -920,6 +923,8 @@ cifs_demultiplex_thread(void *p)if (!mid_entry->multiRsp || mid_entry->multiEnd) mid_entry->callback (mid_entry); + +cifs_mid_q_entry_release (mid_entry); }else if (server->ops->is_oplock_break && server->ops->is_oplock_break (buf, server)) {cifs_dbg (FYI ,"Received oplock break\n" );
fs/cifs/smb1ops.c +1 -0
@@ -104,6 +104,7 @@ cifs_find_mid(struct TCP_Server_Info *seif (compare_mid (mid->mid, buf) && mid->mid_state ==MID_REQUEST_SUBMITTED &&le16_to_cpu (mid->command) == buf->Command) { +kref_get (&mid->refcount);spin_unlock (&GlobalMid_Lock);return mid; }
fs/cifs/smb2ops.c +1 -0
@@ -138,6 +138,7 @@ smb2_find_mid(struct TCP_Server_Info *seif ((mid->mid == hdr->MessageId) && (mid->mid_state ==MID_REQUEST_SUBMITTED ) && (mid->command == hdr->Command)) { +kref_get (&mid->refcount);spin_unlock (&GlobalMid_Lock);return mid; }
fs/cifs/smb2transport.c +1 -0
@@ -531,6 +531,7 @@ smb2_mid_entry_alloc(const struct smb2_hreturn temp; else {memset (temp,0 ,sizeof (struct mid_q_entry )); +kref_init (&temp->refcount); temp->mid = smb_buffer->MessageId;/* always LE */ temp->pid = current->pid; temp->command = smb_buffer->Command;/* Always LE */
fs/cifs/transport.c +17 -1
@@ -58,6 +58,7 @@ AllocMidQEntry(const struct smb_hdr *smbreturn temp; else {memset (temp,0 ,sizeof (struct mid_q_entry )); +kref_init (&temp->refcount); temp->mid =get_mid (smb_buffer); temp->pid = current->pid; temp->command =cpu_to_le16 (smb_buffer->Command);
@@ -80,6 +81,21 @@ AllocMidQEntry(const struct smb_hdr *smbreturn temp; } +static void _cifs_mid_q_entry_release (struct kref *refcount) +{ + struct mid_q_entry *mid = container_of(refcount, struct mid_q_entry, + refcount); + +mempool_free (mid, cifs_mid_poolp); +} + +void cifs_mid_q_entry_release (struct mid_q_entry *midEntry) +{ +spin_lock (&GlobalMid_Lock); +kref_put (&midEntry->refcount, _cifs_mid_q_entry_release); +spin_unlock (&GlobalMid_Lock); +} +void DeleteMidQEntry (struct mid_q_entry *midEntry) {
@@ -108,7 +124,7 @@ DeleteMidQEntry(struct mid_q_entry *midE } }#endif -mempool_free (midEntry, cifs_mid_poolp); +cifs_mid_q_entry_release (midEntry); }void
PATCH 232/366 cifs: Fix infinite loop when using hard mount option
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
commit 7ffbe65578b44fafdef577a360eb0583929f7c6e upstream.
For every request we send, whether it is SMB1 or SMB2+, we attempt to reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying out the request.
So, while server->tcpStatus != CifsNeedReconnect, we wait for the reconnection to succeed on wait_event_interruptible_timeout(). If it returns, that means that either the condition was evaluated to true, or timeout elapsed, or it was interrupted by a signal.
Since we're not handling the case where the process woke up due to a received signal (-ERESTARTSYS), the next call to wait_event_interruptible_timeout() will _always_ fail and we end up looping forever inside either cifs_reconnect_tcon() or smb2_reconnect().
Here's an example of how to trigger that:
$ mount.cifs //foo/share /mnt/test -o username=foo,password=foo,vers=1.0,hard
(break connection to server before executing bellow cmd)
$ stat -f /mnt/test & sleep 140 [1] 2511
$ ps -aux -q 2511 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2511 0.0 0.0 12892 1008 pts/0 S 12:24 0:00 stat -f /mnt/test
$ kill -9 2511
(wait for a while; process is stuck in the kernel)
$ ps -aux -q 2511 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2511 83.2 0.0 12892 1008 pts/0 R 12:24 30:01 stat -f /mnt/test
By using 'hard' mount point means that cifs.ko will keep retrying indefinitely, however we must allow the process to be killed otherwise it would hang the system.
--- fs/cifs/cifssmb.c | 10 ++++++++-- fs/cifs/smb2pdu.c | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-)
fs/cifs/cifssmb.c +8 -2
@@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tc* greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { -wait_event_interruptible_timeout (server->response_q, - (server->tcpStatus != CifsNeedReconnect),10 *HZ ); + rc =wait_event_interruptible_timeout (server->response_q, + (server->tcpStatus != CifsNeedReconnect), +10 *HZ ); +if (rc <0 ) { +cifs_dbg (FYI ,"%s: aborting reconnect due to a received" +" signal by the process\n" , __func__); +return -ERESTARTSYS ; + }/* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect)
fs/cifs/smb2pdu.c +12 -6
@@ -158,7 +158,7 @@ out:static int smb2_reconnect (__le16 smb2_command,struct cifs_tcon *tcon) { -int rc =0 ; +int rc;struct nls_table *nls_codepage;struct cifs_ses *ses;struct TCP_Server_Info *server;
@@ -169,10 +169,10 @@ smb2_reconnect(__le16 smb2_command, stru* for those three - in the calling routine. */ if (tcon ==NULL ) -return rc; +return 0 ;if (smb2_command ==SMB2_TREE_CONNECT ) -return rc; +return 0 ;if (tcon->tidStatus == CifsExiting) {/*
@@ -215,8 +215,14 @@ smb2_reconnect(__le16 smb2_command, strureturn -EAGAIN ; } -wait_event_interruptible_timeout (server->response_q, - (server->tcpStatus != CifsNeedReconnect),10 *HZ ); + rc =wait_event_interruptible_timeout (server->response_q, + (server->tcpStatus != CifsNeedReconnect), +10 *HZ ); +if (rc <0 ) { +cifs_dbg (FYI ,"%s: aborting reconnect due to a received" +" signal by the process\n" , __func__); +return -ERESTARTSYS ; + }/* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect)
@@ -234,7 +240,7 @@ smb2_reconnect(__le16 smb2_command, stru }if (!tcon->ses->need_reconnect && !tcon->need_reconnect) -return rc; +return 0 ; nls_codepage =load_nls_default ();
PATCH 233/366 cifs: store the leaseKey in the fid on SMB2_open
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ronnie Sahlberg <[email protected]>
commit 96164ab2d880c9539989bea68d4790f6fd619b1f upstream.
In SMB2_open(), if we got a lease we need to store this in the fid structure or else we will never be able to map a lease break back to which file/fid it applies to.
--- fs/cifs/cifsglob.h | 2 +- fs/cifs/smb2ops.c | 7 +++++-- fs/cifs/smb2pdu.c | 8 +++++--- 3 files changed, 11 insertions(+), 6 deletions(-)
fs/cifs/cifsglob.h +1 -1
@@ -383,7 +383,7 @@ struct smb_version_operations {/* create lease context buffer for CREATE request */ char * (*create_lease_buf)(u8 *,u8 );/* parse lease context buffer and return oplock/epoch info */ -__u8 (*parse_lease_buf)(void *,unsigned int *); +__u8 (*parse_lease_buf)(void *buf,unsigned int *epoch,char *lkey);int (*clone_range)(const unsigned int ,struct cifsFileInfo *src_file,struct cifsFileInfo *target_file,u64 src_off,u64 len,u64 dest_off);
fs/cifs/smb2ops.c +5 -2
@@ -1118,7 +1118,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 }static __u8 -smb2_parse_lease_buf (void *buf,unsigned int *epoch) +smb2_parse_lease_buf (void *buf,unsigned int *epoch,char *lease_key) {struct create_lease *lc = (struct create_lease *)buf;
@@ -1129,13 +1129,16 @@ smb2_parse_lease_buf(void *buf, unsigned }static __u8 -smb3_parse_lease_buf (void *buf,unsigned int *epoch) +smb3_parse_lease_buf (void *buf,unsigned int *epoch,char *lease_key) {struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; *epoch =le16_to_cpu (lc->lcontext.Epoch);if (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS )return SMB2_OPLOCK_LEVEL_NOCHANGE ; +if (lease_key) +memcpy (lease_key, &lc->lcontext.LeaseKeyLow, +SMB2_LEASE_KEY_SIZE );return le32_to_cpu (lc->lcontext.LeaseState); }
fs/cifs/smb2pdu.c +5 -3
@@ -1054,7 +1054,7 @@ create_reconnect_durable_buf(struct cifsstatic __u8 parse_lease_state (struct TCP_Server_Info *server,struct smb2_create_rsp *rsp, -unsigned int *epoch) +unsigned int *epoch,char *lease_key) {char *data_offset;struct create_context *cc;
@@ -1069,7 +1069,8 @@ parse_lease_state(struct TCP_Server_Info name =le16_to_cpu (cc->NameOffset) + (char *)cc;if (le16_to_cpu (cc->NameLength) ==4 &&strncmp (name,"RqLs" ,4 ) ==0 ) -return server->ops->parse_lease_buf (cc, epoch); +return server->ops->parse_lease_buf (cc, epoch, + lease_key); next =le32_to_cpu (cc->Next);if (!next)
@@ -1262,7 +1263,8 @@ SMB2_open(const unsigned int xid, struct }if (rsp->OplockLevel ==SMB2_OPLOCK_LEVEL_LEASE ) - *oplock =parse_lease_state (server, rsp, &oparms->fid->epoch); + *oplock =parse_lease_state (server, rsp, &oparms->fid->epoch, + oparms->fid->lease_key);else *oplock = rsp->OplockLevel; creat_exit:
PATCH 234/366 cifs: Fix stack out-of-bounds in smb{2,3}_create_lease_buf()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Brivio <[email protected]>
commit 729c0c9dd55204f0c9a823ac8a7bfa83d36c7e78 upstream.
smb{2,3}_create_lease_buf() store a lease key in the lease context for later usage on a lease break.
In most paths, the key is currently sourced from data that happens to be on the stack near local variables for oplock in SMB2_open() callers, e.g. from open_shroot(), whereas smb2_open_file() properly allocates space on its stack for it.
The address of those local variables holding the oplock is then passed to create_lease_buf handlers via SMB2_open(), and 16 bytes near oplock are used. This causes a stack out-of-bounds access as reported by KASAN on SMB2.1 and SMB3 mounts (first out-of-bounds access is shown here):
[ 111.528823] BUG: KASAN: stack-out-of-bounds in smb3_create_lease_buf+0x399/0x3b0 [cifs] [ 111.530815] Read of size 8 at addr ffff88010829f249 by task mount.cifs/985 [ 111.532838] CPU: 3 PID: 985 Comm: mount.cifs Not tainted 4.18.0-rc3+ #91 [ 111.534656] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 [ 111.536838] Call Trace: [ 111.537528] dump_stack+0xc2/0x16b [ 111.540890] print_address_description+0x6a/0x270 [ 111.542185] kasan_report+0x258/0x380 [ 111.544701] smb3_create_lease_buf+0x399/0x3b0 [cifs] [ 111.546134] SMB2_open+0x1ef8/0x4b70 [cifs] [ 111.575883] open_shroot+0x339/0x550 [cifs] [ 111.591969] smb3_qfs_tcon+0x32c/0x1e60 [cifs] [ 111.617405] cifs_mount+0x4f3/0x2fc0 [cifs] [ 111.674332] cifs_smb3_do_mount+0x263/0xf10 [cifs] [ 111.677915] mount_fs+0x55/0x2b0 [ 111.679504] vfs_kern_mount.part.22+0xaa/0x430 [ 111.684511] do_mount+0xc40/0x2660 [ 111.698301] ksys_mount+0x80/0xd0 [ 111.701541] do_syscall_64+0x14e/0x4b0 [ 111.711807] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 111.713665] RIP: 0033:0x7f372385b5fa [ 111.715311] Code: 48 8b 0d 99 78 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 66 78 2c 00 f7 d8 64 89 01 48 [ 111.720330] RSP: 002b:00007ffff27049d8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 [ 111.722601] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f372385b5fa [ 111.724842] RDX: 000055c2ecdc73b2 RSI: 000055c2ecdc73f9 RDI: 00007ffff270580f [ 111.727083] RBP: 00007ffff2705804 R08: 000055c2ee976060 R09: 0000000000001000 [ 111.729319] R10: 0000000000000000 R11: 0000000000000206 R12: 00007f3723f4d000 [ 111.731615] R13: 000055c2ee976060 R14: 00007f3723f4f90f R15: 0000000000000000
[ 111.735448] The buggy address belongs to the page: [ 111.737420] page:ffffea000420a7c0 count:0 mapcount:0 mapping:0000000000000000 index:0x0 [ 111.739890] flags: 0x17ffffc0000000() [ 111.741750] raw: 0017ffffc0000000 0000000000000000 dead000000000200 0000000000000000 [ 111.744216] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 [ 111.746679] page dumped because: kasan: bad access detected
[ 111.750482] Memory state around the buggy address: [ 111.752562] ffff88010829f100: 00 f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00 [ 111.754991] ffff88010829f180: 00 00 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 [ 111.757401] >ffff88010829f200: 00 00 00 00 00 f1 f1 f1 f1 01 f2 f2 f2 f2 f2 f2 [ 111.759801] ^ [ 111.762034] ffff88010829f280: f2 02 f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 [ 111.764486] ffff88010829f300: f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 111.766913] ==================================================================
Lease keys are however already generated and stored in fid data on open and create paths: pass them down to the lease context creation handlers and use them.
--- fs/cifs/cifsglob.h | 2 +- fs/cifs/smb2file.c | 11 ++++------- fs/cifs/smb2ops.c | 9 +++------ fs/cifs/smb2pdu.c | 7 ++++--- fs/cifs/smb2pdu.h | 6 ++---- 5 files changed, 14 insertions(+), 21 deletions(-)
fs/cifs/cifsglob.h +1 -1
@@ -381,7 +381,7 @@ struct smb_version_operations {void (*set_oplock_level)(struct cifsInodeInfo *,__u32 ,unsigned int ,bool *);/* create lease context buffer for CREATE request */ -char * (*create_lease_buf)(u8 *,u8 ); +char * (*create_lease_buf)(u8 *lease_key,u8 oplock);/* parse lease context buffer and return oplock/epoch info */ __u8 (*parse_lease_buf)(void *buf,unsigned int *epoch,char *lkey); int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file,
fs/cifs/smb2file.c +4 -7
@@ -41,7 +41,7 @@ smb2_open_file(const unsigned int xid, sint rc;__le16 *smb2_path;struct smb2_file_all_info *smb2_data =NULL ; -__u8 smb2_oplock[17 ]; +__u8 smb2_oplock;struct cifs_fid *fid = oparms->fid; smb2_path =cifs_convert_path_to_utf16 (oparms->path, oparms->cifs_sb);
@@ -58,12 +58,9 @@ smb2_open_file(const unsigned int xid, s } oparms->desired_access |=FILE_READ_ATTRIBUTES ; - *smb2_oplock =SMB2_OPLOCK_LEVEL_BATCH ; + smb2_oplock =SMB2_OPLOCK_LEVEL_BATCH ; -if (oparms->tcon->ses->server->capabilities &SMB2_GLOBAL_CAP_LEASING ) -memcpy (smb2_oplock +1 , fid->lease_key,SMB2_LEASE_KEY_SIZE ); - - rc =SMB2_open (xid, oparms, smb2_path, smb2_oplock, smb2_data,NULL ); + rc =SMB2_open (xid, oparms, smb2_path, &smb2_oplock, smb2_data,NULL );if (rc) goto out;
@@ -80,7 +77,7 @@ smb2_open_file(const unsigned int xid, smove_smb2_info_to_cifs (buf, smb2_data); } - *oplock = *smb2_oplock; + *oplock = smb2_oplock; out:kfree (smb2_data);kfree (smb2_path);
fs/cifs/smb2ops.c +3 -6
@@ -1072,8 +1072,7 @@ smb2_create_lease_buf(u8 *lease_key, u8if (!buf)return NULL ; - buf->lcontext.LeaseKeyLow =cpu_to_le64 (*((u64 *)lease_key)); - buf->lcontext.LeaseKeyHigh =cpu_to_le64 (*((u64 *)(lease_key +8 ))); +memcpy (&buf->lcontext.LeaseKey, lease_key,SMB2_LEASE_KEY_SIZE ); buf->lcontext.LeaseState =map_oplock_to_lease (oplock); buf->ccontext.DataOffset = cpu_to_le16(offsetof
@@ -1099,8 +1098,7 @@ smb3_create_lease_buf(u8 *lease_key, u8if (!buf)return NULL ; - buf->lcontext.LeaseKeyLow =cpu_to_le64 (*((u64 *)lease_key)); - buf->lcontext.LeaseKeyHigh =cpu_to_le64 (*((u64 *)(lease_key +8 ))); +memcpy (&buf->lcontext.LeaseKey, lease_key,SMB2_LEASE_KEY_SIZE ); buf->lcontext.LeaseState =map_oplock_to_lease (oplock); buf->ccontext.DataOffset = cpu_to_le16(offsetof
@@ -1137,8 +1135,7 @@ smb3_parse_lease_buf(void *buf, unsignedif (lc->lcontext.LeaseFlags &SMB2_LEASE_FLAG_BREAK_IN_PROGRESS )return SMB2_OPLOCK_LEVEL_NOCHANGE ;if (lease_key) -memcpy (lease_key, &lc->lcontext.LeaseKeyLow, -SMB2_LEASE_KEY_SIZE ); +memcpy (lease_key, &lc->lcontext.LeaseKey,SMB2_LEASE_KEY_SIZE );return le32_to_cpu (lc->lcontext.LeaseState); }
fs/cifs/smb2pdu.c +4 -3
@@ -1084,12 +1084,12 @@ parse_lease_state(struct TCP_Server_Infostatic int add_lease_context (struct TCP_Server_Info *server,struct kvec *iov, -unsigned int *num_iovec,__u8 *oplock) +unsigned int *num_iovec,u8 *lease_key,__u8 *oplock) {struct smb2_create_req *req = iov[0 ].iov_base;unsigned int num = *num_iovec; - iov[num].iov_base = server->ops->create_lease_buf (oplock+1 , *oplock); + iov[num].iov_base = server->ops->create_lease_buf (lease_key, *oplock);if (iov[num].iov_base ==NULL )return -ENOMEM ; iov[num].iov_len = server->vals->create_lease_size;
@@ -1212,7 +1212,8 @@ SMB2_open(const unsigned int xid, struct *oplock == SMB2_OPLOCK_LEVEL_NONE) req->RequestedOplockLevel = *oplock; else { - rc =add_lease_context (server, iov, &num_iovecs, oplock); + rc =add_lease_context (server, iov, &num_iovecs, + oparms->fid->lease_key, oplock);if (rc) {cifs_small_buf_release (req);kfree (copy_path);
fs/cifs/smb2pdu.h +2 -4
@@ -510,16 +510,14 @@ struct create_context {#define SMB2_LEASE_KEY_SIZE 16struct lease_context { -__le64 LeaseKeyLow; -__le64 LeaseKeyHigh; +u8 LeaseKey[SMB2_LEASE_KEY_SIZE ];__le32 LeaseState;__le32 LeaseFlags;__le64 LeaseDuration; } __packed;struct lease_context_v2 { -__le64 LeaseKeyLow; -__le64 LeaseKeyHigh; +u8 LeaseKey[SMB2_LEASE_KEY_SIZE ];__le32 LeaseState;__le32 LeaseFlags;__le64 LeaseDuration;
PATCH 235/366 USB: serial: keyspan_pda: fix modem-status error handling
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 01b3cdfca263a17554f7b249d20a247b2a751521 upstream.
Fix broken modem-status error handling which could lead to bits of slab data leaking to user space.
--- drivers/usb/serial/keyspan_pda.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/serial/keyspan_pda.c +3 -1
@@ -373,8 +373,10 @@ static int keyspan_pda_get_modem_info(st3 ,/* get pins */ USB_TYPE_VENDOR |USB_RECIP_INTERFACE |USB_DIR_IN , 0, 0, data, 1, 2000); -if (rc >=0 ) +if (rc ==1 ) *value = *data; +else if (rc >=0 ) + rc = -EIO ;kfree (data);return rc;
PATCH 236/366 USB: serial: mos7840: fix status-register error handling
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 794744abfffef8b1f3c0c8a4896177d6d13d653d upstream.
Add missing transfer-length sanity check to the status-register completion handler to avoid leaking bits of uninitialised slab data to user space.
--- drivers/usb/serial/mos7840.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/mos7840.c +3 -0
@@ -471,6 +471,9 @@ static void mos7840_control_callback(str }dev_dbg (dev,"%s urb buffer size is %d\n" , __func__, urb->actual_length); +if (urb->actual_length <1 ) + goto out; +dev_dbg (dev,"%s mos7840_port->MsrLsr is %d port %d\n" , __func__, mos7840_port->MsrLsr, mos7840_port->port_num); data = urb->transfer_buffer;
PATCH 237/366 xhci: xhci-mem: off by one in xhci_stream_id_to_ring()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit 313db3d6488bb03b61b99de9dbca061f1fd838e1 upstream.
The > should be >= here so that we don't read one element beyond the end of the ep->stream_info->stream_rings[] array.
--- drivers/usb/host/xhci-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/host/xhci-mem.c +1 -1
@@ -638,7 +638,7 @@ struct xhci_ring *xhci_stream_id_to_ringif (!ep->stream_info)return NULL ; -if (stream_id > ep->stream_info->num_streams) +if (stream_id >= ep->stream_info->num_streams)return NULL ;return ep->stream_info->stream_rings[stream_id]; }
PATCH 238/366 usb: quirks: add delay quirks for Corsair Strafe
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nico Sneck <[email protected]>
commit bba57eddadda936c94b5dccf73787cb9e159d0a5 upstream.
Corsair Strafe appears to suffer from the same issues as the Corsair Strafe RGB.
Apply the same quirks (control message delay and init delay) that the RGB version has to 1b1c:1b15.
With these quirks in place the keyboard works correctly upon booting the system, and no longer requires reattaching the device.
--- drivers/usb/core/quirks.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/core/quirks.c +4 -0
@@ -228,6 +228,10 @@ static const struct usb_device_id usb_qu/* Corsair K70 RGB */ { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair Strafe */ + { USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, + /* Corsair Strafe RGB */ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT | USB_QUIRK_DELAY_CTRL_MSG },
PATCH 239/366 sh_eth: fix invalid context bug while changing link options by ethtool
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
commit 5cb3f52a11e18628fc4bee76dd14b1f0b76349de upstream.
The change fixes sleep in atomic context bug, which is encountered every time when link settings are changed by ethtool.
Since commit 35b5f6b1a82b ("PHYLIB: Locking fixes for PHY I/O potentially sleeping") phy_start_aneg() function utilizes a mutex to serialize changes to phy state, however that helper function is called in atomic context under a grabbed spinlock, because phy_start_aneg() is called by phy_ethtool_ksettings_set() and by replaced phy_ethtool_sset() helpers from phylib.
Now duplex mode setting is enforced in sh_eth_adjust_link() only, also now RX/TX is disabled when link is put down or modifications to E-MAC registers ECMR and GECMR are expected for both cases of checked and ignored link status pin state from E-MAC interrupt handler.
For reference the change is a partial rework of commit 1e1b812bbe10 ("sh_eth: fix handling of no LINK signal").
[bwh: Backported to 3.16:
- Keep using phy_ethtool_sset()
- Adjust context]
---
drivers/net/ethernet/renesas/sh_eth.c +15 -32
@@ -1727,8 +1727,15 @@ static void sh_eth_adjust_link(struct ne {struct sh_eth_private *mdp =netdev_priv (ndev);struct phy_device *phydev = mdp->phydev; +unsigned long flags;int new_state =0 ; +spin_lock_irqsave (&mdp->lock, flags); + +/* Disable TX and RX right over here, if E-MAC change is ignored */ +if (mdp->cd->no_psr || mdp->no_ether_link) +sh_eth_rcv_snd_disable (ndev); +if (phydev->link) {if (phydev->duplex != mdp->duplex) { new_state =1 ;
@@ -1749,18 +1756,21 @@ static void sh_eth_adjust_link(struct ne ECMR); new_state =1 ; mdp->link = phydev->link; -if (mdp->cd->no_psr || mdp->no_ether_link) -sh_eth_rcv_snd_enable (ndev); } }else if (mdp->link) { new_state =1 ; mdp->link =0 ; mdp->speed =0 ; mdp->duplex =-1 ; -if (mdp->cd->no_psr || mdp->no_ether_link) -sh_eth_rcv_snd_disable (ndev); } +/* Enable TX and RX right over here, if E-MAC change is ignored */ +if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link) +sh_eth_rcv_snd_enable (ndev); + +mmiowb (); +spin_unlock_irqrestore (&mdp->lock, flags); +if (new_state &&netif_msg_link (mdp))phy_print_status (phydev); }
@@ -1843,35 +1853,8 @@ static int sh_eth_set_settings(struct ne struct ethtool_cmd *ecmd) {struct sh_eth_private *mdp =netdev_priv (ndev); -unsigned long flags; -int ret; - -spin_lock_irqsave (&mdp->lock, flags); -/* disable tx and rx */ -sh_eth_rcv_snd_disable (ndev); - - ret =phy_ethtool_sset (mdp->phydev, ecmd); -if (ret) - goto error_exit; - -if (ecmd->duplex ==DUPLEX_FULL ) - mdp->duplex =1 ; -else - mdp->duplex =0 ; - -if (mdp->cd->set_duplex) - mdp->cd->set_duplex (ndev); - -error_exit: -mdelay (1 ); - -/* enable tx and rx */ -sh_eth_rcv_snd_enable (ndev); - -spin_unlock_irqrestore (&mdp->lock, flags); - -return ret; +return phy_ethtool_sset (mdp->phydev, ecmd); }static int sh_eth_nway_reset (struct net_device *ndev)
PATCH 240/366 ibmasm: don't write out of bounds in read handler
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit a0341fc1981a950c1e902ab901e98f60e0e243f3 upstream.
This read handler had a lot of custom logic and wrote outside the bounds of the provided buffer. This could lead to kernel and userspace memory corruption. Just use simple_read_from_buffer() with a stack buffer.
--- drivers/misc/ibmasm/ibmasmfs.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-)
drivers/misc/ibmasm/ibmasmfs.c +3 -24
@@ -507,35 +507,14 @@ static int remote_settings_file_close(ststatic ssize_t remote_settings_file_read (struct file *file,char __user *buf,size_t count,loff_t *offset) {void __iomem *address = (void __iomem *)file->private_data; -unsigned char *page; -int retval;int len =0 ;unsigned int value; - -if (*offset <0 ) -return -EINVAL ; -if (count ==0 || count >1024 ) -return 0 ; -if (*offset !=0 ) -return 0 ; - - page = (unsigned char *)__get_free_page (GFP_KERNEL ); -if (!page) -return -ENOMEM ; +char lbuf[20 ]; value =readl (address); - len =sprintf (page,"%d\n" , value); - -if (copy_to_user (buf, page, len)) { - retval = -EFAULT ; - goto exit; - } - *offset += len; - retval = len; + len =snprintf (lbuf,sizeof (lbuf),"%d\n" , value); -exit: -free_page ((unsigned long )page); -return retval; +return simple_read_from_buffer (buf, count, offset, lbuf, len); }static ssize_t remote_settings_file_write (struct file *file,const char __user *ubuff,size_t count,loff_t *offset)
PATCH 241/366 mmc: sdhci-esdhc-imx: allow 1.8V modes without 100/200MHz pinctrl states
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Agner <[email protected]>
commit 92748beac07c471d995fbec642b63572dc01b3dc upstream.
If pinctrl nodes for 100/200MHz are missing, the controller should not select any mode which need signal frequencies 100MHz or higher. To prevent such speed modes the driver currently uses the quirk flag SDHCI_QUIRK2_NO_1_8_V. This works nicely for SD cards since 1.8V signaling is required for all faster modes and slower modes use 3.3V signaling only.
However, there are eMMC modes which use 1.8V signaling and run below 100MHz, e.g. DDR52 at 1.8V. With using SDHCI_QUIRK2_NO_1_8_V this mode is prevented. When using a fixed 1.8V regulator as vqmmc-supply the stack has no valid mode to use. In this tenuous situation the kernel continuously prints voltage switching errors:
mmc1: Switching to 3.3V signalling voltage failed
Avoid using SDHCI_QUIRK2_NO_1_8_V and prevent faster modes by altering the SDHCI capability register. With that the stack is able to select 1.8V modes even if no faster pinctrl states are available:
# cat /sys/kernel/debug/mmc1/ios ... timing spec: 8 (mmc DDR52) signal voltage: 1 (1.80 V) ...
to uhs mode")
[bwh: Backported to 3.16:
- There is no SDHCI_SUPPORT_HS400 flag to clear
- Adjust context]
---
drivers/mmc/host/sdhci-esdhc-imx.c +9 -9
@@ -261,6 +261,15 @@ static u32 esdhc_readl_le(struct sdhci_h val =SDHCI_SUPPORT_DDR50 |SDHCI_SUPPORT_SDR104 |SDHCI_SUPPORT_SDR50 |SDHCI_USE_SDR50_TUNING ; + +/* +* Do not advertise faster UHS modes if there are no +* pinctrl states for 100MHz/200MHz. +*/ +if (IS_ERR_OR_NULL (imx_data->pins_100mhz) || +IS_ERR_OR_NULL (imx_data->pins_200mhz)) + val &= ~(SDHCI_SUPPORT_SDR50 |SDHCI_SUPPORT_DDR50 + |SDHCI_SUPPORT_SDR104 ); } }
@@ -1108,15 +1117,6 @@ static int sdhci_esdhc_imx_probe(struct ESDHC_PINCTRL_STATE_100MHZ); imx_data->pins_200mhz =pinctrl_lookup_state (imx_data->pinctrl,ESDHC_PINCTRL_STATE_200MHZ ); -if (IS_ERR (imx_data->pins_100mhz) || -IS_ERR (imx_data->pins_200mhz)) { -dev_warn (mmc_dev (host->mmc), -"could not get ultra high speed state, work on normal mode\n" ); -/* fall back to not support uhs by specify no 1.8v quirk */ - host->quirks2 |=SDHCI_QUIRK2_NO_1_8_V ; - } - }else { - host->quirks2 |=SDHCI_QUIRK2_NO_1_8_V ; } err =sdhci_add_host (host);
PATCH 242/366 HID: hiddev: fix potential Spectre v1
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Gustavo A. R. Silva" <[email protected]>
commit 4f65245f2d178b9cba48350620d76faa4a098841 upstream.
uref->field_index, uref->usage_index, finfo.field_index and cinfo.index can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability.
This issue was detected with the help of Smatch:
drivers/hid/usbhid/hiddev.c:473 hiddev_ioctl_usage() warn: potential spectre issue 'report->field' (local cap) drivers/hid/usbhid/hiddev.c:477 hiddev_ioctl_usage() warn: potential spectre issue 'field->usage' (local cap) drivers/hid/usbhid/hiddev.c:757 hiddev_ioctl() warn: potential spectre issue 'report->field' (local cap) drivers/hid/usbhid/hiddev.c:801 hiddev_ioctl() warn: potential spectre issue 'hid->collection' (local cap)
Fix this by sanitizing such structure fields before using them to index report->field, field->usage and hid->collection
Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1].
[1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2
--- drivers/hid/usbhid/hiddev.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/hid/usbhid/hiddev.c +11 -0
@@ -35,6 +35,7 @@#include <linux/hiddev.h> #include <linux/compat.h> #include <linux/vmalloc.h> +#include <linux/nospec.h> #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -478,10 +479,14 @@ static noinline int hiddev_ioctl_usage(sif (uref->field_index >= report->maxfield) goto inval; + uref->field_index =array_index_nospec (uref->field_index, + report->maxfield); field = report->field[uref->field_index];if (uref->usage_index >= field->maxusage) goto inval; + uref->usage_index =array_index_nospec (uref->usage_index, + field->maxusage); uref->usage_code = field->usage[uref->usage_index].hid;
@@ -508,6 +513,8 @@ static noinline int hiddev_ioctl_usage(sif (uref->field_index >= report->maxfield) goto inval; + uref->field_index =array_index_nospec (uref->field_index, + report->maxfield); field = report->field[uref->field_index];
@@ -761,6 +768,8 @@ static long hiddev_ioctl(struct file *fiif (finfo.field_index >= report->maxfield)break ; + finfo.field_index =array_index_nospec (finfo.field_index, + report->maxfield); field = report->field[finfo.field_index];memset (&finfo,0 ,sizeof (finfo));
@@ -801,6 +810,8 @@ static long hiddev_ioctl(struct file *fiif (cinfo.index >= hid->maxcollection)break ; + cinfo.index =array_index_nospec (cinfo.index, + hid->maxcollection); cinfo.type = hid->collection[cinfo.index].type; cinfo.usage = hid->collection[cinfo.index].usage;
PATCH 243/366 ARC: Fix CONFIG_SWAP
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Brodkin <[email protected]>
commit 6e3761145a9ba3ce267c330b6bff51cf6a057b06 upstream.
swap was broken on ARC due to silly copy-paste issue.
We encode offset from swapcache page in __swp_entry() as (off << 13) but were not decoding back in __swp_offset() as (off >> 13) - it was still (off << 13).
This finally fixes swap usage on ARC.
| # mkswap /dev/sda2 | | # swapon -a -e /dev/sda2 | Adding 500728k swap on /dev/sda2. Priority:-2 extents:1 across:500728k | | # free | total used free shared buffers cached | Mem: 765104 13456 751648 4736 8 4736 | -/+ buffers/cache: 8712 756392 | Swap: 500728 0 500728
--- arch/arc/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arc/include/asm/pgtable.h +1 -1
@@ -361,7 +361,7 @@ void update_mmu_cache(struct vm_area_str/* Decode a PTE containing swap "identifier "into constituents */ #define __swp_type (pte_lookalike) (((pte_lookalike).val) & 0x1f) -#define __swp_offset (pte_lookalike) ((pte_lookalike).val << 13) +#define __swp_offset (pte_lookalike) ((pte_lookalike).val >> 13)/* NOPs, to keep generic kernel happy */ #define __pte_to_swp_entry (pte) ((swp_entry_t) { pte_val(pte) })
PATCH 244/366 ext4: fix inline data updates with checksums enabled
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit 362eca70b53389bddf3143fe20f53dcce2cfdf61 upstream.
The inline data code was updating the raw inode directly; this is problematic since if metadata checksums are enabled, ext4_mark_inode_dirty() must be called to update the inode's checksum. In addition, the jbd2 layer requires that get_write_access() be called before the metadata buffer is modified. Fix both of these problems.
https://bugzilla.kernel.org/show_bug.cgi?id=200443
--- fs/ext4/inline.c | 19 +++++++++++-------- fs/ext4/inode.c | 16 +++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-)
fs/ext4/inline.c +11 -7
@@ -681,6 +681,10 @@ int ext4_try_to_write_inline_data(struct goto convert; } + ret =ext4_journal_get_write_access (handle, iloc.bh); +if (ret) + goto out; + flags |=AOP_FLAG_NOFS ; page =grab_cache_page_write_begin (mapping,0 , flags);
@@ -709,7 +713,7 @@ int ext4_try_to_write_inline_data(struct out_up_read:up_read (&EXT4_I (inode)->xattr_sem); out: -if (handle) +if (handle && (ret !=1 ))ext4_journal_stop (handle);brelse (iloc.bh);return ret;
@@ -751,6 +755,7 @@ int ext4_write_inline_data_end(struct inext4_write_unlock_xattr (inode, &no_expand);brelse (iloc.bh); +mark_inode_dirty (inode); out:return copied; }
@@ -911,6 +916,9 @@ retry_journal:if (ret <0 ) goto out_release_page; } + ret =ext4_journal_get_write_access (handle, iloc.bh); +if (ret) + goto out_release_page;up_read (&EXT4_I (inode)->xattr_sem); *pagep = page;
@@ -931,7 +939,6 @@ int ext4_da_write_inline_data_end(struct unsigned len, unsigned copied, struct page *page) { - int i_size_changed = 0; int ret; ret =ext4_write_inline_data_end (inode, pos, len, copied, page);
@@ -949,10 +956,8 @@ int ext4_da_write_inline_data_end(struct* But it's important to update i_size while still holding page lock: * page writeout could otherwise come in and zero beyond i_size. */ -if (pos+copied > inode->i_size) { +if (pos+copied > inode->i_size)i_size_write (inode, pos+copied); - i_size_changed =1 ; - }unlock_page (page);page_cache_release (page);
@@ -962,8 +967,7 @@ int ext4_da_write_inline_data_end(struct* ordering of page lock and transaction start for journaling * filesystems. */ -if (i_size_changed) -mark_inode_dirty (inode); +mark_inode_dirty (inode);return copied; }
fs/ext4/inode.c +7 -9
@@ -1113,9 +1113,10 @@ static int ext4_write_end(struct file *fstruct inode *inode = mapping->host;int ret =0 , ret2;int i_size_changed =0 ; +int inline_data =ext4_has_inline_data (inode);trace_ext4_write_end (inode, pos, len, copied); -if (ext4_has_inline_data (inode)) { +if (inline_data) { ret =ext4_write_inline_data_end (inode, pos, len, copied, page);if (ret <0 ) {
@@ -1141,7 +1142,7 @@ static int ext4_write_end(struct file *f* ordering of page lock and transaction start for journaling * filesystems. */ -if (i_size_changed) +if (i_size_changed || inline_data)ext4_mark_inode_dirty (handle, inode);if (pos + len > inode->i_size &&ext4_can_truncate (inode))
@@ -1214,6 +1215,7 @@ static int ext4_journalled_write_end(strint partial =0 ;unsigned from, to;int size_changed =0 ; +int inline_data =ext4_has_inline_data (inode);trace_ext4_journalled_write_end (inode, pos, len, copied); from = pos & (PAGE_CACHE_SIZE -1 );
@@ -1221,7 +1223,7 @@ static int ext4_journalled_write_end(strBUG_ON (!ext4_handle_valid (handle)); -if (ext4_has_inline_data (inode)) { +if (inline_data) { ret =ext4_write_inline_data_end (inode, pos, len, copied, page);if (ret <0 ) {
@@ -1249,7 +1251,7 @@ static int ext4_journalled_write_end(strunlock_page (page);page_cache_release (page); -if (size_changed) { +if (size_changed || inline_data) { ret2 =ext4_mark_inode_dirty (handle, inode);if (!ret) ret = ret2;
@@ -1856,11 +1858,7 @@ static int __ext4_journalled_writepage(s }if (inline_data) { -BUFFER_TRACE (inode_bh,"get write access" ); - ret =ext4_journal_get_write_access (handle, inode_bh); - - err =ext4_handle_dirty_metadata (handle, inode, inode_bh); - + ret =ext4_mark_inode_dirty (handle, inode); }else { ret =ext4_walk_page_buffers (handle, page_bufs,0 , len,NULL , do_journal_get_write_access);
PATCH 245/366 ARC: mm: allow mprotect to make stack mappings executable
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vineet Gupta <[email protected]>
commit 93312b6da4df31e4102ce5420e6217135a16c7ea upstream.
mprotect(EXEC) was failing for stack mappings as default vm flags was missing MAYEXEC.
This was triggered by glibc test suite nptl/tst-execstack testcase
What is surprising is that despite running LTP for years on, we didn't catch this issue as it lacks a directed test case.
gcc dejagnu tests with nested functions also requiring exec stack work fine though because they rely on the GNU_STACK segment spit out by compiler and handled in kernel elf loader.
This glibc case is different as the stack is non exec to begin with and a dlopen of shared lib with GNU_STACK segment triggers the exec stack proceedings using a mprotect(PROT_EXEC) which was broken.
--- arch/arc/include/asm/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arc/include/asm/page.h +1 -1
@@ -97,7 +97,7 @@ typedef unsigned long pgtable_t;#define virt_addr_valid (kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)/* Default Permissions for stack/heaps pages (Non Executable) */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE) +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)#define WANT_PAGE_VIRTUAL 1
PATCH 246/366 RDMA/mlx5: Fix memory leak in mlx5_ib_create_srq() error path
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kamal Heib <[email protected]>
commit d63c46734c545ad0488761059004a65c46efdde3 upstream.
Fix memory leak in the error path of mlx5_ib_create_srq() by making sure to free the allocated srq.
--- drivers/infiniband/hw/mlx5/srq.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/infiniband/hw/mlx5/srq.c +12 -6
@@ -261,18 +261,24 @@ struct ib_srq *mlx5_ib_create_srq(struct desc_size =sizeof (struct mlx5_wqe_srq_next_seg ) + srq->msrq.max_gs *sizeof (struct mlx5_wqe_data_seg ); -if (desc_size ==0 || srq->msrq.max_gs > desc_size) -return ERR_PTR (-EINVAL ); +if (desc_size ==0 || srq->msrq.max_gs > desc_size) { + err = -EINVAL ; + goto err_srq; + } desc_size =roundup_pow_of_two (desc_size); desc_size =max_t (size_t,32 , desc_size); -if (desc_size <sizeof (struct mlx5_wqe_srq_next_seg )) -return ERR_PTR (-EINVAL ); +if (desc_size <sizeof (struct mlx5_wqe_srq_next_seg )) { + err = -EINVAL ; + goto err_srq; + } srq->msrq.max_avail_gather = (desc_size -sizeof (struct mlx5_wqe_srq_next_seg )) /sizeof (struct mlx5_wqe_data_seg ); srq->msrq.wqe_shift =ilog2 (desc_size); buf_size = srq->msrq.max * desc_size; -if (buf_size < desc_size) -return ERR_PTR (-EINVAL ); +if (buf_size < desc_size) { + err = -EINVAL ; + goto err_srq; + }if (pd->uobject) err =create_srq_user (pd, srq, &in, udata, buf_size, &inlen);
PATCH 247/366 ext4: check for allocation block validity with block group locked
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit 8d5a803c6a6ce4ec258e31f76059ea5153ba46ef upstream.
With commit 044e6e3d74a3: "ext4: don't update checksum of new initialized bitmaps" the buffer valid bit will get set without actually setting up the checksum for the allocation bitmap, since the checksum will get calculated once we actually allocate an inode or block.
If we are doing this, then we need to (re-)check the verified bit after we take the block group lock. Otherwise, we could race with another process reading and verifying the bitmap, which would then complain about the checksum being invalid.
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1780137
---
fs/ext4/balloc.c +3 -0
@@ -377,6 +377,8 @@ static void ext4_validate_block_bitmap(sreturn ;ext4_lock_group (sb, block_group); +if (buffer_verified (bh)) + goto verified; blk =ext4_valid_block_bitmap (sb, desc, block_group, bh);if (unlikely (blk !=0 )) {ext4_unlock_group (sb, block_group);
@@ -399,6 +401,7 @@ static void ext4_validate_block_bitmap(sreturn ; }set_buffer_verified (bh); +verified:ext4_unlock_group (sb, block_group); }
fs/ext4/ialloc.c +4 -1
@@ -166,6 +166,8 @@ ext4_read_inode_bitmap(struct super_bloc verify:ext4_lock_group (sb, block_group); +if (buffer_verified (bh)) + goto verified;if (!buffer_verified (bh) && !ext4_inode_bitmap_csum_verify (sb, block_group, desc, bh,EXT4_INODES_PER_GROUP (sb) /8 )) {
@@ -183,8 +185,9 @@ verify:set_bit (EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT , &grp->bb_state);return NULL ; } -ext4_unlock_group (sb, block_group);set_buffer_verified (bh); +verified: +ext4_unlock_group (sb, block_group);return bh; }
PATCH 248/366 skbuff: Unconditionally copy pfmemalloc in __skb_clone()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Brivio <[email protected]>
commit e78bfb0751d4e312699106ba7efbed2bab1a53ca upstream.
Commit 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_header()") introduced a different handling for the pfmemalloc flag in copy and clone paths.
In __skb_clone(), now, the flag is set only if it was set in the original skb, but not cleared if it wasn't. This is wrong and might lead to socket buffers being flagged with pfmemalloc even if the skb data wasn't allocated from pfmemalloc reserves. Copy the flag instead of ORing it.
[bwh: Backported to 3.16: We didn't set the pfmemalloc flag in either copy
or clone path until now]
---
net/core/skbuff.c +1 -0
@@ -768,6 +768,7 @@ static struct sk_buff *__skb_clone(struc n->cloned =1 ; n->nohdr =0 ; n->peeked =0 ; +C (pfmemalloc); n->destructor =NULL ;C (tail);C (end);
PATCH 249/366 qlogic: check kstrtoul() for errors
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit 5fc853cc01c68f84984ecc2d5fd777ecad78240f upstream.
We accidentally left out the error handling for kstrtoul().
--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +2 -0
@@ -1122,6 +1122,8 @@ static ssize_t qlcnic_83xx_sysfs_flash_wreturn QL_STATUS_INVALID_PARAM ; ret =kstrtoul (buf,16 , &data); +if (ret) +return ret;switch (data) {case QLC_83XX_FLASH_SECTOR_ERASE_CMD :
PATCH 250/366 mm, elf: handle vm_brk error
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Michal Hocko <[email protected]>
commit ecc2bc8ac03884266cf73f8a2a42b911465b2fbc upstream.
load_elf_library doesn't handle vm_brk failure although nothing really indicates it cannot do that because the function is allowed to fail due to vm_mmap failures already. This might be not a problem now but later patch will make vm_brk killable (resp. mmap_sem for write waiting will become killable) and so the failure will be more probable.
--- fs/binfmt_elf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
fs/binfmt_elf.c +5 -2
@@ -1084,8 +1084,11 @@ static int load_elf_library(struct file len =ELF_PAGESTART (eppnt->p_filesz + eppnt->p_vaddr +ELF_MIN_ALIGN -1 ); bss = eppnt->p_memsz + eppnt->p_vaddr; -if (bss > len) -vm_brk (len, bss - len); +if (bss > len) { + error =vm_brk (len, bss - len); +if (BAD_ADDR (error)) + goto out_free_ph; + } error =0 ; out_free_ph:
PATCH 251/366 binfmt_elf: fix calculations for bss padding
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit 0036d1f7eb95bcc52977f15507f00dd07018e7e2 upstream.
A double-bug exists in the bss calculation code, where an overflow can happen in the "last_bss - elf_bss" calculation, but vm_brk internally aligns the argument, underflowing it, wrapping back around safe. We shouldn't depend on these bugs staying in sync, so this cleans up the bss padding handling to avoid the overflow.
This moves the bss padzero() before the last_bss > elf_bss case, since the zero-filling of the ELF_PAGE should have nothing to do with the relationship of last_bss and elf_bss: any trailing portion should be zeroed, and a zero size is already handled by padzero().
Then it handles the math on elf_bss vs last_bss correctly. These need to both be ELF_PAGE aligned to get the comparison correct, since that's the expected granularity of the mappings. Since elf_bss already had alignment-based padding happen in padzero(), the "start" of the new vm_brk() should be moved forward as done in the original code. However, since the "end" of the vm_brk() area will already become PAGE_ALIGNed in vm_brk() then last_bss should get aligned here to avoid hiding it as a side-effect.
Additionally makes a cosmetic change to the initial last_bss calculation so it's easier to read in comparison to the load_addr calculation above it (i.e. the only difference is p_filesz vs p_memsz).
--- fs/binfmt_elf.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-)
fs/binfmt_elf.c +18 -16
@@ -508,28 +508,30 @@ static unsigned long load_elf_interp(str* Do the same thing for the memory mapping - between * elf_bss and last_bss is the bss section. */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;if (k > last_bss) last_bss = k; } } +/* +* Now fill out the bss section: first pad the last page from +* the file up to the page boundary, and zero it from elf_bss +* up to the end of the page. +*/ +if (padzero (elf_bss)) { + error = -EFAULT ; + goto out_close; + } +/* +* Next, align both the file and mem bss up to the page size, +* since this is where elf_bss was just zeroed up to, and where +* last_bss will end after the vm_brk() below. +*/ + elf_bss =ELF_PAGEALIGN (elf_bss); + last_bss =ELF_PAGEALIGN (last_bss); +/* Finally, if there is still more bss to allocate, do it. */ if (last_bss > elf_bss) { -/* -* Now fill out the bss section. First pad the last page up -* to the page boundary, and then perform a mmap to make sure -* that there are zero-mapped pages up to and including the -* last bss page. -*/ -if (padzero (elf_bss)) { - error = -EFAULT ; - goto out_close; - } - -/* What we have mapped so far */ - elf_bss =ELF_PAGESTART (elf_bss +ELF_MIN_ALIGN -1 ); - -/* Map the last of the bss segment */ error =vm_brk (elf_bss, last_bss - elf_bss);if (BAD_ADDR (error)) goto out_close;
PATCH 252/366 mm: refuse wrapped vm_brk requests
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit ba093a6d9397da8eafcfbaa7d95bd34255da39a0 upstream.
The vm_brk() alignment calculations should refuse to overflow. The ELF loader depending on this, but it has been fixed now. No other unsafe callers have been found.
--- mm/mmap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
mm/mmap.c +5 -3
@@ -2751,16 +2751,18 @@ static inline void verify_mm_writelocked* anonymous maps. eventually we may be able to do some * brk-specific accounting here. */ -static unsigned long do_brk (unsigned long addr,unsigned long len) +static unsigned long do_brk (unsigned long addr,unsigned long request) {struct mm_struct * mm = current->mm;struct vm_area_struct * vma, * prev; -unsigned long flags; +unsigned long flags, len;struct rb_node ** rb_link, * rb_parent;pgoff_t pgoff = addr >>PAGE_SHIFT ;int error; - len =PAGE_ALIGN (len); + len =PAGE_ALIGN (request); +if (len < request) +return -ENOMEM ;if (!len)return addr;
PATCH 253/366 fs, elf: make sure to page align bss in load_elf_library
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Oscar Salvador <[email protected]>
commit 24962af7e1041b7e50c1bc71d8d10dc678c556b5 upstream.
The current code does not make sure to page align bss before calling vm_brk(), and this can lead to a VM_BUG_ON() in __mm_populate() due to the requested lenght not being correctly aligned.
Let us make sure to align it properly.
Kees: only applicable to CONFIG_USELIB kernels: 32-bit and configured for libc5.
--- fs/binfmt_elf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/binfmt_elf.c +2 -3
@@ -1083,9 +1083,8 @@ static int load_elf_library(struct file goto out_free_ph; } - len =ELF_PAGESTART (eppnt->p_filesz + eppnt->p_vaddr + -ELF_MIN_ALIGN -1 ); - bss = eppnt->p_memsz + eppnt->p_vaddr; + len =ELF_PAGEALIGN (eppnt->p_filesz + eppnt->p_vaddr); + bss =ELF_PAGEALIGN (eppnt->p_memsz + eppnt->p_vaddr);if (bss > len) { error =vm_brk (len, bss - len);if (BAD_ADDR (error))
PATCH 254/366 mm: do not bug_on on incorrect length in __mm_populate()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Michal Hocko <[email protected]>
commit bb177a732c4369bb58a1fe1df8f552b6f0f7db5f upstream.
syzbot has noticed that a specially crafted library can easily hit VM_BUG_ON in __mm_populate
kernel BUG at mm/gup.c:1242!
invalid opcode: 0000 [#1] SMP
CPU: 2 PID: 9667 Comm: a.out Not tainted 4.18.0-rc3 #644
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/19/2017
RIP: 0010:__mm_populate+0x1e2/0x1f0
Code: 55 d0 65 48 33 14 25 28 00 00 00 89 d8 75 21 48 83 c4 20 5b 41 5c 41 5d 41 5e 41 5f 5d c3 e8 75 18 f1 ff 0f 0b e8 6e 18 f1 ff <0f> 0b 31 db eb c9 e8 93 06 e0 ff 0f 1f 00 55 48 89 e5 53 48 89 fb
Call Trace:
vm_brk_flags+0xc3/0x100
vm_brk+0x1f/0x30
load_elf_library+0x281/0x2e0
__ia32_sys_uselib+0x170/0x1e0
do_fast_syscall_32+0xca/0x420
entry_SYSENTER_compat+0x70/0x7fThe reason is that the length of the new brk is not page aligned when we try to populate the it. There is no reason to bug on that though. do_brk_flags already aligns the length properly so the mapping is expanded as it should. All we need is to tell mm_populate about it. Besides that there is absolutely no reason to to bug_on in the first place. The worst thing that could happen is that the last page wouldn't get populated and that is far from putting system into an inconsistent state.
Fix the issue by moving the length sanitization code from do_brk_flags up to vm_brk_flags. The only other caller of do_brk_flags is brk syscall entry and it makes sure to provide the proper length so t here is no need for sanitation and so we can use do_brk_flags without it.
Also remove the bogus BUG_ONs.
[bwh: Backported to 3.16:
- There is no do_brk_flags() function; update do_brk()
- do_brk(), vm_brk() return the address on success
- Adjust filename, context]
---
mm/mlock.c +0 -2
@@ -669,8 +669,6 @@ int __mm_populate(unsigned long start, uint locked =0 ;long ret =0 ; -VM_BUG_ON (start & ~PAGE_MASK ); -VM_BUG_ON (len !=PAGE_ALIGN (len)); end = start + len;for (nstart = start; nstart < end; nstart = nend) {
mm/mmap.c +10 -9
@@ -2751,21 +2751,15 @@ static inline void verify_mm_writelocked* anonymous maps. eventually we may be able to do some * brk-specific accounting here. */ -static unsigned long do_brk (unsigned long addr,unsigned long request) +static unsigned long do_brk (unsigned long addr,unsigned long len) {struct mm_struct * mm = current->mm;struct vm_area_struct * vma, * prev; -unsigned long flags, len; +unsigned long flags;struct rb_node ** rb_link, * rb_parent;pgoff_t pgoff = addr >>PAGE_SHIFT ;int error; - len =PAGE_ALIGN (request); -if (len < request) -return -ENOMEM ; -if (!len) -return addr; - flags =VM_DATA_DEFAULT_FLAGS |VM_ACCOUNT | mm->def_flags; error =get_unmapped_area (NULL , addr, len,0 ,MAP_FIXED );
@@ -2834,12 +2828,19 @@ out:return addr; } -unsigned long vm_brk (unsigned long addr,unsigned long len) +unsigned long vm_brk (unsigned long addr,unsigned long request) {struct mm_struct *mm = current->mm; +unsigned long len;unsigned long ret;bool populate; + len =PAGE_ALIGN (request); +if (len < request) +return -ENOMEM ; +if (!len) +return addr; +down_write (&mm->mmap_sem); ret =do_brk (addr, len); populate = ((mm->def_flags &VM_LOCKED ) !=0 );
PATCH 255/366 string: drop __must_check from strscpy()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ben Hutchings <[email protected]>
This was done as part of commit 08a77676f9c5 upstream, from which the following description is taken:
Quoted 6 lines
strlcpy()is worse thanstrlcpy()because it unconditionally runsstrlen()on the source string, and the only reason we switched tostrlcpy()here was because it was lacking__must_check, which doesn't reflect any material differences between the two function. It's just that someone added__must_checktostrscpy()and not tostrlcpy().
Quoted 6 lines
These basic string copy operations are used in variety of ways, and one of not-so-uncommon use cases is safely handling truncated copies, where the caller naturally doesn't care about the return value. The
__must_checkdoesn't match the actual use cases and forces users to opt for inferior variants which lack__must_checkby happenstance or spread ugly (void) casts.
---
include/linux/string.h +1 -1
@@ -26,7 +26,7 @@ extern char * strncpy(char *,const charsize_t strlcpy (char *,const char *,size_t );#endif #ifndef __HAVE_ARCH_STRSCPY -ssize_t __must_check strscpy (char *,const char *,size_t ); +ssize_t strscpy (char *,const char *,size_t );#endif #ifndef __HAVE_ARCH_STRCATextern char *strcat (char *,const char *);
PATCH 256/366 reiserfs: fix buffer overflow with long warning messages
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit fe10e398e860955bac4d28ec031b701d358465e4 upstream.
ReiserFS prepares log messages into a 1024-byte buffer with no bounds checks. Long messages, such as the "unknown mount option" warning when userspace passes a crafted mount options string, overflow this buffer. This causes KASAN to report a global-out-of-bounds write.
Fix it by truncating messages to the buffer size.
--- fs/reiserfs/prints.c | 141 +++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 60 deletions(-)
fs/reiserfs/prints.c +81 -60
@@ -76,85 +76,101 @@ static char *le_type(struct reiserfs_key }/* %k */ -static void sprintf_le_key (char *buf,struct reiserfs_key *key) +static int scnprintf_le_key (char *buf,size_t size,struct reiserfs_key *key) {if (key) -sprintf (buf,"[%d %d %s %s]" ,le32_to_cpu (key->k_dir_id), -le32_to_cpu (key->k_objectid),le_offset (key), -le_type (key)); +return scnprintf (buf, size,"[%d %d %s %s]" , +le32_to_cpu (key->k_dir_id), +le32_to_cpu (key->k_objectid),le_offset (key), +le_type (key));else -sprintf (buf,"[NULL]" ); +return scnprintf (buf, size,"[NULL]" ); }/* %K */ -static void sprintf_cpu_key (char *buf,struct cpu_key *key) +static int scnprintf_cpu_key (char *buf,size_t size,struct cpu_key *key) {if (key) -sprintf (buf,"[%d %d %s %s]" , key->on_disk_key.k_dir_id, - key->on_disk_key.k_objectid,reiserfs_cpu_offset (key), -cpu_type (key)); +return scnprintf (buf, size,"[%d %d %s %s]" , + key->on_disk_key.k_dir_id, + key->on_disk_key.k_objectid, +reiserfs_cpu_offset (key),cpu_type (key));else -sprintf (buf,"[NULL]" ); +return scnprintf (buf, size,"[NULL]" ); } -static void sprintf_de_head (char *buf,struct reiserfs_de_head *deh) +static int scnprintf_de_head (char *buf,size_t size, +struct reiserfs_de_head *deh) {if (deh) -sprintf (buf, -"[offset=%d dir_id=%d objectid=%d location=%d state=%04x]" , -deh_offset (deh),deh_dir_id (deh),deh_objectid (deh), -deh_location (deh),deh_state (deh)); +return scnprintf (buf, size, +"[offset=%d dir_id=%d objectid=%d location=%d state=%04x]" , +deh_offset (deh),deh_dir_id (deh), +deh_objectid (deh),deh_location (deh), +deh_state (deh));else -sprintf (buf,"[NULL]" ); +return scnprintf (buf, size,"[NULL]" ); } -static void sprintf_item_head (char *buf,struct item_head *ih) +static int scnprintf_item_head (char *buf,size_t size,struct item_head *ih) {if (ih) { -strcpy (buf, - (ih_version (ih) ==KEY_FORMAT_3_6 ) ?"*3.6* " :"*3.5*" ); -sprintf_le_key (buf +strlen (buf), &(ih->ih_key)); -sprintf (buf +strlen (buf),", item_len %d, item_location %d, " -"free_space(entry_count) %d" , -ih_item_len (ih),ih_location (ih),ih_free_space (ih)); +char *p = buf; +char *const end = buf + size; + + p +=scnprintf (p, end - p,"%s" , + (ih_version (ih) ==KEY_FORMAT_3_6 ) ? +"*3.6* " :"*3.5*" ); + + p +=scnprintf_le_key (p, end - p, &ih->ih_key); + + p +=scnprintf (p, end - p, +", item_len %d, item_location %d, free_space(entry_count) %d" , +ih_item_len (ih),ih_location (ih), +ih_free_space (ih)); +return p - buf; }else -sprintf (buf,"[NULL]" ); +return scnprintf (buf, size,"[NULL]" ); } -static void sprintf_direntry (char *buf,struct reiserfs_dir_entry *de) +static int scnprintf_direntry (char *buf,size_t size, +struct reiserfs_dir_entry *de) {char name[20 ];memcpy (name, de->de_name, de->de_namelen >19 ?19 : de->de_namelen); name[de->de_namelen >19 ?19 : de->de_namelen] =0 ; -sprintf (buf,"\"%s\"==>[%d %d]" , name, de->de_dir_id, de->de_objectid); +return scnprintf (buf, size,"\"%s\"==>[%d %d]" , + name, de->de_dir_id, de->de_objectid); } -static void sprintf_block_head (char *buf,struct buffer_head *bh) +static int scnprintf_block_head (char *buf,size_t size,struct buffer_head *bh) { -sprintf (buf,"level=%d, nr_items=%d, free_space=%d rdkey " , -B_LEVEL (bh),B_NR_ITEMS (bh),B_FREE_SPACE (bh)); +return scnprintf (buf, size, +"level=%d, nr_items=%d, free_space=%d rdkey " , +B_LEVEL (bh),B_NR_ITEMS (bh),B_FREE_SPACE (bh)); } -static void sprintf_buffer_head (char *buf,struct buffer_head *bh) +static int scnprintf_buffer_head (char *buf,size_t size,struct buffer_head *bh) {char b[BDEVNAME_SIZE ]; -sprintf (buf, -"dev %s, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)" , -bdevname (bh->b_bdev, b), bh->b_size, - (unsigned long long )bh->b_blocknr,atomic_read (&(bh->b_count)), - bh->b_state, bh->b_page, -buffer_uptodate (bh) ?"UPTODATE" :"!UPTODATE" , -buffer_dirty (bh) ?"DIRTY" :"CLEAN" , -buffer_locked (bh) ?"LOCKED" :"UNLOCKED" ); +return scnprintf (buf, size, +"dev %s, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)" , +bdevname (bh->b_bdev, b), bh->b_size, + (unsigned long long )bh->b_blocknr, +atomic_read (&(bh->b_count)), + bh->b_state, bh->b_page, +buffer_uptodate (bh) ?"UPTODATE" :"!UPTODATE" , +buffer_dirty (bh) ?"DIRTY" :"CLEAN" , +buffer_locked (bh) ?"LOCKED" :"UNLOCKED" ); } -static void sprintf_disk_child (char *buf,struct disk_child *dc) +static int scnprintf_disk_child (char *buf,size_t size,struct disk_child *dc) { -sprintf (buf,"[dc_number=%d, dc_size=%u]" ,dc_block_number (dc), -dc_size (dc)); +return scnprintf (buf, size,"[dc_number=%d, dc_size=%u]" , +dc_block_number (dc),dc_size (dc)); }static char *is_there_reiserfs_struct (char *fmt,int *what)
@@ -191,55 +207,60 @@ static void prepare_error_buf(const charchar *fmt1 = fmt_buf;char *k;char *p = error_buf; +char *const end = &error_buf[sizeof (error_buf)];int what;spin_lock (&error_lock); -strcpy (fmt1, fmt); +if (WARN_ON (strscpy (fmt_buf, fmt,sizeof (fmt_buf)) <0 )) { +strscpy (error_buf,"format string too long" , end - error_buf); + goto out_unlock; + }while ((k =is_there_reiserfs_struct (fmt1, &what)) !=NULL ) { *k =0 ; - p +=vsprintf (p, fmt1, args); + p +=vscnprintf (p, end - p, fmt1, args);switch (what) {case 'k' : - sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); + p +=scnprintf_le_key (p, end - p, + va_arg(args, struct reiserfs_key *));break ;case 'K' : - sprintf_cpu_key(p, va_arg(args, struct cpu_key *)); + p +=scnprintf_cpu_key (p, end - p, + va_arg(args, struct cpu_key *));break ;case 'h' : - sprintf_item_head(p, va_arg(args, struct item_head *)); + p +=scnprintf_item_head (p, end - p, + va_arg(args, struct item_head *));break ;case 't' : -sprintf_direntry (p, -va_arg (args, - struct reiserfs_dir_entry *)); + p +=scnprintf_direntry (p, end - p, + va_arg(args, struct reiserfs_dir_entry *));break ;case 'y' : -sprintf_disk_child (p, - va_arg(args, struct disk_child *)); + p +=scnprintf_disk_child (p, end - p, + va_arg(args, struct disk_child *));break ;case 'z' : -sprintf_block_head (p, - va_arg(args, struct buffer_head *)); + p +=scnprintf_block_head (p, end - p, + va_arg(args, struct buffer_head *));break ;case 'b' : -sprintf_buffer_head (p, - va_arg(args, struct buffer_head *)); + p +=scnprintf_buffer_head (p, end - p, + va_arg(args, struct buffer_head *));break ;case 'a' : -sprintf_de_head (p, -va_arg (args, - struct reiserfs_de_head *)); + p +=scnprintf_de_head (p, end - p, + va_arg(args, struct reiserfs_de_head *));break ; } - p +=strlen (p); fmt1 = k +2 ; } -vsprintf (p, fmt1, args); + p +=vscnprintf (p, end - p, fmt1, args); +out_unlock:spin_unlock (&error_lock); }
PATCH 257/366 usb: cdc_acm: Add quirk for Castles VEGA3000
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lubomir Rintel <[email protected]>
commit 1445cbe476fc3dd09c0b380b206526a49403c071 upstream.
The device (a POS terminal) implements CDC ACM, but has not union descriptor.
--- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/class/cdc-acm.c +3 -0
@@ -1784,6 +1784,9 @@ static const struct usb_device_id acm_id { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ .driver_info =NO_UNION_NORMAL ,/* has misplaced union descriptor */ }, + { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ .driver_info = CLEAR_HALT_CONDITIONS,
PATCH 258/366 drm/nouveau/gem: off by one bugs in nouveau_gem_pushbuf_reloc_apply()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit 7f073d011f93e92d4d225526b9ab6b8b0bbd6613 upstream.
The bo array has req->nr_buffers elements so the > should be >= so we don't read beyond the end of the array.
--- drivers/gpu/drm/nouveau/nouveau_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nouveau_gem.c +2 -2
@@ -613,7 +613,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nstruct nouveau_bo *nvbo;uint32_t data; -if (unlikely (r->bo_index > req->nr_buffers)) { +if (unlikely (r->bo_index >= req->nr_buffers)) {NV_ERROR (cli,"reloc bo index invalid\n" ); ret = -EINVAL ;break ;
@@ -623,7 +623,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nif (b->presumed.valid)continue ; -if (unlikely (r->reloc_bo_index > req->nr_buffers)) { +if (unlikely (r->reloc_bo_index >= req->nr_buffers)) {NV_ERROR (cli,"reloc container bo index invalid\n" ); ret = -EINVAL ;break ;
PATCH 259/366 drm/nouveau: Remove bogus crtc check in pmops_runtime_idle
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lyude Paul <[email protected]>
commit 68fe23a626b67b56c912c496ea43ed537ea9708f upstream.
This both uses the legacy modesetting structures in a racy manner, and additionally also doesn't even check the right variable (enabled != the CRTC is actually turned on for atomic).
This fixes issues on my P50 regarding the dedicated GPU not entering runtime suspend.
[bwh: Backported to 3.16:
- Preserve local variables that are still needed
- Adjust context]
---
drivers/gpu/drm/nouveau/nouveau_drm.c +0 -7
@@ -927,7 +927,6 @@ static int nouveau_pmops_runtime_idle(ststruct pci_dev *pdev =to_pci_dev (dev);struct drm_device *drm_dev =pci_get_drvdata (pdev);struct nouveau_drm *drm =nouveau_drm (drm_dev); -struct drm_crtc *crtc;if (nouveau_runtime_pm ==0 ) {pm_runtime_forbid (dev);
@@ -950,12 +949,6 @@ static int nouveau_pmops_runtime_idle(st } } -list_for_each_entry (crtc, &drm->dev->mode_config.crtc_list, head) { -if (crtc->enabled) { -DRM_DEBUG_DRIVER ("failing to power off - crtc active\n" ); -return -EBUSY ; - } - }pm_runtime_mark_last_busy (dev);pm_runtime_autosuspend (dev);/* we don't want the main rpm_idle to call suspend - we want to autosuspend */
PATCH 260/366 drm: re-enable error handling
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Mc Guire <[email protected]>
commit d530b5f1ca0bb66958a2b714bebe40a1248b9c15 upstream.
drm_legacy_ctxbitmap_next() returns idr_alloc() which can return -ENOMEM, -EINVAL or -ENOSPC none of which are -1 . but the call sites of drm_legacy_ctxbitmap_next() seem to be assuming that the error case would be -1 (original return of drm_ctxbitmap_next() prior to 2.6.23 was actually -1). Thus reenable error handling by checking for < 0.
--- drivers/gpu/drm/drm_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/drm_context.c +1 -1
@@ -316,7 +316,7 @@ int drm_addctx(struct drm_device *dev, v ctx->handle =drm_ctxbitmap_next (dev); }DRM_DEBUG ("%d\n" , ctx->handle); -if (ctx->handle ==-1 ) { +if (ctx->handle <0 ) {DRM_DEBUG ("Not enough free contexts.\n" );/* Should this return -EBUSY instead? */ return -ENOMEM ;
PATCH 261/366 MIPS: Fix off-by-one in pci_resource_to_user()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Paul Burton <[email protected]>
commit 38c0a74fe06da3be133cae3fb7bde6a9438e698b upstream.
The MIPS implementation of pci_resource_to_user() introduced in v3.12 by commit 4c2924b725fb ("MIPS: PCI: Use pci_resource_to_user to map pci memory space properly") incorrectly sets *end to the address of the byte after the resource, rather than the last byte of the resource.
This results in userland seeing resources as a byte larger than they actually are, for example a 32 byte BAR will be reported by a tool such as lspci as being 33 bytes in size:
Region 2: I/O ports at 1000 [disabled] [size=33]
Correct this by subtracting one from the calculated end address, reporting the correct address to userland.
Patchwork: https://patchwork.linux-mips.org/patch/19829/
--- arch/mips/include/asm/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/include/asm/pci.h +1 -1
@@ -87,7 +87,7 @@ static inline void pci_resource_to_user(phys_t size =resource_size (rsrc); *start =fixup_bigphys_addr (rsrc->start, size); - *end = rsrc->start + size; + *end = rsrc->start + size -1 ; }/*
PATCH 262/366 x86/apm: Don't access __preempt_count with zeroed fs
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <[email protected]>
commit 6f6060a5c9cc76fdbc22748264e6aa3779ec2427 upstream.
APM_DO_POP_SEGS does not restore fs/gs which were zeroed by APM_DO_ZERO_SEGS. Trying to access __preempt_count with zeroed fs doesn't really work.
Move the ibrs call outside the APM_DO_SAVE_SEGS/APM_DO_RESTORE_SEGS invocations so that fs is actually restored before calling preempt_enable().
Fixes the following sort of oopses:
[ 0.313581] general protection fault: 0000 [#1] PREEMPT SMP [ 0.313803] Modules linked in: [ 0.314040] CPU: 0 PID: 268 Comm: kapmd Not tainted 4.16.0-rc1-triton-bisect-00090-gdd84441a7971 #19 [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 [ 0.316161] EFLAGS: 00210016 CPU: 0 [ 0.316161] EAX: 00000102 EBX: 00000000 ECX: 00000102 EDX: 00000000 [ 0.316161] ESI: 0000530e EDI: dea95f64 EBP: dea95f18 ESP: dea95ef0 [ 0.316161] DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 [ 0.316161] CR0: 80050033 CR2: 00000000 CR3: 015d3000 CR4: 000006d0 [ 0.316161] Call Trace: [ 0.316161] ? cpumask_weight.constprop.15+0x20/0x20 [ 0.316161] on_cpu0+0x44/0x70 [ 0.316161] apm+0x54e/0x720 [ 0.316161] ? __switch_to_asm+0x26/0x40 [ 0.316161] ? __schedule+0x17d/0x590 [ 0.316161] kthread+0xc0/0xf0 [ 0.316161] ? proc_apm_show+0x150/0x150 [ 0.316161] ? kthread_create_worker_on_cpu+0x20/0x20 [ 0.316161] ret_from_fork+0x2e/0x38 [ 0.316161] Code: da 8e c2 8e e2 8e ea 57 55 2e ff 1d e0 bb 5d b1 0f 92 c3 5d 5f 07 1f 89 47 0c 90 8d b4 26 00 00 00 00 90 8d b4 26 00 00 00 00 90 <64> ff 0d 84 16 5c b1 74 7f 8b 45 dc 8e e0 8b 45 d8 8e e8 8b 45 [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 SS:ESP: 0068:dea95ef0 [ 0.316161] ---[ end trace 656253db2deaa12c ]---
Cc: David Woodhouse <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: [email protected]
--- arch/x86/include/asm/apm.h | 6 ------ arch/x86/kernel/apm_32.c | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-)
arch/x86/include/asm/apm.h +0 -6
@@ -6,8 +6,6 @@#ifndef _ASM_X86_MACH_DEFAULT_APM_H#define _ASM_X86_MACH_DEFAULT_APM_H -#include <asm/nospec-branch.h> -#ifdef APM_ZERO_SEGS # define APM_DO_ZERO_SEGS \ "pushl %%ds\n\t" \
@@ -33,7 +31,6 @@ static inline void apm_bios_call_asm(u32* N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ -firmware_restrict_branch_speculation_start (); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t"
@@ -46,7 +43,6 @@ static inline void apm_bios_call_asm(u32 "=S" (*esi) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); -firmware_restrict_branch_speculation_end (); } static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in,
@@ -59,7 +55,6 @@ static inline u8 apm_bios_call_simple_as* N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ -firmware_restrict_branch_speculation_start (); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t"
@@ -72,7 +67,6 @@ static inline u8 apm_bios_call_simple_as "=S" (si) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); -firmware_restrict_branch_speculation_end ();return error; }
arch/x86/kernel/apm_32.c +5 -0
@@ -239,6 +239,7 @@#include <asm/olpc.h> #include <asm/paravirt.h> #include <asm/reboot.h> +#include <asm/nospec-branch.h> #if defined(CONFIG_APM_DISPLAY_BLANK ) && defined(CONFIG_VT )extern int (*console_blank_hook)(int );
@@ -614,11 +615,13 @@ static long __apm_bios_call(void *_call) gdt[0x40 /8 ] = bad_bios_desc;apm_irq_save (flags); +firmware_restrict_branch_speculation_start ();APM_DO_SAVE_SEGS ;apm_bios_call_asm (call->func, call->ebx, call->ecx, &call->eax, &call->ebx, &call->ecx, &call->edx, &call->esi);APM_DO_RESTORE_SEGS ; +firmware_restrict_branch_speculation_end ();apm_irq_restore (flags); gdt[0x40 /8 ] = save_desc_40;put_cpu ();
@@ -690,10 +693,12 @@ static long __apm_bios_call_simple(void gdt[0x40 /8 ] = bad_bios_desc;apm_irq_save (flags); +firmware_restrict_branch_speculation_start ();APM_DO_SAVE_SEGS ; error =apm_bios_call_simple_asm (call->func, call->ebx, call->ecx, &call->eax);APM_DO_RESTORE_SEGS ; +firmware_restrict_branch_speculation_end ();apm_irq_restore (flags); gdt[0x40 /8 ] = save_desc_40;put_cpu ();
PATCH 263/366 KEYS: DNS: fix parsing multiple options
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit c604cb767049b78b3075497b80ebb8fd530ea2cc upstream.
My recent fix for dns_resolver_preparse() printing very long strings was incomplete, as shown by syzbot which still managed to hit the WARN_ONCE() in set_precision() by adding a crafted "dns_resolver" key:
precision 50001 too large
WARNING: CPU: 7 PID: 864 at lib/vsprintf.c:2164 vsnprintf+0x48a/0x5a0
The bug this time isn't just a printing bug, but also a logical error when multiple options ("#"-separated strings) are given in the key payload. Specifically, when separating an option string into name and value, if there is no value then the name is incorrectly considered to end at the end of the key payload, rather than the end of the current option. This bypasses validation of the option length, and also means that specifying multiple options is broken -- which presumably has gone unnoticed as there is currently only one valid option anyway.
A similar problem also applied to option values, as the kstrtoul() when parsing the "dnserror" option will read past the end of the current option and into the next option.
Fix these bugs by correctly computing the length of the option name and by copying the option value, null-terminated, into a temporary buffer.
Reproducer for the WARN_ONCE() that syzbot hit:
perl -e 'print "#A#", "\0" x 50000' | keyctl padd dns_resolver desc @s
Reproducer for "dnserror" option being parsed incorrectly (expected behavior is to fail when seeing the unknown option "foo", actual behavior was to read the dnserror value as "1#foo" and fail there):
perl -e 'print "#dnserror=1#foo\0"' | keyctl padd dns_resolver desc @s
--- net/dns_resolver/dns_key.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-)
net/dns_resolver/dns_key.c +17 -13
@@ -89,35 +89,39 @@ dns_resolver_instantiate(struct key *key opt++;kdebug ("options: '%s'" , opt); do { + int opt_len, opt_nlen; const char *eq; - int opt_len, opt_nlen, opt_vlen, tmp; + char optval[128]; next_opt = memchr(opt, '#', end - opt) ?: end; opt_len = next_opt - opt; - if (opt_len <= 0 || opt_len > 128) { + if (opt_len <= 0 || opt_len > sizeof(optval)) { pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n", opt_len); return -EINVAL; } - eq = memchr(opt, '=', opt_len) ?: end; - opt_nlen = eq - opt; - eq++; - opt_vlen = next_opt - eq; /* will be -1 if no value */ - - tmp = opt_vlen >= 0 ? opt_vlen : 0; - kdebug("option '%*.*s' val '%*.*s'", - opt_nlen, opt_nlen, opt, tmp, tmp, eq); + eq = memchr(opt, '=', opt_len); + if (eq) { + opt_nlen = eq - opt; + eq++; + memcpy(optval, eq, next_opt - eq); + optval[next_opt - eq] = '\0'; + } else { + opt_nlen = opt_len; + optval[0] = '\0'; + } + + kdebug("option '%*.*s' val '%s'", + opt_nlen, opt_nlen, opt, optval); /* see if it's an error number representing a DNS error * that's to be recorded as the result in this key */ if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 && memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) { kdebug("dns error number option"); - if (opt_vlen <= 0) - goto bad_option_value; - ret = kstrtoul(eq, 10, &derrno); + ret = kstrtoul(optval, 10, &derrno); if (ret < 0) goto bad_option_value;
PATCH 264/366 usb: gadget: u_audio: update hw_ptr in iso_complete after data copied
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Frkuska <[email protected]>
commit 6b37bd78d30c890e575a1bda22978d1d2a233362 upstream.
In u_audio_iso_complete, the runtime hw_ptr is updated before the data is actually copied over to/from the buffer/dma area. When ALSA uses this hw_ptr, the data may not actually be available to be used. This causes trash/stale audio to play/record. This patch updates the hw_ptr after the data has been copied to avoid this.
[bwh: Backported to 3.16:
- Don't use a local hw_ptr variable
- Adjust filename]
---
drivers/usb/gadget/f_uac2.c +6 -2
@@ -229,12 +229,16 @@ agdev_iso_complete(struct usb_ep *ep, stif (pending >= prm->period_size) update_alsa = true; - prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes; -spin_unlock_irqrestore (&prm->lock, flags);/* Pack USB load in ALSA ring buffer */ memcpy (dst, src, req->actual); + +spin_lock_irqsave (&prm->lock, flags); +/* update hw_ptr after data is copied to memory */ + prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes; +spin_unlock_irqrestore (&prm->lock, flags); + exit:if (usb_ep_queue (ep, req,GFP_ATOMIC ))dev_err (&uac2->pdev.dev,"%d Error!\n" , __LINE__);
PATCH 265/366 x86/MCE: Remove min interval polling limitation
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dewet Thibaut <[email protected]>
commit fbdb328c6bae0a7c78d75734a738b66b86dffc96 upstream.
commit b3b7c4795c ("x86/MCE: Serialize sysfs changes") introduced a min interval limitation when setting the check interval for polled MCEs. However, the logic is that 0 disables polling for corrected MCEs, see Documentation/x86/x86_64/machinecheck. The limitation prevents disabling.
Remove this limitation and allow the value 0 to disable polling again.
--- arch/x86/kernel/cpu/mcheck/mce.c | 3 --- 1 file changed, 3 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +0 -3
@@ -2260,9 +2260,6 @@ static ssize_t store_int_with_restart(stif (check_interval == old_check_interval)return ret; -if (check_interval <1 ) - check_interval =1 ; -mutex_lock (&mce_sysfs_mutex);mce_restart ();mutex_unlock (&mce_sysfs_mutex);
PATCH 266/366 random: mix rdrand with entropy sent in from userspace
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit 81e69df38e2911b642ec121dec319fad2a4782f3 upstream.
Fedora has integrated the jitter entropy daemon to work around slow boot problems, especially on VM's that don't support virtio-rng:
https://bugzilla.redhat.com/show_bug.cgi?id=1572944
It's understandable why they did this, but the Jitter entropy daemon works fundamentally on the principle: "the CPU microarchitecture is **so** complicated and we can't figure it out, so it *must* be random". Yes, it uses statistical tests to "prove" it is secure, but AES_ENCRYPT(NSA_KEY, COUNTER++) will also pass statistical tests with flying colors.
So if RDRAND is available, mix it into entropy submitted from userspace. It can't hurt, and if you believe the NSA has backdoored RDRAND, then they probably have enough details about the Intel microarchitecture that they can reverse engineer how the Jitter entropy daemon affects the microarchitecture, and attack its output stream. And if RDRAND is in fact an honest DRNG, it will immeasurably improve on what the Jitter entropy daemon might produce.
This also provides some protection against someone who is able to read or set the entropy seed file.
--- drivers/char/random.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/char/random.c +9 -1
@@ -1418,14 +1418,22 @@ static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { size_t bytes; -__u32 buf[16 ]; +__u32 t, buf[16 ];const char __user *p = buffer;while (count >0 ) { +int b, i =0 ; + bytes =min (count,sizeof (buf));if (copy_from_user (&buf, p, bytes))return -EFAULT ; +for (b = bytes ; b >0 ; b -=sizeof (__u32), i++) { +if (!arch_get_random_int (&t)) +break ; + buf[i] ^= t; + } + count -= bytes; p += bytes;
PATCH 267/366 Input: i8042 - add TUXEDO BU1406 (N24_25BU) to the nomux list
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit a4c2a13129f7c5bcf81704c06851601593303fd5 upstream.
TUXEDO BU1406 does not implement active multiplexing mode properly, and takes around 550 ms in i8042_set_mux_mode(). Given that the device does not have external AUX port, there is no downside in disabling the MUX mode.
--- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/input/serio/i8042-x86ia64io.h +7 -0
@@ -513,6 +513,13 @@ static const struct dmi_system_id __init DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), }, }, + { + /* TUXEDO BU1406 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), + DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), + }, + }, { } };
PATCH 268/366 Input: i8042 - add Lenovo LaVie Z to the i8042 reset list
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai <[email protected]>
commit 384cf4285b34e08917e3e66603382f2b0c4f6e1b upstream.
The Lenovo LaVie Z laptop requires i8042 to be reset in order to consistently detect its Elantech touchpad. The nomux and kbdreset quirks are not sufficient.
It's possible the other LaVie Z models from NEC require this as well.
--- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/input/serio/i8042-x86ia64io.h +7 -0
@@ -520,6 +520,13 @@ static const struct dmi_system_id __init DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), }, }, + { + /* Lenovo LaVie Z */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), + }, + }, { } };
PATCH 269/366 net: cxgb3_main: fix potential Spectre v1
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Gustavo A. R. Silva" <[email protected]>
commit 676bcfece19f83621e905aa55b5ed2d45cc4f2d3 upstream.
t.qset_idx can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability.
This issue was detected with the help of Smatch:
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c:2286 cxgb_extension_ioctl()
warn: potential spectre issue 'adapter->msix_info'
Fix this by sanitizing t.qset_idx before using it to index adapter->msix_info
Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1].
[1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2
--- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +2 -0
@@ -51,6 +51,7 @@#include <linux/sched.h> #include <linux/slab.h> #include <asm/uaccess.h> +#include <linux/nospec.h> #include "common.h" #include "cxgb3_ioctl.h"
@@ -2256,6 +2257,7 @@ static int cxgb_extension_ioctl(struct nif (t.qset_idx >= nqsets)return -EINVAL ; + t.qset_idx =array_index_nospec (t.qset_idx, nqsets); q = &adapter->params.sge.qset[q1 + t.qset_idx]; t.rspq_size = q->rspq_size;
PATCH 270/366 scsi: qla2xxx: Fix ISP recovery on unload
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Quinn Tran <[email protected]>
commit b08abbd9f5996309f021684f9ca74da30dcca36a upstream.
During unload process, the chip can encounter problem where a FW dump would be captured. For this case, the full reset sequence will be skip to bring the chip back to full operational state.
--- drivers/scsi/qla2xxx/qla_os.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_os.c +3 -2
@@ -4963,8 +4963,9 @@ qla2x00_do_dpc(void *data) } } -if (test_and_clear_bit (ISP_ABORT_NEEDED , - &base_vha->dpc_flags)) { +if (test_and_clear_bit + (ISP_ABORT_NEEDED , &base_vha->dpc_flags) && + !test_bit (UNLOADING , &base_vha->dpc_flags)) {ql_dbg (ql_dbg_dpc, base_vha,0x4007 ,"ISP abort scheduled.\n" );
PATCH 271/366 scsi: qla2xxx: Return error when TMF returns
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anil Gurumurthy <[email protected]>
commit b4146c4929ef61d5afca011474d59d0918a0cd82 upstream.
Propagate the task management completion status properly to avoid unnecessary waits for commands to complete.
--- drivers/scsi/qla2xxx/qla_init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_init.c +3 -4
@@ -323,11 +323,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport,wait_for_completion (&tm_iocb->u.tmf.comp); - rval = tm_iocb->u.tmf.comp_status ==CS_COMPLETE ? -QLA_SUCCESS :QLA_FUNCTION_FAILED ; + rval = tm_iocb->u.tmf.data; -if ((rval !=QLA_SUCCESS ) || tm_iocb->u.tmf.data) { -ql_dbg (ql_dbg_taskm, vha,0x8030 , +if (rval !=QLA_SUCCESS ) { +ql_log (ql_log_warn, vha,0x8030 ,"TM IOCB failed (%x).\n" , rval); }
PATCH 272/366 crypto: padlock-aes - Fix Nano workaround data corruption
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Herbert Xu <[email protected]>
commit 46d8c4b28652d35dc6cfb5adf7f54e102fc04384 upstream.
This was detected by the self-test thanks to Ard's chunking patch.
I finally got around to testing this out on my ancient Via box. It turns out that the workaround got the assembly wrong and we end up doing count + initial cycles of the loop instead of just count.
This obviously causes corruption, either by overwriting the source that is yet to be processed, or writing over the end of the buffer.
On CPUs that don't require the workaround only ECB is affected. On Nano CPUs both ECB and CBC are affected.
This patch fixes it by doing the subtraction prior to the assembly.
--- drivers/crypto/padlock-aes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/crypto/padlock-aes.c +6 -2
@@ -266,6 +266,8 @@ static inline void padlock_xcrypt_ecb(coreturn ; } + count -= initial; +if (initial) asmvolatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output)
@@ -273,7 +275,7 @@ static inline void padlock_xcrypt_ecb(co asmvolatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ :"+S" (input),"+D" (output) - :"d" (control_word),"b" (key),"c" (count - initial)); + :"d" (control_word),"b" (key),"c" (count)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
@@ -284,6 +286,8 @@ static inline u8 *padlock_xcrypt_cbc(conif (count < cbc_fetch_blocks)return cbc_crypt (input, output, key, iv, control_word, count); + count -= initial; +if (initial) asmvolatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv)
@@ -291,7 +295,7 @@ static inline u8 *padlock_xcrypt_cbc(con asmvolatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ :"+S" (input),"+D" (output),"+a" (iv) - :"d" (control_word),"b" (key),"c" (count-initial)); + :"d" (control_word),"b" (key),"c" (count));return iv; }
PATCH 273/366 usb: core: handle hub C_PORT_OVER_CURRENT condition
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Bin Liu <[email protected]>
commit 249a32b7eeb3edb6897dd38f89651a62163ac4ed upstream.
Based on USB2.0 Spec Section 11.12.5,
"If a hub has per-port power switching and per-port current limiting, an over-current on one port may still cause the power on another port to fall below specific minimums. In this case, the affected port is placed in the Power-Off state and C_PORT_OVER_CURRENT is set for the port, but PORT_OVER_CURRENT is not set."
so let's check C_PORT_OVER_CURRENT too for over current condition.
--- drivers/usb/core/hub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/usb/core/hub.c +6 -2
@@ -1119,10 +1119,14 @@ static void hub_activate(struct usb_hubif (!udev || udev->state ==USB_STATE_NOTATTACHED ) {/* Tell khubd to disconnect the device or -* check for a new connection +* check for a new connection or over current condition. +* Based on USB2.0 Spec Section 11.12.5, +* C_PORT_OVER_CURRENT could be set while +* PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus &USB_PORT_STAT_CONNECTION ) || - (portstatus &USB_PORT_STAT_OVERCURRENT )) + (portstatus &USB_PORT_STAT_OVERCURRENT ) || + (portchange &USB_PORT_STAT_C_OVERCURRENT ))set_bit (port1, hub->change_bits); }else if (portstatus &USB_PORT_STAT_ENABLE ) {
PATCH 274/366 fat: fix memory allocation failure handling of match_strdup()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: OGAWA Hirofumi <[email protected]>
commit 35033ab988c396ad7bce3b6d24060c16a9066db8 upstream.
In parse_options(), if match_strdup() failed, parse_options() leaves opts->iocharset in unexpected state (i.e. still pointing the freed string). And this can be the cause of double free.
To fix, this initialize opts->iocharset always when freeing.
--- fs/fat/inode.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
fs/fat/inode.c +13 -7
@@ -610,13 +610,21 @@ static void fat_set_state(struct super_bbrelse (bh); } +static void fat_reset_iocharset (struct fat_mount_options *opts) +{ +if (opts->iocharset != fat_default_iocharset) { +/* Note: opts->iocharset can be NULL here */ +kfree (opts->iocharset); + opts->iocharset = fat_default_iocharset; + } +} +static void delayed_free (struct rcu_head *p) { struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu);unload_nls (sbi->nls_disk);unload_nls (sbi->nls_io); -if (sbi->options.iocharset != fat_default_iocharset) -kfree (sbi->options.iocharset); +fat_reset_iocharset (&sbi->options);kfree (sbi); }
@@ -1031,7 +1039,7 @@ static int parse_options(struct super_bl opts->fs_fmask = opts->fs_dmask =current_umask (); opts->allow_utime =-1 ; opts->codepage = fat_default_codepage; - opts->iocharset = fat_default_iocharset; +fat_reset_iocharset (opts);if (is_vfat) { opts->shortname =VFAT_SFN_DISPLAY_WINNT |VFAT_SFN_CREATE_WIN95 ; opts->rodir =0 ;
@@ -1181,8 +1189,7 @@ static int parse_options(struct super_bl/* vfat specific */ case Opt_charset: -if (opts->iocharset != fat_default_iocharset) -kfree (opts->iocharset); +fat_reset_iocharset (opts); iocharset =match_strdup (&args[0 ]);if (!iocharset)return -ENOMEM ;
@@ -1763,8 +1770,7 @@ out_fail:iput (fat_inode);unload_nls (sbi->nls_io);unload_nls (sbi->nls_disk); -if (sbi->options.iocharset != fat_default_iocharset) -kfree (sbi->options.iocharset); +fat_reset_iocharset (&sbi->options); sb->s_fs_info =NULL ;kfree (sbi);return error;
PATCH 275/366 net: caif: Add a missing rcu_read_unlock() in caif_flow_cb
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: YueHaibing <[email protected]>
commit 64119e05f7b31e83e2555f6782e6cdc8f81c63f4 upstream.
Add a missing rcu_read_unlock in the error path
--- net/caif/caif_dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/caif/caif_dev.c +3 -1
@@ -131,8 +131,10 @@ static void caif_flow_cb(struct sk_buff caifd =caif_get (skb->dev);WARN_ON (caifd ==NULL ); -if (caifd ==NULL ) +if (!caifd) { +rcu_read_unlock ();return ; + }caifd_hold (caifd);rcu_read_unlock ();
PATCH 276/366 multicast: do not restore deleted record source filter mode to new one
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu <[email protected]>
commit 08d3ffcc0cfaba36f6b86fd568cc3bc773061fa6 upstream.
There are two scenarios that we will restore deleted records. The first is when device down and up(or unmap/remap). In this scenario the new filter mode is same with previous one. Because we get it from in_dev->mc_list and we do not touch it during device down and up.
The other scenario is when a new socket join a group which was just delete and not finish sending status reports. In this scenario, we should use the current filter mode instead of restore old one. Here are 4 cases in total.
old_socket new_socket before_fix after_fix
IN(A) IN(A) ALLOW(A) ALLOW(A) IN(A) EX( ) TO_IN( ) TO_EX( ) EX( ) IN(A) TO_EX( ) ALLOW(A) EX( ) EX( ) TO_EX( ) TO_EX( )
--- net/ipv4/igmp.c | 3 +-- net/ipv6/mcast.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-)
net/ipv4/igmp.c +1 -2
@@ -1159,8 +1159,7 @@ static void igmpv3_del_delrec(struct in_if (pmc) { im->interface = pmc->interface; im->crcount = in_dev->mr_qrv ?: IGMP_Unsolicited_Report_Count; - im->sfmode = pmc->sfmode; -if (pmc->sfmode ==MCAST_INCLUDE ) { +if (im->sfmode ==MCAST_INCLUDE ) { im->tomb = pmc->tomb; im->sources = pmc->sources;for (psf = im->sources; psf; psf = psf->sf_next)
net/ipv6/mcast.c +1 -2
@@ -806,8 +806,7 @@ static void mld_del_delrec(struct inet6_if (pmc) { im->idev = pmc->idev; im->mca_crcount = idev->mc_qrv; - im->mca_sfmode = pmc->mca_sfmode; -if (pmc->mca_sfmode ==MCAST_INCLUDE ) { +if (im->mca_sfmode ==MCAST_INCLUDE ) { im->mca_tomb = pmc->mca_tomb; im->mca_sources = pmc->mca_sources;for (psf = im->mca_sources; psf; psf = psf->sf_next)
PATCH 277/366 atl1c: reserve min skb headroom
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit 6e56830776828d8ca9897fc4429eeab47c3bb432 upstream.
Got crash report with following backtrace:
BUG: unable to handle kernel paging request at ffff8801869daffe RIP: 0010:[<ffffffff816429c4>] [<ffffffff816429c4>] ip6_finish_output2+0x394/0x4c0 RSP: 0018:ffff880186c83a98 EFLAGS: 00010283 RAX: ffff8801869db00e ... [<ffffffff81644cdc>] ip6_finish_output+0x8c/0xf0 [<ffffffff81644d97>] ip6_output+0x57/0x100 [<ffffffff81643dc9>] ip6_forward+0x4b9/0x840 [<ffffffff81645566>] ip6_rcv_finish+0x66/0xc0 [<ffffffff81645db9>] ipv6_rcv+0x319/0x530 [<ffffffff815892ac>] netif_receive_skb+0x1c/0x70 [<ffffffffc0060bec>] atl1c_clean+0x1ec/0x310 [atl1c] ...
The bad access is in neigh_hh_output(), at skb->data - 16 (HH_DATA_MOD). atl1c driver provided skb with no headroom, so 14 bytes (ethernet header) got pulled, but then 16 are copied.
Reserve NET_SKB_PAD bytes headroom, like netdev_alloc_skb().
Compile tested only; I lack hardware.
--- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/atheros/atl1c/atl1c_main.c +1 -0
@@ -1674,6 +1674,7 @@ static struct sk_buff *atl1c_alloc_skb(s skb =build_skb (page_address (page) + adapter->rx_page_offset, adapter->rx_frag_size);if (likely (skb)) { +skb_reserve (skb,NET_SKB_PAD ); adapter->rx_page_offset += adapter->rx_frag_size;if (adapter->rx_page_offset >=PAGE_SIZE ) adapter->rx_page =NULL ;
PATCH 278/366 can: constify of_device_id array
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Fabian Frederick <[email protected]>
commit 486e957033623656298a07c39a8bf2fd81db285b upstream.
of_device_id is always used as const.
(See driver.of_match_table and open firmware functions)
--- drivers/net/can/cc770/cc770_platform.c | 2 +- drivers/net/can/grcan.c | 2 +- drivers/net/can/mscan/mpc5xxx_can.c | 2 +- drivers/net/can/sja1000/sja1000_platform.c | 2 +- drivers/net/can/xilinx_can.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/can/cc770/cc770_platform.c +1 -1
@@ -254,7 +254,7 @@ static int cc770_platform_remove(structreturn 0 ; } -static struct of_device_id cc770_platform_table[] = { +static const struct of_device_id cc770_platform_table[] = { {.compatible ="bosch,cc770" },/* CC770 from Bosch */ {.compatible ="intc,82527" },/* AN82527 from Intel CP */ {},
drivers/net/can/grcan.c +1 -1
@@ -1725,7 +1725,7 @@ static int grcan_remove(struct platform_return 0 ; } -static struct of_device_id grcan_match[] = { +static const struct of_device_id grcan_match[] = { {.name ="GAISLER_GRCAN" }, {.name ="01_03d" }, {.name ="GAISLER_GRHCAN" },
drivers/net/can/mscan/mpc5xxx_can.c +1 -1
@@ -43,7 +43,7 @@ struct mpc5xxx_can_data { };#ifdef CONFIG_PPC_MPC52xx -static struct of_device_id mpc52xx_cdm_ids[] = { +static const struct of_device_id mpc52xx_cdm_ids[] = { { .compatible ="fsl,mpc5200-cdm" , }, {} };
drivers/net/can/sja1000/sja1000_platform.c +1 -1
@@ -242,7 +242,7 @@ static int sp_remove(struct platform_devreturn 0 ; } -static struct of_device_id sp_of_table[] = { +static const struct of_device_id sp_of_table[] = { {.compatible ="nxp,sja1000" }, {}, };
drivers/net/can/xilinx_can.c +1 -1
@@ -1184,7 +1184,7 @@ static int xcan_remove(struct platform_d }/* Match table for OF platform binding */ -static struct of_device_id xcan_of_match[] = { +static const struct of_device_id xcan_of_match[] = { { .compatible ="xlnx,zynq-can-1.0" , }, { .compatible ="xlnx,axi-can-1.00.a" , }, {/* end of list */ },
PATCH 279/366 can: mpc5xxx_can: check of_iomap return before use
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Mc Guire <[email protected]>
commit b5c1a23b17e563b656cc9bb76ce5323b997d90e8 upstream.
of_iomap() can return NULL so that return needs to be checked and NULL treated as failure. While at it also take care of the missing of_node_put() in the error path.
--- drivers/net/can/mscan/mpc5xxx_can.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/can/mscan/mpc5xxx_can.c +5 -0
@@ -86,6 +86,11 @@ static u32 mpc52xx_can_get_clock(structreturn 0 ; } cdm =of_iomap (np_cdm,0 ); +if (!cdm) { +of_node_put (np_cdm); +dev_err (&ofdev->dev,"can't map clock node!\n" ); +return 0 ; + }if (in_8 (&cdm->ipb_clk_sel) &0x1 ) freq *=2 ;
PATCH 280/366 can: dev: Consolidate and unify state change handling
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Andri Yngvason <[email protected]>
commit bac78aabcfece0c493b2ad824c68fbdc20448cbc upstream.
The handling of can error states is different between platforms. This is an attempt to correct that problem.
I've moved this handling into a generic function for changing the error state. This ensures that error state changes are handled the same way everywhere (where this function is used).
This new mechanism also adds reverse state transitioning in error frames, i.e. the user will be notified through the socket interface when the state goes down.
--- drivers/net/can/dev.c | 78 ++++++++++++++++++++++++++++++++++ include/linux/can/dev.h | 3 ++ include/uapi/linux/can/error.h | 1 + 3 files changed, 82 insertions(+)
drivers/net/can/dev.c +78 -0
@@ -275,6 +275,84 @@ static int can_get_bittiming(struct net_return err; } +static void can_update_state_error_stats (struct net_device *dev, +enum can_state new_state) +{ +struct can_priv *priv =netdev_priv (dev); + +if (new_state <= priv->state) +return ; + +switch (new_state) { +case CAN_STATE_ERROR_WARNING : + priv->can_stats.error_warning++; +break ; +case CAN_STATE_ERROR_PASSIVE : + priv->can_stats.error_passive++; +break ; +case CAN_STATE_BUS_OFF : +default : +break ; + }; +} + +static int can_tx_state_to_frame (struct net_device *dev,enum can_state state) +{ +switch (state) { +case CAN_STATE_ERROR_ACTIVE : +return CAN_ERR_CRTL_ACTIVE ; +case CAN_STATE_ERROR_WARNING : +return CAN_ERR_CRTL_TX_WARNING ; +case CAN_STATE_ERROR_PASSIVE : +return CAN_ERR_CRTL_TX_PASSIVE ; +default : +return 0 ; + } +} + +static int can_rx_state_to_frame (struct net_device *dev,enum can_state state) +{ +switch (state) { +case CAN_STATE_ERROR_ACTIVE : +return CAN_ERR_CRTL_ACTIVE ; +case CAN_STATE_ERROR_WARNING : +return CAN_ERR_CRTL_RX_WARNING ; +case CAN_STATE_ERROR_PASSIVE : +return CAN_ERR_CRTL_RX_PASSIVE ; +default : +return 0 ; + } +} + +void can_change_state (struct net_device *dev,struct can_frame *cf, +enum can_state tx_state,enum can_state rx_state) +{ +struct can_priv *priv =netdev_priv (dev); +enum can_state new_state =max (tx_state, rx_state); + +if (unlikely (new_state == priv->state)) { +netdev_warn (dev,"%s: oops, state did not change" , __func__); +return ; + } + +netdev_dbg (dev,"New error state: %d\n" , new_state); + +can_update_state_error_stats (dev, new_state); + priv->state = new_state; + +if (unlikely (new_state ==CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_BUSOFF ; +return ; + } + + cf->can_id |=CAN_ERR_CRTL ; + cf->data[1 ] |= tx_state >= rx_state ? +can_tx_state_to_frame (dev, tx_state) :0 ; + cf->data[1 ] |= tx_state <= rx_state ? +can_rx_state_to_frame (dev, rx_state) :0 ; +} +EXPORT_SYMBOL_GPL (can_change_state); +/* * Local echo of CAN messages *
include/linux/can/dev.h +3 -0
@@ -122,6 +122,9 @@ void unregister_candev(struct net_deviceint can_restart_now (struct net_device *dev);void can_bus_off (struct net_device *dev); +void can_change_state (struct net_device *dev,struct can_frame *cf, +enum can_state tx_state,enum can_state rx_state); +void can_put_echo_skb (struct sk_buff *skb,struct net_device *dev,unsigned int idx);unsigned int can_get_echo_skb (struct net_device *dev,unsigned int idx);
include/uapi/linux/can/error.h +1 -0
@@ -71,6 +71,7 @@#define CAN_ERR_CRTL_TX_PASSIVE 0x20/* reached error passive status TX */ /* (at least one error counter exceeds */ /* the protocol-defined level of 127) */ +#define CAN_ERR_CRTL_ACTIVE 0x40/* recovered to error active state */ /* error in CAN protocol (type) / data[2] */ #define CAN_ERR_PROT_UNSPEC 0x00/* unspecified */
PATCH 281/366 can: xilinx_can: fix device dropping off bus on RX overrun
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 2574fe54515ed3487405de329e4e9f13d7098c10 upstream.
The xilinx_can driver performs a software reset when an RX overrun is detected. This causes the device to enter Configuration mode where no messages are received or transmitted.
The documentation does not mention any need to perform a reset on an RX overrun, and testing by inducing an RX overflow also indicated that the device continues to work just fine without a reset.
Remove the software reset.
Tested with the integrated CAN on Zynq-7000 SoC.
--- drivers/net/can/xilinx_can.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/can/xilinx_can.c +0 -1
@@ -598,7 +598,6 @@ static void xcan_err_interrupt(struct neif (isr &XCAN_IXR_RXOFLW_MASK ) { stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg (priv,XCAN_SRR_OFFSET ,XCAN_SRR_RESET_MASK );if (skb) { cf->can_id |=CAN_ERR_CRTL ; cf->data[1 ] |=CAN_ERR_CRTL_RX_OVERFLOW ;
PATCH 282/366 can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 32852c561bffd613d4ed7ec464b1e03e1b7b6c5c upstream.
If the device gets into a state where RXNEMP (RX FIFO not empty) interrupt is asserted without RXOK (new frame received successfully) interrupt being asserted, xcan_rx_poll() will continue to try to clear RXNEMP without actually reading frames from RX FIFO. If the RX FIFO is not empty, the interrupt will not be cleared and napi_schedule() will just be called again.
This situation can occur when:
(a) xcan_rx() returns without reading RX FIFO due to an error condition. The code tries to clear both RXOK and RXNEMP but RXNEMP will not clear due to a frame still being in the FIFO. The frame will never be read from the FIFO as RXOK is no longer set.
(b) A frame is received between xcan_rx_poll() reading interrupt status and clearing RXOK. RXOK will be cleared, but RXNEMP will again remain set as the new message is still in the FIFO.
I'm able to trigger case (b) by flooding the bus with frames under load.
There does not seem to be any benefit in using both RXNEMP and RXOK in the way the driver does, and the polling example in the reference manual (UG585 v1.10 18.3.7 Read Messages from RxFIFO) also says that either RXOK or RXNEMP can be used for detecting incoming messages.
Fix the issue and simplify the RX processing by only using RXNEMP without RXOK.
Tested with the integrated CAN on Zynq-7000 SoC.
--- drivers/net/can/xilinx_can.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-)
drivers/net/can/xilinx_can.c +5 -13
@@ -100,7 +100,7 @@ enum xcan_reg {#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + XCAN_IXR_ARBLST_MASK)/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ #define XCAN_BTR_SJW_SHIFT 7/* Synchronous jump width */
@@ -709,15 +709,7 @@ static int xcan_rx_poll(struct napi_stru isr = priv->read_reg (priv,XCAN_ISR_OFFSET );while ((isr &XCAN_IXR_RXNEMP_MASK ) && (work_done < quota)) { -if (isr &XCAN_IXR_RXOK_MASK ) { - priv->write_reg (priv,XCAN_ICR_OFFSET , -XCAN_IXR_RXOK_MASK ); - work_done +=xcan_rx (ndev); - }else { - priv->write_reg (priv,XCAN_ICR_OFFSET , -XCAN_IXR_RXNEMP_MASK ); -break ; - } + work_done +=xcan_rx (ndev); priv->write_reg (priv,XCAN_ICR_OFFSET ,XCAN_IXR_RXNEMP_MASK ); isr = priv->read_reg (priv,XCAN_ISR_OFFSET ); }
@@ -728,7 +720,7 @@ static int xcan_rx_poll(struct napi_struif (work_done < quota) {napi_complete (napi); ier = priv->read_reg (priv,XCAN_IER_OFFSET ); - ier |= (XCAN_IXR_RXOK_MASK |XCAN_IXR_RXNEMP_MASK ); + ier |=XCAN_IXR_RXNEMP_MASK ; priv->write_reg (priv,XCAN_IER_OFFSET , ier); }return work_done;
@@ -800,9 +792,9 @@ static irqreturn_t xcan_interrupt(int ir }/* Check for the type of receive interrupt and Processing it */ -if (isr & (XCAN_IXR_RXNEMP_MASK |XCAN_IXR_RXOK_MASK )) { +if (isr &XCAN_IXR_RXNEMP_MASK ) { ier = priv->read_reg (priv,XCAN_IER_OFFSET ); - ier &= ~(XCAN_IXR_RXNEMP_MASK |XCAN_IXR_RXOK_MASK ); + ier &= ~XCAN_IXR_RXNEMP_MASK ; priv->write_reg (priv,XCAN_IER_OFFSET , ier);napi_schedule (&priv->napi); }
PATCH 283/366 can: xilinx_can: fix recovery from error states not being propagated
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 877e0b75947e2c7acf5624331bb17ceb093c98ae upstream.
The xilinx_can driver contains no mechanism for propagating recovery from CAN_STATE_ERROR_WARNING and CAN_STATE_ERROR_PASSIVE.
Add such a mechanism by factoring the handling of XCAN_STATE_ERROR_PASSIVE and XCAN_STATE_ERROR_WARNING out of xcan_err_interrupt and checking for recovery after RX and TX if the interface is in one of those states.
Tested with the integrated CAN on Zynq-7000 SoC.
--- drivers/net/can/xilinx_can.c | 155 ++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 28 deletions(-)
drivers/net/can/xilinx_can.c +127 -28
@@ -2,6 +2,7 @@* * Copyright (C) 2012 - 2014 Xilinx, Inc. * Copyright (C) 2009 PetaLogix. All rights reserved. +* Copyright (C) 2017 Sandvik Mining and Construction Oy * * Description: * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
@@ -528,6 +529,123 @@ static int xcan_rx(struct net_device *nd }/** +* xcan_current_error_state - Get current error state from HW +* @ndev: Pointer to net_device structure +* +* Checks the current CAN error state from the HW. Note that this +* only checks for ERROR_PASSIVE and ERROR_WARNING. +* +* Return: +* ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE +* otherwise. +*/ +static enum can_state xcan_current_error_state (struct net_device *ndev) +{ +struct xcan_priv *priv =netdev_priv (ndev); +u32 status = priv->read_reg (priv,XCAN_SR_OFFSET ); + +if ((status &XCAN_SR_ESTAT_MASK ) ==XCAN_SR_ESTAT_MASK ) +return CAN_STATE_ERROR_PASSIVE ; +else if (status &XCAN_SR_ERRWRN_MASK ) +return CAN_STATE_ERROR_WARNING ; +else +return CAN_STATE_ERROR_ACTIVE ; +} + +/** +* xcan_set_error_state - Set new CAN error state +* @ndev: Pointer to net_device structure +* @new_state: The new CAN state to be set +* @cf: Error frame to be populated or NULL +* +* Set new CAN error state for the device, updating statistics and +* populating the error frame if given. +*/ +static void xcan_set_error_state (struct net_device *ndev, +enum can_state new_state, +struct can_frame *cf) +{ +struct xcan_priv *priv =netdev_priv (ndev); +u32 ecr = priv->read_reg (priv,XCAN_ECR_OFFSET ); +u32 txerr = ecr &XCAN_ECR_TEC_MASK ; +u32 rxerr = (ecr &XCAN_ECR_REC_MASK ) >>XCAN_ESR_REC_SHIFT ; + + priv->can.state = new_state; + +if (cf) { + cf->can_id |=CAN_ERR_CRTL ; + cf->data[6 ] = txerr; + cf->data[7 ] = rxerr; + } + +switch (new_state) { +case CAN_STATE_ERROR_PASSIVE : + priv->can.can_stats.error_passive++; +if (cf) + cf->data[1 ] = (rxerr >127 ) ? +CAN_ERR_CRTL_RX_PASSIVE : +CAN_ERR_CRTL_TX_PASSIVE ; +break ; +case CAN_STATE_ERROR_WARNING : + priv->can.can_stats.error_warning++; +if (cf) + cf->data[1 ] |= (txerr > rxerr) ? +CAN_ERR_CRTL_TX_WARNING : +CAN_ERR_CRTL_RX_WARNING ; +break ; +case CAN_STATE_ERROR_ACTIVE : +if (cf) + cf->data[1 ] |=CAN_ERR_CRTL_ACTIVE ; +break ; +default : +/* non-ERROR states are handled elsewhere */ +WARN_ON (1 ); +break ; + } +} + +/** +* xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX +* @ndev: Pointer to net_device structure +* +* If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if +* the performed RX/TX has caused it to drop to a lesser state and set +* the interface state accordingly. +*/ +static void xcan_update_error_state_after_rxtx (struct net_device *ndev) +{ +struct xcan_priv *priv =netdev_priv (ndev); +enum can_state old_state = priv->can.state; +enum can_state new_state; + +/* changing error state due to successful frame RX/TX can only +* occur from these states +*/ +if (old_state !=CAN_STATE_ERROR_WARNING && + old_state !=CAN_STATE_ERROR_PASSIVE ) +return ; + + new_state =xcan_current_error_state (ndev); + +if (new_state != old_state) { +struct sk_buff *skb; +struct can_frame *cf; + + skb =alloc_can_err_skb (ndev, &cf); + +xcan_set_error_state (ndev, new_state, skb ? cf :NULL ); + +if (skb) { +struct net_device_stats *stats = &ndev->stats; + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +netif_rx (skb); + } + } +} + +/** * xcan_err_interrupt - error frame Isr * @ndev: net_device pointer * @isr: interrupt status register value
@@ -542,16 +660,12 @@ static void xcan_err_interrupt(struct nestruct net_device_stats *stats = &ndev->stats;struct can_frame *cf;struct sk_buff *skb; -u32 err_status, status, txerr =0 , rxerr =0 ; +u32 err_status; skb =alloc_can_err_skb (ndev, &cf); err_status = priv->read_reg (priv,XCAN_ESR_OFFSET ); priv->write_reg (priv,XCAN_ESR_OFFSET , err_status); - txerr = priv->read_reg (priv,XCAN_ECR_OFFSET ) &XCAN_ECR_TEC_MASK ; - rxerr = ((priv->read_reg (priv,XCAN_ECR_OFFSET ) & -XCAN_ECR_REC_MASK ) >>XCAN_ESR_REC_SHIFT ); - status = priv->read_reg (priv,XCAN_SR_OFFSET );if (isr &XCAN_IXR_BSOFF_MASK ) { priv->can.state =CAN_STATE_BUS_OFF ;
@@ -561,28 +675,10 @@ static void xcan_err_interrupt(struct necan_bus_off (ndev);if (skb) cf->can_id |=CAN_ERR_BUSOFF ; - }else if ((status &XCAN_SR_ESTAT_MASK ) ==XCAN_SR_ESTAT_MASK ) { - priv->can.state =CAN_STATE_ERROR_PASSIVE ; - priv->can.can_stats.error_passive++; -if (skb) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (rxerr >127 ) ? -CAN_ERR_CRTL_RX_PASSIVE : -CAN_ERR_CRTL_TX_PASSIVE ; - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; - } - }else if (status &XCAN_SR_ERRWRN_MASK ) { - priv->can.state =CAN_STATE_ERROR_WARNING ; - priv->can.can_stats.error_warning++; -if (skb) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] |= (txerr > rxerr) ? -CAN_ERR_CRTL_TX_WARNING : -CAN_ERR_CRTL_RX_WARNING ; - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; - } + }else { +enum can_state new_state =xcan_current_error_state (ndev); + +xcan_set_error_state (ndev, new_state, skb ? cf :NULL ); }/* Check for Arbitration lost interrupt */
@@ -714,8 +810,10 @@ static int xcan_rx_poll(struct napi_stru isr = priv->read_reg (priv,XCAN_ISR_OFFSET ); } -if (work_done) +if (work_done) {can_led_event (ndev,CAN_LED_EVENT_RX ); +xcan_update_error_state_after_rxtx (ndev); + }if (work_done < quota) {napi_complete (napi);
@@ -746,6 +844,7 @@ static void xcan_tx_interrupt(struct net isr = priv->read_reg (priv,XCAN_ISR_OFFSET ); }can_led_event (ndev,CAN_LED_EVENT_TX ); +xcan_update_error_state_after_rxtx (ndev);netif_wake_queue (ndev); }
PATCH 284/366 can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 620050d9c2be15c47017ba95efe59e0832e99a56 upstream.
The xilinx_can driver assumes that the TXOK interrupt only clears after it has been acknowledged as many times as there have been successfully sent frames.
However, the documentation does not mention such behavior, instead saying just that the interrupt is cleared when the clear bit is set.
Similarly, testing seems to also suggest that it is immediately cleared regardless of the amount of frames having been sent. Performing some heavy TX load and then going back to idle has the tx_head drifting further away from tx_tail over time, steadily reducing the amount of frames the driver keeps in the TX FIFO (but not to zero, as the TXOK interrupt always frees up space for 1 frame from the driver's perspective, so frames continue to be sent) and delaying the local echo frames.
The TX FIFO tracking is also otherwise buggy as it does not account for TX FIFO being cleared after software resets, causing
BUG!, TX FIFO full when queue awake!
messages to be output.
There does not seem to be any way to accurately track the state of the TX FIFO for local echo support while using the full TX FIFO.
The Zynq version of the HW (but not the soft-AXI version) has watermark programming support and with it an additional TX-FIFO-empty interrupt bit.
Modify the driver to only put 1 frame into TX FIFO at a time on soft-AXI and 2 frames at a time on Zynq. On Zynq the TXFEMP interrupt bit is used to detect whether 1 or 2 frames have been sent at interrupt processing time.
Tested with the integrated CAN on Zynq-7000 SoC. The 1-frame-FIFO mode was also tested.
An alternative way to solve this would be to drop local echo support but keep using the full TX FIFO.
v2: Add FIFO space check before TX queue wake with locking to synchronize with queue stop. This avoids waking the queue when xmit() had just filled it.
v3: Keep local echo support and reduce the amount of frames in FIFO instead as suggested by Marc Kleine-Budde.
--- drivers/net/can/xilinx_can.c | 139 +++++++++++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 16 deletions(-)
drivers/net/can/xilinx_can.c +123 -16
@@ -26,8 +26,10 @@#include <linux/module.h> #include <linux/netdevice.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/skbuff.h> +#include <linux/spinlock.h> #include <linux/string.h> #include <linux/types.h> #include <linux/can/dev.h>
@@ -118,6 +120,7 @@ enum xcan_reg {/** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. +* @tx_lock: Lock for synchronizing TX interrupt handling * @tx_head: Tx CAN packets ready to send on the queue * @tx_tail: Tx CAN packets successfully sended on the queue * @tx_max: Maximum number packets the driver can send
@@ -132,6 +135,7 @@ enum xcan_reg {*/ struct xcan_priv {struct can_priv can; +spinlock_t tx_lock;unsigned int tx_head;unsigned int tx_tail;unsigned int tx_max;
@@ -159,6 +163,11 @@ static const struct can_bittiming_const .brp_inc = 1, }; +#define XCAN_CAP_WATERMARK 0x0001 +struct xcan_devtype_data { +unsigned int caps; +}; +/** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure
@@ -238,6 +247,10 @@ static int set_reset_mode(struct net_devusleep_range (500 ,10000 ); } +/* reset clears FIFOs */ + priv->tx_head =0 ; + priv->tx_tail =0 ; +return 0 ; }
@@ -391,6 +404,7 @@ static int xcan_start_xmit(struct sk_bufstruct net_device_stats *stats = &ndev->stats;struct can_frame *cf = (struct can_frame *)skb->data;u32 id, dlc, data[2 ] = {0 ,0 }; +unsigned long flags;if (can_dropped_invalid_skb (ndev, skb))return NETDEV_TX_OK ;
@@ -438,6 +452,9 @@ static int xcan_start_xmit(struct sk_buf data[1 ] =be32_to_cpup ((__be32 *)(cf->data +4 ));can_put_echo_skb (skb, ndev, priv->tx_head % priv->tx_max); + +spin_lock_irqsave (&priv->tx_lock, flags); + priv->tx_head++;/* Write the Frame to Xilinx CAN TX FIFO */
@@ -453,10 +470,16 @@ static int xcan_start_xmit(struct sk_buf stats->tx_bytes += cf->can_dlc; } +/* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ +if (priv->tx_max >1 ) + priv->write_reg (priv,XCAN_ICR_OFFSET ,XCAN_IXR_TXFEMP_MASK ); +/* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max)netif_stop_queue (ndev); +spin_unlock_irqrestore (&priv->tx_lock, flags); +return NETDEV_TX_OK ; }
@@ -833,19 +856,71 @@ static void xcan_tx_interrupt(struct net {struct xcan_priv *priv =netdev_priv (ndev);struct net_device_stats *stats = &ndev->stats; +unsigned int frames_in_fifo; +int frames_sent =1 ;/* TXOK => at least 1 frame was sent */ +unsigned long flags; +int retries =0 ; + +/* Synchronize with xmit as we need to know the exact number +* of frames in the FIFO to stay in sync due to the TXFEMP +* handling. +* This also prevents a race between netif_wake_queue() and +* netif_stop_queue(). +*/ +spin_lock_irqsave (&priv->tx_lock, flags); + + frames_in_fifo = priv->tx_head - priv->tx_tail; + +if (WARN_ON_ONCE (frames_in_fifo ==0 )) { +/* clear TXOK anyway to avoid getting back here */ + priv->write_reg (priv,XCAN_ICR_OFFSET ,XCAN_IXR_TXOK_MASK ); +spin_unlock_irqrestore (&priv->tx_lock, flags); +return ; + } + +/* Check if 2 frames were sent (TXOK only means that at least 1 +* frame was sent). +*/ +if (frames_in_fifo >1 ) { +WARN_ON (frames_in_fifo > priv->tx_max); + +/* Synchronize TXOK and isr so that after the loop: +* (1) isr variable is up-to-date at least up to TXOK clear +* time. This avoids us clearing a TXOK of a second frame +* but not noticing that the FIFO is now empty and thus +* marking only a single frame as sent. +* (2) No TXOK is left. Having one could mean leaving a +* stray TXOK as we might process the associated frame +* via TXFEMP handling as we read TXFEMP *after* TXOK +* clear to satisfy (1). +*/ +while ((isr &XCAN_IXR_TXOK_MASK ) && !WARN_ON (++retries ==100 )) { + priv->write_reg (priv,XCAN_ICR_OFFSET ,XCAN_IXR_TXOK_MASK ); + isr = priv->read_reg (priv,XCAN_ISR_OFFSET ); + } -while ((priv->tx_head - priv->tx_tail >0 ) && - (isr &XCAN_IXR_TXOK_MASK )) { +if (isr &XCAN_IXR_TXFEMP_MASK ) { +/* nothing in FIFO anymore */ + frames_sent = frames_in_fifo; + } + }else { +/* single frame in fifo, just clear TXOK */ priv->write_reg (priv,XCAN_ICR_OFFSET ,XCAN_IXR_TXOK_MASK ); + } + +while (frames_sent--) {can_get_echo_skb (ndev, priv->tx_tail % priv->tx_max); priv->tx_tail++; stats->tx_packets++; - isr = priv->read_reg (priv,XCAN_ISR_OFFSET ); } + +netif_wake_queue (ndev); + +spin_unlock_irqrestore (&priv->tx_lock, flags); +can_led_event (ndev,CAN_LED_EVENT_TX );xcan_update_error_state_after_rxtx (ndev); -netif_wake_queue (ndev); }/**
@@ -1121,6 +1196,18 @@ static int __maybe_unused xcan_resume(st static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); +static const struct xcan_devtype_data xcan_zynq_data = { + .caps =XCAN_CAP_WATERMARK , +}; + +/* Match table for OF platform binding */ +static const struct of_device_id xcan_of_match[] = { + { .compatible ="xlnx,zynq-can-1.0" , .data = &xcan_zynq_data }, + { .compatible ="xlnx,axi-can-1.00.a" , }, + {/* end of list */ }, +}; +MODULE_DEVICE_TABLE (of, xcan_of_match); +/** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure
@@ -1135,8 +1222,10 @@ static int xcan_probe(struct platform_destruct resource *res;/* IO mem resources */ struct net_device *ndev;struct xcan_priv *priv; +const struct of_device_id *of_id; +int caps =0 ;void __iomem *addr; -int ret, rx_max, tx_max; +int ret, rx_max, tx_max, tx_fifo_depth;/* Get the virtual base address for the device */ res =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
@@ -1146,7 +1235,8 @@ static int xcan_probe(struct platform_de goto err; } - ret =of_property_read_u32 (pdev->dev.of_node,"tx-fifo-depth" , &tx_max); + ret =of_property_read_u32 (pdev->dev.of_node,"tx-fifo-depth" , + &tx_fifo_depth);if (ret <0 ) goto err;
@@ -1154,6 +1244,30 @@ static int xcan_probe(struct platform_deif (ret <0 ) goto err; + of_id =of_match_device (xcan_of_match, &pdev->dev); +if (of_id) { +const struct xcan_devtype_data *devtype_data = of_id->data; + +if (devtype_data) + caps = devtype_data->caps; + } + +/* There is no way to directly figure out how many frames have been +* sent when the TXOK interrupt is processed. If watermark programming +* is supported, we can have 2 frames in the FIFO and use TXFEMP +* to determine if 1 or 2 frames have been sent. +* Theoretically we should be able to use TXFWMEMP to determine up +* to 3 frames, but it seems that after putting a second frame in the +* FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less +* than 2 frames in FIFO) is set anyway with no TXOK (a frame was +* sent), which is not a sensible state - possibly TXFWMEMP is not +* completely synchronized with the rest of the bits? +*/ +if (caps &XCAN_CAP_WATERMARK ) + tx_max =min (tx_fifo_depth,2 ); +else + tx_max =1 ; +/* Create a CAN device instance */ ndev =alloc_candev (sizeof (struct xcan_priv ), tx_max);if (!ndev)
@@ -1168,6 +1282,7 @@ static int xcan_probe(struct platform_deCAN_CTRLMODE_BERR_REPORTING ; priv->reg_base = addr; priv->tx_max = tx_max; +spin_lock_init (&priv->tx_lock);/* Get IRQ for the device */ ndev->irq =platform_get_irq (pdev,0 );
@@ -1235,9 +1350,9 @@ static int xcan_probe(struct platform_dedevm_can_led_init (ndev);clk_disable_unprepare (priv->bus_clk);clk_disable_unprepare (priv->can_clk); -netdev_dbg (ndev,"reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n" , +netdev_dbg (ndev,"reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n" , priv->reg_base, ndev->irq, priv->can.clock.freq, - priv->tx_max); + tx_fifo_depth, priv->tx_max);return 0 ;
@@ -1273,14 +1388,6 @@ static int xcan_remove(struct platform_dreturn 0 ; } -/* Match table for OF platform binding */ -static const struct of_device_id xcan_of_match[] = { - { .compatible ="xlnx,zynq-can-1.0" , }, - { .compatible ="xlnx,axi-can-1.00.a" , }, - {/* end of list */ }, -}; -MODULE_DEVICE_TABLE (of, xcan_of_match); -static struct platform_driver xcan_driver = { .probe = xcan_probe, .remove = xcan_remove,
PATCH 285/366 can: xilinx_can: fix RX overflow interrupt not being enabled
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 83997997252f5d3fc7f04abc24a89600c2b504ab upstream.
RX overflow interrupt (RXOFLW) is disabled even though xcan_interrupt() processes it. This means that an RX overflow interrupt will only be processed when another interrupt gets asserted (e.g. for RX/TX).
Fix that by enabling the RXOFLW interrupt.
--- drivers/net/can/xilinx_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/can/xilinx_can.c +1 -1
@@ -103,7 +103,7 @@ enum xcan_reg {#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK) + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK)/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ #define XCAN_BTR_SJW_SHIFT 7/* Synchronous jump width */
PATCH 286/366 can: xilinx_can: fix incorrect clear of non-processed interrupts
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anssi Hannula <[email protected]>
commit 2f4f0f338cf453bfcdbcf089e177c16f35f023c8 upstream.
xcan_interrupt() clears ERROR|RXOFLV|BSOFF|ARBLST interrupts if any of them is asserted. This does not take into account that some of them could have been asserted between interrupt status read and interrupt clear, therefore clearing them without handling them.
Fix the code to only clear those interrupts that it knows are asserted and therefore going to be processed in xcan_err_interrupt().
--- drivers/net/can/xilinx_can.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/net/can/xilinx_can.c +5 -5
@@ -939,6 +939,7 @@ static irqreturn_t xcan_interrupt(int irstruct net_device *ndev = (struct net_device *)dev_id;struct xcan_priv *priv =netdev_priv (ndev);u32 isr, ier; +u32 isr_errors;/* Get the interrupt status from Xilinx CAN */ isr = priv->read_reg (priv,XCAN_ISR_OFFSET );
@@ -957,11 +958,10 @@ static irqreturn_t xcan_interrupt(int irxcan_tx_interrupt (ndev, isr);/* Check for the type of error interrupt and Processing it */ -if (isr & (XCAN_IXR_ERROR_MASK |XCAN_IXR_RXOFLW_MASK | -XCAN_IXR_BSOFF_MASK |XCAN_IXR_ARBLST_MASK )) { - priv->write_reg (priv,XCAN_ICR_OFFSET , (XCAN_IXR_ERROR_MASK | -XCAN_IXR_RXOFLW_MASK |XCAN_IXR_BSOFF_MASK | -XCAN_IXR_ARBLST_MASK )); + isr_errors = isr & (XCAN_IXR_ERROR_MASK |XCAN_IXR_RXOFLW_MASK | +XCAN_IXR_BSOFF_MASK |XCAN_IXR_ARBLST_MASK ); +if (isr_errors) { + priv->write_reg (priv,XCAN_ICR_OFFSET , isr_errors);xcan_err_interrupt (ndev, isr); }
PATCH 287/366 net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jack Morgenstein <[email protected]>
commit 958c696f5a7274d9447a458ad7aa70719b29a50a upstream.
Function mlx4_RST2INIT_QP_wrapper saved the qp number passed in the qp context, rather than the one passed in the input modifier.
However, the qp number in the qp context is not defined as a required parameter by the FW. Therefore, drivers may choose to not specify the qp number in the qp context for the reset-to-init transition.
Thus, we must save the qp number passed in the command input modifier -- which is always present. (This saved qp number is used as the input modifier for command 2RST_QP when a slave's qp's are destroyed).
--- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +1 -1
@@ -2673,7 +2673,7 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4u32 srqn =qp_get_srqn (qpc) &0xffffff ;int use_srq = (qp_get_srqn (qpc) >>24 ) &1 ;struct res_srq *srq; -int local_qpn =be32_to_cpu (qpc->local_qpn) &0xffffff ; +int local_qpn = vhcr->in_modifier &0xffffff ; err =qp_res_start_move_to (dev, slave, qpn,RES_QP_HW , &qp,0 );if (err)
PATCH 288/366 fscache: Allow cancelled operations to be enqueued
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kiran Kumar Modukuri <[email protected]>
commit d0eb06afe712b7b103b6361f40a9a0c638524669 upstream.
Alter the state-check assertion in fscache_enqueue_operation() to allow cancelled operations to be given processing time so they can be cleaned up.
Also fix a debugging statement that was requiring such operations to have an object assigned.
--- fs/fscache/operation.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/fscache/operation.c +4 -2
@@ -37,7 +37,8 @@ void fscache_enqueue_operation(struct fsASSERT (op->processor !=NULL );ASSERT (fscache_object_is_available (op->object)); ASSERTCMP(atomic_read(&op->usage), >, 0); - ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); +ASSERTIFCMP (op->state !=FSCACHE_OP_ST_IN_PROGRESS , + op->state, ==, FSCACHE_OP_ST_CANCELLED);fscache_stat (&fscache_n_op_enqueue);switch (op->flags &FSCACHE_OP_TYPE ) {
@@ -401,7 +402,8 @@ void fscache_put_operation(struct fscachstruct fscache_cache *cache;_enter ("{OBJ%x OP%x,%d}" , - op->object->debug_id, op->debug_id,atomic_read (&op->usage)); + op->object ? op->object->debug_id :0 , + op->debug_id,atomic_read (&op->usage)); ASSERTCMP(atomic_read(&op->usage), >, 0);
PATCH 289/366 cachefiles: Fix refcounting bug in backing-file read monitoring
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kiran Kumar Modukuri <[email protected]>
commit 934140ab028713a61de8bca58c05332416d037d1 upstream.
cachefiles_read_waiter() has the right to access a 'monitor' object by virtue of being called under the waitqueue lock for one of the pages in its purview. However, it has no ref on that monitor object or on the associated operation.
What it is allowed to do is to move the monitor object to the operation's to_do list, but once it drops the work_lock, it's actually no longer permitted to access that object. However, it is trying to enqueue the retrieval operation for processing - but it can only do this via a pointer in the monitor object, something it shouldn't be doing.
If it doesn't enqueue the operation, the operation may not get processed. If the order is flipped so that the enqueue is first, then it's possible for the work processor to look at the to_do list before the monitor is enqueued upon it.
Fix this by getting a ref on the operation so that we can trust that it will still be there once we've added the monitor to the to_do list and dropped the work_lock. The op can then be enqueued after the lock is dropped.
The bug can manifest in one of a couple of ways. The first manifestation looks like:
FS-Cache:
FS-Cache: Assertion failed
FS-Cache: 6 == 5 is false
------------[ cut here ]------------ kernel BUG at fs/fscache/operation.c:494! RIP: 0010:fscache_put_operation+0x1e3/0x1f0 ... fscache_op_work_func+0x26/0x50 process_one_work+0x131/0x290 worker_thread+0x45/0x360 kthread+0xf8/0x130 ? create_worker+0x190/0x190 ? kthread_cancel_work_sync+0x10/0x10 ret_from_fork+0x1f/0x30
This is due to the operation being in the DEAD state (6) rather than INITIALISED, COMPLETE or CANCELLED (5) because it's already passed through fscache_put_operation().
The bug can also manifest like the following:
kernel BUG at fs/fscache/operation.c:69!
...
[exception RIP: fscache_enqueue_operation+246]
...
#7 [ffff883fff083c10] fscache_enqueue_operation at ffffffffa0b793c6 #8 [ffff883fff083c28] cachefiles_read_waiter at ffffffffa0b15a48 #9 [ffff883fff083c48] __wake_up_common at ffffffff810af028
I'm not entirely certain as to which is line 69 in Lei's kernel, so I'm not entirely clear which assertion failed.
--- fs/cachefiles/rdwr.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
fs/cachefiles/rdwr.c +12 -5
@@ -27,6 +27,7 @@ static int cachefiles_read_waiter(wait_qstruct cachefiles_one_read *monitor = container_of(wait, struct cachefiles_one_read, monitor);struct cachefiles_object *object; +struct fscache_retrieval *op = monitor->op;struct wait_bit_key *key = _key;struct page *page = wait->private;
@@ -51,16 +52,22 @@ static int cachefiles_read_waiter(wait_qlist_del (&wait->task_list);/* move onto the action list and queue for FS-Cache thread pool */ -ASSERT (monitor->op); +ASSERT (op); - object =container_of (monitor->op->op.object, - struct cachefiles_object, fscache); +/* We need to temporarily bump the usage count as we don't own a ref +* here otherwise cachefiles_read_copier() may free the op between the +* monitor being enqueued on the op->to_do list and the op getting +* enqueued on the work queue. +*/ +fscache_get_retrieval (op); + object = container_of(op->op.object, struct cachefiles_object, fscache);spin_lock (&object->work_lock); -list_add_tail (&monitor->op_link, &monitor->op->to_do); +list_add_tail (&monitor->op_link, &op->to_do);spin_unlock (&object->work_lock); -fscache_enqueue_retrieval (monitor->op); +fscache_enqueue_retrieval (op); +fscache_put_retrieval (op);return 0 ; }
PATCH 290/366 fscache: Fix reference overput in fscache_attach_object() error handling
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kiran Kumar Modukuri <[email protected]>
commit f29507ce66701084c39aeb1b0ae71690cbff3554 upstream.
When a cookie is allocated that causes fscache_object structs to be allocated, those objects are initialised with the cookie pointer, but aren't blessed with a ref on that cookie unless the attachment is successfully completed in fscache_attach_object().
If attachment fails because the parent object was dying or there was a collision, fscache_attach_object() returns without incrementing the cookie counter - but upon failure of this function, the object is released which then puts the cookie, whether or not a ref was taken on the cookie.
Fix this by taking a ref on the cookie when it is assigned in fscache_object_init(), even when we're creating a root object.
Analysis from Kiran Kumar:
This bug has been seen in 4.4.0-124-generic #148-Ubuntu kernel
fscache cookie ref count updated incorrectly during fscache object allocation resulting in following Oops.
kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/internal.h:321! kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!
[Cause]
Two threads are trying to do operate on a cookie and two objects.
(1) One thread tries to unmount the filesystem and in process goes over a
huge list of objects marking them dead and deleting the objects.
cookie->usage is also decremented in following path:
nfs_fscache_release_super_cookie
-> __fscache_relinquish_cookie
->__fscache_cookie_put
->BUG_ON(atomic_read(&cookie->usage) <= 0);(2) A second thread tries to lookup an object for reading data in following
path:
fscache_alloc_object
1) cachefiles_alloc_object
-> fscache_object_init
-> assign cookie, but usage not bumped.
2) fscache_attach_object -> fails in cant_attach_object because the
cookie's backing object or cookie's->parent object are going away
3) fscache_put_object
-> cachefiles_put_object
->fscache_object_destroy
->fscache_cookie_put
->BUG_ON(atomic_read(&cookie->usage) <= 0);[NOTE from dhowells] It's unclear as to the circumstances in which (2) can take place, given that thread (1) is in nfs_kill_super(), however a conflicting NFS mount with slightly different parameters that creates a different superblock would do it. A backtrace from Kiran seems to show that this is a possibility:
kernel BUG at/build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!
...
RIP: __fscache_cookie_put+0x3a/0x40 [fscache]
Call Trace:
__fscache_relinquish_cookie+0x87/0x120 [fscache]
nfs_fscache_release_super_cookie+0x2d/0xb0 [nfs]
nfs_kill_super+0x29/0x40 [nfs]
deactivate_locked_super+0x48/0x80
deactivate_super+0x5c/0x60
cleanup_mnt+0x3f/0x90
__cleanup_mnt+0x12/0x20
task_work_run+0x86/0xb0
exit_to_usermode_loop+0xc2/0xd0
syscall_return_slowpath+0x4e/0x60
int_ret_from_sys_call+0x25/0x9f[Fix] Bump up the cookie usage in fscache_object_init, when it is first being assigned a cookie atomically such that the cookie is added and bumped up if its refcount is not zero. Remove the assignment in fscache_attach_object().
[Testcase]
I have run ~100 hours of NFS stress tests and not seen this bug recur.
[Regression Potential]
- Limited to fscache/cachefiles.
[bwh: Backported to 3.16: Keep using atomic_inc() instead of
fscache_cookie_get()]
--- fs/cachefiles/bind.c | 3 ++- fs/fscache/cache.c | 2 +- fs/fscache/cookie.c | 7 ++++--- fs/fscache/object.c | 1 + 4 files changed, 8 insertions(+), 5 deletions(-)
fs/cachefiles/bind.c +2 -1
@@ -218,7 +218,8 @@ static int cachefiles_daemon_add_cache(s"%s" , fsdef->dentry->d_sb->s_id); -fscache_object_init (&fsdef->fscache,NULL , &cache->cache); +fscache_object_init (&fsdef->fscache, &fscache_fsdef_index, + &cache->cache); ret =fscache_add_cache (&cache->cache, &fsdef->fscache, cache->tag);if (ret <0 )
fs/fscache/cache.c +1 -1
@@ -220,6 +220,7 @@ int fscache_add_cache(struct fscache_cac {struct fscache_cache_tag *tag; + ASSERTCMP(ifsdef->cookie, ==, &fscache_fsdef_index);BUG_ON (!cache->ops);BUG_ON (!ifsdef);
@@ -248,7 +249,6 @@ int fscache_add_cache(struct fscache_cacif (!cache->kobj) goto error; - ifsdef->cookie = &fscache_fsdef_index; ifsdef->cache = cache; cache->fsdef = ifsdef;
fs/fscache/cookie.c +4 -3
@@ -302,6 +302,7 @@ static int fscache_alloc_object(struct f goto error; } + ASSERTCMP(object->cookie, ==, cookie);fscache_stat (&fscache_n_object_alloc); object->debug_id =atomic_inc_return (&fscache_object_debug_id);
@@ -356,6 +357,8 @@ static int fscache_attach_object(struct_enter ("{%s},{OBJ%x}" , cookie->def->name, object->debug_id); + ASSERTCMP(object->cookie, ==, cookie); +spin_lock (&cookie->lock);/* there may be multiple initial creations of this object, but we only
@@ -395,9 +398,7 @@ static int fscache_attach_object(structspin_unlock (&cache->object_list_lock); } -/* attach to the cookie */ - object->cookie = cookie; -atomic_inc (&cookie->usage); +/* Attach to the cookie. The object already has a ref on it. */ hlist_add_head (&object->cookie_link, &cookie->backing_objects);fscache_objlist_add (object);
fs/fscache/object.c +1 -0
@@ -313,6 +313,7 @@ void fscache_object_init(struct fscache_ object->store_limit_l =0 ; object->cache = cache; object->cookie = cookie; +atomic_inc (&cookie->usage); object->parent =NULL ;#ifdef CONFIG_FSCACHE_OBJECT_LIST RB_CLEAR_NODE (&object->objlist_link);
PATCH 291/366 cachefiles: Fix missing clear of the CACHEFILES_OBJECT_ACTIVE flag
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kiran Kumar Modukuri <[email protected]>
commit 5ce83d4bb7d8e11e8c1c687d09f4b5ae67ef3ce3 upstream.
In cachefiles_mark_object_active(), the new object is marked active and then we try to add it to the active object tree. If a conflicting object is already present, we want to wait for that to go away. After the wait, we go round again and try to re-mark the object as being active - but it's already marked active from the first time we went through and a BUG is issued.
Fix this by clearing the CACHEFILES_OBJECT_ACTIVE flag before we try again.
Analysis from Kiran Kumar Modukuri:
[Impact]
Oops during heavy NFS + FSCache + Cachefiles
CacheFiles: Error: Overlong wait for old active object to go away.
BUG: unable to handle kernel NULL pointer dereference at 0000000000000002
CacheFiles: Error: Object already active kernel BUG at fs/cachefiles/namei.c:163!
[Cause]
In a heavily loaded system with big files being read and truncated, an fscache object for a cookie is being dropped and a new object being looked. The new object being looked for has to wait for the old object to go away before the new object is moved to active state.
[Fix]
Clear the flag 'CACHEFILES_OBJECT_ACTIVE' for the new object when retrying the object lookup.
[Testcase]
Have run ~100 hours of NFS stress tests and have not seen this bug recur.
[Regression Potential]
- Limited to fscache/cachefiles.
--- fs/cachefiles/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/cachefiles/namei.c +1 -1
@@ -189,6 +189,7 @@ try_again:/* an old object from a previous incarnation is hogging the slot - we * need to wait for it to be destroyed */ wait_for_old_object: +clear_bit (CACHEFILES_OBJECT_ACTIVE , &object->flags);if (fscache_object_is_live (&object->fscache)) {pr_err ("\n" );pr_err ("Error: Unexpected object collision\n" );
@@ -250,7 +251,6 @@ wait_for_old_object: goto try_again; requeue: -clear_bit (CACHEFILES_OBJECT_ACTIVE , &object->flags); cache->cache.ops->put_object (&xobject->fscache);_leave (" = -ETIMEDOUT" );return -ETIMEDOUT ;
PATCH 292/366 cachefiles: Wait rather than BUG'ing on "Unexpected object collision"
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kiran Kumar Modukuri <[email protected]>
commit c2412ac45a8f8f1cd582723c1a139608694d410d upstream.
If we meet a conflicting object that is marked FSCACHE_OBJECT_IS_LIVE in the active object tree, we have been emitting a BUG after logging information about it and the new object.
Instead, we should wait for the CACHEFILES_OBJECT_ACTIVE flag to be cleared on the old object (or return an error). The ACTIVE flag should be cleared after it has been removed from the active object tree. A timeout of 60s is used in the wait, so we shouldn't be able to get stuck there.
--- fs/cachefiles/namei.c | 1 - 1 file changed, 1 deletion(-)
fs/cachefiles/namei.c +0 -1
@@ -194,7 +194,6 @@ wait_for_old_object:pr_err ("\n" );pr_err ("Error: Unexpected object collision\n" );cachefiles_printk_object (object, xobject); -BUG (); }atomic_inc (&xobject->usage);write_unlock (&cache->active_lock);
PATCH 293/366 tracing: Fix double free of event_trigger_data
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <[email protected]>
commit 1863c387259b629e4ebfb255495f67cd06aa229b upstream.
Running the following:
# cd /sys/kernel/debug/tracing # echo 500000 > buffer_size_kb [ Or some other number that takes up most of memory ] # echo snapshot > events/sched/sched_switch/trigger
Triggers the following bug:
------------[ cut here ]------------ kernel BUG at mm/slub.c:296! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC PTI CPU: 6 PID: 6878 Comm: bash Not tainted 4.18.0-rc6-test+ #1066 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016 RIP: 0010:kfree+0x16c/0x180 Code: 05 41 0f b6 72 51 5b 5d 41 5c 4c 89 d7 e9 ac b3 f8 ff 48 89 d9 48 89 da 41 b8 01 00 00 00 5b 5d 41 5c 4c 89 d6 e9 f4 f3 ff ff <0f> 0b 0f 0b 48 8b 3d d9 d8 f9 00 e9 c1 fe ff ff 0f 1f 40 00 0f 1f RSP: 0018:ffffb654436d3d88 EFLAGS: 00010246 RAX: ffff91a9d50f3d80 RBX: ffff91a9d50f3d80 RCX: ffff91a9d50f3d80 RDX: 00000000000006a4 RSI: ffff91a9de5a60e0 RDI: ffff91a9d9803500 RBP: ffffffff8d267c80 R08: 00000000000260e0 R09: ffffffff8c1a56be R10: fffff0d404543cc0 R11: 0000000000000389 R12: ffffffff8c1a56be R13: ffff91a9d9930e18 R14: ffff91a98c0c2890 R15: ffffffff8d267d00 FS: 00007f363ea64700(0000) GS:ffff91a9de580000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055c1cacc8e10 CR3: 00000000d9b46003 CR4: 00000000001606e0 Call Trace: event_trigger_callback+0xee/0x1d0 event_trigger_write+0xfc/0x1a0 __vfs_write+0x33/0x190 ? handle_mm_fault+0x115/0x230 ? _cond_resched+0x16/0x40 vfs_write+0xb0/0x190 ksys_write+0x52/0xc0 do_syscall_64+0x5a/0x160 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f363e16ab50 Code: 73 01 c3 48 8b 0d 38 83 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d 79 db 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 1e e3 01 00 48 89 04 24 RSP: 002b:00007fff9a4c6378 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000009 RCX: 00007f363e16ab50 RDX: 0000000000000009 RSI: 000055c1cacc8e10 RDI: 0000000000000001 RBP: 000055c1cacc8e10 R08: 00007f363e435740 R09: 00007f363ea64700 R10: 0000000000000073 R11: 0000000000000246 R12: 0000000000000009 R13: 0000000000000001 R14: 00007f363e4345e0 R15: 00007f363e4303c0 Modules linked in: ip6table_filter ip6_tables snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq snd_seq_device i915 snd_pcm snd_timer i2c_i801 snd soundcore i2c_algo_bit drm_kms_helper 86_pkg_temp_thermal video kvm_intel kvm irqbypass wmi e1000e ---[ end trace d301afa879ddfa25 ]---
The cause is because the register_snapshot_trigger() call failed to allocate the snapshot buffer, and then called unregister_trigger() which freed the data that was passed to it. Then on return to the function that called register_snapshot_trigger(), as it sees it failed to register, it frees the trigger_data again and causes a double free.
By calling event_trigger_init() on the trigger_data (which only ups the reference counter for it), and then event_trigger_free() afterward, the trigger_data would not get freed by the registering trigger function as it would only up and lower the ref count for it. If the register trigger function fails, then the event_trigger_free() called after it will free the trigger data normally.
--- kernel/trace/trace_events_trigger.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
kernel/trace/trace_events_trigger.c +8 -4
@@ -663,6 +663,8 @@ event_trigger_callback(struct event_comm goto out_free; out_reg: +/* Up the trigger_data count to make sure reg doesn't free it on failure */ +event_trigger_init (trigger_ops, trigger_data); ret = cmd_ops->reg (glob, trigger_ops, trigger_data, file);/* * The above returns on success the # of functions enabled,
@@ -670,11 +672,13 @@ event_trigger_callback(struct event_comm* Consider no functions a failure too. */ if (!ret) { + cmd_ops->unreg (glob, trigger_ops, trigger_data, file); ret = -ENOENT ; - goto out_free; - }else if (ret <0 ) - goto out_free; - ret =0 ; + }else if (ret >0 ) + ret =0 ; + +/* Down the counter of trigger_data or free it if not used anymore */ +event_trigger_free (trigger_ops, trigger_data); out:return ret;
PATCH 294/366 ring_buffer: tracing: Inherit the tracing setting to next ring buffer
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu <[email protected]>
commit 73c8d8945505acdcbae137c2e00a1232e0be709f upstream.
Maintain the tracing on/off setting of the ring_buffer when switching to the trace buffer snapshot.
Taking a snapshot is done by swapping the backup ring buffer (max_tr_buffer). But since the tracing on/off setting is defined by the ring buffer, when swapping it, the tracing on/off setting can also be changed. This causes a strange result like below:
/sys/kernel/debug/tracing # cat tracing_on
1
/sys/kernel/debug/tracing # echo 0 > tracing_on
/sys/kernel/debug/tracing # cat tracing_on
0
/sys/kernel/debug/tracing # echo 1 > snapshot
/sys/kernel/debug/tracing # cat tracing_on
1
/sys/kernel/debug/tracing # echo 1 > snapshot
/sys/kernel/debug/tracing # cat tracing_on
0
We don't touch tracing_on, but snapshot changes tracing_on setting each time. This is an anomaly, because user doesn't know that each "ring_buffer" stores its own tracing-enable state and the snapshot is done by swapping ring buffers.
--- include/linux/ring_buffer.h | 1 + kernel/trace/ring_buffer.c | 16 ++++++++++++++++ kernel/trace/trace.c | 6 ++++++ 3 files changed, 23 insertions(+)
include/linux/ring_buffer.h +1 -0
@@ -162,6 +162,7 @@ void ring_buffer_record_enable(struct rivoid ring_buffer_record_off (struct ring_buffer *buffer);void ring_buffer_record_on (struct ring_buffer *buffer);int ring_buffer_record_is_on (struct ring_buffer *buffer); +int ring_buffer_record_is_set_on (struct ring_buffer *buffer);void ring_buffer_record_disable_cpu (struct ring_buffer *buffer,int cpu);void ring_buffer_record_enable_cpu (struct ring_buffer *buffer,int cpu);
kernel/trace/ring_buffer.c +16 -0
@@ -3165,6 +3165,22 @@ int ring_buffer_record_is_on(struct ring }/** +* ring_buffer_record_is_set_on - return true if the ring buffer is set writable +* @buffer: The ring buffer to see if write is set enabled +* +* Returns true if the ring buffer is set writable by ring_buffer_record_on(). +* Note that this does NOT mean it is in a writable state. +* +* It may return true when the ring buffer has been disabled by +* ring_buffer_record_disable(), as that is a temporary disabling of +* the ring buffer. +*/ +int ring_buffer_record_is_set_on (struct ring_buffer *buffer) +{ +return !(atomic_read (&buffer->record_disabled) &RB_BUFFER_OFF ); +} + +/** * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer * @buffer: The ring buffer to stop writes to. * @cpu: The CPU buffer to stop
kernel/trace/trace.c +6 -0
@@ -1046,6 +1046,12 @@ update_max_tr(struct trace_array *tr, starch_spin_lock (&tr->max_lock); +/* Inherit the recordable setting from trace_buffer */ +if (ring_buffer_record_is_set_on (tr->trace_buffer.buffer)) +ring_buffer_record_on (tr->max_buffer.buffer); +else +ring_buffer_record_off (tr->max_buffer.buffer); + buf = tr->trace_buffer.buffer; tr->trace_buffer.buffer = tr->max_buffer.buffer; tr->max_buffer.buffer = buf;
PATCH 295/366 tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Artem Savkov <[email protected]>
commit 57ea2a34adf40f3a6e88409aafcf803b8945619a upstream.
If enable_trace_kprobe fails to enable the probe in enable_k(ret)probe it returns an error, but does not unset the tp flags it set previously. This results in a probe being considered enabled and failures like being unable to remove the probe through kprobe_events file since probes_open() expects every probe to be disabled.
--- kernel/trace/trace_kprobe.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
kernel/trace/trace_kprobe.c +11 -2
@@ -361,11 +361,10 @@ static struct trace_kprobe *find_trace_kstatic int enable_trace_kprobe (struct trace_kprobe *tk,struct ftrace_event_file *file) { +struct event_file_link *link;int ret =0 ;if (file) { -struct event_file_link *link; - link =kmalloc (sizeof (*link),GFP_KERNEL );if (!link) { ret = -ENOMEM ;
@@ -385,6 +384,16 @@ enable_trace_kprobe(struct trace_kprobeelse ret =enable_kprobe (&tk->rp.kp); } + +if (ret) { +if (file) { +list_del_rcu (&link->list); +kfree (link); + tk->tp.flags &= ~TP_FLAG_TRACE ; + }else { + tk->tp.flags &= ~TP_FLAG_PROFILE ; + } + } out:return ret; }
PATCH 296/366 tracing: Fix possible double free in event_enable_trigger_func()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <[email protected]>
commit 15cc78644d0075e76d59476a4467e7143860f660 upstream.
There was a case that triggered a double free in event_trigger_callback() due to the called reg() function freeing the trigger_data and then it getting freed again by the error return by the caller. The solution there was to up the trigger_data ref count.
Code inspection found that event_enable_trigger_func() has the same issue, but is not as easy to trigger (requires harder to trigger failures). It needs to be solved slightly different as it needs more to clean up when the reg() function fails.
--- kernel/trace/trace_events_trigger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/trace/trace_events_trigger.c +5 -1
@@ -1231,6 +1231,9 @@ event_enable_trigger_func(struct event_c goto out; } +/* Up the trigger_data count to make sure nothing frees it on failure */ +event_trigger_init (trigger_ops, trigger_data); +if (trigger) { number =strsep (&trigger,":" );
@@ -1281,6 +1284,7 @@ event_enable_trigger_func(struct event_c goto out_disable;/* Just return zero, not the number of enabled functions */ ret =0 ; +event_trigger_free (trigger_ops, trigger_data); out:return ret;
@@ -1291,7 +1295,7 @@ event_enable_trigger_func(struct event_c out_free:if (cmd_ops->set_filter) cmd_ops->set_filter (NULL , trigger_data,NULL ); -kfree (trigger_data); +event_trigger_free (trigger_ops, trigger_data);kfree (enable_data); goto out; }
PATCH 297/366 tracing: Quiet gcc warning about maybe unused link variable
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <[email protected]>
commit 2519c1bbe38d7acacc9aacba303ca6f97482ed53 upstream.
Commit 57ea2a34adf4 ("tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure") added an if statement that depends on another if statement that gcc doesn't see will initialize the "link" variable and gives the warning:
"warning: 'link' may be used uninitialized in this function"
It is really a false positive, but to quiet the warning, and also to make sure that it never actually is used uninitialized, initialize the "link" variable to NULL and add an if (!WARN_ON_ONCE(!link)) where the compiler thinks it could be used uninitialized.
--- kernel/trace/trace_kprobe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/trace/trace_kprobe.c +4 -2
@@ -361,7 +361,7 @@ static struct trace_kprobe *find_trace_kstatic int enable_trace_kprobe (struct trace_kprobe *tk,struct ftrace_event_file *file) { -struct event_file_link *link; +struct event_file_link *link =NULL ;int ret =0 ;if (file) {
@@ -387,7 +387,9 @@ enable_trace_kprobe(struct trace_kprobeif (ret) {if (file) { -list_del_rcu (&link->list); +/* Notice the if is true on not WARN() */ +if (!WARN_ON_ONCE (!link)) +list_del_rcu (&link->list);kfree (link); tk->tp.flags &= ~TP_FLAG_TRACE ; }else {
PATCH 298/366 kthread, tracing: Don't expose half-written comm when creating kthreads
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Snild Dolkow <[email protected]>
commit 3e536e222f2930534c252c1cc7ae799c725c5ff9 upstream.
There is a window for racing when printing directly to task->comm, allowing other threads to see a non-terminated string. The vsnprintf function fills the buffer, counts the truncated chars, then finally writes the \0 at the end.
creator other
vsnprintf:
fill (not terminated)
count the rest trace_sched_waking(p):
... memcpy(comm, p->comm, TASK_COMM_LEN)
write \0
The consequences depend on how 'other' uses the string. In our case, it was copied into the tracing system's saved cmdlines, a buffer of adjacent TASK_COMM_LEN-byte buffers (note the 'n' where 0 should be):
crash-arm64> x/1024s savedcmd->saved_cmdlines | grep 'evenk' 0xffffffd5b3818640: "irq/497-pwr_evenkworker/u16:12"
...and a strcpy out of there would cause stack corruption:
[224761.522292] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff9bf9783c78
crash-arm64> kbt | grep 'comm\|trace_print_context' #6 0xffffff9bf9783c78 in trace_print_context+0x18c(+396) comm (char [16]) = "irq/497-pwr_even" crash-arm64> rd 0xffffffd4d0e17d14 8 ffffffd4d0e17d14: 2f71726900000000 5f7277702d373934 ....irq/497-pwr_ ffffffd4d0e17d24: 726f776b6e657665 3a3631752f72656b evenkworker/u16: ffffffd4d0e17d34: f9780248ff003231 cede60e0ffffff9b 12..H.x......`.. ffffffd4d0e17d44: cede60c8ffffffd4 00000fffffffffd4 .....`..........
The workaround in e09e28671 (use strlcpy in __trace_find_cmdline) was likely needed because of this same bug.
Solved by vsnprintf:ing to a local buffer, then using set_task_comm(). This way, there won't be a window where comm is not terminated.
--- kernel/kthread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/kthread.c +7 -1
@@ -309,10 +309,16 @@ struct task_struct *kthread_create_on_noif (!IS_ERR (task)) {static const struct sched_param param = { .sched_priority =0 };va_list args; +char name[TASK_COMM_LEN ]; +/* +* task is already visible to other tasks, so updating +* COMM must be protected. +*/ va_start (args, namefmt); -vsnprintf (task->comm,sizeof (task->comm), namefmt, args); +vsnprintf (name,sizeof (name), namefmt, args);va_end (args); +set_task_comm (task, name);/* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties.
Re: [PATCH 3.16 298/366] kthread, tracing: Don't expose half-written comm when creating kthreads
Quoted 71 lines · Ben Hutchings
3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Snild Dolkow <[email protected]>
commit
3e536e222f2930534c252c1cc7ae799c725c5ff9upstream.There is a window for racing when printing directly to
task->comm, allowing other threads to see a non-terminated string. The vsnprintf function fills the buffer, counts the truncated chars, then finally writes the \0 at the end.creator other
vsnprintf:
fill (not terminated)
count the resttrace_sched_waking(p):
...memcpy(comm, p->comm, TASK_COMM_LEN)
write \0The consequences depend on how 'other' uses the string. In our case, it was copied into the tracing system's saved cmdlines, a buffer of adjacent TASK_COMM_LEN-byte buffers (note the 'n' where 0 should be):
crash-arm64> x/1024s savedcmd->saved_cmdlines | grep 'evenk' 0xffffffd5b3818640: "irq/497-pwr_evenkworker/u16:12"...and a strcpy out of there would cause stack corruption:
[224761.522292] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff9bf9783c78crash-arm64> kbt | grep 'comm\|trace_print_context' #6 0xffffff9bf9783c78 in trace_print_context+0x18c(+396) comm (char [16]) = "irq/497-pwr_even" crash-arm64> rd 0xffffffd4d0e17d14 8 ffffffd4d0e17d14: 2f71726900000000 5f7277702d373934 ....irq/497-pwr_ ffffffd4d0e17d24: 726f776b6e657665 3a3631752f72656b evenkworker/u16: ffffffd4d0e17d34: f9780248ff003231 cede60e0ffffff9b 12..H.x......`.. ffffffd4d0e17d44: cede60c8ffffffd4 00000fffffffffd4 .....`..........The workaround in
e09e28671(use strlcpy in__trace_find_cmdline) was likely needed because of this same bug.Solved by vsnprintf:ing to a local buffer, then using
set_task_comm(). This way, there won't be a window where comm is not terminated.Fixes bc0c38d139ec7 ("ftrace: latency tracer infrastructure")Reviewed-by Steven Rostedt (VMware) <[email protected]>Signed-off-by Snild Dolkow <[email protected]>Signed-off-by Steven Rostedt (VMware) <[email protected]>[bwh: Backported to 3.16: adjust context]Signed-off-by Ben Hutchings <[email protected]>--- kernel/kthread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)kernel/kthread.c +3
-0@@ -309,10 +309,16 @@ struct task_struct *kthread_create_on_noif (!IS_ERR (task)) {static const struct sched_param param = { .sched_priority =0 };va_list args; +char name[TASK_COMM_LEN ]; +/* +* task is already visible to other tasks, so updating
kernel/kthread.c struct task_struct *kthread_create_on_no · line 324
Quoted 10 lines
kernel/kthread.c +4
-1+* COMM must be protected. +*/ va_start (args, namefmt); -vsnprintf (task->comm,sizeof (task->comm), namefmt, args); +vsnprintf (name,sizeof (name), namefmt, args);va_end (args); +set_task_comm (task, name);/* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties.
Re: [PATCH 3.16 298/366] kthread, tracing: Don't expose half-written comm when creating kthreads
Quoted 8 lines · Snild Dolkow
Quoted 7 lines · Ben Hutchings
3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Snild Dolkow <[email protected]>
commit
3e536e222f2930534c252c1cc7ae799c725c5ff9upstream.
[...]
Quoted 1 line
Reviewed-by Snild Dolkow <[email protected]>
Thanks!
Ben.
Signature · 3 lines
Ben Hutchings Time is nature's way of making sure that everything doesn't happen at once.
PATCH 299/366 ipv4: remove BUG_ON() from fib_compute_spec_dst
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
commit 9fc12023d6f51551d6ca9ed7e02ecc19d79caf17 upstream.
Remove BUG_ON() from fib_compute_spec_dst routine and check in_dev pointer during flowi4 data structure initialization. fib_compute_spec_dst routine can be run concurrently with device removal where ip_ptr net_device pointer is set to NULL. This can happen if userspace enables pkt info on UDP rx socket and the device is removed while traffic is flowing
---
net/ipv4/fib_frontend.c +3 -2
@@ -209,19 +209,20 @@ __be32 fib_compute_spec_dst(struct sk_bureturn ip_hdr (skb)->daddr; in_dev =__in_dev_get_rcu (dev); -BUG_ON (!in_dev); net =dev_net (dev); scope =RT_SCOPE_UNIVERSE ;if (!ipv4_is_zeronet (ip_hdr (skb)->saddr)) { +bool vmark = in_dev &&IN_DEV_SRC_VMARK (in_dev); + fl4.flowi4_oif =0 ; fl4.flowi4_iif =LOOPBACK_IFINDEX ; fl4.daddr =ip_hdr (skb)->saddr; fl4.saddr =0 ; fl4.flowi4_tos =RT_TOS (ip_hdr (skb)->tos); fl4.flowi4_scope = scope; - fl4.flowi4_mark =IN_DEV_SRC_VMARK (in_dev) ? skb->mark :0 ; + fl4.flowi4_mark = vmark ? skb->mark :0 ;if (!fib_lookup (net, &fl4, &res))return FIB_RES_PREFSRC (net, res); }else {
PATCH 300/366 net: socket: fix potential spectre v1 gadget in socketcall
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jeremy Cline <[email protected]>
commit c8e8cd579bb4265651df8223730105341e61a2d1 upstream.
'call' is a user-controlled value, so sanitize the array index after the bounds check to avoid speculating past the bounds of the 'nargs' array.
Found with the help of Smatch:
net/socket.c:2508 __do_sys_socketcall() warn: potential spectre issue 'nargs' [r] (local cap)
--- net/socket.c | 2 ++ 1 file changed, 2 insertions(+)
net/socket.c +2 -0
@@ -89,6 +89,7 @@#include <linux/magic.h> #include <linux/slab.h> #include <linux/xattr.h> +#include <linux/nospec.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -2494,6 +2495,7 @@ SYSCALL_DEFINE2(socketcall, int, call, uif (call <1 || call >SYS_SENDMMSG )return -EINVAL ; + call =array_index_nospec (call,SYS_SENDMMSG +1 ); len = nargs[call];if (len >sizeof (a))
PATCH 301/366 squashfs: be more careful about metadata corruption
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Linus Torvalds <[email protected]>
commit 01cfb7937a9af2abb1136c7e89fbf3fd92952956 upstream.
Anatoly Trosinenko reports that a corrupted squashfs image can cause a kernel oops. It turns out that squashfs can end up being confused about negative fragment lengths.
The regular squashfs_read_data() does check for negative lengths, but squashfs_read_metadata() did not, and the fragment size code just blindly trusted the on-disk value. Fix both the fragment parsing and the metadata reading code.
--- fs/squashfs/cache.c | 3 +++ fs/squashfs/file.c | 8 ++++++-- fs/squashfs/fragment.c | 4 +--- fs/squashfs/squashfs_fs.h | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-)
fs/squashfs/cache.c +3 -0
@@ -350,6 +350,9 @@ int squashfs_read_metadata(struct super_TRACE ("Entered squashfs_read_metadata [%llx:%x]\n" , *block, *offset); +if (unlikely (length <0 )) +return -EIO ; +while (length) { entry =squashfs_cache_get (sb, msblk->block_cache, *block,0 );if (entry->error) {
fs/squashfs/file.c +6 -2
@@ -194,7 +194,11 @@ static long long read_indexes(struct sup }for (i =0 ; i < blocks; i++) { -int size =le32_to_cpu (blist[i]); +int size =squashfs_block_size (blist[i]); +if (size <0 ) { + err = size; + goto failure; + } block +=SQUASHFS_COMPRESSED_SIZE_BLOCK (size); } n -= blocks;
@@ -367,7 +371,7 @@ static int read_blocklist(struct inode * sizeof(size));if (res <0 )return res; -return le32_to_cpu (size); +return squashfs_block_size (size); }/* Copy data into page cache */
fs/squashfs/fragment.c +1 -3
@@ -61,9 +61,7 @@ int squashfs_frag_lookup(struct super_blreturn size; *fragment_block =le64_to_cpu (fragment_entry.start_block); - size =le32_to_cpu (fragment_entry.size); - -return size; +return squashfs_block_size (fragment_entry.size); }
fs/squashfs/squashfs_fs.h +6 -0
@@ -129,6 +129,12 @@#define SQUASHFS_COMPRESSED_BLOCK (B ) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +static inline int squashfs_block_size (__le32 raw) +{ +u32 size =le32_to_cpu (raw); +return (size >>25 ) ? -EIO : size; +} +/* * Inode number ops. Inodes consist of a compressed block number, and an * uncompressed offset within that block
PATCH 302/366 can: ems_usb: Fix memory leak on ems_usb_disconnect()
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Anton Vasilyev <[email protected]>
commit 72c05f32f4a5055c9c8fe889bb6903ec959c0aad upstream.
ems_usb_probe() allocates memory for dev->tx_msg_buffer, but there is no its deallocation in ems_usb_disconnect().
Found by Linux Driver Verification project (linuxtesting.org).
--- drivers/net/can/usb/ems_usb.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/can/usb/ems_usb.c +1 -0
@@ -1084,6 +1084,7 @@ static void ems_usb_disconnect(struct ususb_free_urb (dev->intr_urb);kfree (dev->intr_in_buffer); +kfree (dev->tx_msg_buffer); } }
PATCH 303/366 virtio_balloon: fix another race between migration and ballooning
In reply to Ben Hutchings3.16.61-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiang Biao <[email protected]>
commit 89da619bc18d79bca5304724c11d4ba3b67ce2c6 upstream.
Kernel panic when with high memory pressure, calltrace looks like,
PID: 21439 TASK: ffff881be3afedd0 CPU: 16 COMMAND: "java"
#0 [ffff881ec7ed7630] machine_kexec at ffffffff81059beb #1 [ffff881ec7ed7690] __crash_kexec at ffffffff81105942 #2 [ffff881ec7ed7760] crash_kexec at ffffffff81105a30 #3 [ffff881ec7ed7778] oops_end at ffffffff816902c8
#4 [ffff881ec7ed77a0] no_context at ffffffff8167ff46 #5 [ffff881ec7ed77f0] __bad_area_nosemaphore at ffffffff8167ffdc #6 [ffff881ec7ed7838] __node_set at ffffffff81680300 #7 [ffff881ec7ed7860] __do_page_fault at ffffffff8169320f #8 [ffff881ec7ed78c0] do_page_fault at ffffffff816932b5 #9 [ffff881ec7ed78f0] page_fault at ffffffff8168f4c8
[exception RIP: _raw_spin_lock_irqsave+47]
RIP: ffffffff8168edef RSP: ffff881ec7ed79a8 RFLAGS: 00010046
RAX: 0000000000000246 RBX: ffffea0019740d00 RCX: ffff881ec7ed7fd8
RDX: 0000000000020000 RSI: 0000000000000016 RDI: 0000000000000008
RBP: ffff881ec7ed79a8 R8: 0000000000000246 R9: 000000000001a098
R10: ffff88107ffda000 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000008 R14: ffff881ec7ed7a80 R15: ffff881be3afedd0
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018It happens in the pagefault and results in double pagefault during compacting pages when memory allocation fails.
Analysed the vmcore, the page leads to second pagefault is corrupted with _mapcount=-256, but private=0.
It's caused by the race between migration and ballooning, and lock missing in virtballoon_migratepage() of virtio_balloon driver. This patch fix the bug.
--- drivers/virtio/virtio_balloon.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/virtio/virtio_balloon.c +2 -0
@@ -413,7 +413,9 @@ static int virtballoon_migratepage(structell_host (vb, vb->inflate_vq);/* balloon's page migration 2nd step -- deflate "page" */ +spin_lock_irqsave (&vb_dev_info->pages_lock, flags);balloon_page_delete (page); +spin_unlock_irqrestore (&vb_dev_info->pages_lock, flags); vb->num_pfns =VIRTIO_BALLOON_PAGES_PER_PAGE ;set_page_pfns (vb->pfns, page);tell_host (vb, vb->deflate_vq);