diff options
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1094_linux-3.10.95.patch | 1222 |
2 files changed, 1226 insertions, 0 deletions
diff --git a/0000_README b/0000_README index a9b48f65..0edba9c0 100644 --- a/0000_README +++ b/0000_README @@ -418,6 +418,10 @@ Patch: 1093_linux-3.10.94.patch From: http://www.kernel.org Desc: Linux 3.10.94 +Patch: 1094_linux-3.10.95.patch +From: http://www.kernel.org +Desc: Linux 3.10.95 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1094_linux-3.10.95.patch b/1094_linux-3.10.95.patch new file mode 100644 index 00000000..199647cd --- /dev/null +++ b/1094_linux-3.10.95.patch @@ -0,0 +1,1222 @@ +diff --git a/Makefile b/Makefile +index f73ae0748cbc..eb120001bc12 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 94 ++SUBLEVEL = 95 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c +index 0f3e3047e29c..14ca13a0698b 100644 +--- a/drivers/firewire/ohci.c ++++ b/drivers/firewire/ohci.c +@@ -3670,6 +3670,11 @@ static int pci_probe(struct pci_dev *dev, + + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); + ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); ++ /* JMicron JMB38x often shows 0 at first read, just ignore it */ ++ if (!ohci->it_context_support) { ++ ohci_notice(ohci, "overriding IsoXmitIntMask\n"); ++ ohci->it_context_support = 0xf; ++ } + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); + ohci->it_context_mask = ohci->it_context_support; + ohci->n_it = hweight32(ohci->it_context_mask); +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +index 11cdf1d43041..297c3e5ec3f3 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +@@ -1016,13 +1016,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) + sizeof(struct atl1c_recv_ret_status) * rx_desc_count + + 8 * 4; + +- ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, +- &ring_header->dma); ++ ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size, ++ &ring_header->dma, GFP_KERNEL); + if (unlikely(!ring_header->desc)) { +- dev_err(&pdev->dev, "pci_alloc_consistend failed\n"); ++ dev_err(&pdev->dev, "could not get memory for DMA buffer\n"); + goto err_nomem; + } +- memset(ring_header->desc, 0, ring_header->size); + /* init TPD ring */ + + tpd_ring[0].dma = roundup(ring_header->dma, 8); +diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c +index e29fe8dbd226..b93a0fb17236 100644 +--- a/drivers/net/ethernet/renesas/sh_eth.c ++++ b/drivers/net/ethernet/renesas/sh_eth.c +@@ -1421,6 +1421,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) + desc_status >>= 16; + #endif + ++ skb = mdp->rx_skbuff[entry]; + if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | + RD_RFS5 | RD_RFS6 | RD_RFS10)) { + ndev->stats.rx_errors++; +@@ -1436,12 +1437,11 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) + ndev->stats.rx_missed_errors++; + if (desc_status & RD_RFS10) + ndev->stats.rx_over_errors++; +- } else { ++ } else if (skb) { + if (!mdp->cd->hw_swap) + sh_eth_soft_swap( + phys_to_virt(ALIGN(rxdesc->addr, 4)), + pkt_len + 2); +- skb = mdp->rx_skbuff[entry]; + mdp->rx_skbuff[entry] = NULL; + if (mdp->cd->rpadir) + skb_reserve(skb, NET_IP_ALIGN); +diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c +index f8c90ea75108..7a1ff5797f12 100644 +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -848,7 +848,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = { + { PHY_ID_BCM5421, 0xfffffff0 }, + { PHY_ID_BCM5461, 0xfffffff0 }, + { PHY_ID_BCM5464, 0xfffffff0 }, +- { PHY_ID_BCM5482, 0xfffffff0 }, ++ { PHY_ID_BCM5481, 0xfffffff0 }, + { PHY_ID_BCM5482, 0xfffffff0 }, + { PHY_ID_BCM50610, 0xfffffff0 }, + { PHY_ID_BCM50610M, 0xfffffff0 }, +diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c +index 0d5a5faaf83b..9a423435039a 100644 +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -420,6 +420,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, + struct pptp_opt *opt = &po->proto.pptp; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + lock_sock(sk); + + opt->src_addr = sp->sa_addr.pptp; +@@ -441,6 +444,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, + struct flowi4 fl4; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + if (sp->sa_protocol != PX_PROTO_PPTP) + return -EINVAL; + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 43204f4be2da..0244a1fb38f9 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -742,6 +742,7 @@ static const struct usb_device_id products[] = { + {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ + {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ + {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ ++ {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */ + {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */ + {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */ + {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */ +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 2800776b2e91..d2ea64de92df 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1726,6 +1726,11 @@ static const struct usb_device_id acm_ids[] = { + }, + #endif + ++ /* Exclude Infineon Flash Loader utility */ ++ { USB_DEVICE(0x058b, 0x0041), ++ .driver_info = IGNORE_DEVICE, ++ }, ++ + /* control interfaces without any protocol set */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_PROTO_NONE) }, +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index 85756bd36746..9b05e88d6220 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -117,7 +117,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, + USB_SS_MULT(desc->bmAttributes) > 3) { + dev_warn(ddev, "Isoc endpoint has Mult of %d in " + "config %d interface %d altsetting %d ep %d: " +- "setting to 3\n", desc->bmAttributes + 1, ++ "setting to 3\n", ++ USB_SS_MULT(desc->bmAttributes), + cfgno, inum, asnum, ep->desc.bEndpointAddress); + ep->ss_ep_comp.bmAttributes = 2; + } +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 11a073cda1d6..92873f2773fc 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -137,6 +137,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) + + static int usb_device_supports_lpm(struct usb_device *udev) + { ++ /* Some devices have trouble with LPM */ ++ if (udev->quirks & USB_QUIRK_NO_LPM) ++ return 0; ++ + /* USB 2.1 (and greater) devices indicate LPM support through + * their USB 2.0 Extended Capabilities BOS descriptor. + */ +@@ -4289,6 +4293,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, + goto fail; + } + ++ usb_detect_quirks(udev); ++ + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { + retval = usb_get_bos_descriptor(udev); + if (!retval) { +@@ -4530,7 +4536,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, + if (status < 0) + goto loop; + +- usb_detect_quirks(udev); + if (udev->quirks & USB_QUIRK_DELAY_INIT) + msleep(1000); + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index d4db4ea4a92d..94e9cddc05c1 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -182,6 +182,12 @@ static const struct usb_device_id usb_interface_quirk_list[] = { + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + ++ /* Blackmagic Design Intensity Shuttle */ ++ { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, ++ ++ /* Blackmagic Design UltraStudio SDI */ ++ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, ++ + { } /* terminating entry must be last */ + }; + +diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c +index dc31c425ce01..9f1c0538b211 100644 +--- a/drivers/usb/host/whci/qset.c ++++ b/drivers/usb/host/whci/qset.c +@@ -377,6 +377,10 @@ static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_f + if (std->pl_virt == NULL) + return -ENOMEM; + std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) { ++ kfree(std->pl_virt); ++ return -EFAULT; ++ } + + for (p = 0; p < std->num_pointers; p++) { + std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index dd84416a23cd..25522e98602e 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -132,7 +132,6 @@ static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ +- { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index f22beda91ffc..ae29b403a7e2 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1286,8 +1286,14 @@ next_slot: + num_bytes = 0; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + +- if (found_key.objectid > ino || +- found_key.type > BTRFS_EXTENT_DATA_KEY || ++ if (found_key.objectid > ino) ++ break; ++ if (WARN_ON_ONCE(found_key.objectid < ino) || ++ found_key.type < BTRFS_EXTENT_DATA_KEY) { ++ path->slots[0]++; ++ goto next_slot; ++ } ++ if (found_key.type > BTRFS_EXTENT_DATA_KEY || + found_key.offset > end) + break; + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index af1eaed96a91..a7e079749425 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -400,9 +400,13 @@ static void ext4_handle_error(struct super_block *sb) + ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); + sb->s_flags |= MS_RDONLY; + } +- if (test_opt(sb, ERRORS_PANIC)) ++ if (test_opt(sb, ERRORS_PANIC)) { ++ if (EXT4_SB(sb)->s_journal && ++ !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) ++ return; + panic("EXT4-fs (device %s): panic forced after error\n", + sb->s_id); ++ } + } + + void __ext4_error(struct super_block *sb, const char *function, +@@ -576,8 +580,12 @@ void __ext4_abort(struct super_block *sb, const char *function, + jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); + save_error_info(sb, function, line); + } +- if (test_opt(sb, ERRORS_PANIC)) ++ if (test_opt(sb, ERRORS_PANIC)) { ++ if (EXT4_SB(sb)->s_journal && ++ !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) ++ return; + panic("EXT4-fs panic from previous error\n"); ++ } + } + + void ext4_msg(struct super_block *sb, const char *prefix, const char *fmt, ...) +diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c +index 3e7ef8874ffb..644f95e7208f 100644 +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -2049,8 +2049,12 @@ static void __journal_abort_soft (journal_t *journal, int errno) + + __jbd2_journal_abort_hard(journal); + +- if (errno) ++ if (errno) { + jbd2_journal_update_sb_errno(journal); ++ write_lock(&journal->j_state_lock); ++ journal->j_flags |= JBD2_REC_ERR; ++ write_unlock(&journal->j_state_lock); ++ } + } + + /** +diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c +index e9be01b2cc5a..02c6eade0bdc 100644 +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -1503,7 +1503,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) + nfsi->attrtimeo_timestamp = now; + } + } +- invalid &= ~NFS_INO_INVALID_ATTR; ++ ++ /* Don't declare attrcache up to date if there were no attrs! */ ++ if (fattr->valid != 0) ++ invalid &= ~NFS_INO_INVALID_ATTR; ++ + /* Don't invalidate the data if we were to blame */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) + || S_ISLNK(inode->i_mode))) +diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c +index 5f8d5ffdad8f..498811c09da7 100644 +--- a/fs/nfs/nfs4client.c ++++ b/fs/nfs/nfs4client.c +@@ -32,7 +32,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) + return ret; + idr_preload(GFP_KERNEL); + spin_lock(&nn->nfs_client_lock); +- ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); ++ ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT); + if (ret >= 0) + clp->cl_cb_ident = ret; + spin_unlock(&nn->nfs_client_lock); +diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h +index 0c67c1f2a890..7d4a932305be 100644 +--- a/include/linux/jbd2.h ++++ b/include/linux/jbd2.h +@@ -977,6 +977,7 @@ struct journal_s + #define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file + * data write error in ordered + * mode */ ++#define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */ + + /* + * Function declarations for the journaling transaction and buffer +diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h +index 49587dc22f5d..41ea53c39389 100644 +--- a/include/linux/usb/quirks.h ++++ b/include/linux/usb/quirks.h +@@ -33,4 +33,7 @@ + /* device generates spurious wakeup, ignore remote wakeup capability */ + #define USB_QUIRK_IGNORE_REMOTE_WAKEUP 0x00000200 + ++/* device can't handle Link Power Management */ ++#define USB_QUIRK_NO_LPM BIT(10) ++ + #endif /* __LINUX_USB_QUIRKS_H */ +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index e927d3e80b61..686760024572 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -62,6 +62,7 @@ struct unix_sock { + #define UNIX_GC_CANDIDATE 0 + #define UNIX_GC_MAYBE_CYCLE 1 + struct socket_wq peer_wq; ++ wait_queue_t peer_wake; + }; + + static inline struct unix_sock *unix_sk(struct sock *sk) +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index 087370ff05f1..413e23be60d1 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -478,6 +478,7 @@ struct ip6_create_arg { + u32 user; + const struct in6_addr *src; + const struct in6_addr *dst; ++ int iif; + u8 ecn; + }; + +diff --git a/include/net/sock.h b/include/net/sock.h +index 95dc0c8a9dac..2317d122874e 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -352,6 +352,7 @@ struct sock { + sk_no_check : 2, + sk_userlocks : 4, + sk_protocol : 8, ++#define SK_PROTOCOL_MAX U8_MAX + sk_type : 16; + kmemcheck_bitfield_end(flags); + int sk_wmem_queued; +@@ -672,6 +673,8 @@ enum sock_flags { + SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + }; + ++#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) ++ + static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) + { + nsk->sk_flags = osk->sk_flags; +diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c +index ba6db78a02b1..69940a723abd 100644 +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -806,6 +806,9 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, + struct sock *sk; + ax25_cb *ax25; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index c9ae6b703c13..b586a3230247 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -456,6 +456,9 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le + if (!addr || addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + ++ if (addr_len < sizeof(struct sockaddr_sco)) ++ return -EINVAL; ++ + lock_sock(sk); + + if (sk->sk_state != BT_OPEN) { +diff --git a/net/core/scm.c b/net/core/scm.c +index b4da80b1cc07..dbc6bfcdf446 100644 +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -306,6 +306,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) + err = put_user(cmlen, &cm->cmsg_len); + if (!err) { + cmlen = CMSG_SPACE(i*sizeof(int)); ++ if (msg->msg_controllen < cmlen) ++ cmlen = msg->msg_controllen; + msg->msg_control += cmlen; + msg->msg_controllen -= cmlen; + } +diff --git a/net/core/sock.c b/net/core/sock.c +index af65d17517b8..5a954fccc7d3 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -419,8 +419,6 @@ static void sock_warn_obsolete_bsdism(const char *name) + } + } + +-#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) +- + static void sock_disable_timestamp(struct sock *sk, unsigned long flags) + { + if (sk->sk_flags & flags) { +diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c +index c21f200eed93..ca6106562769 100644 +--- a/net/decnet/af_decnet.c ++++ b/net/decnet/af_decnet.c +@@ -677,6 +677,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol, + { + struct sock *sk; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index c4adc319cc2e..975c369d4e6d 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -288,6 +288,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol, + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + sock->state = SS_UNCONNECTED; + + /* Look for the requested type/protocol pair. */ +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index 6f5f943ff395..b31553d385bb 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -136,7 +136,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, + struct mfc_cache *c, struct rtmsg *rtm); + static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, + int cmd); +-static void mroute_clean_tables(struct mr_table *mrt); ++static void mroute_clean_tables(struct mr_table *mrt, bool all); + static void ipmr_expire_process(unsigned long arg); + + #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES +@@ -348,7 +348,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) + static void ipmr_free_table(struct mr_table *mrt) + { + del_timer_sync(&mrt->ipmr_expire_timer); +- mroute_clean_tables(mrt); ++ mroute_clean_tables(mrt, true); + kfree(mrt); + } + +@@ -1199,7 +1199,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, + * Close the multicast socket, and clear the vif tables etc + */ + +-static void mroute_clean_tables(struct mr_table *mrt) ++static void mroute_clean_tables(struct mr_table *mrt, bool all) + { + int i; + LIST_HEAD(list); +@@ -1208,8 +1208,9 @@ static void mroute_clean_tables(struct mr_table *mrt) + /* Shut down all active vif entries */ + + for (i = 0; i < mrt->maxvif; i++) { +- if (!(mrt->vif_table[i].flags & VIFF_STATIC)) +- vif_delete(mrt, i, 0, &list); ++ if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) ++ continue; ++ vif_delete(mrt, i, 0, &list); + } + unregister_netdevice_many(&list); + +@@ -1217,7 +1218,7 @@ static void mroute_clean_tables(struct mr_table *mrt) + + for (i = 0; i < MFC_LINES; i++) { + list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { +- if (c->mfc_flags & MFC_STATIC) ++ if (!all && (c->mfc_flags & MFC_STATIC)) + continue; + list_del_rcu(&c->list); + mroute_netlink_event(mrt, c, RTM_DELROUTE); +@@ -1252,7 +1253,7 @@ static void mrtsock_destruct(struct sock *sk) + NETCONFA_IFINDEX_ALL, + net->ipv4.devconf_all); + RCU_INIT_POINTER(mrt->mroute_sk, NULL); +- mroute_clean_tables(mrt); ++ mroute_clean_tables(mrt, false); + } + } + rtnl_unlock(); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index a8be45e4d34f..f89087c3cfc8 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -5575,6 +5575,7 @@ discard: + } + + tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; ++ tp->copied_seq = tp->rcv_nxt; + tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; + + /* RFC1323: The window in SYN & SYN/ACK segments is +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index 7c3eec386a4b..11f27a45b8ef 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1015,7 +1015,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, + } + + md5sig = rcu_dereference_protected(tp->md5sig_info, +- sock_owned_by_user(sk)); ++ sock_owned_by_user(sk) || ++ lockdep_is_held(&sk->sk_lock.slock)); + if (!md5sig) { + md5sig = kmalloc(sizeof(*md5sig), gfp); + if (!md5sig) +diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c +index ab5c7ad482cd..a944f1313c5f 100644 +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -113,6 +113,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, + !inet_ehash_secret) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + /* Look for the requested type/protocol pair. */ + lookup_protocol: + err = -ESOCKTNOSUPPORT; +diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c +index bf6233cdb753..7eb7267861ac 100644 +--- a/net/ipv6/ip6_gre.c ++++ b/net/ipv6/ip6_gre.c +@@ -1541,13 +1541,11 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], + return -EEXIST; + } else { + t = nt; +- +- ip6gre_tunnel_unlink(ign, t); +- ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); +- ip6gre_tunnel_link(ign, t); +- netdev_state_change(dev); + } + ++ ip6gre_tunnel_unlink(ign, t); ++ ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); ++ ip6gre_tunnel_link(ign, t); + return 0; + } + +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index 57dd3e7d86cc..9ec416552cc5 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -120,7 +120,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, + int cmd); + static int ip6mr_rtm_dumproute(struct sk_buff *skb, + struct netlink_callback *cb); +-static void mroute_clean_tables(struct mr6_table *mrt); ++static void mroute_clean_tables(struct mr6_table *mrt, bool all); + static void ipmr_expire_process(unsigned long arg); + + #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES +@@ -337,7 +337,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) + static void ip6mr_free_table(struct mr6_table *mrt) + { + del_timer(&mrt->ipmr_expire_timer); +- mroute_clean_tables(mrt); ++ mroute_clean_tables(mrt, true); + kfree(mrt); + } + +@@ -1537,7 +1537,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, + * Close the multicast socket, and clear the vif tables etc + */ + +-static void mroute_clean_tables(struct mr6_table *mrt) ++static void mroute_clean_tables(struct mr6_table *mrt, bool all) + { + int i; + LIST_HEAD(list); +@@ -1547,8 +1547,9 @@ static void mroute_clean_tables(struct mr6_table *mrt) + * Shut down all active vif entries + */ + for (i = 0; i < mrt->maxvif; i++) { +- if (!(mrt->vif6_table[i].flags & VIFF_STATIC)) +- mif6_delete(mrt, i, &list); ++ if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) ++ continue; ++ mif6_delete(mrt, i, &list); + } + unregister_netdevice_many(&list); + +@@ -1557,7 +1558,7 @@ static void mroute_clean_tables(struct mr6_table *mrt) + */ + for (i = 0; i < MFC6_LINES; i++) { + list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) { +- if (c->mfc_flags & MFC_STATIC) ++ if (!all && (c->mfc_flags & MFC_STATIC)) + continue; + write_lock_bh(&mrt_lock); + list_del(&c->list); +@@ -1620,7 +1621,7 @@ int ip6mr_sk_done(struct sock *sk) + net->ipv6.devconf_all); + write_unlock_bh(&mrt_lock); + +- mroute_clean_tables(mrt); ++ mroute_clean_tables(mrt, false); + err = 0; + break; + } +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 734aec059ffd..7ba6180ff8bd 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1441,7 +1441,6 @@ out: + if (!err) { + ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); + ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); +- IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len); + } else { + IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); + } +@@ -1805,7 +1804,6 @@ out: + if (!err) { + ICMP6MSGOUT_INC_STATS(net, idev, type); + ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); +- IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len); + } else + IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); + +diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c +index 253566a8d55b..7cd623588532 100644 +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -172,7 +172,7 @@ static void nf_ct_frag6_expire(unsigned long data) + /* Creation primitives. */ + static inline struct frag_queue *fq_find(struct net *net, __be32 id, + u32 user, struct in6_addr *src, +- struct in6_addr *dst, u8 ecn) ++ struct in6_addr *dst, int iif, u8 ecn) + { + struct inet_frag_queue *q; + struct ip6_create_arg arg; +@@ -182,6 +182,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, + arg.user = user; + arg.src = src; + arg.dst = dst; ++ arg.iif = iif; + arg.ecn = ecn; + + read_lock_bh(&nf_frags.lock); +@@ -590,7 +591,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) + local_bh_enable(); + + fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, +- ip6_frag_ecn(hdr)); ++ skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); + if (fq == NULL) { + pr_debug("Can't find and can't create new queue\n"); + goto ret_orig; +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 1aeb473b2cc6..a1fb511da3b5 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -111,7 +111,10 @@ bool ip6_frag_match(struct inet_frag_queue *q, void *a) + return fq->id == arg->id && + fq->user == arg->user && + ipv6_addr_equal(&fq->saddr, arg->src) && +- ipv6_addr_equal(&fq->daddr, arg->dst); ++ ipv6_addr_equal(&fq->daddr, arg->dst) && ++ (arg->iif == fq->iif || ++ !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST | ++ IPV6_ADDR_LINKLOCAL))); + } + EXPORT_SYMBOL(ip6_frag_match); + +@@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data) + + static __inline__ struct frag_queue * + fq_find(struct net *net, __be32 id, const struct in6_addr *src, +- const struct in6_addr *dst, u8 ecn) ++ const struct in6_addr *dst, int iif, u8 ecn) + { + struct inet_frag_queue *q; + struct ip6_create_arg arg; +@@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, + arg.user = IP6_DEFRAG_LOCAL_DELIVER; + arg.src = src; + arg.dst = dst; ++ arg.iif = iif; + arg.ecn = ecn; + + read_lock(&ip6_frags.lock); +@@ -558,7 +562,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) + IPSTATS_MIB_REASMFAILS, evicted); + + fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, +- ip6_frag_ecn(hdr)); ++ skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); + if (fq != NULL) { + int ret; + +diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c +index a5e62ef57155..f8133ff5b081 100644 +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -1105,6 +1105,9 @@ static int irda_create(struct net *net, struct socket *sock, int protocol, + + IRDA_DEBUG(2, "%s()\n", __func__); + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (net != &init_net) + return -EAFNOSUPPORT; + +diff --git a/net/sctp/auth.c b/net/sctp/auth.c +index bc2fae7e67be..62433f797f3f 100644 +--- a/net/sctp/auth.c ++++ b/net/sctp/auth.c +@@ -812,8 +812,8 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, + if (!has_sha1) + return -EINVAL; + +- memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0], +- hmacs->shmac_num_idents * sizeof(__u16)); ++ for (i = 0; i < hmacs->shmac_num_idents; i++) ++ ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]); + ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + + hmacs->shmac_num_idents * sizeof(__u16)); + return 0; +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index 422d8bdacc0d..bee032a7003f 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -639,6 +639,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, + struct sock *newsk; + struct ipv6_pinfo *newnp, *np = inet6_sk(sk); + struct sctp6_sock *newsctp6sk; ++ struct ipv6_txoptions *opt; + + newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot); + if (!newsk) +@@ -658,6 +659,13 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, + + memcpy(newnp, np, sizeof(struct ipv6_pinfo)); + ++ rcu_read_lock(); ++ opt = rcu_dereference(np->opt); ++ if (opt) ++ opt = ipv6_dup_options(newsk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ rcu_read_unlock(); ++ + /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() + * and getpeername(). + */ +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index ec5766dc3946..80bd61ae5945 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6969,6 +6969,9 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, + newinet->mc_ttl = 1; + newinet->mc_index = 0; + newinet->mc_list = NULL; ++ ++ if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) ++ net_enable_timestamp(); + } + + static inline void sctp_copy_descendant(struct sock *sk_to, +@@ -7149,6 +7152,13 @@ struct proto sctp_prot = { + + #if IS_ENABLED(CONFIG_IPV6) + ++#include <net/transp_v6.h> ++static void sctp_v6_destroy_sock(struct sock *sk) ++{ ++ sctp_destroy_sock(sk); ++ inet6_destroy_sock(sk); ++} ++ + struct proto sctpv6_prot = { + .name = "SCTPv6", + .owner = THIS_MODULE, +@@ -7158,7 +7168,7 @@ struct proto sctpv6_prot = { + .accept = sctp_accept, + .ioctl = sctp_ioctl, + .init = sctp_init_sock, +- .destroy = sctp_destroy_sock, ++ .destroy = sctp_v6_destroy_sock, + .shutdown = sctp_shutdown, + .setsockopt = sctp_setsockopt, + .getsockopt = sctp_getsockopt, +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 825c029bf092..f934e7ba5eb8 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -313,6 +313,118 @@ found: + return s; + } + ++/* Support code for asymmetrically connected dgram sockets ++ * ++ * If a datagram socket is connected to a socket not itself connected ++ * to the first socket (eg, /dev/log), clients may only enqueue more ++ * messages if the present receive queue of the server socket is not ++ * "too large". This means there's a second writeability condition ++ * poll and sendmsg need to test. The dgram recv code will do a wake ++ * up on the peer_wait wait queue of a socket upon reception of a ++ * datagram which needs to be propagated to sleeping would-be writers ++ * since these might not have sent anything so far. This can't be ++ * accomplished via poll_wait because the lifetime of the server ++ * socket might be less than that of its clients if these break their ++ * association with it or if the server socket is closed while clients ++ * are still connected to it and there's no way to inform "a polling ++ * implementation" that it should let go of a certain wait queue ++ * ++ * In order to propagate a wake up, a wait_queue_t of the client ++ * socket is enqueued on the peer_wait queue of the server socket ++ * whose wake function does a wake_up on the ordinary client socket ++ * wait queue. This connection is established whenever a write (or ++ * poll for write) hit the flow control condition and broken when the ++ * association to the server socket is dissolved or after a wake up ++ * was relayed. ++ */ ++ ++static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags, ++ void *key) ++{ ++ struct unix_sock *u; ++ wait_queue_head_t *u_sleep; ++ ++ u = container_of(q, struct unix_sock, peer_wake); ++ ++ __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, ++ q); ++ u->peer_wake.private = NULL; ++ ++ /* relaying can only happen while the wq still exists */ ++ u_sleep = sk_sleep(&u->sk); ++ if (u_sleep) ++ wake_up_interruptible_poll(u_sleep, key); ++ ++ return 0; ++} ++ ++static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ int rc; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ rc = 0; ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (!u->peer_wake.private) { ++ u->peer_wake.private = other; ++ __add_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ ++ rc = 1; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++ return rc; ++} ++ ++static void unix_dgram_peer_wake_disconnect(struct sock *sk, ++ struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (u->peer_wake.private == other) { ++ __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ u->peer_wake.private = NULL; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++} ++ ++static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, ++ struct sock *other) ++{ ++ unix_dgram_peer_wake_disconnect(sk, other); ++ wake_up_interruptible_poll(sk_sleep(sk), ++ POLLOUT | ++ POLLWRNORM | ++ POLLWRBAND); ++} ++ ++/* preconditions: ++ * - unix_peer(sk) == other ++ * - association is stable ++ */ ++static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) ++{ ++ int connected; ++ ++ connected = unix_dgram_peer_wake_connect(sk, other); ++ ++ if (unix_recvq_full(other)) ++ return 1; ++ ++ if (connected) ++ unix_dgram_peer_wake_disconnect(sk, other); ++ ++ return 0; ++} ++ + static inline int unix_writable(struct sock *sk) + { + return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; +@@ -417,6 +529,8 @@ static void unix_release_sock(struct sock *sk, int embrion) + skpair->sk_state_change(skpair); + sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); + } ++ ++ unix_dgram_peer_wake_disconnect(sk, skpair); + sock_put(skpair); /* It may now die */ + unix_peer(sk) = NULL; + } +@@ -650,6 +764,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) + INIT_LIST_HEAD(&u->link); + mutex_init(&u->readlock); /* single task reading lock */ + init_waitqueue_head(&u->peer_wait); ++ init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); + unix_insert_socket(unix_sockets_unbound(sk), sk); + out: + if (sk == NULL) +@@ -1017,6 +1132,8 @@ restart: + if (unix_peer(sk)) { + struct sock *old_peer = unix_peer(sk); + unix_peer(sk) = other; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); ++ + unix_state_double_unlock(sk, other); + + if (other != old_peer) +@@ -1456,6 +1573,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, + struct scm_cookie tmp_scm; + int max_level; + int data_len = 0; ++ int sk_locked; + + if (NULL == siocb->scm) + siocb->scm = &tmp_scm; +@@ -1532,12 +1650,14 @@ restart: + goto out_free; + } + ++ sk_locked = 0; + unix_state_lock(other); ++restart_locked: + err = -EPERM; + if (!unix_may_send(sk, other)) + goto out_unlock; + +- if (sock_flag(other, SOCK_DEAD)) { ++ if (unlikely(sock_flag(other, SOCK_DEAD))) { + /* + * Check with 1003.1g - what should + * datagram error +@@ -1545,10 +1665,14 @@ restart: + unix_state_unlock(other); + sock_put(other); + ++ if (!sk_locked) ++ unix_state_lock(sk); ++ + err = 0; +- unix_state_lock(sk); + if (unix_peer(sk) == other) { + unix_peer(sk) = NULL; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, other); ++ + unix_state_unlock(sk); + + unix_dgram_disconnected(sk, other); +@@ -1574,21 +1698,38 @@ restart: + goto out_unlock; + } + +- if (unix_peer(other) != sk && unix_recvq_full(other)) { +- if (!timeo) { +- err = -EAGAIN; +- goto out_unlock; ++ if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { ++ if (timeo) { ++ timeo = unix_wait_for_peer(other, timeo); ++ ++ err = sock_intr_errno(timeo); ++ if (signal_pending(current)) ++ goto out_free; ++ ++ goto restart; + } + +- timeo = unix_wait_for_peer(other, timeo); ++ if (!sk_locked) { ++ unix_state_unlock(other); ++ unix_state_double_lock(sk, other); ++ } + +- err = sock_intr_errno(timeo); +- if (signal_pending(current)) +- goto out_free; ++ if (unix_peer(sk) != other || ++ unix_dgram_peer_wake_me(sk, other)) { ++ err = -EAGAIN; ++ sk_locked = 1; ++ goto out_unlock; ++ } + +- goto restart; ++ if (!sk_locked) { ++ sk_locked = 1; ++ goto restart_locked; ++ } + } + ++ if (unlikely(sk_locked)) ++ unix_state_unlock(sk); ++ + if (sock_flag(other, SOCK_RCVTSTAMP)) + __net_timestamp(skb); + maybe_add_creds(skb, sock, other); +@@ -1602,6 +1743,8 @@ restart: + return len; + + out_unlock: ++ if (sk_locked) ++ unix_state_unlock(sk); + unix_state_unlock(other); + out_free: + kfree_skb(skb); +@@ -1791,14 +1934,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, + if (flags&MSG_OOB) + goto out; + +- err = mutex_lock_interruptible(&u->readlock); +- if (unlikely(err)) { +- /* recvmsg() in non blocking mode is supposed to return -EAGAIN +- * sk_rcvtimeo is not honored by mutex_lock_interruptible() +- */ +- err = noblock ? -EAGAIN : -ERESTARTSYS; +- goto out; +- } ++ mutex_lock(&u->readlock); + + skip = sk_peek_offset(sk, flags); + +@@ -1990,12 +2126,12 @@ again: + + timeo = unix_stream_data_wait(sk, timeo, last); + +- if (signal_pending(current) +- || mutex_lock_interruptible(&u->readlock)) { ++ if (signal_pending(current)) { + err = sock_intr_errno(timeo); + goto out; + } + ++ mutex_lock(&u->readlock); + continue; + unlock: + unix_state_unlock(sk); +@@ -2260,14 +2396,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, + return mask; + + writable = unix_writable(sk); +- other = unix_peer_get(sk); +- if (other) { +- if (unix_peer(other) != sk) { +- sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); +- if (unix_recvq_full(other)) +- writable = 0; +- } +- sock_put(other); ++ if (writable) { ++ unix_state_lock(sk); ++ ++ other = unix_peer(sk); ++ if (other && unix_peer(other) != sk && ++ unix_recvq_full(other) && ++ unix_dgram_peer_wake_me(sk, other)) ++ writable = 0; ++ ++ unix_state_unlock(sk); + } + + if (writable) +diff --git a/security/keys/gc.c b/security/keys/gc.c +index 797818695c87..de34c290bd6f 100644 +--- a/security/keys/gc.c ++++ b/security/keys/gc.c +@@ -187,6 +187,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys) + kdebug("- %u", key->serial); + key_check(key); + ++ /* Throw away the key data if the key is instantiated */ ++ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && ++ !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && ++ key->type->destroy) ++ key->type->destroy(key); ++ + security_key_free(key); + + /* deal with the user's key tracking and quota */ +@@ -201,10 +207,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys) + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + atomic_dec(&key->user->nikeys); + +- /* now throw away the key memory */ +- if (key->type->destroy) +- key->type->destroy(key); +- + key_user_put(key->user); + + kfree(key->description); +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 33cfd27b4de2..3242195bfa95 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -744,16 +744,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) + + /* the key is probably readable - now try to read it */ + can_read_key: +- ret = key_validate(key); +- if (ret == 0) { +- ret = -EOPNOTSUPP; +- if (key->type->read) { +- /* read the data with the semaphore held (since we +- * might sleep) */ +- down_read(&key->sem); ++ ret = -EOPNOTSUPP; ++ if (key->type->read) { ++ /* Read the data with the semaphore held (since we might sleep) ++ * to protect against the key being updated or revoked. ++ */ ++ down_read(&key->sem); ++ ret = key_validate(key); ++ if (ret == 0) + ret = key->type->read(key, buffer, buflen); +- up_read(&key->sem); +- } ++ up_read(&key->sem); + } + + error2: +diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c +index 42defae1e161..cd871dc8b7c0 100644 +--- a/security/keys/process_keys.c ++++ b/security/keys/process_keys.c +@@ -792,6 +792,7 @@ long join_session_keyring(const char *name) + ret = PTR_ERR(keyring); + goto error2; + } else if (keyring == new->session_keyring) { ++ key_put(keyring); + ret = 0; + goto error2; + } |