diff options
author | 2015-08-11 22:13:21 -0400 | |
---|---|---|
committer | 2015-08-11 22:13:21 -0400 | |
commit | 1de11cdd8e7748bb66eca924f709d2055f64efe0 (patch) | |
tree | 7a7097d1c05ab726e674e737b5708fc4a9eeda3b /3.2.69/1056_linux-3.2.57.patch | |
parent | grsecurity-{3.14.49,4.1.4}-201508032312 (diff) | |
download | hardened-patchset-1de11cdd8e7748bb66eca924f709d2055f64efe0.tar.gz hardened-patchset-1de11cdd8e7748bb66eca924f709d2055f64efe0.tar.bz2 hardened-patchset-1de11cdd8e7748bb66eca924f709d2055f64efe0.zip |
grsecurity-{3.2.70,3.14.50,4.1.5}-20150810212920150810
Diffstat (limited to '3.2.69/1056_linux-3.2.57.patch')
-rw-r--r-- | 3.2.69/1056_linux-3.2.57.patch | 905 |
1 files changed, 0 insertions, 905 deletions
diff --git a/3.2.69/1056_linux-3.2.57.patch b/3.2.69/1056_linux-3.2.57.patch deleted file mode 100644 index 7b8f174..0000000 --- a/3.2.69/1056_linux-3.2.57.patch +++ /dev/null @@ -1,905 +0,0 @@ -diff --git a/Makefile b/Makefile -index ec90bfb..c92db9b 100644 ---- a/Makefile -+++ b/Makefile -@@ -1,6 +1,6 @@ - VERSION = 3 - PATCHLEVEL = 2 --SUBLEVEL = 56 -+SUBLEVEL = 57 - EXTRAVERSION = - NAME = Saber-toothed Squirrel - -diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S -index 99348c0..78be245 100644 ---- a/arch/s390/kernel/head64.S -+++ b/arch/s390/kernel/head64.S -@@ -61,7 +61,7 @@ ENTRY(startup_continue) - .quad 0 # cr12: tracing off - .quad 0 # cr13: home space segment table - .quad 0xc0000000 # cr14: machine check handling off -- .quad 0 # cr15: linkage stack operations -+ .quad .Llinkage_stack # cr15: linkage stack operations - .Lpcmsk:.quad 0x0000000180000000 - .L4malign:.quad 0xffffffffffc00000 - .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 -@@ -69,12 +69,15 @@ ENTRY(startup_continue) - .Lparmaddr: - .quad PARMAREA - .align 64 --.Lduct: .long 0,0,0,0,.Lduald,0,0,0 -+.Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0 - .long 0,0,0,0,0,0,0,0 -+.Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0 - .align 128 - .Lduald:.rept 8 - .long 0x80000000,0,0,0 # invalid access-list entries - .endr -+.Llinkage_stack: -+ .long 0,0,0x89000000,0,0,0,0x8a000000,0 - - ENTRY(_ehead) - -diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c -index f1b36cf..db2ffef 100644 ---- a/arch/x86/kvm/mmu.c -+++ b/arch/x86/kvm/mmu.c -@@ -2451,6 +2451,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, - int emulate = 0; - gfn_t pseudo_gfn; - -+ if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) -+ return 0; -+ - for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) { - if (iterator.level == level) { - unsigned pte_access = ACC_ALL; -diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c -index aac5ea7..a4f6bda 100644 ---- a/arch/x86/kvm/vmx.c -+++ b/arch/x86/kvm/vmx.c -@@ -6273,8 +6273,8 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu) - struct vcpu_vmx *vmx = to_vmx(vcpu); - - free_vpid(vmx); -- free_nested(vmx); - free_loaded_vmcs(vmx->loaded_vmcs); -+ free_nested(vmx); - kfree(vmx->guest_msrs); - kvm_vcpu_uninit(vcpu); - kmem_cache_free(kvm_vcpu_cache, vmx); -diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c -index 7be5fd9..bc35070 100644 ---- a/drivers/input/mouse/synaptics.c -+++ b/drivers/input/mouse/synaptics.c -@@ -237,11 +237,22 @@ static int synaptics_identify(struct psmouse *psmouse) - * Read touchpad resolution and maximum reported coordinates - * Resolution is left zero if touchpad does not support the query - */ -+ -+static const int *quirk_min_max; -+ - static int synaptics_resolution(struct psmouse *psmouse) - { - struct synaptics_data *priv = psmouse->private; - unsigned char resp[3]; - -+ if (quirk_min_max) { -+ priv->x_min = quirk_min_max[0]; -+ priv->x_max = quirk_min_max[1]; -+ priv->y_min = quirk_min_max[2]; -+ priv->y_max = quirk_min_max[3]; -+ return 0; -+ } -+ - if (SYN_ID_MAJOR(priv->identity) < 4) - return 0; - -@@ -1364,10 +1375,54 @@ static const struct dmi_system_id __initconst olpc_dmi_table[] = { - { } - }; - -+static const struct dmi_system_id min_max_dmi_table[] __initconst = { -+#if defined(CONFIG_DMI) -+ { -+ /* Lenovo ThinkPad Helix */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"), -+ }, -+ .driver_data = (int []){1024, 5052, 2258, 4832}, -+ }, -+ { -+ /* Lenovo ThinkPad X240 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"), -+ }, -+ .driver_data = (int []){1232, 5710, 1156, 4696}, -+ }, -+ { -+ /* Lenovo ThinkPad T440s */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"), -+ }, -+ .driver_data = (int []){1024, 5112, 2024, 4832}, -+ }, -+ { -+ /* Lenovo ThinkPad T540p */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"), -+ }, -+ .driver_data = (int []){1024, 5056, 2058, 4832}, -+ }, -+#endif -+ { } -+}; -+ - void __init synaptics_module_init(void) - { -+ const struct dmi_system_id *min_max_dmi; -+ - impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); - broken_olpc_ec = dmi_check_system(olpc_dmi_table); -+ -+ min_max_dmi = dmi_first_match(min_max_dmi_table); -+ if (min_max_dmi) -+ quirk_min_max = min_max_dmi->driver_data; - } - - int synaptics_init(struct psmouse *psmouse) -diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c -index 6729585..98ab759 100644 ---- a/drivers/net/usb/asix.c -+++ b/drivers/net/usb/asix.c -@@ -183,6 +183,17 @@ struct ax88172_int_data { - __le16 res3; - } __packed; - -+struct asix_rx_fixup_info { -+ struct sk_buff *ax_skb; -+ u32 header; -+ u16 size; -+ bool split_head; -+}; -+ -+struct asix_common_private { -+ struct asix_rx_fixup_info rx_fixup_info; -+}; -+ - static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) - { -@@ -304,97 +315,89 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - } - } - --static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -+static int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, -+ struct asix_rx_fixup_info *rx) - { -- u8 *head; -- u32 header; -- char *packet; -- struct sk_buff *ax_skb; -- u16 size; -+ int offset = 0; -+ -+ while (offset + sizeof(u16) <= skb->len) { -+ u16 remaining = 0; -+ unsigned char *data; -+ -+ if (!rx->size) { -+ if ((skb->len - offset == sizeof(u16)) || -+ rx->split_head) { -+ if(!rx->split_head) { -+ rx->header = get_unaligned_le16( -+ skb->data + offset); -+ rx->split_head = true; -+ offset += sizeof(u16); -+ break; -+ } else { -+ rx->header |= (get_unaligned_le16( -+ skb->data + offset) -+ << 16); -+ rx->split_head = false; -+ offset += sizeof(u16); -+ } -+ } else { -+ rx->header = get_unaligned_le32(skb->data + -+ offset); -+ offset += sizeof(u32); -+ } - -- head = (u8 *) skb->data; -- memcpy(&header, head, sizeof(header)); -- le32_to_cpus(&header); -- packet = head + sizeof(header); -- -- skb_pull(skb, 4); -- -- while (skb->len > 0) { -- if ((header & 0x07ff) != ((~header >> 16) & 0x07ff)) -- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); -- -- /* get the packet length */ -- size = (u16) (header & 0x000007ff); -- -- if ((skb->len) - ((size + 1) & 0xfffe) == 0) { -- u8 alignment = (unsigned long)skb->data & 0x3; -- if (alignment != 0x2) { -- /* -- * not 16bit aligned so use the room provided by -- * the 32 bit header to align the data -- * -- * note we want 16bit alignment as MAC header is -- * 14bytes thus ip header will be aligned on -- * 32bit boundary so accessing ipheader elements -- * using a cast to struct ip header wont cause -- * an unaligned accesses. -- */ -- u8 realignment = (alignment + 2) & 0x3; -- memmove(skb->data - realignment, -- skb->data, -- size); -- skb->data -= realignment; -- skb_set_tail_pointer(skb, size); -+ /* get the packet length */ -+ rx->size = (u16) (rx->header & 0x7ff); -+ if (rx->size != ((~rx->header >> 16) & 0x7ff)) { -+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n", -+ rx->header, offset); -+ rx->size = 0; -+ return 0; - } -- return 2; -+ rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, -+ rx->size); -+ if (!rx->ax_skb) -+ return 0; - } - -- if (size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) { -+ if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) { - netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", -- size); -- return 0; -- } -- ax_skb = skb_clone(skb, GFP_ATOMIC); -- if (ax_skb) { -- u8 alignment = (unsigned long)packet & 0x3; -- ax_skb->len = size; -- -- if (alignment != 0x2) { -- /* -- * not 16bit aligned use the room provided by -- * the 32 bit header to align the data -- */ -- u8 realignment = (alignment + 2) & 0x3; -- memmove(packet - realignment, packet, size); -- packet -= realignment; -- } -- ax_skb->data = packet; -- skb_set_tail_pointer(ax_skb, size); -- usbnet_skb_return(dev, ax_skb); -- } else { -+ rx->size); -+ kfree_skb(rx->ax_skb); - return 0; - } - -- skb_pull(skb, (size + 1) & 0xfffe); -+ if (rx->size > skb->len - offset) { -+ remaining = rx->size - (skb->len - offset); -+ rx->size = skb->len - offset; -+ } - -- if (skb->len < sizeof(header)) -- break; -+ data = skb_put(rx->ax_skb, rx->size); -+ memcpy(data, skb->data + offset, rx->size); -+ if (!remaining) -+ usbnet_skb_return(dev, rx->ax_skb); - -- head = (u8 *) skb->data; -- memcpy(&header, head, sizeof(header)); -- le32_to_cpus(&header); -- packet = head + sizeof(header); -- skb_pull(skb, 4); -+ offset += (rx->size + 1) & 0xfffe; -+ rx->size = remaining; - } - -- if (skb->len < 0) { -- netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", -- skb->len); -+ if (skb->len != offset) { -+ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n", -+ skb->len, offset); - return 0; - } -+ - return 1; - } - -+static int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb) -+{ -+ struct asix_common_private *dp = dev->driver_priv; -+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; -+ -+ return asix_rx_fixup_internal(dev, skb, rx); -+} -+ - static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) - { -@@ -1154,9 +1157,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) - dev->rx_urb_size = 2048; - } - -+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); -+ if (!dev->driver_priv) -+ return -ENOMEM; -+ - return 0; - } - -+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) -+{ -+ if (dev->driver_priv) -+ kfree(dev->driver_priv); -+} -+ - static struct ethtool_ops ax88178_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, -@@ -1489,6 +1502,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) - dev->rx_urb_size = 2048; - } - -+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); -+ if (!dev->driver_priv) -+ return -ENOMEM; -+ - return 0; - } - -@@ -1535,22 +1552,25 @@ static const struct driver_info hawking_uf200_info = { - static const struct driver_info ax88772_info = { - .description = "ASIX AX88772 USB 2.0 Ethernet", - .bind = ax88772_bind, -+ .unbind = ax88772_unbind, - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_reset, -- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, -- .rx_fixup = asix_rx_fixup, -+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, -+ .rx_fixup = asix_rx_fixup_common, - .tx_fixup = asix_tx_fixup, - }; - - static const struct driver_info ax88178_info = { - .description = "ASIX AX88178 USB 2.0 Ethernet", - .bind = ax88178_bind, -+ .unbind = ax88772_unbind, - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_reset, -- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, -- .rx_fixup = asix_rx_fixup, -+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | -+ FLAG_MULTI_PACKET, -+ .rx_fixup = asix_rx_fixup_common, - .tx_fixup = asix_tx_fixup, - }; - -diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c -index 07a7f54..6829195 100644 ---- a/drivers/staging/speakup/kobjects.c -+++ b/drivers/staging/speakup/kobjects.c -@@ -521,9 +521,9 @@ static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr, - spk_lock(flags); - - if (*punc_buf == 'd' || *punc_buf == 'r') -- x = set_mask_bits(0, var->value, 3); -+ x = spk_set_mask_bits(0, var->value, 3); - else -- x = set_mask_bits(punc_buf, var->value, 3); -+ x = spk_set_mask_bits(punc_buf, var->value, 3); - - spk_unlock(flags); - return count; -diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c -index 0d70f68..a076351 100644 ---- a/drivers/staging/speakup/main.c -+++ b/drivers/staging/speakup/main.c -@@ -2265,7 +2265,7 @@ static int __init speakup_init(void) - (var->var_id >= 0) && (var->var_id < MAXVARS); var++) - speakup_register_var(var); - for (i = 1; punc_info[i].mask != 0; i++) -- set_mask_bits(0, i, 2); -+ spk_set_mask_bits(0, i, 2); - - set_key_info(key_defaults, key_buf); - if (quiet_boot) -diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h -index 412b879..f39c0a2 100644 ---- a/drivers/staging/speakup/speakup.h -+++ b/drivers/staging/speakup/speakup.h -@@ -71,7 +71,7 @@ extern struct st_var_header *var_header_by_name(const char *name); - extern struct punc_var_t *get_punc_var(enum var_id_t var_id); - extern int set_num_var(int val, struct st_var_header *var, int how); - extern int set_string_var(const char *page, struct st_var_header *var, int len); --extern int set_mask_bits(const char *input, const int which, const int how); -+extern int spk_set_mask_bits(const char *input, const int which, const int how); - extern special_func special_handler; - extern int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key); - extern int synth_init(char *name); -diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c -index ab7de93..75eaf27 100644 ---- a/drivers/staging/speakup/varhandlers.c -+++ b/drivers/staging/speakup/varhandlers.c -@@ -267,11 +267,11 @@ int set_string_var(const char *page, struct st_var_header *var, int len) - return ret; - } - --/* set_mask_bits sets or clears the punc/delim/repeat bits, -+/* spk_set_mask_bits sets or clears the punc/delim/repeat bits, - * if input is null uses the defaults. - * values for how: 0 clears bits of chars supplied, - * 1 clears allk, 2 sets bits for chars */ --int set_mask_bits(const char *input, const int which, const int how) -+int spk_set_mask_bits(const char *input, const int which, const int how) - { - u_char *cp; - short mask = punc_info[which].mask; -diff --git a/fs/cifs/file.c b/fs/cifs/file.c -index c55808e..aa05d5e 100644 ---- a/fs/cifs/file.c -+++ b/fs/cifs/file.c -@@ -2107,7 +2107,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, - { - unsigned int written; - unsigned long num_pages, npages, i; -- size_t copied, len, cur_len; -+ size_t bytes, copied, len, cur_len; - ssize_t total_written = 0; - struct kvec *to_send; - struct page **pages; -@@ -2165,17 +2165,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, - do { - size_t save_len = cur_len; - for (i = 0; i < npages; i++) { -- copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE); -+ bytes = min_t(const size_t, cur_len, PAGE_CACHE_SIZE); - copied = iov_iter_copy_from_user(pages[i], &it, 0, -- copied); -+ bytes); - cur_len -= copied; - iov_iter_advance(&it, copied); - to_send[i+1].iov_base = kmap(pages[i]); - to_send[i+1].iov_len = copied; -+ /* -+ * If we didn't copy as much as we expected, then that -+ * may mean we trod into an unmapped area. Stop copying -+ * at that point. On the next pass through the big -+ * loop, we'll likely end up getting a zero-length -+ * write and bailing out of it. -+ */ -+ if (copied < bytes) -+ break; - } - - cur_len = save_len - cur_len; - -+ /* -+ * If we have no data to send, then that probably means that -+ * the copy above failed altogether. That's most likely because -+ * the address in the iovec was bogus. Set the rc to -EFAULT, -+ * free anything we allocated and bail out. -+ */ -+ if (!cur_len) { -+ kunmap(pages[0]); -+ if (!total_written) -+ total_written = -EFAULT; -+ break; -+ } -+ -+ /* -+ * i + 1 now represents the number of pages we actually used in -+ * the copy phase above. -+ */ -+ npages = min(npages, i + 1); -+ - do { - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file, false); -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 45778a6..dc9f0ec 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -38,6 +38,7 @@ - #include <linux/printk.h> - #include <linux/slab.h> - #include <linux/ratelimit.h> -+#include <linux/bitops.h> - - #include "ext4_jbd2.h" - #include "xattr.h" -@@ -3694,18 +3695,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) - void ext4_set_inode_flags(struct inode *inode) - { - unsigned int flags = EXT4_I(inode)->i_flags; -+ unsigned int new_fl = 0; - -- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (flags & EXT4_SYNC_FL) -- inode->i_flags |= S_SYNC; -+ new_fl |= S_SYNC; - if (flags & EXT4_APPEND_FL) -- inode->i_flags |= S_APPEND; -+ new_fl |= S_APPEND; - if (flags & EXT4_IMMUTABLE_FL) -- inode->i_flags |= S_IMMUTABLE; -+ new_fl |= S_IMMUTABLE; - if (flags & EXT4_NOATIME_FL) -- inode->i_flags |= S_NOATIME; -+ new_fl |= S_NOATIME; - if (flags & EXT4_DIRSYNC_FL) -- inode->i_flags |= S_DIRSYNC; -+ new_fl |= S_DIRSYNC; -+ set_mask_bits(&inode->i_flags, -+ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); - } - - /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ -diff --git a/include/linux/bitops.h b/include/linux/bitops.h -index fc8a3ff..87a375f 100644 ---- a/include/linux/bitops.h -+++ b/include/linux/bitops.h -@@ -168,6 +168,21 @@ static inline unsigned long __ffs64(u64 word) - - #ifdef __KERNEL__ - -+#ifndef set_mask_bits -+#define set_mask_bits(ptr, _mask, _bits) \ -+({ \ -+ const typeof(*ptr) mask = (_mask), bits = (_bits); \ -+ typeof(*ptr) old, new; \ -+ \ -+ do { \ -+ old = ACCESS_ONCE(*ptr); \ -+ new = (old & ~mask) | bits; \ -+ } while (cmpxchg(ptr, old, new) != old); \ -+ \ -+ new; \ -+}) -+#endif -+ - #ifndef find_last_bit - /** - * find_last_bit - find the last set bit in a memory region -diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h -index 85180bf..13bd6d0 100644 ---- a/include/linux/skbuff.h -+++ b/include/linux/skbuff.h -@@ -2143,6 +2143,8 @@ extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, - - extern struct sk_buff *skb_segment(struct sk_buff *skb, u32 features); - -+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); -+ - static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, - int len, void *buffer) - { -@@ -2555,5 +2557,22 @@ static inline bool skb_is_recycleable(const struct sk_buff *skb, int skb_size) - - return true; - } -+ -+/** -+ * skb_gso_network_seglen - Return length of individual segments of a gso packet -+ * -+ * @skb: GSO skb -+ * -+ * skb_gso_network_seglen is used to determine the real size of the -+ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). -+ * -+ * The MAC/L2 header is not accounted for. -+ */ -+static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) -+{ -+ unsigned int hdr_len = skb_transport_header(skb) - -+ skb_network_header(skb); -+ return hdr_len + skb_gso_transport_seglen(skb); -+} - #endif /* __KERNEL__ */ - #endif /* _LINUX_SKBUFF_H */ -diff --git a/ipc/msg.c b/ipc/msg.c -index 7385de2..25f1a61 100644 ---- a/ipc/msg.c -+++ b/ipc/msg.c -@@ -296,7 +296,9 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) - } - atomic_sub(msq->q_cbytes, &ns->msg_bytes); - security_msg_queue_free(msq); -+ ipc_lock_by_ptr(&msq->q_perm); - ipc_rcu_putref(msq); -+ ipc_unlock(&msq->q_perm); - } - - /* -diff --git a/net/core/skbuff.c b/net/core/skbuff.c -index 5d6cb54..8ac4a0f 100644 ---- a/net/core/skbuff.c -+++ b/net/core/skbuff.c -@@ -45,6 +45,8 @@ - #include <linux/in.h> - #include <linux/inet.h> - #include <linux/slab.h> -+#include <linux/tcp.h> -+#include <linux/udp.h> - #include <linux/netdevice.h> - #ifdef CONFIG_NET_CLS_ACT - #include <net/pkt_sched.h> -@@ -3181,3 +3183,26 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb) - " while LRO is enabled\n", skb->dev->name); - } - EXPORT_SYMBOL(__skb_warn_lro_forwarding); -+ -+/** -+ * skb_gso_transport_seglen - Return length of individual segments of a gso packet -+ * -+ * @skb: GSO skb -+ * -+ * skb_gso_transport_seglen is used to determine the real size of the -+ * individual segments, including Layer4 headers (TCP/UDP). -+ * -+ * The MAC/L2 or network (IP, IPv6) headers are not accounted for. -+ */ -+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) -+{ -+ const struct skb_shared_info *shinfo = skb_shinfo(skb); -+ unsigned int hdr_len; -+ -+ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) -+ hdr_len = tcp_hdrlen(skb); -+ else -+ hdr_len = sizeof(struct udphdr); -+ return hdr_len + shinfo->gso_size; -+} -+EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); -diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c -index 29a07b6..e0d9f02 100644 ---- a/net/ipv4/ip_forward.c -+++ b/net/ipv4/ip_forward.c -@@ -39,6 +39,68 @@ - #include <net/route.h> - #include <net/xfrm.h> - -+static bool ip_may_fragment(const struct sk_buff *skb) -+{ -+ return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) || -+ !skb->local_df; -+} -+ -+static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) -+{ -+ if (skb->len <= mtu || skb->local_df) -+ return false; -+ -+ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) -+ return false; -+ -+ return true; -+} -+ -+static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb) -+{ -+ unsigned int mtu; -+ -+ if (skb->local_df || !skb_is_gso(skb)) -+ return false; -+ -+ mtu = dst_mtu(skb_dst(skb)); -+ -+ /* if seglen > mtu, do software segmentation for IP fragmentation on -+ * output. DF bit cannot be set since ip_forward would have sent -+ * icmp error. -+ */ -+ return skb_gso_network_seglen(skb) > mtu; -+} -+ -+/* called if GSO skb needs to be fragmented on forward */ -+static int ip_forward_finish_gso(struct sk_buff *skb) -+{ -+ struct sk_buff *segs; -+ int ret = 0; -+ -+ segs = skb_gso_segment(skb, 0); -+ if (IS_ERR(segs)) { -+ kfree_skb(skb); -+ return -ENOMEM; -+ } -+ -+ consume_skb(skb); -+ -+ do { -+ struct sk_buff *nskb = segs->next; -+ int err; -+ -+ segs->next = NULL; -+ err = dst_output(segs); -+ -+ if (err && ret == 0) -+ ret = err; -+ segs = nskb; -+ } while (segs); -+ -+ return ret; -+} -+ - static int ip_forward_finish(struct sk_buff *skb) - { - struct ip_options * opt = &(IPCB(skb)->opt); -@@ -48,6 +110,9 @@ static int ip_forward_finish(struct sk_buff *skb) - if (unlikely(opt->optlen)) - ip_forward_options(skb); - -+ if (ip_gso_exceeds_dst_mtu(skb)) -+ return ip_forward_finish_gso(skb); -+ - return dst_output(skb); - } - -@@ -87,8 +152,7 @@ int ip_forward(struct sk_buff *skb) - if (opt->is_strictroute && opt->nexthop != rt->rt_gateway) - goto sr_failed; - -- if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && -- (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { -+ if (!ip_may_fragment(skb) && ip_exceeds_mtu(skb, dst_mtu(&rt->dst))) { - IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(dst_mtu(&rt->dst))); -diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c -index d3fde7e..cd4b529 100644 ---- a/net/ipv6/ip6_output.c -+++ b/net/ipv6/ip6_output.c -@@ -381,6 +381,17 @@ static inline int ip6_forward_finish(struct sk_buff *skb) - return dst_output(skb); - } - -+static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) -+{ -+ if (skb->len <= mtu || skb->local_df) -+ return false; -+ -+ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) -+ return false; -+ -+ return true; -+} -+ - int ip6_forward(struct sk_buff *skb) - { - struct dst_entry *dst = skb_dst(skb); -@@ -504,7 +515,7 @@ int ip6_forward(struct sk_buff *skb) - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - -- if (skb->len > mtu && !skb_is_gso(skb)) { -+ if (ip6_pkt_too_big(skb, mtu)) { - /* Again, force OUTPUT device used as source address */ - skb->dev = dst->dev; - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); -diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c -index 2e664a6..8aa94ee 100644 ---- a/net/netfilter/nf_conntrack_proto_dccp.c -+++ b/net/netfilter/nf_conntrack_proto_dccp.c -@@ -431,7 +431,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, - const char *msg; - u_int8_t state; - -- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); -+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - BUG_ON(dh == NULL); - - state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; -@@ -483,7 +483,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, - u_int8_t type, old_state, new_state; - enum ct_dccp_roles role; - -- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); -+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - BUG_ON(dh == NULL); - type = dh->dccph_type; - -@@ -575,7 +575,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, - unsigned int cscov; - const char *msg; - -- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); -+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - if (dh == NULL) { - msg = "nf_ct_dccp: short packet "; - goto out_invalid; -diff --git a/scripts/package/builddeb b/scripts/package/builddeb -index 3c6c0b1..bee55f6 100644 ---- a/scripts/package/builddeb -+++ b/scripts/package/builddeb -@@ -41,9 +41,9 @@ create_package() { - parisc*) - debarch=hppa ;; - mips*) -- debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;; -+ debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; - arm*) -- debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;; -+ debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; - *) - echo "" >&2 - echo "** ** ** WARNING ** ** **" >&2 -@@ -62,7 +62,7 @@ create_package() { - fi - - # Create the package -- dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir" -+ dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" - dpkg --build "$pdir" .. - } - -@@ -105,12 +105,12 @@ fi - if [ "$ARCH" = "um" ] ; then - $MAKE linux - cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map" -- cp .config "$tmpdir/usr/share/doc/$packagename/config" -+ cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config" - gzip "$tmpdir/usr/share/doc/$packagename/config" - cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version" - else - cp System.map "$tmpdir/boot/System.map-$version" -- cp .config "$tmpdir/boot/config-$version" -+ cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version" - # Not all arches include the boot path in KBUILD_IMAGE - if [ -e $KBUILD_IMAGE ]; then - cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" -@@ -119,7 +119,7 @@ else - fi - fi - --if grep -q '^CONFIG_MODULES=y' .config ; then -+if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then - INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install - if [ "$ARCH" = "um" ] ; then - mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/" -@@ -240,21 +240,21 @@ fi - # Build header package - (cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") - (cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") --(cd $objtree; find .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") -+(cd $objtree; find Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") - destdir=$kernel_headers_dir/usr/src/linux-headers-$version - mkdir -p "$destdir" - (cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) - (cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -) -+(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be - rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" --arch=$(dpkg --print-architecture) - - cat <<EOF >> debian/control - - Package: $kernel_headers_packagename - Provides: linux-headers, linux-headers-2.6 --Architecture: $arch --Description: Linux kernel headers for $KERNELRELEASE on $arch -- This package provides kernel header files for $KERNELRELEASE on $arch -+Architecture: any -+Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch} -+ This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch} - . - This is useful for people who need to build external modules - EOF |