I'm announcing the release of the 3.2.89 kernel. All users of the 3.2 kernel series should upgrade. The updated 3.2.y git tree can be found at: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-3.2.y and can be browsed at the normal kernel.org git web browser: https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git The diff from 3.2.88 is attached to this message. Ben. ------------ Makefile | 2 +- arch/mips/Makefile | 4 +- arch/mips/cavium-octeon/octeon-memcpy.S | 20 ++- arch/mips/configs/ip27_defconfig | 1 - arch/mips/include/asm/checksum.h | 2 + arch/powerpc/kernel/hw_breakpoint.c | 4 +- arch/x86/kernel/pci-calgary_64.c | 2 +- crypto/ahash.c | 203 +++++++++++++++++--------- drivers/bcma/main.c | 4 + drivers/bluetooth/ath3k.c | 2 + drivers/bluetooth/btusb.c | 1 + drivers/gpu/drm/radeon/radeon_bios.c | 68 +++++---- drivers/gpu/drm/ttm/ttm_bo.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 9 +- drivers/hv/hv.c | 2 +- drivers/infiniband/core/cma.c | 3 + drivers/infiniband/ulp/ipoib/ipoib_cm.c | 10 +- drivers/md/linear.c | 29 +++- drivers/md/linear.h | 1 + drivers/md/md.c | 7 + drivers/media/dvb/dm1105/Kconfig | 2 +- drivers/mmc/host/omap_hsmmc.c | 7 +- drivers/net/wireless/adm8211.c | 3 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 3 +- drivers/net/wireless/mwifiex/debugfs.c | 3 +- drivers/s390/cio/qdio_thinint.c | 8 +- drivers/scsi/aacraid/commsup.c | 36 +++-- drivers/scsi/aacraid/src.c | 21 ++- drivers/staging/rtl8712/rtl871x_recv.c | 7 +- drivers/tty/serial/8250_pci.c | 13 ++ drivers/tty/serial/msm_serial.c | 1 + drivers/usb/dwc3/gadget.c | 6 + drivers/usb/gadget/f_hid.c | 51 ++++--- drivers/usb/misc/iowarrior.c | 13 +- drivers/usb/serial/ark3116.c | 38 +++-- drivers/usb/serial/ch341.c | 26 ++-- drivers/usb/serial/cp210x.c | 2 + drivers/usb/serial/digi_acceleport.c | 52 ++++--- drivers/usb/serial/ftdi_sio.c | 39 +++-- drivers/usb/serial/io_edgeport.c | 48 ++++-- drivers/usb/serial/io_ti.c | 2 +- drivers/usb/serial/keyspan_pda.c | 19 ++- drivers/usb/serial/mct_u232.c | 6 +- drivers/usb/serial/mos7840.c | 4 +- drivers/usb/serial/omninet.c | 4 - drivers/usb/serial/ssu100.c | 31 +++- drivers/usb/serial/ti_usb_3410_5052.c | 12 +- fs/ext4/inode.c | 55 +++++-- fs/ext4/mballoc.c | 7 + fs/ext4/super.c | 6 +- fs/fuse/file.c | 1 + fs/jbd2/transaction.c | 4 +- fs/nfs/nfs4proc.c | 26 ++-- fs/nfs/nfs4xdr.c | 2 + fs/nfsd/nfs3xdr.c | 12 +- fs/nfsd/nfssvc.c | 36 +++++ fs/nfsd/nfsxdr.c | 10 +- fs/nfsd/vfs.c | 67 ++++++--- include/crypto/internal/hash.h | 10 ++ include/linux/lockd/lockd.h | 3 +- include/rdma/ib_sa.h | 6 +- kernel/trace/trace.c | 2 +- mm/mempolicy.c | 20 +-- net/dccp/ipv4.c | 6 + net/dccp/ipv6.c | 12 ++ net/ipv4/inet_connection_sock.c | 2 + net/ipv4/ping.c | 5 +- net/ipv6/af_inet6.c | 7 +- net/ipv6/ip6_output.c | 34 +++-- net/ipv6/tcp_ipv6.c | 2 + net/ipv6/udp.c | 6 +- net/ipx/af_ipx.c | 5 +- net/packet/af_packet.c | 22 +++ net/sched/act_api.c | 5 +- net/sctp/ipv6.c | 3 + net/xfrm/xfrm_user.c | 9 +- security/keys/encrypted-keys/encrypted.c | 2 +- security/keys/keyctl.c | 24 +-- security/keys/process_keys.c | 44 +++--- sound/core/seq/seq_fifo.c | 3 + sound/core/timer.c | 18 ++- sound/pci/ctxfi/cthw20k1.c | 19 +-- sound/pci/ctxfi/cthw20k2.c | 18 +-- tools/perf/Documentation/perf-script.txt | 4 +- 84 files changed, 916 insertions(+), 436 deletions(-) Alex Deucher (1): drm/radeon: handle vfct with multiple vbios images Amey Telawane (1): tracing: Use strlcpy() instead of strcpy() in __trace_find_cmdline() Andrey Konovalov (3): net/packet: fix overflow in check for priv area size net/packet: fix overflow in check for tp_frame_nr net/packet: fix overflow in check for tp_reserve Andrey Ryabinin (1): net/dccp: fix use after free in tw_timer_handler() Andy Whitcroft (2): xfrm_user: validate XFRM_MSG_NEWAE XFRMA_REPLAY_ESN_VAL replay_window xfrm_user: validate XFRM_MSG_NEWAE incoming ESN size harder Arnd Bergmann (3): staging: rtl: fix possible NULL pointer dereference MIPS: 'make -s' should be silent MIPS: ip27: Disable qlge driver in defconfig Ben Hutchings (1): Linux 3.2.89 Brian Norris (1): mwifiex: debugfs: Fix (sometimes) off-by-1 SSID print Chris Salls (1): mm/mempolicy.c: fix error handling in set_mempolicy and mbind. Christoph Hellwig (3): nfsd: update mtime on truncate nfsd: minor nfsd_setattr cleanup nfsd: special case truncates some more Craig Gallek (1): ipv6: Prevent overrun when parsing v6 header options Dan Carpenter (3): adm80211: return an error if adm8211_alloc_rings() fails KEYS: Fix an error code in request_master_key() ipx: call ipxitf_put() in ioctl error path David Howells (2): KEYS: Reinstate EPERM for a key type name beginning with a '.' KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings David S. Miller (1): ipv6: Check ip6_find_1stfragopt() return value properly. Dmitry Tunin (1): Bluetooth: Add another AR3012 04ca:3018 device Eric Biggers (1): KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings Eric Dumazet (5): ping: implement proper locking packet: handle too big packets for PACKET_V3 dccp/tcp: do not inherit mc_list from parent sctp: do not inherit ipv6_{mc|ac|fl}_list from parent ipv6: fix out of bound writes in __ip6_append_data() Felipe Balbi (1): usb: dwc3: gadget: skip Set/Clear Halt when invalid Felix Fietkau (1): ath5k: drop bogus warning on drv_set_key with unsupported cipher Feras Daoud (2): IB/ipoib: Set device connection mode only when needed IB/ipoib: Change list_del to list_del_init in the tx object Herbert Xu (1): crypto: ahash - Fix EINPROGRESS notification callback Ian Abbott (1): serial: 8250_pci: Add MKS Tenta SCOM-0800 and SCOM-0801 cards J. Bruce Fields (3): nfsd: check for oversized NFSv2/v3 arguments nfsd4: minor NFSv2/v3 write decoding cleanup nfsd: stricter decoding of write-like NFSv2/v3 ops James Cowgill (1): MIPS: OCTEON: Fix copy_from_user fault handling for large buffers Jan Kara (2): ext4: trim allocation requests to group size ext4: fix data corruption in data=journal mode Jason Gunthorpe (1): RDMA/core: Fix incorrect structure packing for booleans Javier Martinez Canillas (1): tty: serial: msm: Fix module autoload Johan Hovold (20): USB: serial: ch341: fix modem-status handling USB: serial: ark3116: fix register-accessor error handling USB: serial: ark3116: fix open error handling USB: serial: ftdi_sio: fix modem-status error handling USB: serial: ftdi_sio: fix latency-timer error handling USB: serial: io_edgeport: fix epic-descriptor handling USB: serial: io_edgeport: fix descriptor error handling USB: serial: mct_u232: fix modem-status error handling USB: serial: ssu100: fix control-message error handling USB: serial: ti_usb_3410_5052: fix control-message error handling USB: serial: ftdi_sio: fix extreme low-latency setting USB: serial: digi_acceleport: fix OOB data sanity check USB: serial: digi_acceleport: fix OOB-event processing USB: serial: digi_acceleport: fix incomplete rx sanity check USB: serial: keyspan_pda: fix receive sanity checks USB: serial: ftdi_sio: fix line-status over-reporting USB: serial: mos7840: fix another NULL-deref at open USB: iowarrior: fix NULL-deref at probe USB: serial: io_ti: fix information leak in completion handler USB: serial: omninet: fix reference leaks at open Julian Wiedmann (1): s390/qdio: clear DSCI prior to scanning multiple input queues K. Y. Srinivasan (1): drivers: hv: Turn off write permission on the hypercall page Ken Lin (1): USB: serial: cp210x: add new IDs for GE Bx50v3 boards Krzysztof Opasiak (1): usb: gadget: f_hid: Use spinlock instead of mutex Li Qiang (1): drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl() Marek Vasut (4): crypto: ahash - Fully restore ahash request before completing crypto: hash - Fix the pointer voodoo in unaligned ahash crypto: hash - Pull out the functions to save/restore request crypto: hash - Simplify the ahash_finup implementation Michael Petlan (1): perf script: Fix man page about --dump-raw-trace option Michel Dänzer (1): drm/ttm: Make sure BOs being swapped out are cacheable Miklos Szeredi (1): fuse: add missing FR_FORCE Mimi Zohar (1): KEYS: special dot prefixed keyring name bug fix Murray McAllister (1): drm/vmwgfx: NULL pointer dereference in vmw_surface_define_ioctl() NeilBrown (1): md: ensure md devices are freed before module is unloaded. Nikola Pajkovsky (1): x86/pci-calgary: Fix iommu_free() comparison of unsigned expression >= 0 Rafał Miłecki (1): bcma: use (get|put)_device when probing/removing device driver Raghava Aditya Renukunta (2): scsi: aacraid: Fix memory leak in fib init path scsi: aacraid: Reorder Adapter status check Ralf Baechle (1): MIPS: Fix special case in 64 bit IP checksumming. Randy Dunlap (1): media: fix dm1105.c build error Ravi Bangoria (1): powerpc/xmon: Fix data-breakpoint Ravikumar Kattekola (1): mmc: host: omap_hsmmc: avoid possible overflow of timeout value Roman Mashak (1): net sched actions: decrement module reference count after table flush. Steve Wise (1): rdma_cm: fail iwarp accepts w/o connection params Takashi Iwai (3): ALSA: timer: Reject user params with too small ticks ALSA: ctxfi: Fallback DMA mask to 32bit ALSA: seq: Fix link corruption by event error handling Theodore Ts'o (3): ext4: use private version of page_zero_new_buffers() for data=journal mode jbd2: don't leak modified metadata buffers on an aborted journal ext4: preserve the needs_recovery flag when the journal is aborted Trond Myklebust (3): nlm: Ensure callback code also checks that the files match NFSv4: Fix the underestimation of delegation XDR space reservation NFSv4: Fix range checking in __nfs4_get_acl_uncached and __nfs4_proc_set_acl WANG Cong (1): ipv6/dccp: do not inherit ipv6_mc_list from parent Weston Andros Adamson (1): NFSv4: fix getacl ERANGE for some ACL buffer sizes colyli@xxxxxxx (1): md linear: fix a race between linear_add() and linear_congested()
diff --git a/Makefile b/Makefile index 4507a9f653f2..df4aefae8171 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 2 -SUBLEVEL = 88 +SUBLEVEL = 89 EXTRAVERSION = NAME = Saber-toothed Squirrel diff --git a/arch/mips/Makefile b/arch/mips/Makefile index aaf74443cd68..97ba1d6683b1 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -285,11 +285,11 @@ CLEAN_FILES += vmlinux.32 vmlinux.64 archprepare: ifdef CONFIG_MIPS32_N32 - @echo ' Checking missing-syscalls for N32' + @$(kecho) ' Checking missing-syscalls for N32' $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=n32" endif ifdef CONFIG_MIPS32_O32 - @echo ' Checking missing-syscalls for O32' + @$(kecho) ' Checking missing-syscalls for O32' $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=32" endif diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S index 88e0cddca205..e8feb1d5bd49 100644 --- a/arch/mips/cavium-octeon/octeon-memcpy.S +++ b/arch/mips/cavium-octeon/octeon-memcpy.S @@ -223,18 +223,18 @@ EXC( STORE t2, UNIT(6)(dst), s_exc_p10u) ADD src, src, 16*NBYTES EXC( STORE t3, UNIT(7)(dst), s_exc_p9u) ADD dst, dst, 16*NBYTES -EXC( LOAD t0, UNIT(-8)(src), l_exc_copy) -EXC( LOAD t1, UNIT(-7)(src), l_exc_copy) -EXC( LOAD t2, UNIT(-6)(src), l_exc_copy) -EXC( LOAD t3, UNIT(-5)(src), l_exc_copy) +EXC( LOAD t0, UNIT(-8)(src), l_exc_copy_rewind16) +EXC( LOAD t1, UNIT(-7)(src), l_exc_copy_rewind16) +EXC( LOAD t2, UNIT(-6)(src), l_exc_copy_rewind16) +EXC( LOAD t3, UNIT(-5)(src), l_exc_copy_rewind16) EXC( STORE t0, UNIT(-8)(dst), s_exc_p8u) EXC( STORE t1, UNIT(-7)(dst), s_exc_p7u) EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u) EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u) -EXC( LOAD t0, UNIT(-4)(src), l_exc_copy) -EXC( LOAD t1, UNIT(-3)(src), l_exc_copy) -EXC( LOAD t2, UNIT(-2)(src), l_exc_copy) -EXC( LOAD t3, UNIT(-1)(src), l_exc_copy) +EXC( LOAD t0, UNIT(-4)(src), l_exc_copy_rewind16) +EXC( LOAD t1, UNIT(-3)(src), l_exc_copy_rewind16) +EXC( LOAD t2, UNIT(-2)(src), l_exc_copy_rewind16) +EXC( LOAD t3, UNIT(-1)(src), l_exc_copy_rewind16) EXC( STORE t0, UNIT(-4)(dst), s_exc_p4u) EXC( STORE t1, UNIT(-3)(dst), s_exc_p3u) EXC( STORE t2, UNIT(-2)(dst), s_exc_p2u) @@ -400,6 +400,10 @@ done: nop END(memcpy) +l_exc_copy_rewind16: + /* Rewind src and dst by 16*NBYTES for l_exc_copy */ + SUB src, src, 16*NBYTES + SUB dst, dst, 16*NBYTES l_exc_copy: /* * Copy bytes from src until faulting load address (or until a diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 0e36abcd39cc..7446284dd7b3 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -206,7 +206,6 @@ CONFIG_MLX4_EN=m # CONFIG_MLX4_DEBUG is not set CONFIG_TEHUTI=m CONFIG_BNX2X=m -CONFIG_QLGE=m CONFIG_SFC=m CONFIG_BE2NET=m CONFIG_LIBERTAS_THINFIRM=m diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h index f2f7c6c264da..9b8401798d8b 100644 --- a/arch/mips/include/asm/checksum.h +++ b/arch/mips/include/asm/checksum.h @@ -155,7 +155,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, " daddu %0, %4 \n" " dsll32 $1, %0, 0 \n" " daddu %0, $1 \n" + " sltu $1, %0, $1 \n" " dsra32 %0, %0, 0 \n" + " addu %0, $1 \n" #endif " .set pop" : "=r" (sum) diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 2bc0584be81c..844c0e66dd30 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -226,8 +226,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) rcu_read_lock(); bp = __get_cpu_var(bp_per_reg); - if (!bp) + if (!bp) { + rc = NOTIFY_DONE; goto out; + } info = counter_arch_bp(bp); /* diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 726494b58345..809b35e1612e 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -295,7 +295,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, /* were we called with bad_dma_address? */ badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE); - if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) { + if (unlikely(dma_addr < badend)) { WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA " "address 0x%Lx\n", dma_addr); return; diff --git a/crypto/ahash.c b/crypto/ahash.c index 8271185d4ad9..a6f94c4d7564 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -30,6 +30,7 @@ struct ahash_request_priv { crypto_completion_t complete; void *data; u8 *result; + u32 flags; void *ubuf[] CRYPTO_MINALIGN_ATTR; }; @@ -191,58 +192,133 @@ static inline unsigned int ahash_align_buffer_size(unsigned len, return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); } -static void ahash_op_unaligned_finish(struct ahash_request *req, int err) +static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) { - struct ahash_request_priv *priv = req->priv; + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + unsigned long alignmask = crypto_ahash_alignmask(tfm); + unsigned int ds = crypto_ahash_digestsize(tfm); + struct ahash_request_priv *priv; - if (err == -EINPROGRESS) - return; + priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + /* + * WARNING: Voodoo programming below! + * + * The code below is obscure and hard to understand, thus explanation + * is necessary. See include/crypto/hash.h and include/linux/crypto.h + * to understand the layout of structures used here! + * + * The code here will replace portions of the ORIGINAL request with + * pointers to new code and buffers so the hashing operation can store + * the result in aligned buffer. We will call the modified request + * an ADJUSTED request. + * + * The newly mangled request will look as such: + * + * req { + * .result = ADJUSTED[new aligned buffer] + * .base.complete = ADJUSTED[pointer to completion function] + * .base.data = ADJUSTED[*req (pointer to self)] + * .priv = ADJUSTED[new priv] { + * .result = ORIGINAL(result) + * .complete = ORIGINAL(base.complete) + * .data = ORIGINAL(base.data) + * } + */ + + priv->result = req->result; + priv->complete = req->base.complete; + priv->data = req->base.data; + priv->flags = req->base.flags; + + /* + * WARNING: We do not backup req->priv here! The req->priv + * is for internal use of the Crypto API and the + * user must _NOT_ _EVER_ depend on it's content! + */ + + req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); + req->base.complete = cplt; + req->base.data = req; + req->priv = priv; + + return 0; +} + +static void ahash_restore_req(struct ahash_request *req, int err) +{ + struct ahash_request_priv *priv = req->priv; if (!err) memcpy(priv->result, req->result, crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); + /* Restore the original crypto request. */ + req->result = priv->result; + + ahash_request_set_callback(req, priv->flags, + priv->complete, priv->data); + req->priv = NULL; + + /* Free the req->priv.priv from the ADJUSTED request. */ kzfree(priv); } +static void ahash_notify_einprogress(struct ahash_request *req) +{ + struct ahash_request_priv *priv = req->priv; + struct crypto_async_request oreq; + + oreq.data = priv->data; + + priv->complete(&oreq, -EINPROGRESS); +} + static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) { struct ahash_request *areq = req->data; - struct ahash_request_priv *priv = areq->priv; - crypto_completion_t complete = priv->complete; - void *data = priv->data; - ahash_op_unaligned_finish(areq, err); + if (err == -EINPROGRESS) { + ahash_notify_einprogress(areq); + return; + } + + /* + * Restore the original request, see ahash_op_unaligned() for what + * goes where. + * + * The "struct ahash_request *req" here is in fact the "req.base" + * from the ADJUSTED request from ahash_op_unaligned(), thus as it + * is a pointer to self, it is also the ADJUSTED "req" . + */ - complete(data, err); + /* First copy req->result into req->priv.result */ + ahash_restore_req(areq, err); + + /* Complete the ORIGINAL request. */ + areq->base.complete(&areq->base, err); } static int ahash_op_unaligned(struct ahash_request *req, int (*op)(struct ahash_request *)) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - unsigned long alignmask = crypto_ahash_alignmask(tfm); - unsigned int ds = crypto_ahash_digestsize(tfm); - struct ahash_request_priv *priv; int err; - priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), - (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC); - if (!priv) - return -ENOMEM; - - priv->result = req->result; - priv->complete = req->base.complete; - priv->data = req->base.data; - - req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); - req->base.complete = ahash_op_unaligned_done; - req->base.data = req; - req->priv = priv; + err = ahash_save_req(req, ahash_op_unaligned_done); + if (err) + return err; err = op(req); - ahash_op_unaligned_finish(req, err); + if (err == -EINPROGRESS || + (err == -EBUSY && (ahash_request_flags(req) & + CRYPTO_TFM_REQ_MAY_BACKLOG))) + return err; + + ahash_restore_req(req, err); return err; } @@ -277,30 +353,16 @@ int crypto_ahash_digest(struct ahash_request *req) } EXPORT_SYMBOL_GPL(crypto_ahash_digest); -static void ahash_def_finup_finish2(struct ahash_request *req, int err) +static void ahash_def_finup_done2(struct crypto_async_request *req, int err) { - struct ahash_request_priv *priv = req->priv; + struct ahash_request *areq = req->data; if (err == -EINPROGRESS) return; - if (!err) - memcpy(priv->result, req->result, - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); - - kzfree(priv); -} + ahash_restore_req(areq, err); -static void ahash_def_finup_done2(struct crypto_async_request *req, int err) -{ - struct ahash_request *areq = req->data; - struct ahash_request_priv *priv = areq->priv; - crypto_completion_t complete = priv->complete; - void *data = priv->data; - - ahash_def_finup_finish2(areq, err); - - complete(data, err); + areq->base.complete(&areq->base, err); } static int ahash_def_finup_finish1(struct ahash_request *req, int err) @@ -309,49 +371,52 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err) goto out; req->base.complete = ahash_def_finup_done2; - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_ahash_reqtfm(req)->final(req); + if (err == -EINPROGRESS || + (err == -EBUSY && (ahash_request_flags(req) & + CRYPTO_TFM_REQ_MAY_BACKLOG))) + return err; out: - ahash_def_finup_finish2(req, err); + ahash_restore_req(req, err); return err; } static void ahash_def_finup_done1(struct crypto_async_request *req, int err) { struct ahash_request *areq = req->data; - struct ahash_request_priv *priv = areq->priv; - crypto_completion_t complete = priv->complete; - void *data = priv->data; + + if (err == -EINPROGRESS) { + ahash_notify_einprogress(areq); + return; + } + + areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; err = ahash_def_finup_finish1(areq, err); + if (areq->priv) + return; - complete(data, err); + areq->base.complete(&areq->base, err); } static int ahash_def_finup(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - unsigned long alignmask = crypto_ahash_alignmask(tfm); - unsigned int ds = crypto_ahash_digestsize(tfm); - struct ahash_request_priv *priv; - - priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), - (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC); - if (!priv) - return -ENOMEM; + int err; - priv->result = req->result; - priv->complete = req->base.complete; - priv->data = req->base.data; + err = ahash_save_req(req, ahash_def_finup_done1); + if (err) + return err; - req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); - req->base.complete = ahash_def_finup_done1; - req->base.data = req; - req->priv = priv; + err = tfm->update(req); + if (err == -EINPROGRESS || + (err == -EBUSY && (ahash_request_flags(req) & + CRYPTO_TFM_REQ_MAY_BACKLOG))) + return err; - return ahash_def_finup_finish1(req, tfm->update(req)); + return ahash_def_finup_finish1(req, err); } static int ahash_no_export(struct ahash_request *req, void *out) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7a987a7803c9..94dd240beef3 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -297,8 +297,11 @@ static int bcma_device_probe(struct device *dev) drv); int err = 0; + get_device(dev); if (adrv->probe) err = adrv->probe(core); + if (err) + put_device(dev); return err; } @@ -311,6 +314,7 @@ static int bcma_device_remove(struct device *dev) if (adrv->remove) adrv->remove(core); + put_device(dev); return 0; } diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 5554a5b713a9..6e3a4e5bb0c3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -91,6 +91,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300f) }, { USB_DEVICE(0x04CA, 0x3010) }, { USB_DEVICE(0x04CA, 0x3014) }, + { USB_DEVICE(0x04CA, 0x3018) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x021c) }, { USB_DEVICE(0x0930, 0x0220) }, @@ -157,6 +158,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 59838695c46b..a5a141d5cb91 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -176,6 +176,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 6e9870341467..e6a5162d81b3 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -570,51 +570,57 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev) #ifdef CONFIG_ACPI static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { - bool ret = false; struct acpi_table_header *hdr; acpi_size tbl_size; UEFI_ACPI_VFCT *vfct; - GOP_VBIOS_CONTENT *vbios; - VFCT_IMAGE_HEADER *vhdr; + unsigned offset; if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) return false; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); - goto out_unmap; + return false; } vfct = (UEFI_ACPI_VFCT *)hdr; - if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { - DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); - goto out_unmap; - } + offset = vfct->VBIOSImageOffset; - vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); - vhdr = &vbios->VbiosHeader; - DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", - vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, - vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); - - if (vhdr->PCIBus != rdev->pdev->bus->number || - vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) || - vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) || - vhdr->VendorID != rdev->pdev->vendor || - vhdr->DeviceID != rdev->pdev->device) { - DRM_INFO("ACPI VFCT table is not for this card\n"); - goto out_unmap; - }; - - if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { - DRM_ERROR("ACPI VFCT image truncated\n"); - goto out_unmap; - } + while (offset < tbl_size) { + GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset); + VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader; - rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL); - ret = !!rdev->bios; + offset += sizeof(VFCT_IMAGE_HEADER); + if (offset > tbl_size) { + DRM_ERROR("ACPI VFCT image header truncated\n"); + return false; + } -out_unmap: - return ret; + offset += vhdr->ImageLength; + if (offset > tbl_size) { + DRM_ERROR("ACPI VFCT image truncated\n"); + return false; + } + + if (vhdr->ImageLength && + vhdr->PCIBus == rdev->pdev->bus->number && + vhdr->PCIDevice == PCI_SLOT(rdev->pdev->devfn) && + vhdr->PCIFunction == PCI_FUNC(rdev->pdev->devfn) && + vhdr->VendorID == rdev->pdev->vendor && + vhdr->DeviceID == rdev->pdev->device) { + rdev->bios = kmemdup(&vbios->VbiosContent, + vhdr->ImageLength, + GFP_KERNEL); + + if (!rdev->bios) { + kfree(rdev->bios); + return false; + } + return true; + } + } + + DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); + return false; } #else static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 22a89cd5aa5d..f5e5037e0daa 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1807,7 +1807,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) struct ttm_buffer_object *bo; int ret = -EBUSY; int put_count; - uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM); spin_lock(&glob->lru_lock); while (ret == -EBUSY) { @@ -1860,7 +1859,8 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) if (unlikely(ret != 0)) goto out; - if ((bo->mem.placement & swap_placement) != swap_placement) { + if (bo->mem.mem_type != TTM_PL_SYSTEM || + bo->ttm->caching_state != tt_cached) { struct ttm_mem_reg evict_mem; evict_mem = bo->mem; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 0795d1733c1b..e7af6c8617ce 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1304,11 +1304,14 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, 128; num_sizes = 0; - for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) + for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { + if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS) + return -EINVAL; num_sizes += req->mip_levels[i]; + } - if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * - DRM_VMW_MAX_MIP_LEVELS) + if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS || + num_sizes == 0) return -EINVAL; size = vmw_user_surface_size + 128 + diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 17ed6fbb9b56..f5cccd0edf56 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -178,7 +178,7 @@ int hv_init(void) /* See if the hypercall page is already set */ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC); + virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX); if (!virtaddr) goto cleanup; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index d0d4aa9f4802..09cc0fc7d423 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2737,6 +2737,9 @@ static int cma_accept_iw(struct rdma_id_private *id_priv, struct iw_cm_conn_param iw_param; int ret; + if (!conn_param) + return -EINVAL; + ret = cma_modify_qp_rtr(id_priv, conn_param); if (ret) return ret; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 0bbe030d26a8..74aa1310449e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1366,7 +1366,7 @@ static void ipoib_cm_tx_reap(struct work_struct *work) while (!list_empty(&priv->cm.reap_list)) { p = list_entry(priv->cm.reap_list.next, typeof(*p), list); - list_del(&p->list); + list_del_init(&p->list); spin_unlock_irqrestore(&priv->lock, flags); netif_tx_unlock_bh(dev); ipoib_cm_tx_destroy(p); @@ -1480,6 +1480,14 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (!rtnl_trylock()) return restart_syscall(); + if ((test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && + !strcmp(buf, "connected\n")) || + (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && + !strcmp(buf, "datagram\n"))) { + rtnl_unlock(); + return 0; + } + /* flush paths if we switch modes so that connections are restarted */ if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 627456542fb3..a118c5a90dd7 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -88,6 +88,12 @@ static int linear_mergeable_bvec(struct request_queue *q, return maxsectors << 9; } +/* + * In linear_congested() conf->raid_disks is used as a copy of + * mddev->raid_disks to iterate conf->disks[], because conf->raid_disks + * and conf->disks[] are created in linear_conf(), they are always + * consitent with each other, but mddev->raid_disks does not. + */ static int linear_congested(void *data, int bits) { struct mddev *mddev = data; @@ -100,7 +106,7 @@ static int linear_congested(void *data, int bits) rcu_read_lock(); conf = rcu_dereference(mddev->private); - for (i = 0; i < mddev->raid_disks && !ret ; i++) { + for (i = 0; i < conf->raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev); ret |= bdi_congested(&q->backing_dev_info, bits); } @@ -188,6 +194,19 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks) conf->disks[i-1].end_sector + conf->disks[i].rdev->sectors; + /* + * conf->raid_disks is copy of mddev->raid_disks. The reason to + * keep a copy of mddev->raid_disks in struct linear_conf is, + * mddev->raid_disks may not be consistent with pointers number of + * conf->disks[] when it is updated in linear_add() and used to + * iterate old conf->disks[] earray in linear_congested(). + * Here conf->raid_disks is always consitent with number of + * pointers in conf->disks[] array, and mddev->private is updated + * with rcu_assign_pointer() in linear_addr(), such race can be + * avoided. + */ + conf->raid_disks = raid_disks; + return conf; out: @@ -237,8 +256,16 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev) if (!newconf) return -ENOMEM; + /* newconf->raid_disks already keeps a copy of * the increased + * value of mddev->raid_disks, WARN_ONCE() is just used to make + * sure of this. It is possible that oldconf is still referenced + * in linear_congested(), therefore kfree_rcu() is used to free + * oldconf until no one uses it anymore. + */ oldconf = rcu_dereference(mddev->private); mddev->raid_disks++; + WARN_ONCE(mddev->raid_disks != newconf->raid_disks, + "copied raid_disks doesn't match mddev->raid_disks"); rcu_assign_pointer(mddev->private, newconf); md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); diff --git a/drivers/md/linear.h b/drivers/md/linear.h index b685ddd7d7f7..8d392e6098b3 100644 --- a/drivers/md/linear.h +++ b/drivers/md/linear.h @@ -10,6 +10,7 @@ struct linear_conf { struct rcu_head rcu; sector_t array_sectors; + int raid_disks; /* a copy of mddev->raid_disks */ struct dev_info disks[0]; }; #endif diff --git a/drivers/md/md.c b/drivers/md/md.c index 09145341f5cc..b8f9202f9e2f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8292,7 +8292,14 @@ static __exit void md_exit(void) remove_proc_entry("mdstat", NULL); for_each_mddev(mddev, tmp) { export_array(mddev); + mddev->ctime = 0; mddev->hold_active = 0; + /* + * for_each_mddev() will call mddev_put() at the end of each + * iteration. As the mddev is now fully clear, this will + * schedule the mddev for destruction by a workqueue, and the + * destroy_workqueue() below will wait for that to complete. + */ } destroy_workqueue(md_misc_wq); destroy_workqueue(md_wq); diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig index f3de0a4d63f2..5691fe9ac71b 100644 --- a/drivers/media/dvb/dm1105/Kconfig +++ b/drivers/media/dvb/dm1105/Kconfig @@ -1,6 +1,6 @@ config DVB_DM1105 tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C + depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_STV0288 if !DVB_FE_CUSTOMISE diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bc27065f31c0..2b47f3479e14 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1499,10 +1499,11 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, } static void set_data_timeout(struct omap_hsmmc_host *host, - unsigned int timeout_ns, + unsigned long long timeout_ns, unsigned int timeout_clks) { - unsigned int timeout, cycle_ns; + unsigned long long timeout = timeout_ns; + unsigned int cycle_ns; uint32_t reg, clkd, dto = 0; reg = OMAP_HSMMC_READ(host->base, SYSCTL); @@ -1511,7 +1512,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host, clkd = 1; cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd); - timeout = timeout_ns / cycle_ns; + do_div(timeout, cycle_ns); timeout += timeout_clks; if (timeout) { while ((timeout & 0x80000000) == 0) { diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index f5ce5623da99..b98323b76fdd 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1842,7 +1842,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->rx_ring_size = rx_ring_size; priv->tx_ring_size = tx_ring_size; - if (adm8211_alloc_rings(dev)) { + err = adm8211_alloc_rings(dev); + if (err) { printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n", pci_name(pdev)); goto err_iounmap; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 6ed4c0717e3e..75ff5e19bd5a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -493,8 +493,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; return -EOPNOTSUPP; default: - WARN_ON(1); - return -EINVAL; + return -EOPNOTSUPP; } mutex_lock(&ah->lock); diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 1c0e1a4f5385..fa0b5f52fff7 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -221,7 +221,8 @@ mwifiex_info_read(struct file *file, char __user *ubuf, if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { p += sprintf(p, "multicast_count=\"%d\"\n", netdev_mc_count(netdev)); - p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); + p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len, + info.ssid.ssid); p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 011eadea3ee4..89643be83b90 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -146,11 +146,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) struct qdio_q *q; int i; - for_each_input_queue(irq, q, i) { - if (!references_shared_dsci(irq) && - has_multiple_inq_on_dsci(irq)) - xchg(q->irq_ptr->dsci, 0); + if (!references_shared_dsci(irq) && + has_multiple_inq_on_dsci(irq)) + xchg(irq->dsci, 0); + for_each_input_queue(irq, q, i) { if (q->u.in.queue_start_poll) { /* skip if polling is enabled or already in work */ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index a03ab8eb097b..7a89f442a775 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -83,12 +83,20 @@ static int fib_map_alloc(struct aac_dev *dev) void aac_fib_map_free(struct aac_dev *dev) { - if (dev->hw_fib_va && dev->max_fib_size) { - pci_free_consistent(dev->pdev, - (dev->max_fib_size * - (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)), - dev->hw_fib_va, dev->hw_fib_pa); - } + size_t alloc_size; + size_t fib_size; + int num_fibs; + + if(!dev->hw_fib_va || !dev->max_fib_size) + return; + + num_fibs = dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB; + fib_size = dev->max_fib_size + sizeof(struct aac_fib_xporthdr); + alloc_size = fib_size * num_fibs + ALIGN32 - 1; + + pci_free_consistent(dev->pdev, alloc_size, dev->hw_fib_va, + dev->hw_fib_pa); + dev->hw_fib_va = NULL; dev->hw_fib_pa = 0; } @@ -116,22 +124,20 @@ int aac_fib_setup(struct aac_dev * dev) if (i<0) return -ENOMEM; - /* 32 byte alignment for PMC */ - hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); - dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + - (hw_fib_pa - dev->hw_fib_pa)); - dev->hw_fib_pa = hw_fib_pa; memset(dev->hw_fib_va, 0, (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); + /* 32 byte alignment for PMC */ + hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); + hw_fib = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + (hw_fib_pa - dev->hw_fib_pa)); + /* add Xport header */ - dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + sizeof(struct aac_fib_xporthdr)); - dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr); + hw_fib_pa += sizeof(struct aac_fib_xporthdr); - hw_fib = dev->hw_fib_va; - hw_fib_pa = dev->hw_fib_pa; /* * Initialise the fibs */ diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 957595a7a45c..ee9c560b820f 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -317,16 +317,23 @@ static int aac_src_check_health(struct aac_dev *dev) u32 status = src_readl(dev, MUnit.OMR); /* + * Check to see if the board panic'd. + */ + if (unlikely(status & KERNEL_PANIC)) + goto err_blink; + + /* * Check to see if the board failed any self tests. */ if (unlikely(status & SELF_TEST_FAILED)) - return -1; + goto err_out; /* - * Check to see if the board panic'd. + * Check to see if the board failed any self tests. */ - if (unlikely(status & KERNEL_PANIC)) - return (status >> 16) & 0xFF; + if (unlikely(status & MONITOR_PANIC)) + goto err_out; + /* * Wait for the adapter to be up and running. */ @@ -336,6 +343,12 @@ static int aac_src_check_health(struct aac_dev *dev) * Everything is OK */ return 0; + +err_out: + return -1; + +err_blink: + return (status > 16) & 0xFF; } /** diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index 4cc68d1b5069..3b4a6617a5f2 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -641,11 +641,16 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) /* append rx status for mp test packets */ ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); + if (!ptr) + return _FAIL; memcpy(ptr, get_rxmem(precvframe), 24); ptr += 24; - } else + } else { ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + if (!ptr) + return _FAIL; + } memcpy(ptr, pattrib->dst, ETH_ALEN); memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index c1c1e525444a..7619e98828ab 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c @@ -1768,6 +1768,8 @@ enum pci_board_num_t { pbn_b0_4_1152000, + pbn_b0_4_1250000, + pbn_b0_2_1843200, pbn_b0_4_1843200, @@ -1964,6 +1966,13 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b0_4_1250000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1250000, + .uart_offset = 8, + }, + [pbn_b0_2_1843200] = { .flags = FL_BASE0, .num_ports = 2, @@ -4162,6 +4171,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_brcm_trumanage }, + /* MKS Tenta SCOM-080x serial cards */ + { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, + { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 8131e2c28015..b09e0686c2ec 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -930,6 +930,7 @@ static struct of_device_id msm_match_table[] = { { .compatible = "qcom,msm-uart" }, {} }; +MODULE_DEVICE_TABLE(of, msm_match_table); static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 392222ba28b7..33fe3d3bebbd 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -925,6 +925,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) memset(¶ms, 0x00, sizeof(params)); if (value) { + if (dep->flags & DWC3_EP_STALL) + return 0; + if (dep->number == 0 || dep->number == 1) { /* * Whenever EP0 is stalled, we will restart @@ -943,6 +946,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) else dep->flags |= DWC3_EP_STALL; } else { + if (!(dep->flags & DWC3_EP_STALL)) + return 0; + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_CLEARSTALL, ¶ms); if (ret) diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index b2113420b806..501d3e3eac23 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -37,11 +37,11 @@ struct f_hidg { /* recv report */ char *set_report_buff; unsigned short set_report_length; - spinlock_t spinlock; + spinlock_t read_spinlock; wait_queue_head_t read_queue; /* send report */ - struct mutex lock; + spinlock_t write_spinlock; bool write_pending; wait_queue_head_t write_queue; struct usb_request *req; @@ -140,19 +140,19 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); #define READ_COND (hidg->set_report_buff != NULL) while (!READ_COND) { - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(hidg->read_queue, READ_COND)) return -ERESTARTSYS; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); } @@ -160,7 +160,7 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, tmp_buff = hidg->set_report_buff; hidg->set_report_buff = NULL; - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); if (tmp_buff != NULL) { /* copy to user outside spinlock */ @@ -175,13 +175,16 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) { struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; + unsigned long flags; if (req->status != 0) { ERROR(hidg->func.config->cdev, "End Point Request ERROR: %d\n", req->status); } + spin_lock_irqsave(&hidg->write_spinlock, flags); hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); wake_up(&hidg->write_queue); } @@ -189,18 +192,19 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, size_t count, loff_t *offp) { struct f_hidg *hidg = file->private_data; + unsigned long flags; ssize_t status = -ENOMEM; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); #define WRITE_COND (!hidg->write_pending) /* write queue */ while (!WRITE_COND) { - mutex_unlock(&hidg->lock); + spin_unlock_irqrestore(&hidg->write_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; @@ -208,17 +212,20 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, hidg->write_queue, WRITE_COND)) return -ERESTARTSYS; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); } + hidg->write_pending = 1; count = min_t(unsigned, count, hidg->report_length); + + spin_unlock_irqrestore(&hidg->write_spinlock, flags); status = copy_from_user(hidg->req->buf, buffer, count); if (status != 0) { ERROR(hidg->func.config->cdev, "copy_from_user error\n"); - mutex_unlock(&hidg->lock); - return -EINVAL; + status = -EINVAL; + goto release_write_pending; } hidg->req->status = 0; @@ -226,19 +233,23 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, hidg->req->length = count; hidg->req->complete = f_hidg_req_complete; hidg->req->context = hidg; - hidg->write_pending = 1; status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); if (status < 0) { ERROR(hidg->func.config->cdev, "usb_ep_queue error on int endpoint %zd\n", status); - hidg->write_pending = 0; - wake_up(&hidg->write_queue); + goto release_write_pending; } else { status = count; } - mutex_unlock(&hidg->lock); + return status; +release_write_pending: + spin_lock_irqsave(&hidg->write_spinlock, flags); + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); return status; } @@ -291,19 +302,19 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) return; } - spin_lock(&hidg->spinlock); + spin_lock(&hidg->read_spinlock); hidg->set_report_buff = krealloc(hidg->set_report_buff, req->actual, GFP_ATOMIC); if (hidg->set_report_buff == NULL) { - spin_unlock(&hidg->spinlock); + spin_unlock(&hidg->read_spinlock); return; } hidg->set_report_length = req->actual; memcpy(hidg->set_report_buff, req->buf, req->actual); - spin_unlock(&hidg->spinlock); + spin_unlock(&hidg->read_spinlock); wake_up(&hidg->read_queue); } @@ -505,8 +516,8 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } - mutex_init(&hidg->lock); - spin_lock_init(&hidg->spinlock); + spin_lock_init(&hidg->write_spinlock); + spin_lock_init(&hidg->read_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 2fce7197fa7b..c19a219cd5a6 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -792,12 +792,6 @@ static int iowarrior_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); - if (iface_desc->desc.bNumEndpoints < 1) { - dev_err(&interface->dev, "Invalid number of endpoints\n"); - retval = -EINVAL; - goto error; - } - /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -808,6 +802,13 @@ static int iowarrior_probe(struct usb_interface *interface, /* this one will match for the IOWarrior56 only */ dev->int_out_endpoint = endpoint; } + + if (!dev->int_in_endpoint) { + dev_err(&interface->dev, "no interrupt-in endpoint found\n"); + retval = -ENODEV; + goto error; + } + /* we have to check the report_size often, so remember it in the endianess suitable for our machine */ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 1a715f6587aa..078a1d6a2ca7 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -107,10 +107,17 @@ static int ark3116_read_reg(struct usb_serial *serial, usb_rcvctrlpipe(serial->dev, 0), 0xfe, 0xc0, 0, reg, buf, 1, ARK_TIMEOUT); - if (result < 0) + if (result < 1) { + dev_err(&serial->interface->dev, + "failed to read register %u: %d\n", + reg, result); + if (result >= 0) + result = -EIO; + return result; - else - return buf[0]; + } + + return buf[0]; } static inline int calc_divisor(int bps) @@ -375,23 +382,29 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) if (result) { dbg("%s - usb_serial_generic_open failed: %d", __func__, result); - goto err_out; + goto err_free; } /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); /* read modem status */ - priv->msr = ark3116_read_reg(serial, UART_MSR, buf); + result = ark3116_read_reg(serial, UART_MSR, buf); + if (result < 0) + goto err_close; + priv->msr = *buf; + /* read line status */ - priv->lsr = ark3116_read_reg(serial, UART_LSR, buf); + result = ark3116_read_reg(serial, UART_LSR, buf); + if (result < 0) + goto err_close; + priv->lsr = *buf; result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "submit irq_in urb failed %d\n", result); - ark3116_close(port); - goto err_out; + goto err_close; } /* activate interrupts */ @@ -404,8 +417,15 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ark3116_set_termios(tty, port, NULL); -err_out: kfree(buf); + + return 0; + +err_close: + usb_serial_generic_close(port); +err_free: + kfree(buf); + return result; } diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index d50a6a696a8d..57cb577e0be2 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -255,21 +255,11 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - /* expect 0xff 0xee */ - r = ch341_get_status(dev, priv); - if (r < 0) - goto out; - r = ch341_set_baudrate_lcr(dev, priv, 0); if (r < 0) goto out; r = ch341_set_handshake(dev, priv->line_control); - if (r < 0) - goto out; - - /* expect 0x9f 0xee */ - r = ch341_get_status(dev, priv); out: kfree(buffer); return r; @@ -345,10 +335,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("ch341_open()"); - r = ch341_configure(serial->dev, priv); - if (r) - return r; - if (tty) ch341_set_termios(tty, port, NULL); @@ -361,6 +347,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) return r; } + r = ch341_get_status(port->serial->dev, priv); + if (r < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", r); + goto err_kill_interrupt_urb; + } + r = usb_serial_generic_open(tty, port); if (r) goto err_kill_interrupt_urb; @@ -656,6 +648,12 @@ static int ch341_reset_resume(struct usb_interface *intf) ret); return ret; } + + ret = ch341_get_status(port->serial->dev, priv); + if (ret < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", + ret); + } } return usb_serial_generic_resume(serial); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4238c275edfe..8dfb599bc0ec 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -177,6 +177,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */ + { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */ + { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */ { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index e59bd95f05c0..4499bda0523f 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1660,25 +1660,30 @@ static int digi_read_inb_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); - int opcode = ((unsigned char *)urb->transfer_buffer)[0]; - int len = ((unsigned char *)urb->transfer_buffer)[1]; - int port_status = ((unsigned char *)urb->transfer_buffer)[2]; - unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; + unsigned char *buf = urb->transfer_buffer; + int opcode; + int len; + int port_status; + unsigned char *data; int flag, throttled; - int status = urb->status; - - /* do not process callbacks on closed ports */ - /* but do continue the read chain */ - if (urb->status == -ENOENT) - return 0; /* short/multiple packet check */ + if (urb->actual_length < 2) { + dev_warn(&port->dev, "short packet received\n"); + return -1; + } + + opcode = buf[0]; + len = buf[1]; + if (urb->actual_length != len + 2) { - dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " - "status=%d, port=%d, opcode=%d, len=%d, " - "actual_length=%d, status=%d\n", __func__, status, - priv->dp_port_num, opcode, len, urb->actual_length, - port_status); + dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n", + priv->dp_port_num, opcode, len, urb->actual_length); + return -1; + } + + if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) { + dev_err(&port->dev, "malformed data packet received\n"); return -1; } @@ -1693,6 +1698,9 @@ static int digi_read_inb_callback(struct urb *urb) /* receive data */ if (tty && opcode == DIGI_CMD_RECEIVE_DATA) { + port_status = buf[2]; + data = &buf[3]; + /* get flag from port_status */ flag = 0; @@ -1746,6 +1754,7 @@ static int digi_read_oob_callback(struct urb *urb) struct usb_serial *serial = port->serial; struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); + unsigned char *buf = urb->transfer_buffer; int opcode, line, status, val; int i; unsigned int rts; @@ -1753,12 +1762,15 @@ static int digi_read_oob_callback(struct urb *urb) dbg("digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num, urb->actual_length); + if (urb->actual_length < 4) + return -1; + /* handle each oob command */ - for (i = 0; i < urb->actual_length - 3;) { - opcode = ((unsigned char *)urb->transfer_buffer)[i++]; - line = ((unsigned char *)urb->transfer_buffer)[i++]; - status = ((unsigned char *)urb->transfer_buffer)[i++]; - val = ((unsigned char *)urb->transfer_buffer)[i++]; + for (i = 0; i < urb->actual_length - 3; i += 4) { + opcode = buf[i]; + line = buf[i + 1]; + status = buf[i + 2]; + val = buf[i + 3]; dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index dbc437c61fb5..c298c7a05842 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1475,10 +1475,13 @@ static int read_latency_timer(struct usb_serial_port *port) FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, priv->interface, buf, 1, WDR_TIMEOUT); - if (rv < 0) + if (rv < 1) { dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); - else + if (rv >= 0) + rv = -EIO; + } else { priv->latency = buf[0]; + } kfree(buf); @@ -1861,8 +1864,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) mutex_init(&priv->cfg_lock); memset(&priv->icount, 0x00, sizeof(priv->icount)); - priv->flags = ASYNC_LOW_LATENCY; - if (quirk && quirk->port_probe) quirk->port_probe(priv); @@ -2186,6 +2187,20 @@ static int ftdi_process_packet(struct tty_struct *tty, priv->prev_status = status; } + /* save if the transmitter is empty or not */ + if (packet[1] & FTDI_RS_TEMT) + priv->transmit_empty = 1; + else + priv->transmit_empty = 0; + + len -= 2; + if (!len) + return 0; /* status only */ + + /* + * Break and error status must only be processed for packets with + * data payload to avoid over-reporting. + */ flag = TTY_NORMAL; if (packet[1] & FTDI_RS_ERR_MASK) { /* Break takes precedence over parity, which takes precedence @@ -2208,15 +2223,6 @@ static int ftdi_process_packet(struct tty_struct *tty, } } - /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) - priv->transmit_empty = 1; - else - priv->transmit_empty = 0; - - len -= 2; - if (!len) - return 0; /* status only */ priv->icount.rx += len; ch = packet + 2; @@ -2542,8 +2548,13 @@ static int ftdi_tiocmget(struct tty_struct *tty) FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) + + /* NOTE: We allow short responses and handle that below. */ + if (ret < 1) { + if (ret >= 0) + ret = -EIO; goto out; + } ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 5a76b1c493f2..d4109f221e1e 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -496,21 +496,25 @@ static int get_epic_descriptor(struct edgeport_serial *ep) int result; struct usb_serial *serial = ep->serial; struct edgeport_product_info *product_info = &ep->product_info; - struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_descriptor *epic; struct edge_compatibility_bits *bits; ep->is_epic = 0; + + epic = kmalloc(sizeof(*epic), GFP_KERNEL); + if (!epic) + return -ENOMEM; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_GET_EPIC_DESC, 0xC0, 0x00, 0x00, - &ep->epic_descriptor, - sizeof(struct edge_compatibility_descriptor), + epic, sizeof(*epic), 300); - dbg("%s result = %d", __func__, result); - if (result > 0) { + if (result == sizeof(*epic)) { ep->is_epic = 1; + memcpy(&ep->epic_descriptor, epic, sizeof(*epic)); memset(product_info, 0, sizeof(struct edgeport_product_info)); product_info->NumPorts = epic->NumPorts; @@ -539,8 +543,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep) dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE"); dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE"); + + result = 0; + } else if (result >= 0) { + dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n", + result); + result = -EIO; } + kfree(epic); + return result; } @@ -2251,8 +2263,7 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, * rom_read * reads a number of bytes from the Edgeport device starting at the given * address. - * If successful returns the number of bytes read, otherwise it returns - * a negative error number of the problem. + * Returns zero on success or a negative error number. ****************************************************************************/ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) @@ -2284,12 +2295,17 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, USB_REQUEST_ION_READ_ROM, 0xC0, addr, extAddr, transfer_buffer, current_length, 300); - if (result < 0) + if (result < current_length) { + if (result >= 0) + result = -EIO; break; + } memcpy(data, transfer_buffer, current_length); length -= current_length; addr += current_length; data += current_length; + + result = 0; } kfree(transfer_buffer); @@ -2760,10 +2776,11 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) EDGE_MANUF_DESC_LEN, (__u8 *)(&edge_serial->manuf_descriptor)); - if (response < 1) + if (response < 0) { dev_err(&edge_serial->serial->dev->dev, - "error in getting manufacturer descriptor\n"); - else { + "error in getting manufacturer descriptor: %d\n", + response); + } else { char string[30]; dbg("**Manufacturer Descriptor"); dbg(" RomSize: %dK", @@ -2819,10 +2836,11 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) EDGE_BOOT_DESC_LEN, (__u8 *)(&edge_serial->boot_descriptor)); - if (response < 1) + if (response < 0) { dev_err(&edge_serial->serial->dev->dev, - "error in getting boot descriptor\n"); - else { + "error in getting boot descriptor: %d\n", + response); + } else { dbg("**Boot Descriptor:"); dbg(" BootCodeLength: %d", le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); @@ -2965,7 +2983,7 @@ static int edge_startup(struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); /* Read the epic descriptor */ - if (get_epic_descriptor(edge_serial) <= 0) { + if (get_epic_descriptor(edge_serial) < 0) { /* memcpy descriptor to Supports structures */ memcpy(&edge_serial->epic_descriptor.Supports, descriptor, sizeof(struct edge_compatibility_bits)); diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 48749733b117..0fc2da9948f7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1766,7 +1766,7 @@ static void edge_bulk_in_callback(struct urb *urb) port_number = edge_port->port->number - edge_port->port->serial->minor; - if (edge_port->lsr_event) { + if (urb->actual_length > 0 && edge_port->lsr_event) { edge_port->lsr_event = 0; dbg("%s ===== Port %u LSR Status = %02x, Data = %02x ======", __func__, port_number, edge_port->lsr_mask, *data); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 65a090660e73..611904f1650c 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -212,6 +212,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) struct usb_serial_port *port = urb->context; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; + unsigned int len = urb->actual_length; int retval; int status = urb->status; struct keyspan_pda_private *priv; @@ -234,20 +235,28 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) goto exit; } + if (len < 1) { + dev_warn(&port->dev, "short message received\n"); + goto exit; + } + /* see if the message is data or a status interrupt */ switch (data[0]) { case 0: tty = tty_port_tty_get(&port->port); /* rest of message is rx data */ - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data + 1, - urb->actual_length - 1); - tty_flip_buffer_push(tty); - } + if (!tty || len < 2) + break; + tty_insert_flip_string(tty, data + 1, len - 1); + tty_flip_buffer_push(tty); tty_kref_put(tty); break; case 1: /* status interrupt */ + if (len < 3) { + dev_warn(&port->dev, "short interrupt message received\n"); + break; + } dbg(" rx int, d1=%d, d2=%d", data[1], data[2]); switch (data[1]) { case 1: /* modemline change */ diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a7e7ba65a611..801c697148ef 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -385,9 +385,13 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial, MCT_U232_GET_REQUEST_TYPE, 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, WDR_TIMEOUT); - if (rc < 0) { + if (rc < MCT_U232_GET_MODEM_STAT_SIZE) { dev_err(&serial->dev->dev, "Get MODEM STATus failed (error = %d)\n", rc); + + if (rc >= 0) + rc = -EIO; + *msr = 0; } else { *msr = buf[0]; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 643898943a15..c868953a6839 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1058,6 +1058,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the structures * * were not set up at that time.) */ if (port0->open_ports == 1) { + /* FIXME: Buffer never NULL, so URB is not submitted. */ if (serial->port[0]->interrupt_in_buffer == NULL) { /* set up interrupt urb */ usb_fill_int_urb(serial->port[0]->interrupt_in_urb, @@ -2385,7 +2386,8 @@ static int mos7840_startup(struct usb_serial *serial) } if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) { + serial->num_bulk_out < serial->num_ports || + serial->num_interrupt_in < 1) { dev_err(&serial->interface->dev, "missing endpoints\n"); return -ENODEV; } diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 5c7abfb9aea7..6665f5e59532 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -171,14 +171,10 @@ static int omninet_attach(struct usb_serial *serial) static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct usb_serial_port *wport; int result = 0; dbg("%s - port %d", __func__, port->number); - wport = serial->port[1]; - tty_port_tty_set(&wport->port, tty); - /* Start reading from the device */ usb_fill_bulk_urb(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index ad8e5f36f54a..965812b26b4f 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -107,9 +107,17 @@ static inline int ssu100_setdevice(struct usb_device *dev, u8 *data) static inline int ssu100_getdevice(struct usb_device *dev, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, 300); + if (ret < 3) { + if (ret >= 0) + ret = -EIO; + } + + return ret; } static inline int ssu100_getregister(struct usb_device *dev, @@ -117,10 +125,17 @@ static inline int ssu100_getregister(struct usb_device *dev, unsigned short reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), 300); + if (ret < sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + return ret; } @@ -322,8 +337,10 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) QT_OPEN_CLOSE_CHANNEL, QT_TRANSFER_IN, 0x01, 0, data, 2, 300); - if (result < 0) { + if (result < 2) { dbg("%s - open failed %i", __func__, result); + if (result >= 0) + result = -EIO; kfree(data); return result; } diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 6bf24d10324c..b82f04c1be05 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1614,13 +1614,10 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), value, moduleid, data, size, 1000); - if (status == size) - status = 0; - - if (status > 0) - status = -ECOMM; + if (status < 0) + return status; - return status; + return 0; } @@ -1636,8 +1633,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, if (status == size) status = 0; - - if (status > 0) + else if (status >= 0) status = -ECOMM; return status; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 274c91b5e9f6..f881e3484481 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1068,6 +1068,40 @@ static int ext4_writeback_write_end(struct file *file, return ret ? ret : copied; } +/* + * This is a private version of page_zero_new_buffers() which doesn't + * set the buffer to be dirty, since in data=journalled mode we need + * to call ext4_handle_dirty_metadata() instead. + */ +static void ext4_journalled_zero_new_buffers(handle_t *handle, + struct page *page, + unsigned from, unsigned to) +{ + unsigned int block_start = 0, block_end; + struct buffer_head *head, *bh; + + bh = head = page_buffers(page); + do { + block_end = block_start + bh->b_size; + if (buffer_new(bh)) { + if (block_end > from && block_start < to) { + if (!PageUptodate(page)) { + unsigned start, size; + + start = max(from, block_start); + size = min(to, block_end) - start; + + zero_user(page, start, size); + write_end_fn(handle, bh); + } + clear_buffer_new(bh); + } + } + block_start = block_end; + bh = bh->b_this_page; + } while (bh != head); +} + static int ext4_journalled_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, @@ -1086,16 +1120,19 @@ static int ext4_journalled_write_end(struct file *file, BUG_ON(!ext4_handle_valid(handle)); - if (copied < len) { - if (!PageUptodate(page)) - copied = 0; - page_zero_new_buffers(page, from+copied, to); + if (unlikely(copied < len) && !PageUptodate(page)) { + copied = 0; + ext4_journalled_zero_new_buffers(handle, page, from, to); + } else { + if (unlikely(copied < len)) + ext4_journalled_zero_new_buffers(handle, page, + from + copied, to); + ret = walk_page_buffers(handle, page_buffers(page), from, + from + copied, &partial, + write_end_fn); + if (!partial) + SetPageUptodate(page); } - - ret = walk_page_buffers(handle, page_buffers(page), from, - to, &partial, write_end_fn); - if (!partial) - SetPageUptodate(page); new_i_size = pos + copied; if (new_i_size > inode->i_size) i_size_write(inode, pos+copied); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index ebc50aa7347c..5efe721c1532 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3003,6 +3003,13 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, if (ar->pright && start + size - 1 >= ar->lright) size -= start + size - ar->lright; + /* + * Trim allocation request for filesystems with artificially small + * groups. + */ + if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)) + size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb); + end = start + size; /* check we don't cross already preallocated blocks */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 422ed7946c20..72a75f875813 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -808,6 +808,7 @@ static void ext4_put_super(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; + int aborted = 0; int i, err; ext4_unregister_li_request(sb); @@ -821,9 +822,10 @@ static void ext4_put_super(struct super_block *sb) ext4_commit_super(sb, 1); if (sbi->s_journal) { + aborted = is_journal_aborted(sbi->s_journal); err = jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; - if (err < 0) + if ((err < 0) && !aborted) ext4_abort(sb, "Couldn't clean up the journal"); } @@ -833,7 +835,7 @@ static void ext4_put_super(struct super_block *sb) ext4_ext_release(sb); ext4_xattr_put_super(sb); - if (!(sb->s_flags & MS_RDONLY)) { + if (!(sb->s_flags & MS_RDONLY) && !aborted) { EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); ext4_commit_super(sb, 1); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f507e62204b1..1f78f91dedc4 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -126,6 +126,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) struct fuse_req *req = ff->reserved_req; if (sync) { + req->force = 1; fuse_request_send(ff->fc, req); path_put(&req->misc.release.path); fuse_put_request(ff->fc, req); diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index e3c41c5fd670..61537fe22397 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1601,7 +1601,9 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) __blist_del_buffer(list, jh); jh->b_jlist = BJ_None; - if (test_clear_buffer_jbddirty(bh)) + if (transaction && is_journal_aborted(transaction->t_journal)) + clear_buffer_jbddirty(bh); + else if (test_clear_buffer_jbddirty(bh)) mark_buffer_dirty(bh); /* Expose it to the VM */ } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0ba9bf7704d1..8f509a030f68 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3455,11 +3455,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); } -/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that - * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on +/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that + * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on * the stack. */ -#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) +#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE) static int buf_to_pages_noslab(const void *buf, size_t buflen, struct page **pages, unsigned int *pgbase) @@ -3470,7 +3470,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen, spages = pages; do { - len = min_t(size_t, PAGE_CACHE_SIZE, buflen); + len = min_t(size_t, PAGE_SIZE, buflen); newpage = alloc_page(GFP_KERNEL); if (newpage == NULL) @@ -3569,7 +3569,7 @@ out: */ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) { - struct page *pages[NFS4ACL_MAXPAGES] = {NULL, }; + struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, }; struct nfs_getaclargs args = { .fh = NFS_FH(inode), .acl_pages = pages, @@ -3583,17 +3583,12 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu .rpc_argp = &args, .rpc_resp = &res, }; - int ret = -ENOMEM, npages, i; + unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1; + int ret = -ENOMEM, i; size_t acl_len = 0; - npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; - /* As long as we're doing a round trip to the server anyway, - * let's be prepared for a page of acl data. */ - if (npages == 0) - npages = 1; - - /* Add an extra page to handle the bitmap returned */ - npages++; + if (npages > ARRAY_SIZE(pages)) + return -ERANGE; for (i = 0; i < npages; i++) { pages[i] = alloc_page(GFP_KERNEL); @@ -3692,10 +3687,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl .rpc_argp = &arg, .rpc_resp = &res, }; + unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE); int ret, i; if (!nfs4_server_supports_acls(server)) return -EOPNOTSUPP; + if (npages > ARRAY_SIZE(pages)) + return -ERANGE; i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); if (i < 0) return i; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4479f66f8a73..b6dbf70099b0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -149,8 +149,10 @@ static int nfs4_stat_to_errno(int); open_owner_id_maxsz + \ encode_opentype_maxsz + \ encode_claim_null_maxsz) +#define decode_space_limit_maxsz (3) #define decode_ace_maxsz (3 + nfs4_owner_maxsz) #define decode_delegation_maxsz (1 + decode_stateid_maxsz + 1 + \ + decode_space_limit_maxsz + \ decode_ace_maxsz) #define decode_change_info_maxsz (5) #define decode_open_maxsz (op_decode_hdr_maxsz + \ diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 43f46cd9edea..7b382f82d946 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -354,6 +354,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, { unsigned int len, v, hdr, dlen; u32 max_blocksize = svc_max_payload(rqstp); + struct kvec *head = rqstp->rq_arg.head; if (!(p = decode_fh(p, &args->fh))) return 0; @@ -362,6 +363,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, args->count = ntohl(*p++); args->stable = ntohl(*p++); len = args->len = ntohl(*p++); + if ((void *)p > head->iov_base + head->iov_len) + return 0; /* * The count must equal the amount of data passed. */ @@ -372,9 +375,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, * Check to make sure that we got the right number of * bytes. */ - hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; - dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len - - hdr; + hdr = (void*)p - head->iov_base; + dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; /* * Round the length of the data which was specified up to * the next multiple of XDR units and then compare that @@ -391,7 +393,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, len = args->len = max_blocksize; } rqstp->rq_vec[0].iov_base = (void*)p; - rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; + rqstp->rq_vec[0].iov_len = head->iov_len - hdr; v = 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; @@ -467,6 +469,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, /* first copy and check from the first page */ old = (char*)p; vec = &rqstp->rq_arg.head[0]; + if ((void *)old > vec->iov_base + vec->iov_len) + return 0; avail = vec->iov_len - (old - (char*)vec->iov_base); while (len && avail && *old) { *new++ = *old++; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 7595582f55e7..2bc1a6abd371 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -561,6 +561,37 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) return nfserr; } +/* + * A write procedure can have a large argument, and a read procedure can + * have a large reply, but no NFSv2 or NFSv3 procedure has argument and + * reply that can both be larger than a page. The xdr code has taken + * advantage of this assumption to be a sloppy about bounds checking in + * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that + * problem, we enforce these assumptions here: + */ +static bool nfs_request_too_big(struct svc_rqst *rqstp, + struct svc_procedure *proc) +{ + /* + * The ACL code has more careful bounds-checking and is not + * susceptible to this problem: + */ + if (rqstp->rq_prog != NFS_PROGRAM) + return false; + /* + * Ditto NFSv4 (which can in theory have argument and reply both + * more than a page): + */ + if (rqstp->rq_vers >= 4) + return false; + /* The reply will be small, we're OK: */ + if (proc->pc_xdrressize > 0 && + proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) + return false; + + return rqstp->rq_arg.len > PAGE_SIZE; +} + int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { @@ -573,6 +604,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) rqstp->rq_vers, rqstp->rq_proc); proc = rqstp->rq_procinfo; + if (nfs_request_too_big(rqstp, proc)) { + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); + *statp = rpc_garbage_args; + return 1; + } /* * Give the xdr decoder a chance to change this if it wants * (necessary in the NFSv4.0 compound case) diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 65ec595e2226..830f29b2ebc2 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -277,6 +277,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_writeargs *args) { unsigned int len, hdr, dlen; + struct kvec *head = rqstp->rq_arg.head; int v; if (!(p = decode_fh(p, &args->fh))) @@ -296,9 +297,10 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, * Check to make sure that we got the right number of * bytes. */ - hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; - dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len - - hdr; + hdr = (void*)p - head->iov_base; + if (hdr > head->iov_len) + return 0; + dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; /* * Round the length of the data which was specified up to @@ -312,7 +314,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, return 0; rqstp->rq_vec[0].iov_base = (void*)p; - rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; + rqstp->rq_vec[0].iov_len = head->iov_len - hdr; v = 0; while (len > rqstp->rq_vec[v].iov_len) { len -= rqstp->rq_vec[v].iov_len; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 855e3f80e4e1..acabafd9d0e0 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -409,7 +409,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, __be32 err; int host_err; bool get_write_count; - int size_change = 0; + bool size_change = (iap->ia_valid & ATTR_SIZE); if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; @@ -422,11 +422,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); if (err) - goto out; + return err; if (get_write_count) { host_err = fh_want_write(fhp); if (host_err) - return nfserrno(host_err); + goto out; } dentry = fhp->fh_dentry; @@ -437,26 +437,24 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, iap->ia_valid &= ~ATTR_MODE; if (!iap->ia_valid) - goto out; + return 0; nfsd_sanitize_attrs(dentry, iap); + if (check_guard && guardtime != inode->i_ctime.tv_sec) + return nfserr_notsync; + /* * The size case is special, it changes the file in addition to the - * attributes. + * attributes, and file systems don't expect it to be mixed with + * "random" attribute changes. We thus split out the size change + * into a separate call to ->setattr, and do the rest as a separate + * setattr call. */ - if (iap->ia_valid & ATTR_SIZE) { + if (size_change) { err = nfsd_get_write_access(rqstp, fhp, iap); if (err) - goto out; - size_change = 1; - } - - iap->ia_valid |= ATTR_CTIME; - - if (check_guard && guardtime != inode->i_ctime.tv_sec) { - err = nfserr_notsync; - goto out_put_write_access; + return err; } host_err = nfsd_break_lease(inode); @@ -464,18 +462,45 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, goto out_put_write_access_nfserror; fh_lock(fhp); + if (size_change) { + /* + * RFC5661, Section 18.30.4: + * Changing the size of a file with SETATTR indirectly + * changes the time_modify and change attributes. + * + * (and similar for the older RFCs) + */ + struct iattr size_attr = { + .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME, + .ia_size = iap->ia_size, + }; + + host_err = notify_change(dentry, &size_attr); + if (host_err) + goto out_unlock; + iap->ia_valid &= ~ATTR_SIZE; + + /* + * Avoid the additional setattr call below if the only other + * attribute that the client sends is the mtime, as we update + * it as part of the size change above. + */ + if ((iap->ia_valid & ~ATTR_MTIME) == 0) + goto out_unlock; + } + + iap->ia_valid |= ATTR_CTIME; host_err = notify_change(dentry, iap); - fh_unlock(fhp); +out_unlock: + fh_unlock(fhp); out_put_write_access_nfserror: - err = nfserrno(host_err); -out_put_write_access: if (size_change) put_write_access(inode); - if (!err) - commit_metadata(fhp); out: - return err; + if (!host_err) + commit_metadata(fhp); + return nfserrno(host_err); } #if defined(CONFIG_NFSD_V2_ACL) || \ diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 5bfad8c80595..7bdb81267d44 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -149,6 +149,16 @@ static inline struct ahash_instance *ahash_alloc_instance( return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); } +static inline void ahash_request_complete(struct ahash_request *req, int err) +{ + req->base.complete(&req->base, err); +} + +static inline u32 ahash_request_flags(struct ahash_request *req) +{ + return req->base.flags; +} + static inline struct crypto_ahash *crypto_spawn_ahash( struct crypto_ahash_spawn *spawn) { diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index ff9abff55aa0..92f64c413c3d 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -348,7 +348,8 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp) static inline int nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2) { - return fl1->fl_pid == fl2->fl_pid + return fl1->fl_file->f_dentry->d_inode == fl2->fl_file->f_dentry->d_inode + && fl1->fl_pid == fl2->fl_pid && fl1->fl_owner == fl2->fl_owner && fl1->fl_start == fl2->fl_start && fl1->fl_end == fl2->fl_end diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index d44a56388a3e..16c3d316ea06 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -137,12 +137,12 @@ struct ib_sa_path_rec { union ib_gid sgid; __be16 dlid; __be16 slid; - int raw_traffic; + u8 raw_traffic; /* reserved */ __be32 flow_label; u8 hop_limit; u8 traffic_class; - int reversible; + u8 reversible; u8 numb_path; __be16 pkey; __be16 qos_class; @@ -193,7 +193,7 @@ struct ib_sa_mcmember_rec { u8 hop_limit; u8 scope; u8 join_state; - int proxy_join; + u8 proxy_join; }; /* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */ diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ca7396e4aff4..4c4df05276f8 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1100,7 +1100,7 @@ void trace_find_cmdline(int pid, char comm[]) arch_spin_lock(&trace_cmdline_lock); map = map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) - strcpy(comm, saved_cmdlines[map]); + strlcpy(comm, saved_cmdlines[map], TASK_COMM_LEN); else strcpy(comm, "<...>"); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a72fa33b31cd..c55593549cc9 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1446,7 +1446,6 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy, asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask, compat_ulong_t maxnode) { - long err = 0; unsigned long __user *nm = NULL; unsigned long nr_bits, alloc_size; DECLARE_BITMAP(bm, MAX_NUMNODES); @@ -1455,14 +1454,13 @@ asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask, alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8; if (nmask) { - err = compat_get_bitmap(bm, nmask, nr_bits); + if (compat_get_bitmap(bm, nmask, nr_bits)) + return -EFAULT; nm = compat_alloc_user_space(alloc_size); - err |= copy_to_user(nm, bm, alloc_size); + if (copy_to_user(nm, bm, alloc_size)) + return -EFAULT; } - if (err) - return -EFAULT; - return sys_set_mempolicy(mode, nm, nr_bits+1); } @@ -1470,7 +1468,6 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, compat_ulong_t mode, compat_ulong_t __user *nmask, compat_ulong_t maxnode, compat_ulong_t flags) { - long err = 0; unsigned long __user *nm = NULL; unsigned long nr_bits, alloc_size; nodemask_t bm; @@ -1479,14 +1476,13 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8; if (nmask) { - err = compat_get_bitmap(nodes_addr(bm), nmask, nr_bits); + if (compat_get_bitmap(nodes_addr(bm), nmask, nr_bits)) + return -EFAULT; nm = compat_alloc_user_space(alloc_size); - err |= copy_to_user(nm, nodes_addr(bm), alloc_size); + if (copy_to_user(nm, nodes_addr(bm), alloc_size)) + return -EFAULT; } - if (err) - return -EFAULT; - return sys_mbind(start, len, mode, nm, nr_bits+1, flags); } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 98607e19533e..4cdfa448f8e3 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1032,9 +1032,15 @@ static void __net_exit dccp_v4_exit_net(struct net *net) inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); } +static void __net_exit dccp_v4_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&dccp_hashinfo, &dccp_death_row, AF_INET); +} + static struct pernet_operations dccp_v4_ops = { .init = dccp_v4_init_net, .exit = dccp_v4_exit_net, + .exit_batch = dccp_v4_exit_batch, }; static int __init dccp_v4_init(void) diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index e10d8512d431..c008823aaadb 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -499,6 +499,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newsk->sk_backlog_rcv = dccp_v4_do_rcv; newnp->pktoptions = NULL; newnp->opt = NULL; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; @@ -574,6 +577,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, /* Clone RX bits */ newnp->rxopt.all = np->rxopt.all; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; /* Clone pktoptions received with SYN */ newnp->pktoptions = NULL; if (ireq6->pktopts != NULL) { @@ -1157,9 +1163,15 @@ static void __net_exit dccp_v6_exit_net(struct net *net) inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); } +static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&dccp_hashinfo, &dccp_death_row, AF_INET6); +} + static struct pernet_operations dccp_v6_ops = { .init = dccp_v6_init_net, .exit = dccp_v6_exit_net, + .exit_batch = dccp_v6_exit_batch, }; static int __init dccp_v6_init(void) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 907ef2ce9e55..a6988e710ee9 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -604,6 +604,8 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; newsk->sk_write_space = sk_stream_write_space; + inet_sk(newsk)->mc_list = NULL; + newicsk->icsk_retransmits = 0; newicsk->icsk_backoff = 0; newicsk->icsk_probes_out = 0; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 94248624e261..dac4aeea39b0 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -135,16 +135,17 @@ static void ping_v4_hash(struct sock *sk) static void ping_v4_unhash(struct sock *sk) { struct inet_sock *isk = inet_sk(sk); + pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); + write_lock_bh(&ping_table.lock); if (sk_hashed(sk)) { - write_lock_bh(&ping_table.lock); hlist_nulls_del(&sk->sk_nulls_node); sk_nulls_node_init(&sk->sk_nulls_node); sock_put(sk); isk->inet_num = isk->inet_sport = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&ping_table.lock); } + write_unlock_bh(&ping_table.lock); } static struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 86578237ee6c..b0e4fb8ef93d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -785,7 +785,6 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) const struct inet6_protocol *ops; int proto; struct frag_hdr *fptr; - unsigned int unfrag_ip6hlen; u8 *prevhdr; int offset = 0; @@ -824,9 +823,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) ipv6h->payload_len = htons(skb->len - skb->mac_len - sizeof(*ipv6h)); if (proto == IPPROTO_UDP) { - unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + int err = ip6_find_1stfragopt(skb, &prevhdr); + if (err < 0) + return ERR_PTR(err); fptr = (struct frag_hdr *)(skb_network_header(skb) + - unfrag_ip6hlen); + err); fptr->frag_off = htons(offset); if (skb->next != NULL) fptr->frag_off |= htons(IP6_MF); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c59f646a7d4f..4ce3e3f32802 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -562,13 +562,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); - struct ipv6_opt_hdr *exthdr = - (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); unsigned int packet_len = skb->tail - skb->network_header; int found_rhdr = 0; *nexthdr = &ipv6_hdr(skb)->nexthdr; - while (offset + 1 <= packet_len) { + while (offset <= packet_len) { + struct ipv6_opt_hdr *exthdr; switch (**nexthdr) { @@ -589,13 +588,16 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } - offset += ipv6_optlen(exthdr); - *nexthdr = &exthdr->nexthdr; + if (offset + sizeof(struct ipv6_opt_hdr) > packet_len) + return -EINVAL; + exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + offset); + offset += ipv6_optlen(exthdr); + *nexthdr = &exthdr->nexthdr; } - return offset; + return -EINVAL; } void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) @@ -629,7 +631,10 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) u8 *prevhdr, nexthdr = 0; struct net *net = dev_net(skb_dst(skb)->dev); - hlen = ip6_find_1stfragopt(skb, &prevhdr); + err = ip6_find_1stfragopt(skb, &prevhdr); + if (err < 0) + goto fail; + hlen = err; nexthdr = *prevhdr; mtu = ip6_skb_dst_mtu(skb); @@ -1411,6 +1416,11 @@ alloc_new_skb: */ alloclen += sizeof(struct frag_hdr); + copy = datalen - transhdrlen - fraggap; + if (copy < 0) { + err = -EINVAL; + goto error; + } if (transhdrlen) { skb = sock_alloc_send_skb(sk, alloclen + hh_len, @@ -1462,13 +1472,9 @@ alloc_new_skb: data += fraggap; pskb_trim_unique(skb_prev, maxfraglen); } - copy = datalen - transhdrlen - fraggap; - - if (copy < 0) { - err = -EINVAL; - kfree_skb(skb); - goto error; - } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { + if (copy > 0 && + getfrag(from, data + transhdrlen, offset, + copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); goto error; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2c2d71123251..f0a1b0b247a6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1386,6 +1386,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->af_specific = &tcp_sock_ipv6_mapped_specific; #endif + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; newnp->pktoptions = NULL; @@ -1451,6 +1452,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, First: no IPv4 options. */ newinet->inet_opt = NULL; + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 03a7ed110a1b..5f0d519eb9a0 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1316,6 +1316,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) u8 frag_hdr_sz = sizeof(struct frag_hdr); int offset; __wsum csum; + int err; mss = skb_shinfo(skb)->gso_size; if (unlikely(skb->len <= mss)) @@ -1352,7 +1353,10 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) /* Find the unfragmentable header and shift it left by frag_hdr_sz * bytes to insert fragment header. */ - unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + err = ip6_find_1stfragopt(skb, &prevhdr); + if (err < 0) + return ERR_PTR(err); + unfrag_ip6hlen = err; nexthdr = *prevhdr; *prevhdr = NEXTHDR_FRAGMENT; unfrag_len = skb_network_header(skb) - skb_mac_header(skb) + diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 8c06a5065772..a26ed1ea058a 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1194,11 +1194,10 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) sipx->sipx_network = ipxif->if_netnum; memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node)); - rc = -EFAULT; + rc = 0; if (copy_to_user(arg, &ifr, sizeof(ifr))) - break; + rc = -EFAULT; ipxitf_put(ipxif); - rc = 0; break; } case SIOCAIPXITFCRT: diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d60ca88c22f8..e961773a4138 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -195,6 +195,7 @@ struct tpacket_kbdq_core { char *pkblk_start; char *pkblk_end; int kblk_size; + unsigned int max_frame_len; unsigned int knum_blocks; uint64_t knxt_seq_num; char *prev; @@ -616,6 +617,7 @@ static void init_prb_bdqc(struct packet_sock *po, p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov); p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv; + p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv); prb_init_ft_ops(p1, req_u); prb_setup_retire_blk_timer(po, tx_ring); prb_open_block(p1, pbd); @@ -1775,6 +1777,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if ((int)snaplen < 0) snaplen = 0; } + } else if (unlikely(macoff + snaplen > + GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) { + u32 nval; + + nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff; + pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n", + snaplen, nval, macoff); + snaplen = nval; + if (unlikely((int)snaplen < 0)) { + snaplen = 0; + macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len; + } } spin_lock(&sk->sk_receive_queue.lock); h.raw = packet_current_rx_frame(po, skb, @@ -3122,6 +3136,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + if (val > INT_MAX) + return -EINVAL; po->tp_reserve = val; return 0; } @@ -3622,6 +3638,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) goto out; + if (po->tp_version >= TPACKET_V3 && + req->tp_block_size <= + BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) + goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) goto out; @@ -3631,6 +3651,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, rb->frames_per_block = req->tp_block_size/req->tp_frame_size; if (unlikely(rb->frames_per_block <= 0)) goto out; + if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) + goto out; if (unlikely((rb->frames_per_block * req->tp_block_nr) != req->tp_frame_nr)) goto out; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 93fdf131bd75..943e1c5ae90d 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -807,10 +807,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, goto nla_put_failure; err = a->ops->walk(skb, &dcb, RTM_DELACTION, a); - if (err < 0) + if (err <= 0) goto nla_put_failure; - if (err == 0) - goto noflush_out; nla_nest_end(skb, nest); @@ -829,7 +827,6 @@ nla_put_failure: nlmsg_failure: module_put(a->ops->owner); err_out: -noflush_out: kfree_skb(skb); kfree(a); return err; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 428fa6f69bd8..762b61d84ac1 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -655,6 +655,9 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, newnp = inet6_sk(newsk); memcpy(newnp, np, sizeof(struct ipv6_pinfo)); + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; rcu_read_lock(); opt = rcu_dereference(np->opt); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 09542248f72b..bd26a97bcc03 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -390,7 +390,14 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es up = nla_data(rp); ulen = xfrm_replay_state_esn_len(up); - if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) + /* Check the overall length and the internal bitmap length to avoid + * potential overflow. */ + if (nla_len(rp) < ulen || + xfrm_replay_state_esn_len(replay_esn) != ulen || + replay_esn->bmp_len != up->bmp_len) + return -EINVAL; + + if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) return -EINVAL; return 0; diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 7c5d1d864c1b..720eb8164d2b 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -428,7 +428,7 @@ static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, static struct key *request_master_key(struct encrypted_key_payload *epayload, u8 **master_key, size_t *master_keylen) { - struct key *mkey = NULL; + struct key *mkey = ERR_PTR(-EINVAL); if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 234ce300a96f..b9073ebd0817 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -75,6 +75,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; + } else if ((description[0] == '.') && + (strncmp(type, "keyring", 7) == 0)) { + ret = -EPERM; + goto error2; } /* pull the payload in if one was supplied */ @@ -259,7 +263,8 @@ error: * Create and join an anonymous session keyring or join a named session * keyring, creating it if necessary. A named session keyring must have Search * permission for it to be joined. Session keyrings without this permit will - * be skipped over. + * be skipped over. It is not permitted for userspace to create or join + * keyrings whose name begin with a dot. * * If successful, the ID of the joined session keyring will be returned. */ @@ -276,12 +281,16 @@ long keyctl_join_session_keyring(const char __user *_name) ret = PTR_ERR(name); goto error; } + + ret = -EPERM; + if (name[0] == '.') + goto error_name; } /* join the session */ ret = join_session_keyring(name); +error_name: kfree(name); - error: return ret; } @@ -1174,8 +1183,8 @@ error: * Read or set the default keyring in which request_key() will cache keys and * return the old setting. * - * If a process keyring is specified then this will be created if it doesn't - * yet exist. The old setting will be returned if successful. + * If a thread or process keyring is specified then it will be created if it + * doesn't yet exist. The old setting will be returned if successful. */ long keyctl_set_reqkey_keyring(int reqkey_defl) { @@ -1200,11 +1209,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) case KEY_REQKEY_DEFL_PROCESS_KEYRING: ret = install_process_keyring_to_cred(new); - if (ret < 0) { - if (ret != -EEXIST) - goto error; - ret = 0; - } + if (ret < 0) + goto error; goto set; case KEY_REQKEY_DEFL_DEFAULT: diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 60d0df722dd6..fe5719f793da 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -121,13 +121,18 @@ error: } /* - * Install a fresh thread keyring directly to new credentials. This keyring is - * allowed to overrun the quota. + * Install a thread keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ int install_thread_keyring_to_cred(struct cred *new) { struct key *keyring; + if (new->thread_keyring) + return 0; + keyring = keyring_alloc("_tid", new->uid, new->gid, new, KEY_ALLOC_QUOTA_OVERRUN, NULL); if (IS_ERR(keyring)) @@ -138,7 +143,9 @@ int install_thread_keyring_to_cred(struct cred *new) } /* - * Install a fresh thread keyring, discarding the old one. + * Install a thread keyring to the current task if it didn't have one already. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ static int install_thread_keyring(void) { @@ -149,8 +156,6 @@ static int install_thread_keyring(void) if (!new) return -ENOMEM; - BUG_ON(new->thread_keyring); - ret = install_thread_keyring_to_cred(new); if (ret < 0) { abort_creds(new); @@ -161,10 +166,10 @@ static int install_thread_keyring(void) } /* - * Install a process keyring directly to a credentials struct. + * Install a process keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. * - * Returns -EEXIST if there was already a process keyring, 0 if one installed, - * and other value on any other error + * Return: 0 if a process keyring is now present; -errno on failure. */ int install_process_keyring_to_cred(struct cred *new) { @@ -172,7 +177,7 @@ int install_process_keyring_to_cred(struct cred *new) int ret; if (new->tgcred->process_keyring) - return -EEXIST; + return 0; keyring = keyring_alloc("_pid", new->uid, new->gid, new, KEY_ALLOC_QUOTA_OVERRUN, NULL); @@ -193,11 +198,9 @@ int install_process_keyring_to_cred(struct cred *new) } /* - * Make sure a process keyring is installed for the current process. The - * existing process keyring is not replaced. + * Install a process keyring to the current task if it didn't have one already. * - * Returns 0 if there is a process keyring by the end of this function, some - * error otherwise. + * Return: 0 if a process keyring is now present; -errno on failure. */ static int install_process_keyring(void) { @@ -211,14 +214,18 @@ static int install_process_keyring(void) ret = install_process_keyring_to_cred(new); if (ret < 0) { abort_creds(new); - return ret != -EEXIST ? ret : 0; + return ret; } return commit_creds(new); } /* - * Install a session keyring directly to a credentials struct. + * Install the given keyring as the session keyring of the given credentials + * struct, replacing the existing one if any. If the given keyring is NULL, + * then install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) { @@ -258,8 +265,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) } /* - * Install a session keyring, discarding the old one. If a keyring is not - * supplied, an empty one is invented. + * Install the given keyring as the session keyring of the current task, + * replacing the existing one if any. If the given keyring is NULL, then + * install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ static int install_session_keyring(struct key *keyring) { diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 0d75afa786bc..118481839d46 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -137,6 +137,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, f->tail = cell; if (f->head == NULL) f->head = cell; + cell->next = NULL; f->cells++; spin_unlock_irqrestore(&f->lock, flags); @@ -216,6 +217,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, spin_lock_irqsave(&f->lock, flags); cell->next = f->head; f->head = cell; + if (!f->tail) + f->tail = cell; f->cells++; spin_unlock_irqrestore(&f->lock, flags); } diff --git a/sound/core/timer.c b/sound/core/timer.c index 5628b6548d18..87edf12a1025 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1669,9 +1669,21 @@ static int snd_timer_user_params(struct file *file, return -EBADFD; if (copy_from_user(¶ms, _params, sizeof(params))) return -EFAULT; - if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) { - err = -EINVAL; - goto _end; + if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { + u64 resolution; + + if (params.ticks < 1) { + err = -EINVAL; + goto _end; + } + + /* Don't allow resolution less than 1ms */ + resolution = snd_timer_resolution(tu->timeri); + resolution *= params.ticks; + if (resolution < 1000000) { + err = -EINVAL; + goto _end; + } } if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) { diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index a7df19791f5a..1885bfe6ff7b 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -27,12 +27,6 @@ #include "cthw20k1.h" #include "ct20k1reg.h" -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - struct hw20k1 { struct hw hw; spinlock_t reg_20k1_lock; @@ -1903,19 +1897,18 @@ static int hw_card_start(struct hw *hw) { int err; struct pci_dev *pci = hw->pci; + const unsigned int dma_bits = BITS_PER_LONG; err = pci_enable_device(pci); if (err < 0) return err; /* Set DMA transfer mask */ - if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || - pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", - CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; + if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) { + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits)); + } else { + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } if (!hw->io_base) { diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index d6c54b524bfa..2c47ead1ea49 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -26,12 +26,6 @@ #include "cthw20k2.h" #include "ct20k2reg.h" -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - struct hw20k2 { struct hw hw; /* for i2c */ @@ -2026,18 +2020,18 @@ static int hw_card_start(struct hw *hw) int err = 0; struct pci_dev *pci = hw->pci; unsigned int gctl; + const unsigned int dma_bits = BITS_PER_LONG; err = pci_enable_device(pci); if (err < 0) return err; /* Set DMA transfer mask */ - if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || - pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "ctxfi: architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; + if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) { + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits)); + } else { + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } if (!hw->io_base) { diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index dec87ecb530e..47480e901423 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -36,7 +36,7 @@ There are several variants of perf script: 'perf script report <script> [args]' to run and display the results of <script>. <script> is the name displayed in the output of 'perf - trace --list' i.e. the actual script name minus any language + script --list' i.e. the actual script name minus any language extension. The perf.data output from a previous run of 'perf script record <script>' is used and should be present for this command to succeed. [args] refers to the (mainly optional) args expected by @@ -76,7 +76,7 @@ OPTIONS Any command you can specify in a shell. -D:: ---dump-raw-script=:: +--dump-raw-trace=:: Display verbose dump of the trace data. -L::
Attachment:
signature.asc
Description: Digital signature