From: Greg Kroah-Hartman Date: Thu, 5 Dec 2013 22:45:24 +0000 (-0800) Subject: 3.4-stable patches X-Git-Tag: v3.4.73~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=858d8b8f4cf4fac161beed60d83a1cff951a7b75;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: 6lowpan-uncompression-of-traffic-class-field-was-incorrect.patch af_packet-block-bh-in-prb_shutdown_retire_blk_timer.patch atm-idt77252-fix-dev-refcnt-leak.patch bonding-don-t-permit-to-use-arp-monitoring-in-802.3ad.patch bonding-fix-two-race-conditions-in-bond_store_updelay-downdelay.patch bridge-flush-br-s-address-entry-in-fdb-when-remove-the-bridge-dev.patch connector-improved-unaligned-access-error-fix.patch inet-fix-addr_len-msg-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch inet-fix-possible-seqlock-deadlocks.patch inet-prevent-leakage-of-uninitialized-memory-to-user-in-recv-syscalls.patch ipv4-fix-possible-seqlock-deadlock.patch ipv6-fix-leaking-uninitialized-port-number-of-offender-sockaddr.patch ipv6-fix-possible-seqlock-deadlock-in-ip6_finish_output2.patch ipv6-use-rt6_get_dflt_router-to-get-default-router-in-rt6_route_rcv.patch isdnloop-use-strlcpy-instead-of-strcpy.patch net-add-bug_on-if-kernel-advertises-msg_namelen-sizeof-struct-sockaddr_storage.patch net-clamp-msg_namelen-instead-of-returning-an-error.patch net-core-always-propagate-flag-changes-to-interfaces.patch net-fix-ip-rule-delete-table-256.patch net-rework-recvmsg-handler-msg_name-and-msg_namelen-logic.patch net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch packet-fix-use-after-free-race-in-send-path-when-dev-is-released.patch pktgen-xfrm-update-ipv4-header-total-len-and-checksum-after-tranformation.patch random32-fix-off-by-one-in-seeding-requirement.patch --- diff --git a/queue-3.4/6lowpan-uncompression-of-traffic-class-field-was-incorrect.patch b/queue-3.4/6lowpan-uncompression-of-traffic-class-field-was-incorrect.patch new file mode 100644 index 00000000000..f4fa54dc93d --- /dev/null +++ b/queue-3.4/6lowpan-uncompression-of-traffic-class-field-was-incorrect.patch @@ -0,0 +1,66 @@ +From 9166a67ae670706b04669ff50f1dd9964d13609d Mon Sep 17 00:00:00 2001 +From: Jukka Rissanen +Date: Wed, 13 Nov 2013 11:03:39 +0200 +Subject: 6lowpan: Uncompression of traffic class field was incorrect + +From: Jukka Rissanen + +[ Upstream commit 1188f05497e7bd2f2614b99c54adfbe7413d5749 ] + +If priority/traffic class field in IPv6 header is set (seen when +using ssh), the uncompression sets the TC and Flow fields incorrectly. + +Example: + +This is IPv6 header of a sent packet. Note the priority/TC (=1) in +the first byte. + +00000000: 61 00 00 00 00 2c 06 40 fe 80 00 00 00 00 00 00 +00000010: 02 02 72 ff fe c6 42 10 fe 80 00 00 00 00 00 00 +00000020: 02 1e ab ff fe 4c 52 57 + +This gets compressed like this in the sending side + +00000000: 72 31 04 06 02 1e ab ff fe 4c 52 57 ec c2 00 16 +00000010: aa 2d fe 92 86 4e be c6 .... + +In the receiving end, the packet gets uncompressed to this +IPv6 header + +00000000: 60 06 06 02 00 2a 1e 40 fe 80 00 00 00 00 00 00 +00000010: 02 02 72 ff fe c6 42 10 fe 80 00 00 00 00 00 00 +00000020: ab ff fe 4c 52 57 ec c2 + +First four bytes are set incorrectly and we have also lost +two bytes from destination address. + +The fix is to switch the case values in switch statement +when checking the TC field. + +Signed-off-by: Jukka Rissanen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ieee802154/6lowpan.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ieee802154/6lowpan.c ++++ b/net/ieee802154/6lowpan.c +@@ -803,7 +803,7 @@ lowpan_process_data(struct sk_buff *skb) + * Traffic class carried in-line + * ECN + DSCP (1 byte), Flow Label is elided + */ +- case 1: /* 10b */ ++ case 2: /* 10b */ + if (!skb->len) + goto drop; + tmp = lowpan_fetch_skb_u8(skb); +@@ -816,7 +816,7 @@ lowpan_process_data(struct sk_buff *skb) + * Flow Label carried in-line + * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided + */ +- case 2: /* 01b */ ++ case 1: /* 01b */ + if (!skb->len) + goto drop; + tmp = lowpan_fetch_skb_u8(skb); diff --git a/queue-3.4/af_packet-block-bh-in-prb_shutdown_retire_blk_timer.patch b/queue-3.4/af_packet-block-bh-in-prb_shutdown_retire_blk_timer.patch new file mode 100644 index 00000000000..c602c4b47ee --- /dev/null +++ b/queue-3.4/af_packet-block-bh-in-prb_shutdown_retire_blk_timer.patch @@ -0,0 +1,45 @@ +From 07bf91b33e8ba6a244998e1c71d57cc457976b12 Mon Sep 17 00:00:00 2001 +From: Veaceslav Falico +Date: Fri, 29 Nov 2013 09:53:23 +0100 +Subject: af_packet: block BH in prb_shutdown_retire_blk_timer() + +From: Veaceslav Falico + +[ Upstream commit ec6f809ff6f19fafba3212f6aff0dda71dfac8e8 ] + +Currently we're using plain spin_lock() in prb_shutdown_retire_blk_timer(), +however the timer might fire right in the middle and thus try to re-aquire +the same spinlock, leaving us in a endless loop. + +To fix that, use the spin_lock_bh() to block it. + +Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") +CC: "David S. Miller" +CC: Daniel Borkmann +CC: Willem de Bruijn +CC: Phil Sutter +CC: Eric Dumazet +Reported-by: Jan Stancek +Tested-by: Jan Stancek +Signed-off-by: Veaceslav Falico +Acked-by: Daniel Borkmann +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/packet/af_packet.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -504,9 +504,9 @@ static void prb_shutdown_retire_blk_time + + pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; + +- spin_lock(&rb_queue->lock); ++ spin_lock_bh(&rb_queue->lock); + pkc->delete_blk_timer = 1; +- spin_unlock(&rb_queue->lock); ++ spin_unlock_bh(&rb_queue->lock); + + prb_del_retire_blk_timer(pkc); + } diff --git a/queue-3.4/atm-idt77252-fix-dev-refcnt-leak.patch b/queue-3.4/atm-idt77252-fix-dev-refcnt-leak.patch new file mode 100644 index 00000000000..8a57085cca6 --- /dev/null +++ b/queue-3.4/atm-idt77252-fix-dev-refcnt-leak.patch @@ -0,0 +1,31 @@ +From 45ee678a710241649447c04860469c112bb9403b Mon Sep 17 00:00:00 2001 +From: Ying Xue +Date: Tue, 19 Nov 2013 18:09:27 +0800 +Subject: atm: idt77252: fix dev refcnt leak + +From: Ying Xue + +[ Upstream commit b5de4a22f157ca345cdb3575207bf46402414bc1 ] + +init_card() calls dev_get_by_name() to get a network deceive. But it +doesn't decrease network device reference count after the device is +used. + +Signed-off-by: Ying Xue +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/atm/idt77252.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/atm/idt77252.c ++++ b/drivers/atm/idt77252.c +@@ -3513,7 +3513,7 @@ init_card(struct atm_dev *dev) + tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */ + if (tmp) { + memcpy(card->atmdev->esi, tmp->dev_addr, 6); +- ++ dev_put(tmp); + printk("%s: ESI %pM\n", card->name, card->atmdev->esi); + } + /* diff --git a/queue-3.4/bonding-don-t-permit-to-use-arp-monitoring-in-802.3ad.patch b/queue-3.4/bonding-don-t-permit-to-use-arp-monitoring-in-802.3ad.patch new file mode 100644 index 00000000000..d13442fc642 --- /dev/null +++ b/queue-3.4/bonding-don-t-permit-to-use-arp-monitoring-in-802.3ad.patch @@ -0,0 +1,41 @@ +From 662e7198d3a32ead59e923430aedfe0bcbaf50fb Mon Sep 17 00:00:00 2001 +From: Veaceslav Falico +Date: Tue, 12 Nov 2013 15:37:40 +0100 +Subject: bonding: don't permit to use ARP monitoring in 802.3ad + mode + +From: Veaceslav Falico + +[ Upstream commit ec9f1d15db8185f63a2c3143dc1e90ba18541b08 ] + +Currently the ARP monitoring is not supported with 802.3ad, and it's +prohibited to use it via the module params. + +However we still can set it afterwards via sysfs, cause we only check for +*LB modes there. + +To fix this - add a check for 802.3ad mode in bonding_store_arp_interval. + +Signed-off-by: Veaceslav Falico +CC: Jay Vosburgh +CC: Andy Gospodarek +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/bonding/bond_sysfs.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/net/bonding/bond_sysfs.c ++++ b/drivers/net/bonding/bond_sysfs.c +@@ -533,8 +533,9 @@ static ssize_t bonding_store_arp_interva + goto out; + } + if (bond->params.mode == BOND_MODE_ALB || +- bond->params.mode == BOND_MODE_TLB) { +- pr_info("%s: ARP monitoring cannot be used with ALB/TLB. Only MII monitoring is supported on %s.\n", ++ bond->params.mode == BOND_MODE_TLB || ++ bond->params.mode == BOND_MODE_8023AD) { ++ pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n", + bond->dev->name, bond->dev->name); + ret = -EINVAL; + goto out; diff --git a/queue-3.4/bonding-fix-two-race-conditions-in-bond_store_updelay-downdelay.patch b/queue-3.4/bonding-fix-two-race-conditions-in-bond_store_updelay-downdelay.patch new file mode 100644 index 00000000000..469463c3e24 --- /dev/null +++ b/queue-3.4/bonding-fix-two-race-conditions-in-bond_store_updelay-downdelay.patch @@ -0,0 +1,63 @@ +From c3c1e8d01623d528a8f912fd846460f788eefaa8 Mon Sep 17 00:00:00 2001 +From: Nikolay Aleksandrov +Date: Wed, 13 Nov 2013 17:07:46 +0100 +Subject: bonding: fix two race conditions in bond_store_updelay/downdelay + +From: Nikolay Aleksandrov + +[ Upstream commit b869ccfab1e324507fa3596e3e1308444fb68227 ] + +This patch fixes two race conditions between bond_store_updelay/downdelay +and bond_store_miimon which could lead to division by zero as miimon can +be set to 0 while either updelay/downdelay are being set and thus miss the +zero check in the beginning, the zero div happens because updelay/downdelay +are stored as new_value / bond->params.miimon. Use rtnl to synchronize with +miimon setting. + +Signed-off-by: Nikolay Aleksandrov +CC: Jay Vosburgh +CC: Andy Gospodarek +CC: Veaceslav Falico +Acked-by: Veaceslav Falico +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/bonding/bond_sysfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/bonding/bond_sysfs.c ++++ b/drivers/net/bonding/bond_sysfs.c +@@ -693,6 +693,8 @@ static ssize_t bonding_store_downdelay(s + int new_value, ret = count; + struct bonding *bond = to_bond(d); + ++ if (!rtnl_trylock()) ++ return restart_syscall(); + if (!(bond->params.miimon)) { + pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", + bond->dev->name); +@@ -726,6 +728,7 @@ static ssize_t bonding_store_downdelay(s + } + + out: ++ rtnl_unlock(); + return ret; + } + static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR, +@@ -748,6 +751,8 @@ static ssize_t bonding_store_updelay(str + int new_value, ret = count; + struct bonding *bond = to_bond(d); + ++ if (!rtnl_trylock()) ++ return restart_syscall(); + if (!(bond->params.miimon)) { + pr_err("%s: Unable to set up delay as MII monitoring is disabled\n", + bond->dev->name); +@@ -781,6 +786,7 @@ static ssize_t bonding_store_updelay(str + } + + out: ++ rtnl_unlock(); + return ret; + } + static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR, diff --git a/queue-3.4/bridge-flush-br-s-address-entry-in-fdb-when-remove-the-bridge-dev.patch b/queue-3.4/bridge-flush-br-s-address-entry-in-fdb-when-remove-the-bridge-dev.patch new file mode 100644 index 00000000000..250a53805bb --- /dev/null +++ b/queue-3.4/bridge-flush-br-s-address-entry-in-fdb-when-remove-the-bridge-dev.patch @@ -0,0 +1,67 @@ +From 93080918b643c0ff849ca0a69bb920ddb07d07dc Mon Sep 17 00:00:00 2001 +From: Ding Tianhong +Date: Sat, 7 Dec 2013 22:12:05 +0800 +Subject: bridge: flush br's address entry in fdb when remove the bridge dev + +From: Ding Tianhong + +[ Upstream commit f873042093c0b418d2351fe142222b625c740149 ] + +When the following commands are executed: + +brctl addbr br0 +ifconfig br0 hw ether +rmmod bridge + +The calltrace will occur: + +[ 563.312114] device eth1 left promiscuous mode +[ 563.312188] br0: port 1(eth1) entered disabled state +[ 563.468190] kmem_cache_destroy bridge_fdb_cache: Slab cache still has objects +[ 563.468197] CPU: 6 PID: 6982 Comm: rmmod Tainted: G O 3.12.0-0.7-default+ #9 +[ 563.468199] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 +[ 563.468200] 0000000000000880 ffff88010f111e98 ffffffff814d1c92 ffff88010f111eb8 +[ 563.468204] ffffffff81148efd ffff88010f111eb8 0000000000000000 ffff88010f111ec8 +[ 563.468206] ffffffffa062a270 ffff88010f111ed8 ffffffffa063ac76 ffff88010f111f78 +[ 563.468209] Call Trace: +[ 563.468218] [] dump_stack+0x6a/0x78 +[ 563.468234] [] kmem_cache_destroy+0xfd/0x100 +[ 563.468242] [] br_fdb_fini+0x10/0x20 [bridge] +[ 563.468247] [] br_deinit+0x4e/0x50 [bridge] +[ 563.468254] [] SyS_delete_module+0x199/0x2b0 +[ 563.468259] [] system_call_fastpath+0x16/0x1b +[ 570.377958] Bridge firewalling registered + +--------------------------- cut here ------------------------------- + +The reason is that when the bridge dev's address is changed, the +br_fdb_change_mac_address() will add new address in fdb, but when +the bridge was removed, the address entry in the fdb did not free, +the bridge_fdb_cache still has objects when destroy the cache, Fix +this by flushing the bridge address entry when removing the bridge. + +v2: according to the Toshiaki Makita and Vlad's suggestion, I only + delete the vlan0 entry, it still have a leak here if the vlan id + is other number, so I need to call fdb_delete_by_port(br, NULL, 1) + to flush all entries whose dst is NULL for the bridge. + +Suggested-by: Toshiaki Makita +Suggested-by: Vlad Yasevich +Signed-off-by: Ding Tianhong +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/bridge/br_if.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -170,6 +170,8 @@ void br_dev_delete(struct net_device *de + del_nbp(p); + } + ++ br_fdb_delete_by_port(br, NULL, 1); ++ + del_timer_sync(&br->gc_timer); + + br_sysfs_delbr(br->dev); diff --git a/queue-3.4/connector-improved-unaligned-access-error-fix.patch b/queue-3.4/connector-improved-unaligned-access-error-fix.patch new file mode 100644 index 00000000000..e02a37859cd --- /dev/null +++ b/queue-3.4/connector-improved-unaligned-access-error-fix.patch @@ -0,0 +1,238 @@ +From c34f0776fcd67a39a213552ccb885266b1fe958c Mon Sep 17 00:00:00 2001 +From: Chris Metcalf +Date: Thu, 14 Nov 2013 12:09:21 -0500 +Subject: connector: improved unaligned access error fix + +From: Chris Metcalf + +[ Upstream commit 1ca1a4cf59ea343a1a70084fe7cc96f37f3cf5b1 ] + +In af3e095a1fb4, Erik Jacobsen fixed one type of unaligned access +bug for ia64 by converting a 64-bit write to use put_unaligned(). +Unfortunately, since gcc will convert a short memset() to a series +of appropriately-aligned stores, the problem is now visible again +on tilegx, where the memset that zeros out proc_event is converted +to three 64-bit stores, causing an unaligned access panic. + +A better fix for the original problem is to ensure that proc_event +is aligned to 8 bytes here. We can do that relatively easily by +arranging to start the struct cn_msg aligned to 8 bytes and then +offset by 4 bytes. Doing so means that the immediately following +proc_event structure is then correctly aligned to 8 bytes. + +The result is that the memset() stores are now aligned, and as an +added benefit, we can remove the put_unaligned() calls in the code. + +Signed-off-by: Chris Metcalf +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/connector/cn_proc.c | 66 ++++++++++++++++++++++++++------------------ + 1 file changed, 39 insertions(+), 27 deletions(-) + +--- a/drivers/connector/cn_proc.c ++++ b/drivers/connector/cn_proc.c +@@ -31,11 +31,23 @@ + #include + #include + +-#include +- + #include + +-#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event)) ++/* ++ * Size of a cn_msg followed by a proc_event structure. Since the ++ * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we ++ * add one 4-byte word to the size here, and then start the actual ++ * cn_msg structure 4 bytes into the stack buffer. The result is that ++ * the immediately following proc_event structure is aligned to 8 bytes. ++ */ ++#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4) ++ ++/* See comment above; we test our assumption about sizeof struct cn_msg here. */ ++static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer) ++{ ++ BUILD_BUG_ON(sizeof(struct cn_msg) != 20); ++ return (struct cn_msg *)(buffer + 4); ++} + + static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); + static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; +@@ -55,19 +67,19 @@ void proc_fork_connector(struct task_str + { + struct cn_msg *msg; + struct proc_event *ev; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct timespec ts; + struct task_struct *parent; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg*)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event*)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_FORK; + rcu_read_lock(); + parent = rcu_dereference(task->real_parent); +@@ -90,17 +102,17 @@ void proc_exec_connector(struct task_str + struct cn_msg *msg; + struct proc_event *ev; + struct timespec ts; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg*)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event*)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_EXEC; + ev->event_data.exec.process_pid = task->pid; + ev->event_data.exec.process_tgid = task->tgid; +@@ -116,14 +128,14 @@ void proc_id_connector(struct task_struc + { + struct cn_msg *msg; + struct proc_event *ev; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct timespec ts; + const struct cred *cred; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg*)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event*)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + ev->what = which_id; +@@ -144,7 +156,7 @@ void proc_id_connector(struct task_struc + rcu_read_unlock(); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = 0; /* not used */ +@@ -158,17 +170,17 @@ void proc_sid_connector(struct task_stru + struct cn_msg *msg; + struct proc_event *ev; + struct timespec ts; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg *)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event *)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_SID; + ev->event_data.sid.process_pid = task->pid; + ev->event_data.sid.process_tgid = task->tgid; +@@ -185,17 +197,17 @@ void proc_ptrace_connector(struct task_s + struct cn_msg *msg; + struct proc_event *ev; + struct timespec ts; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg *)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event *)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_PTRACE; + ev->event_data.ptrace.process_pid = task->pid; + ev->event_data.ptrace.process_tgid = task->tgid; +@@ -220,17 +232,17 @@ void proc_comm_connector(struct task_str + struct cn_msg *msg; + struct proc_event *ev; + struct timespec ts; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg *)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event *)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_COMM; + ev->event_data.comm.process_pid = task->pid; + ev->event_data.comm.process_tgid = task->tgid; +@@ -247,18 +259,18 @@ void proc_exit_connector(struct task_str + { + struct cn_msg *msg; + struct proc_event *ev; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct timespec ts; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg*)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event*)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + get_seq(&msg->seq, &ev->cpu); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->what = PROC_EVENT_EXIT; + ev->event_data.exit.process_pid = task->pid; + ev->event_data.exit.process_tgid = task->tgid; +@@ -284,18 +296,18 @@ static void cn_proc_ack(int err, int rcv + { + struct cn_msg *msg; + struct proc_event *ev; +- __u8 buffer[CN_PROC_MSG_SIZE]; ++ __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct timespec ts; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + +- msg = (struct cn_msg*)buffer; ++ msg = buffer_to_cn_msg(buffer); + ev = (struct proc_event*)msg->data; + memset(&ev->event_data, 0, sizeof(ev->event_data)); + msg->seq = rcvd_seq; + ktime_get_ts(&ts); /* get high res monotonic timestamp */ +- put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ++ ev->timestamp_ns = timespec_to_ns(&ts); + ev->cpu = -1; + ev->what = PROC_EVENT_NONE; + ev->event_data.ack.err = err; diff --git a/queue-3.4/inet-fix-addr_len-msg-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch b/queue-3.4/inet-fix-addr_len-msg-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch new file mode 100644 index 00000000000..d3f3dae9c6d --- /dev/null +++ b/queue-3.4/inet-fix-addr_len-msg-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch @@ -0,0 +1,186 @@ +From 33498dfa419c0683dc010d7d6aee79ceac0d2598 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Sat, 23 Nov 2013 00:46:12 +0100 +Subject: inet: fix addr_len/msg->msg_namelen assignment in recv_error and rxpmtu functions + +From: Hannes Frederic Sowa + +[ Upstream commit 85fbaa75037d0b6b786ff18658ddf0b4014ce2a4 ] + +Commit bceaa90240b6019ed73b49965eac7d167610be69 ("inet: prevent leakage +of uninitialized memory to user in recv syscalls") conditionally updated +addr_len if the msg_name is written to. The recv_error and rxpmtu +functions relied on the recvmsg functions to set up addr_len before. + +As this does not happen any more we have to pass addr_len to those +functions as well and set it to the size of the corresponding sockaddr +length. + +This broke traceroute and such. + +Fixes: bceaa90240b6 ("inet: prevent leakage of uninitialized memory to user in recv syscalls") +Reported-by: Brad Spengler +Reported-by: Tom Labanowski +Cc: mpb +Cc: David S. Miller +Cc: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ip.h | 2 +- + include/net/ipv6.h | 6 ++++-- + net/ipv4/ip_sockglue.c | 3 ++- + net/ipv4/ping.c | 2 +- + net/ipv4/raw.c | 2 +- + net/ipv4/udp.c | 2 +- + net/ipv6/datagram.c | 7 +++++-- + net/ipv6/raw.c | 4 ++-- + net/ipv6/udp.c | 4 ++-- + 9 files changed, 19 insertions(+), 13 deletions(-) + +--- a/include/net/ip.h ++++ b/include/net/ip.h +@@ -466,7 +466,7 @@ extern int compat_ip_getsockopt(struct s + int optname, char __user *optval, int __user *optlen); + extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); + +-extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len); ++extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len); + extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, + __be16 port, u32 info, u8 *payload); + extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport, +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -606,8 +606,10 @@ extern int compat_ipv6_getsockopt(stru + extern int ip6_datagram_connect(struct sock *sk, + struct sockaddr *addr, int addr_len); + +-extern int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len); +-extern int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len); ++extern int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, ++ int *addr_len); ++extern int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, ++ int *addr_len); + extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port, + u32 info, u8 *payload); + extern void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -367,7 +367,7 @@ void ip_local_error(struct sock *sk, int + /* + * Handle MSG_ERRQUEUE + */ +-int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) ++int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) + { + struct sock_exterr_skb *serr; + struct sk_buff *skb, *skb2; +@@ -404,6 +404,7 @@ int ip_recv_error(struct sock *sk, struc + serr->addr_offset); + sin->sin_port = serr->port; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ *addr_len = sizeof(*sin); + } + + memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -634,7 +634,7 @@ static int ping_recvmsg(struct kiocb *io + goto out; + + if (flags & MSG_ERRQUEUE) +- return ip_recv_error(sk, msg, len); ++ return ip_recv_error(sk, msg, len, addr_len); + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -689,7 +689,7 @@ static int raw_recvmsg(struct kiocb *ioc + goto out; + + if (flags & MSG_ERRQUEUE) { +- err = ip_recv_error(sk, msg, len); ++ err = ip_recv_error(sk, msg, len, addr_len); + goto out; + } + +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1175,7 +1175,7 @@ int udp_recvmsg(struct kiocb *iocb, stru + bool slow; + + if (flags & MSG_ERRQUEUE) +- return ip_recv_error(sk, msg, len); ++ return ip_recv_error(sk, msg, len, addr_len); + + try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), +--- a/net/ipv6/datagram.c ++++ b/net/ipv6/datagram.c +@@ -315,7 +315,7 @@ void ipv6_local_rxpmtu(struct sock *sk, + /* + * Handle MSG_ERRQUEUE + */ +-int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) ++int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) + { + struct ipv6_pinfo *np = inet6_sk(sk); + struct sock_exterr_skb *serr; +@@ -366,6 +366,7 @@ int ipv6_recv_error(struct sock *sk, str + ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset), + &sin->sin6_addr); + } ++ *addr_len = sizeof(*sin); + } + + memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); +@@ -418,7 +419,8 @@ out: + /* + * Handle IPV6_RECVPATHMTU + */ +-int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len) ++int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, ++ int *addr_len) + { + struct ipv6_pinfo *np = inet6_sk(sk); + struct sk_buff *skb; +@@ -452,6 +454,7 @@ int ipv6_recv_rxpmtu(struct sock *sk, st + sin->sin6_port = 0; + sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; + sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr; ++ *addr_len = sizeof(*sin); + } + + put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -458,10 +458,10 @@ static int rawv6_recvmsg(struct kiocb *i + return -EOPNOTSUPP; + + if (flags & MSG_ERRQUEUE) +- return ipv6_recv_error(sk, msg, len); ++ return ipv6_recv_error(sk, msg, len, addr_len); + + if (np->rxpmtu && np->rxopt.bits.rxpmtu) +- return ipv6_recv_rxpmtu(sk, msg, len); ++ return ipv6_recv_rxpmtu(sk, msg, len, addr_len); + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -349,10 +349,10 @@ int udpv6_recvmsg(struct kiocb *iocb, st + bool slow; + + if (flags & MSG_ERRQUEUE) +- return ipv6_recv_error(sk, msg, len); ++ return ipv6_recv_error(sk, msg, len, addr_len); + + if (np->rxpmtu && np->rxopt.bits.rxpmtu) +- return ipv6_recv_rxpmtu(sk, msg, len); ++ return ipv6_recv_rxpmtu(sk, msg, len, addr_len); + + try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), diff --git a/queue-3.4/inet-fix-possible-seqlock-deadlocks.patch b/queue-3.4/inet-fix-possible-seqlock-deadlocks.patch new file mode 100644 index 00000000000..64224b137e9 --- /dev/null +++ b/queue-3.4/inet-fix-possible-seqlock-deadlocks.patch @@ -0,0 +1,64 @@ +From 88e4ffcdd0da58eb3da8a71a6d9fd0567c9315e5 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 28 Nov 2013 09:51:22 -0800 +Subject: inet: fix possible seqlock deadlocks + +From: Eric Dumazet + +[ Upstream commit f1d8cba61c3c4b1eb88e507249c4cb8d635d9a76 ] + +In commit c9e9042994d3 ("ipv4: fix possible seqlock deadlock") I left +another places where IP_INC_STATS_BH() were improperly used. + +udp_sendmsg(), ping_v4_sendmsg() and tcp_v4_connect() are called from +process context, not from softirq context. + +This was detected by lockdep seqlock support. + +Reported-by: jongman heo +Fixes: 584bdf8cbdf6 ("[IPV4]: Fix "ipOutNoRoutes" counter error for TCP and UDP") +Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") +Signed-off-by: Eric Dumazet +Cc: Hannes Frederic Sowa +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ping.c | 2 +- + net/ipv4/tcp_ipv4.c | 2 +- + net/ipv4/udp.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -568,7 +568,7 @@ static int ping_sendmsg(struct kiocb *io + err = PTR_ERR(rt); + rt = NULL; + if (err == -ENETUNREACH) +- IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); ++ IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); + goto out; + } + +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -176,7 +176,7 @@ int tcp_v4_connect(struct sock *sk, stru + if (IS_ERR(rt)) { + err = PTR_ERR(rt); + if (err == -ENETUNREACH) +- IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); ++ IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); + return err; + } + +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -940,7 +940,7 @@ int udp_sendmsg(struct kiocb *iocb, stru + err = PTR_ERR(rt); + rt = NULL; + if (err == -ENETUNREACH) +- IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); ++ IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); + goto out; + } + diff --git a/queue-3.4/inet-prevent-leakage-of-uninitialized-memory-to-user-in-recv-syscalls.patch b/queue-3.4/inet-prevent-leakage-of-uninitialized-memory-to-user-in-recv-syscalls.patch new file mode 100644 index 00000000000..532ff3e8481 --- /dev/null +++ b/queue-3.4/inet-prevent-leakage-of-uninitialized-memory-to-user-in-recv-syscalls.patch @@ -0,0 +1,198 @@ +From 61506657b555fcf130f6e474b1c1e88437c398b9 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Mon, 18 Nov 2013 04:20:45 +0100 +Subject: inet: prevent leakage of uninitialized memory to user in recv syscalls + +From: Hannes Frederic Sowa + +[ Upstream commit bceaa90240b6019ed73b49965eac7d167610be69 ] + +Only update *addr_len when we actually fill in sockaddr, otherwise we +can return uninitialized memory from the stack to the caller in the +recvfrom, recvmmsg and recvmsg syscalls. Drop the the (addr_len == NULL) +checks because we only get called with a valid addr_len pointer either +from sock_common_recvmsg or inet_recvmsg. + +If a blocking read waits on a socket which is concurrently shut down we +now return zero and set msg_msgnamelen to 0. + +Reported-by: mpb +Suggested-by: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ping.c | 9 ++++----- + net/ipv4/raw.c | 4 +--- + net/ipv4/udp.c | 7 +------ + net/ipv6/raw.c | 4 +--- + net/ipv6/udp.c | 5 +---- + net/l2tp/l2tp_ip.c | 4 +--- + net/phonet/datagram.c | 9 ++++----- + 7 files changed, 13 insertions(+), 29 deletions(-) + +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -624,7 +624,6 @@ static int ping_recvmsg(struct kiocb *io + size_t len, int noblock, int flags, int *addr_len) + { + struct inet_sock *isk = inet_sk(sk); +- struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + struct sk_buff *skb; + int copied, err; + +@@ -634,9 +633,6 @@ static int ping_recvmsg(struct kiocb *io + if (flags & MSG_OOB) + goto out; + +- if (addr_len) +- *addr_len = sizeof(*sin); +- + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + +@@ -658,11 +654,14 @@ static int ping_recvmsg(struct kiocb *io + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ +- if (sin) { ++ if (msg->msg_name) { ++ struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; ++ + sin->sin_family = AF_INET; + sin->sin_port = 0 /* skb->h.uh->source */; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ *addr_len = sizeof(*sin); + } + if (isk->cmsg_flags) + ip_cmsg_recv(msg, skb); +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -688,9 +688,6 @@ static int raw_recvmsg(struct kiocb *ioc + if (flags & MSG_OOB) + goto out; + +- if (addr_len) +- *addr_len = sizeof(*sin); +- + if (flags & MSG_ERRQUEUE) { + err = ip_recv_error(sk, msg, len); + goto out; +@@ -718,6 +715,7 @@ static int raw_recvmsg(struct kiocb *ioc + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + sin->sin_port = 0; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ *addr_len = sizeof(*sin); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1174,12 +1174,6 @@ int udp_recvmsg(struct kiocb *iocb, stru + int is_udplite = IS_UDPLITE(sk); + bool slow; + +- /* +- * Check any passed addresses +- */ +- if (addr_len) +- *addr_len = sizeof(*sin); +- + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + +@@ -1234,6 +1228,7 @@ try_again: + sin->sin_port = udp_hdr(skb)->source; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ *addr_len = sizeof(*sin); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -457,9 +457,6 @@ static int rawv6_recvmsg(struct kiocb *i + if (flags & MSG_OOB) + return -EOPNOTSUPP; + +- if (addr_len) +- *addr_len=sizeof(*sin6); +- + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len); + +@@ -499,6 +496,7 @@ static int rawv6_recvmsg(struct kiocb *i + sin6->sin6_scope_id = 0; + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; ++ *addr_len = sizeof(*sin6); + } + + sock_recv_ts_and_drops(msg, sk, skb); +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -348,9 +348,6 @@ int udpv6_recvmsg(struct kiocb *iocb, st + int is_udp4; + bool slow; + +- if (addr_len) +- *addr_len=sizeof(struct sockaddr_in6); +- + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len); + +@@ -423,7 +420,7 @@ try_again: + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; + } +- ++ *addr_len = sizeof(*sin6); + } + if (is_udp4) { + if (inet->cmsg_flags) +--- a/net/l2tp/l2tp_ip.c ++++ b/net/l2tp/l2tp_ip.c +@@ -569,9 +569,6 @@ static int l2tp_ip_recvmsg(struct kiocb + if (flags & MSG_OOB) + goto out; + +- if (addr_len) +- *addr_len = sizeof(*sin); +- + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; +@@ -594,6 +591,7 @@ static int l2tp_ip_recvmsg(struct kiocb + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + sin->sin_port = 0; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ *addr_len = sizeof(*sin); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); +--- a/net/phonet/datagram.c ++++ b/net/phonet/datagram.c +@@ -139,9 +139,6 @@ static int pn_recvmsg(struct kiocb *iocb + MSG_CMSG_COMPAT)) + goto out_nofree; + +- if (addr_len) +- *addr_len = sizeof(sa); +- + skb = skb_recv_datagram(sk, flags, noblock, &rval); + if (skb == NULL) + goto out_nofree; +@@ -162,8 +159,10 @@ static int pn_recvmsg(struct kiocb *iocb + + rval = (flags & MSG_TRUNC) ? skb->len : copylen; + +- if (msg->msg_name != NULL) +- memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn)); ++ if (msg->msg_name != NULL) { ++ memcpy(msg->msg_name, &sa, sizeof(sa)); ++ *addr_len = sizeof(sa); ++ } + + out: + skb_free_datagram(sk, skb); diff --git a/queue-3.4/ipv4-fix-possible-seqlock-deadlock.patch b/queue-3.4/ipv4-fix-possible-seqlock-deadlock.patch new file mode 100644 index 00000000000..fc5657dd229 --- /dev/null +++ b/queue-3.4/ipv4-fix-possible-seqlock-deadlock.patch @@ -0,0 +1,34 @@ +From c78b16fc2fef309fc0b3f814d6b221baf0685c69 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 14 Nov 2013 13:37:54 -0800 +Subject: ipv4: fix possible seqlock deadlock + +From: Eric Dumazet + +[ Upstream commit c9e9042994d37cbc1ee538c500e9da1bb9d1bcdf ] + +ip4_datagram_connect() being called from process context, +it should use IP_INC_STATS() instead of IP_INC_STATS_BH() +otherwise we can deadlock on 32bit arches, or get corruptions of +SNMP counters. + +Fixes: 584bdf8cbdf6 ("[IPV4]: Fix "ipOutNoRoutes" counter error for TCP and UDP") +Signed-off-by: Eric Dumazet +Reported-by: Dave Jones +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/datagram.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/datagram.c ++++ b/net/ipv4/datagram.c +@@ -57,7 +57,7 @@ int ip4_datagram_connect(struct sock *sk + if (IS_ERR(rt)) { + err = PTR_ERR(rt); + if (err == -ENETUNREACH) +- IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); ++ IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); + goto out; + } + diff --git a/queue-3.4/ipv6-fix-leaking-uninitialized-port-number-of-offender-sockaddr.patch b/queue-3.4/ipv6-fix-leaking-uninitialized-port-number-of-offender-sockaddr.patch new file mode 100644 index 00000000000..bae725c1582 --- /dev/null +++ b/queue-3.4/ipv6-fix-leaking-uninitialized-port-number-of-offender-sockaddr.patch @@ -0,0 +1,28 @@ +From 49376c90b2f7fe89a0b07b029c397c958bd1c8dc Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Sat, 23 Nov 2013 07:22:33 +0100 +Subject: ipv6: fix leaking uninitialized port number of offender sockaddr + +From: Hannes Frederic Sowa + +[ Upstream commit 1fa4c710b6fe7b0aac9907240291b6fe6aafc3b8 ] + +Offenders don't have port numbers, so set it to 0. + +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/datagram.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/ipv6/datagram.c ++++ b/net/ipv6/datagram.c +@@ -375,6 +375,7 @@ int ipv6_recv_error(struct sock *sk, str + if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { + sin->sin6_family = AF_INET6; + sin->sin6_flowinfo = 0; ++ sin->sin6_port = 0; + sin->sin6_scope_id = 0; + if (skb->protocol == htons(ETH_P_IPV6)) { + sin->sin6_addr = ipv6_hdr(skb)->saddr; diff --git a/queue-3.4/ipv6-fix-possible-seqlock-deadlock-in-ip6_finish_output2.patch b/queue-3.4/ipv6-fix-possible-seqlock-deadlock-in-ip6_finish_output2.patch new file mode 100644 index 00000000000..9fa3cfdacfc --- /dev/null +++ b/queue-3.4/ipv6-fix-possible-seqlock-deadlock-in-ip6_finish_output2.patch @@ -0,0 +1,35 @@ +From 6fa73581e6b77e1a5aa8f433db9c0333282bfaed Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Fri, 29 Nov 2013 06:39:44 +0100 +Subject: ipv6: fix possible seqlock deadlock in ip6_finish_output2 + +From: Hannes Frederic Sowa + +[ Upstream commit 7f88c6b23afbd31545c676dea77ba9593a1a14bf ] + +IPv6 stats are 64 bits and thus are protected with a seqlock. By not +disabling bottom-half we could deadlock here if we don't disable bh and +a softirq reentrantly updates the same mib. + +Cc: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_output.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -144,8 +144,8 @@ static int ip6_finish_output2(struct sk_ + return res; + } + rcu_read_unlock(); +- IP6_INC_STATS_BH(dev_net(dst->dev), +- ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); ++ IP6_INC_STATS(dev_net(dst->dev), ++ ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); + kfree_skb(skb); + return -EINVAL; + } diff --git a/queue-3.4/ipv6-use-rt6_get_dflt_router-to-get-default-router-in-rt6_route_rcv.patch b/queue-3.4/ipv6-use-rt6_get_dflt_router-to-get-default-router-in-rt6_route_rcv.patch new file mode 100644 index 00000000000..a152acba536 --- /dev/null +++ b/queue-3.4/ipv6-use-rt6_get_dflt_router-to-get-default-router-in-rt6_route_rcv.patch @@ -0,0 +1,43 @@ +From fd70e6c7a132571d378dba0bd4addea348d00317 Mon Sep 17 00:00:00 2001 +From: Duan Jiong +Date: Fri, 8 Nov 2013 09:56:53 +0800 +Subject: ipv6: use rt6_get_dflt_router to get default router in rt6_route_rcv + +From: Duan Jiong + +[ Upstream commit f104a567e673f382b09542a8dc3500aa689957b4 ] + +As the rfc 4191 said, the Router Preference and Lifetime values in a +::/0 Route Information Option should override the preference and lifetime +values in the Router Advertisement header. But when the kernel deals with +a ::/0 Route Information Option, the rt6_get_route_info() always return +NULL, that means that overriding will not happen, because those default +routers were added without flag RTF_ROUTEINFO in rt6_add_dflt_router(). + +In order to deal with that condition, we should call rt6_get_dflt_router +when the prefix length is 0. + +Signed-off-by: Duan Jiong +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/route.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -617,8 +617,11 @@ int rt6_route_rcv(struct net_device *dev + prefix = &prefix_buf; + } + +- rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr, +- dev->ifindex); ++ if (rinfo->prefix_len == 0) ++ rt = rt6_get_dflt_router(gwaddr, dev); ++ else ++ rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, ++ gwaddr, dev->ifindex); + + if (rt && !lifetime) { + ip6_del_rt(rt); diff --git a/queue-3.4/isdnloop-use-strlcpy-instead-of-strcpy.patch b/queue-3.4/isdnloop-use-strlcpy-instead-of-strcpy.patch new file mode 100644 index 00000000000..c2e23b7b042 --- /dev/null +++ b/queue-3.4/isdnloop-use-strlcpy-instead-of-strcpy.patch @@ -0,0 +1,43 @@ +From 21a51586ad8d6665fde3b8250b3b517bf6440ea3 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 14 Nov 2013 11:21:10 +0300 +Subject: isdnloop: use strlcpy() instead of strcpy() + +From: Dan Carpenter + +[ Upstream commit f9a23c84486ed350cce7bb1b2828abd1f6658796 ] + +These strings come from a copy_from_user() and there is no way to be +sure they are NUL terminated. + +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/isdn/isdnloop/isdnloop.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/isdn/isdnloop/isdnloop.c ++++ b/drivers/isdn/isdnloop/isdnloop.c +@@ -1083,8 +1083,10 @@ isdnloop_start(isdnloop_card *card, isdn + spin_unlock_irqrestore(&card->isdnloop_lock, flags); + return -ENOMEM; + } +- for (i = 0; i < 3; i++) +- strcpy(card->s0num[i], sdef.num[i]); ++ for (i = 0; i < 3; i++) { ++ strlcpy(card->s0num[i], sdef.num[i], ++ sizeof(card->s0num[0])); ++ } + break; + case ISDN_PTYPE_1TR6: + if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", +@@ -1097,7 +1099,7 @@ isdnloop_start(isdnloop_card *card, isdn + spin_unlock_irqrestore(&card->isdnloop_lock, flags); + return -ENOMEM; + } +- strcpy(card->s0num[0], sdef.num[0]); ++ strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0])); + card->s0num[1][0] = '\0'; + card->s0num[2][0] = '\0'; + break; diff --git a/queue-3.4/net-add-bug_on-if-kernel-advertises-msg_namelen-sizeof-struct-sockaddr_storage.patch b/queue-3.4/net-add-bug_on-if-kernel-advertises-msg_namelen-sizeof-struct-sockaddr_storage.patch new file mode 100644 index 00000000000..1403a6c849b --- /dev/null +++ b/queue-3.4/net-add-bug_on-if-kernel-advertises-msg_namelen-sizeof-struct-sockaddr_storage.patch @@ -0,0 +1,40 @@ +From 763799b13192e076a22f19ac4cdeb50ab1e3e3b9 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Thu, 21 Nov 2013 03:14:34 +0100 +Subject: net: add BUG_ON if kernel advertises msg_namelen > sizeof(struct sockaddr_storage) + +From: Hannes Frederic Sowa + +[ Upstream commit 68c6beb373955da0886d8f4f5995b3922ceda4be ] + +In that case it is probable that kernel code overwrote part of the +stack. So we should bail out loudly here. + +The BUG_ON may be removed in future if we are sure all protocols are +conformant. + +Suggested-by: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/socket.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/socket.c ++++ b/net/socket.c +@@ -215,12 +215,13 @@ static int move_addr_to_user(struct sock + int err; + int len; + ++ BUG_ON(klen > sizeof(struct sockaddr_storage)); + err = get_user(len, ulen); + if (err) + return err; + if (len > klen) + len = klen; +- if (len < 0 || len > sizeof(struct sockaddr_storage)) ++ if (len < 0) + return -EINVAL; + if (len) { + if (audit_sockaddr(klen, kaddr)) diff --git a/queue-3.4/net-clamp-msg_namelen-instead-of-returning-an-error.patch b/queue-3.4/net-clamp-msg_namelen-instead-of-returning-an-error.patch new file mode 100644 index 00000000000..141b5f85e7d --- /dev/null +++ b/queue-3.4/net-clamp-msg_namelen-instead-of-returning-an-error.patch @@ -0,0 +1,52 @@ +From 0cd7168f61e9fca226bcc1052463995348ff4e3d Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 27 Nov 2013 15:40:21 +0300 +Subject: net: clamp ->msg_namelen instead of returning an error + +From: Dan Carpenter + +[ Upstream commit db31c55a6fb245fdbb752a2ca4aefec89afabb06 ] + +If kmsg->msg_namelen > sizeof(struct sockaddr_storage) then in the +original code that would lead to memory corruption in the kernel if you +had audit configured. If you didn't have audit configured it was +harmless. + +There are some programs such as beta versions of Ruby which use too +large of a buffer and returning an error code breaks them. We should +clamp the ->msg_namelen value instead. + +Fixes: 1661bf364ae9 ("net: heap overflow in __audit_sockaddr()") +Reported-by: Eric Wong +Signed-off-by: Dan Carpenter +Tested-by: Eric Wong +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/compat.c | 2 +- + net/socket.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/net/compat.c ++++ b/net/compat.c +@@ -72,7 +72,7 @@ int get_compat_msghdr(struct msghdr *kms + __get_user(kmsg->msg_flags, &umsg->msg_flags)) + return -EFAULT; + if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) +- return -EINVAL; ++ kmsg->msg_namelen = sizeof(struct sockaddr_storage); + kmsg->msg_name = compat_ptr(tmp1); + kmsg->msg_iov = compat_ptr(tmp2); + kmsg->msg_control = compat_ptr(tmp3); +--- a/net/socket.c ++++ b/net/socket.c +@@ -1908,7 +1908,7 @@ static int copy_msghdr_from_user(struct + if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) + return -EFAULT; + if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) +- return -EINVAL; ++ kmsg->msg_namelen = sizeof(struct sockaddr_storage); + return 0; + } + diff --git a/queue-3.4/net-core-always-propagate-flag-changes-to-interfaces.patch b/queue-3.4/net-core-always-propagate-flag-changes-to-interfaces.patch new file mode 100644 index 00000000000..3ce72bb34de --- /dev/null +++ b/queue-3.4/net-core-always-propagate-flag-changes-to-interfaces.patch @@ -0,0 +1,66 @@ +From b25ff8eccf41750a86dd50e108db225944ae8149 Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Tue, 19 Nov 2013 20:47:15 -0500 +Subject: net: core: Always propagate flag changes to interfaces + +From: Vlad Yasevich + +[ Upstream commit d2615bf450694c1302d86b9cc8a8958edfe4c3a4 ] + +The following commit: + b6c40d68ff6498b7f63ddf97cf0aa818d748dee7 + net: only invoke dev->change_rx_flags when device is UP + +tried to fix a problem with VLAN devices and promiscuouse flag setting. +The issue was that VLAN device was setting a flag on an interface that +was down, thus resulting in bad promiscuity count. +This commit blocked flag propagation to any device that is currently +down. + +A later commit: + deede2fabe24e00bd7e246eb81cd5767dc6fcfc7 + vlan: Don't propagate flag changes on down interfaces + +fixed VLAN code to only propagate flags when the VLAN interface is up, +thus fixing the same issue as above, only localized to VLAN. + +The problem we have now is that if we have create a complex stack +involving multiple software devices like bridges, bonds, and vlans, +then it is possible that the flags would not propagate properly to +the physical devices. A simple examle of the scenario is the +following: + + eth0----> bond0 ----> bridge0 ---> vlan50 + +If bond0 or eth0 happen to be down at the time bond0 is added to +the bridge, then eth0 will never have promisc mode set which is +currently required for operation as part of the bridge. As a +result, packets with vlan50 will be dropped by the interface. + +The only 2 devices that implement the special flag handling are +VLAN and DSA and they both have required code to prevent incorrect +flag propagation. As a result we can remove the generic solution +introduced in b6c40d68ff6498b7f63ddf97cf0aa818d748dee7 and leave +it to the individual devices to decide whether they will block +flag propagation or not. + +Reported-by: Stefan Priebe +Suggested-by: Veaceslav Falico +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4443,7 +4443,7 @@ static void dev_change_rx_flags(struct n + { + const struct net_device_ops *ops = dev->netdev_ops; + +- if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags) ++ if (ops->ndo_change_rx_flags) + ops->ndo_change_rx_flags(dev, flags); + } + diff --git a/queue-3.4/net-fix-ip-rule-delete-table-256.patch b/queue-3.4/net-fix-ip-rule-delete-table-256.patch new file mode 100644 index 00000000000..ec47ef35fa2 --- /dev/null +++ b/queue-3.4/net-fix-ip-rule-delete-table-256.patch @@ -0,0 +1,41 @@ +From dc15739b011195bd7b778f0b93ad22598538a2ac Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Thu, 7 Nov 2013 18:26:38 +0100 +Subject: net: Fix "ip rule delete table 256" + +From: Andreas Henriksson + +[ Upstream commit 13eb2ab2d33c57ebddc57437a7d341995fc9138c ] + +When trying to delete a table >= 256 using iproute2 the local table +will be deleted. +The table id is specified as a netlink attribute when it needs more then +8 bits and iproute2 then sets the table field to RT_TABLE_UNSPEC (0). +Preconditions to matching the table id in the rule delete code +doesn't seem to take the "table id in netlink attribute" into condition +so the frh_get_table helper function never gets to do its job when +matching against current rule. +Use the helper function twice instead of peaking at the table value directly. + +Originally reported at: http://bugs.debian.org/724783 + +Reported-by: Nicolas HICHER +Signed-off-by: Andreas Henriksson +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/fib_rules.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/core/fib_rules.c ++++ b/net/core/fib_rules.c +@@ -443,7 +443,8 @@ static int fib_nl_delrule(struct sk_buff + if (frh->action && (frh->action != rule->action)) + continue; + +- if (frh->table && (frh_get_table(frh, tb) != rule->table)) ++ if (frh_get_table(frh, tb) && ++ (frh_get_table(frh, tb) != rule->table)) + continue; + + if (tb[FRA_PRIORITY] && diff --git a/queue-3.4/net-rework-recvmsg-handler-msg_name-and-msg_namelen-logic.patch b/queue-3.4/net-rework-recvmsg-handler-msg_name-and-msg_namelen-logic.patch new file mode 100644 index 00000000000..5f3ddc66377 --- /dev/null +++ b/queue-3.4/net-rework-recvmsg-handler-msg_name-and-msg_namelen-logic.patch @@ -0,0 +1,653 @@ +From fc14c68c76c0265cb1c8e1a945923241bebe7b24 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Thu, 21 Nov 2013 03:14:22 +0100 +Subject: net: rework recvmsg handler msg_name and msg_namelen logic + +From: Hannes Frederic Sowa + +[ Upstream commit f3d3342602f8bcbf37d7c46641cb9bca7618eb1c ] + +This patch now always passes msg->msg_namelen as 0. recvmsg handlers must +set msg_namelen to the proper size <= sizeof(struct sockaddr_storage) +to return msg_name to the user. + +This prevents numerous uninitialized memory leaks we had in the +recvmsg handlers and makes it harder for new code to accidentally leak +uninitialized memory. + +Optimize for the case recvfrom is called with NULL as address. We don't +need to copy the address at all, so set it to NULL before invoking the +recvmsg handler. We can do so, because all the recvmsg handlers must +cope with the case a plain read() is called on them. read() also sets +msg_name to NULL. + +Also document these changes in include/linux/net.h as suggested by David +Miller. + +Changes since RFC: + +Set msg->msg_name = NULL if user specified a NULL in msg_name but had a +non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't +affect sendto as it would bail out earlier while trying to copy-in the +address. It also more naturally reflects the logic by the callers of +verify_iovec. + +With this change in place I could remove " +if (!uaddr || msg_sys->msg_namelen == 0) + msg->msg_name = NULL +". + +This change does not alter the user visible error logic as we ignore +msg_namelen as long as msg_name is NULL. + +Also remove two unnecessary curly brackets in ___sys_recvmsg and change +comments to netdev style. + +Cc: David Miller +Suggested-by: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + crypto/algif_hash.c | 2 -- + crypto/algif_skcipher.c | 1 - + drivers/isdn/mISDN/socket.c | 13 ++++--------- + drivers/net/ppp/pppoe.c | 2 -- + include/linux/net.h | 8 ++++++++ + net/appletalk/ddp.c | 16 +++++++--------- + net/atm/common.c | 2 -- + net/ax25/af_ax25.c | 4 ++-- + net/bluetooth/af_bluetooth.c | 4 ---- + net/bluetooth/hci_sock.c | 2 -- + net/bluetooth/rfcomm/sock.c | 1 - + net/caif/caif_socket.c | 4 ---- + net/compat.c | 3 ++- + net/core/iovec.c | 3 ++- + net/ipx/af_ipx.c | 3 +-- + net/irda/af_irda.c | 4 ---- + net/iucv/af_iucv.c | 2 -- + net/key/af_key.c | 1 - + net/l2tp/l2tp_ppp.c | 2 -- + net/llc/af_llc.c | 2 -- + net/netlink/af_netlink.c | 2 -- + net/netrom/af_netrom.c | 3 +-- + net/nfc/rawsock.c | 2 -- + net/packet/af_packet.c | 32 +++++++++++++++----------------- + net/rds/recv.c | 2 -- + net/rose/af_rose.c | 8 +++++--- + net/rxrpc/ar-recvmsg.c | 9 ++++++--- + net/socket.c | 19 +++++++++++-------- + net/tipc/socket.c | 6 ------ + net/unix/af_unix.c | 5 ----- + net/x25/af_x25.c | 3 +-- + 31 files changed, 65 insertions(+), 105 deletions(-) + +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -161,8 +161,6 @@ static int hash_recvmsg(struct kiocb *un + else if (len < ds) + msg->msg_flags |= MSG_TRUNC; + +- msg->msg_namelen = 0; +- + lock_sock(sk); + if (ctx->more) { + ctx->more = 0; +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -432,7 +432,6 @@ static int skcipher_recvmsg(struct kiocb + long copied = 0; + + lock_sock(sk); +- msg->msg_namelen = 0; + for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0; + iovlen--, iov++) { + unsigned long seglen = iov->iov_len; +--- a/drivers/isdn/mISDN/socket.c ++++ b/drivers/isdn/mISDN/socket.c +@@ -117,7 +117,6 @@ mISDN_sock_recvmsg(struct kiocb *iocb, s + { + struct sk_buff *skb; + struct sock *sk = sock->sk; +- struct sockaddr_mISDN *maddr; + + int copied, err; + +@@ -135,9 +134,9 @@ mISDN_sock_recvmsg(struct kiocb *iocb, s + if (!skb) + return err; + +- if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { +- msg->msg_namelen = sizeof(struct sockaddr_mISDN); +- maddr = (struct sockaddr_mISDN *)msg->msg_name; ++ if (msg->msg_name) { ++ struct sockaddr_mISDN *maddr = msg->msg_name; ++ + maddr->family = AF_ISDN; + maddr->dev = _pms(sk)->dev->id; + if ((sk->sk_protocol == ISDN_P_LAPD_TE) || +@@ -150,11 +149,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, s + maddr->sapi = _pms(sk)->ch.addr & 0xFF; + maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; + } +- } else { +- if (msg->msg_namelen) +- printk(KERN_WARNING "%s: too small namelen %d\n", +- __func__, msg->msg_namelen); +- msg->msg_namelen = 0; ++ msg->msg_namelen = sizeof(*maddr); + } + + copied = skb->len + MISDN_HEADER_LEN; +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -985,8 +985,6 @@ static int pppoe_recvmsg(struct kiocb *i + if (error < 0) + goto end; + +- m->msg_namelen = 0; +- + if (skb) { + total_len = min_t(size_t, total_len, skb->len); + error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -198,6 +198,14 @@ struct proto_ops { + #endif + int (*sendmsg) (struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len); ++ /* Notes for implementing recvmsg: ++ * =============================== ++ * msg->msg_namelen should get updated by the recvmsg handlers ++ * iff msg_name != NULL. It is by default 0 to prevent ++ * returning uninitialized memory to user space. The recvfrom ++ * handlers can assume that msg.msg_name is either NULL or has ++ * a minimum size of sizeof(struct sockaddr_storage). ++ */ + int (*recvmsg) (struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len, + int flags); +--- a/net/appletalk/ddp.c ++++ b/net/appletalk/ddp.c +@@ -1740,7 +1740,6 @@ static int atalk_recvmsg(struct kiocb *i + size_t size, int flags) + { + struct sock *sk = sock->sk; +- struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name; + struct ddpehdr *ddp; + int copied = 0; + int offset = 0; +@@ -1769,14 +1768,13 @@ static int atalk_recvmsg(struct kiocb *i + } + err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied); + +- if (!err) { +- if (sat) { +- sat->sat_family = AF_APPLETALK; +- sat->sat_port = ddp->deh_sport; +- sat->sat_addr.s_node = ddp->deh_snode; +- sat->sat_addr.s_net = ddp->deh_snet; +- } +- msg->msg_namelen = sizeof(*sat); ++ if (!err && msg->msg_name) { ++ struct sockaddr_at *sat = msg->msg_name; ++ sat->sat_family = AF_APPLETALK; ++ sat->sat_port = ddp->deh_sport; ++ sat->sat_addr.s_node = ddp->deh_snode; ++ sat->sat_addr.s_net = ddp->deh_snet; ++ msg->msg_namelen = sizeof(*sat); + } + + skb_free_datagram(sk, skb); /* Free the datagram. */ +--- a/net/atm/common.c ++++ b/net/atm/common.c +@@ -520,8 +520,6 @@ int vcc_recvmsg(struct kiocb *iocb, stru + struct sk_buff *skb; + int copied, error = -EINVAL; + +- msg->msg_namelen = 0; +- + if (sock->state != SS_CONNECTED) + return -ENOTCONN; + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -1640,11 +1640,11 @@ static int ax25_recvmsg(struct kiocb *io + + skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + +- if (msg->msg_namelen != 0) { +- struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; ++ if (msg->msg_name) { + ax25_digi digi; + ax25_address src; + const unsigned char *mac = skb_mac_header(skb); ++ struct sockaddr_ax25 *sax = msg->msg_name; + + memset(sax, 0, sizeof(struct full_sockaddr_ax25)); + ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -240,8 +240,6 @@ int bt_sock_recvmsg(struct kiocb *iocb, + if (flags & (MSG_OOB)) + return -EOPNOTSUPP; + +- msg->msg_namelen = 0; +- + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) { + if (sk->sk_shutdown & RCV_SHUTDOWN) +@@ -306,8 +304,6 @@ int bt_sock_stream_recvmsg(struct kiocb + if (flags & MSG_OOB) + return -EOPNOTSUPP; + +- msg->msg_namelen = 0; +- + BT_DBG("sk %p size %zu", sk, size); + + lock_sock(sk); +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -767,8 +767,6 @@ static int hci_sock_recvmsg(struct kiocb + if (!skb) + return err; + +- msg->msg_namelen = 0; +- + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -628,7 +628,6 @@ static int rfcomm_sock_recvmsg(struct ki + + if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { + rfcomm_dlc_accept(d); +- msg->msg_namelen = 0; + return 0; + } + +--- a/net/caif/caif_socket.c ++++ b/net/caif/caif_socket.c +@@ -287,8 +287,6 @@ static int caif_seqpkt_recvmsg(struct ki + if (m->msg_flags&MSG_OOB) + goto read_error; + +- m->msg_namelen = 0; +- + skb = skb_recv_datagram(sk, flags, 0 , &ret); + if (!skb) + goto read_error; +@@ -362,8 +360,6 @@ static int caif_stream_recvmsg(struct ki + if (flags&MSG_OOB) + goto out; + +- msg->msg_namelen = 0; +- + /* + * Lock the socket to prevent queue disordering + * while sleeps in memcpy_tomsg +--- a/net/compat.c ++++ b/net/compat.c +@@ -93,7 +93,8 @@ int verify_compat_iovec(struct msghdr *k + if (err < 0) + return err; + } +- kern_msg->msg_name = kern_address; ++ if (kern_msg->msg_name) ++ kern_msg->msg_name = kern_address; + } else + kern_msg->msg_name = NULL; + +--- a/net/core/iovec.c ++++ b/net/core/iovec.c +@@ -48,7 +48,8 @@ int verify_iovec(struct msghdr *m, struc + if (err < 0) + return err; + } +- m->msg_name = address; ++ if (m->msg_name) ++ m->msg_name = address; + } else { + m->msg_name = NULL; + } +--- a/net/ipx/af_ipx.c ++++ b/net/ipx/af_ipx.c +@@ -1835,8 +1835,6 @@ static int ipx_recvmsg(struct kiocb *ioc + if (skb->tstamp.tv64) + sk->sk_stamp = skb->tstamp; + +- msg->msg_namelen = sizeof(*sipx); +- + if (sipx) { + sipx->sipx_family = AF_IPX; + sipx->sipx_port = ipx->ipx_source.sock; +@@ -1844,6 +1842,7 @@ static int ipx_recvmsg(struct kiocb *ioc + sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net; + sipx->sipx_type = ipx->ipx_type; + sipx->sipx_zero = 0; ++ msg->msg_namelen = sizeof(*sipx); + } + rc = copied; + +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -1386,8 +1386,6 @@ static int irda_recvmsg_dgram(struct kio + + IRDA_DEBUG(4, "%s()\n", __func__); + +- msg->msg_namelen = 0; +- + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &err); + if (!skb) +@@ -1452,8 +1450,6 @@ static int irda_recvmsg_stream(struct ki + target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); + timeo = sock_rcvtimeo(sk, noblock); + +- msg->msg_namelen = 0; +- + do { + int chunk; + struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1331,8 +1331,6 @@ static int iucv_sock_recvmsg(struct kioc + struct sk_buff *skb, *rskb, *cskb; + int err = 0; + +- msg->msg_namelen = 0; +- + if ((sk->sk_state == IUCV_DISCONN) && + skb_queue_empty(&iucv->backlog_skb_q) && + skb_queue_empty(&sk->sk_receive_queue) && +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -3595,7 +3595,6 @@ static int pfkey_recvmsg(struct kiocb *k + if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) + goto out; + +- msg->msg_namelen = 0; + skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); + if (skb == NULL) + goto out; +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -200,8 +200,6 @@ static int pppol2tp_recvmsg(struct kiocb + if (sk->sk_state & PPPOX_BOUND) + goto end; + +- msg->msg_namelen = 0; +- + err = 0; + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &err); +--- a/net/llc/af_llc.c ++++ b/net/llc/af_llc.c +@@ -721,8 +721,6 @@ static int llc_ui_recvmsg(struct kiocb * + int target; /* Read at least this many bytes */ + long timeo; + +- msg->msg_namelen = 0; +- + lock_sock(sk); + copied = -ENOTCONN; + if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN)) +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1443,8 +1443,6 @@ static int netlink_recvmsg(struct kiocb + } + #endif + +- msg->msg_namelen = 0; +- + copied = data_skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; +--- a/net/netrom/af_netrom.c ++++ b/net/netrom/af_netrom.c +@@ -1181,10 +1181,9 @@ static int nr_recvmsg(struct kiocb *iocb + sax->sax25_family = AF_NETROM; + skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call, + AX25_ADDR_LEN); ++ msg->msg_namelen = sizeof(*sax); + } + +- msg->msg_namelen = sizeof(*sax); +- + skb_free_datagram(sk, skb); + + release_sock(sk); +--- a/net/nfc/rawsock.c ++++ b/net/nfc/rawsock.c +@@ -235,8 +235,6 @@ static int rawsock_recvmsg(struct kiocb + if (!skb) + return rc; + +- msg->msg_namelen = 0; +- + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -2691,7 +2691,6 @@ static int packet_recvmsg(struct kiocb * + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err; +- struct sockaddr_ll *sll; + int vnet_hdr_len = 0; + + err = -EINVAL; +@@ -2774,22 +2773,10 @@ static int packet_recvmsg(struct kiocb * + goto out_free; + } + +- /* +- * If the address length field is there to be filled in, we fill +- * it in now. ++ /* You lose any data beyond the buffer you gave. If it worries ++ * a user program they can ask the device for its MTU ++ * anyway. + */ +- +- sll = &PACKET_SKB_CB(skb)->sa.ll; +- if (sock->type == SOCK_PACKET) +- msg->msg_namelen = sizeof(struct sockaddr_pkt); +- else +- msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); +- +- /* +- * You lose any data beyond the buffer you gave. If it worries a +- * user program they can ask the device for its MTU anyway. +- */ +- + copied = skb->len; + if (copied > len) { + copied = len; +@@ -2802,9 +2789,20 @@ static int packet_recvmsg(struct kiocb * + + sock_recv_ts_and_drops(msg, sk, skb); + +- if (msg->msg_name) ++ if (msg->msg_name) { ++ /* If the address length field is there to be filled ++ * in, we fill it in now. ++ */ ++ if (sock->type == SOCK_PACKET) { ++ msg->msg_namelen = sizeof(struct sockaddr_pkt); ++ } else { ++ struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; ++ msg->msg_namelen = sll->sll_halen + ++ offsetof(struct sockaddr_ll, sll_addr); ++ } + memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, + msg->msg_namelen); ++ } + + if (pkt_sk(sk)->auxdata) { + struct tpacket_auxdata aux; +--- a/net/rds/recv.c ++++ b/net/rds/recv.c +@@ -410,8 +410,6 @@ int rds_recvmsg(struct kiocb *iocb, stru + + rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo); + +- msg->msg_namelen = 0; +- + if (msg_flags & MSG_OOB) + goto out; + +--- a/net/rose/af_rose.c ++++ b/net/rose/af_rose.c +@@ -1220,7 +1220,6 @@ static int rose_recvmsg(struct kiocb *io + { + struct sock *sk = sock->sk; + struct rose_sock *rose = rose_sk(sk); +- struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name; + size_t copied; + unsigned char *asmptr; + struct sk_buff *skb; +@@ -1256,8 +1255,11 @@ static int rose_recvmsg(struct kiocb *io + + skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + +- if (srose != NULL) { +- memset(srose, 0, msg->msg_namelen); ++ if (msg->msg_name) { ++ struct sockaddr_rose *srose; ++ ++ memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose)); ++ srose = msg->msg_name; + srose->srose_family = AF_ROSE; + srose->srose_addr = rose->dest_addr; + srose->srose_call = rose->dest_call; +--- a/net/rxrpc/ar-recvmsg.c ++++ b/net/rxrpc/ar-recvmsg.c +@@ -143,10 +143,13 @@ int rxrpc_recvmsg(struct kiocb *iocb, st + + /* copy the peer address and timestamp */ + if (!continue_call) { +- if (msg->msg_name && msg->msg_namelen > 0) ++ if (msg->msg_name) { ++ size_t len = ++ sizeof(call->conn->trans->peer->srx); + memcpy(msg->msg_name, +- &call->conn->trans->peer->srx, +- sizeof(call->conn->trans->peer->srx)); ++ &call->conn->trans->peer->srx, len); ++ msg->msg_namelen = len; ++ } + sock_recv_ts_and_drops(msg, &rx->sk, skb); + } + +--- a/net/socket.c ++++ b/net/socket.c +@@ -1775,8 +1775,10 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void + msg.msg_iov = &iov; + iov.iov_len = size; + iov.iov_base = ubuf; +- msg.msg_name = (struct sockaddr *)&address; +- msg.msg_namelen = sizeof(address); ++ /* Save some cycles and don't copy the address if not needed */ ++ msg.msg_name = addr ? (struct sockaddr *)&address : NULL; ++ /* We assume all kernel code knows the size of sockaddr_storage */ ++ msg.msg_namelen = 0; + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + err = sock_recvmsg(sock, &msg, size, flags); +@@ -2161,16 +2163,14 @@ static int ___sys_recvmsg(struct socket + goto out; + } + +- /* +- * Save the user-mode address (verify_iovec will change the +- * kernel msghdr to use the kernel address space) ++ /* Save the user-mode address (verify_iovec will change the ++ * kernel msghdr to use the kernel address space) + */ +- + uaddr = (__force void __user *)msg_sys->msg_name; + uaddr_len = COMPAT_NAMELEN(msg); +- if (MSG_CMSG_COMPAT & flags) { ++ if (MSG_CMSG_COMPAT & flags) + err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); +- } else ++ else + err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); + if (err < 0) + goto out_freeiov; +@@ -2179,6 +2179,9 @@ static int ___sys_recvmsg(struct socket + cmsg_ptr = (unsigned long)msg_sys->msg_control; + msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); + ++ /* We assume all kernel code knows the size of sockaddr_storage */ ++ msg_sys->msg_namelen = 0; ++ + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, +--- a/net/tipc/socket.c ++++ b/net/tipc/socket.c +@@ -949,9 +949,6 @@ static int recv_msg(struct kiocb *iocb, + goto exit; + } + +- /* will be updated in set_orig_addr() if needed */ +- m->msg_namelen = 0; +- + timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); + restart: + +@@ -1078,9 +1075,6 @@ static int recv_stream(struct kiocb *ioc + goto exit; + } + +- /* will be updated in set_orig_addr() if needed */ +- m->msg_namelen = 0; +- + target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); + timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); + restart: +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1755,7 +1755,6 @@ static void unix_copy_addr(struct msghdr + { + struct unix_sock *u = unix_sk(sk); + +- msg->msg_namelen = 0; + if (u->addr) { + msg->msg_namelen = u->addr->len; + memcpy(msg->msg_name, u->addr->name, u->addr->len); +@@ -1779,8 +1778,6 @@ static int unix_dgram_recvmsg(struct kio + if (flags&MSG_OOB) + goto out; + +- msg->msg_namelen = 0; +- + err = mutex_lock_interruptible(&u->readlock); + if (err) { + err = sock_intr_errno(sock_rcvtimeo(sk, noblock)); +@@ -1922,8 +1919,6 @@ static int unix_stream_recvmsg(struct ki + target = sock_rcvlowat(sk, flags&MSG_WAITALL, size); + timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT); + +- msg->msg_namelen = 0; +- + /* Lock the socket to prevent queue disordering + * while sleeps in memcpy_tomsg + */ +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -1343,10 +1343,9 @@ static int x25_recvmsg(struct kiocb *ioc + if (sx25) { + sx25->sx25_family = AF_X25; + sx25->sx25_addr = x25->dest_addr; ++ msg->msg_namelen = sizeof(*sx25); + } + +- msg->msg_namelen = sizeof(struct sockaddr_x25); +- + x25_check_rbuf(sk); + rc = copied; + out_free_dgram: diff --git a/queue-3.4/net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch b/queue-3.4/net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch new file mode 100644 index 00000000000..b46fc8552e1 --- /dev/null +++ b/queue-3.4/net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch @@ -0,0 +1,70 @@ +From 91cd85f44fa67f075bf729dd4a8e7e3260760c9f Mon Sep 17 00:00:00 2001 +From: Shawn Landden +Date: Sun, 24 Nov 2013 22:36:28 -0800 +Subject: net: update consumers of MSG_MORE to recognize MSG_SENDPAGE_NOTLAST + +From: Shawn Landden + +[ Upstream commit d3f7d56a7a4671d395e8af87071068a195257bf6 ] + +Commit 35f9c09fe (tcp: tcp_sendpages() should call tcp_push() once) +added an internal flag MSG_SENDPAGE_NOTLAST, similar to +MSG_MORE. + +algif_hash, algif_skcipher, and udp used MSG_MORE from tcp_sendpages() +and need to see the new flag as identical to MSG_MORE. + +This fixes sendfile() on AF_ALG. + +v3: also fix udp + +Reported-and-tested-by: Shawn Landden +Cc: Tom Herbert +Cc: Eric Dumazet +Cc: David S. Miller +Original-patch: Richard Weinberger +Signed-off-by: Shawn Landden +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + crypto/algif_hash.c | 3 +++ + crypto/algif_skcipher.c | 3 +++ + net/ipv4/udp.c | 3 +++ + 3 files changed, 9 insertions(+) + +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -114,6 +114,9 @@ static ssize_t hash_sendpage(struct sock + struct hash_ctx *ctx = ask->private; + int err; + ++ if (flags & MSG_SENDPAGE_NOTLAST) ++ flags |= MSG_MORE; ++ + lock_sock(sk); + sg_init_table(ctx->sgl.sg, 1); + sg_set_page(ctx->sgl.sg, page, size, offset); +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -378,6 +378,9 @@ static ssize_t skcipher_sendpage(struct + struct skcipher_sg_list *sgl; + int err = -EINVAL; + ++ if (flags & MSG_SENDPAGE_NOTLAST) ++ flags |= MSG_MORE; ++ + lock_sock(sk); + if (!ctx->more && ctx->used) + goto unlock; +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1039,6 +1039,9 @@ int udp_sendpage(struct sock *sk, struct + struct udp_sock *up = udp_sk(sk); + int ret; + ++ if (flags & MSG_SENDPAGE_NOTLAST) ++ flags |= MSG_MORE; ++ + if (!up->pending) { + struct msghdr msg = { .msg_flags = flags|MSG_MORE }; + diff --git a/queue-3.4/packet-fix-use-after-free-race-in-send-path-when-dev-is-released.patch b/queue-3.4/packet-fix-use-after-free-race-in-send-path-when-dev-is-released.patch new file mode 100644 index 00000000000..ed1344f2d66 --- /dev/null +++ b/queue-3.4/packet-fix-use-after-free-race-in-send-path-when-dev-is-released.patch @@ -0,0 +1,220 @@ +From 747110f5834376c6e616a40167da6b7f2efbb976 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 21 Nov 2013 16:50:58 +0100 +Subject: packet: fix use after free race in send path when dev is released + +From: Daniel Borkmann + +[ Upstream commit e40526cb20b5ee53419452e1f03d97092f144418 ] + +Salam reported a use after free bug in PF_PACKET that occurs when +we're sending out frames on a socket bound device and suddenly the +net device is being unregistered. It appears that commit 827d9780 +introduced a possible race condition between {t,}packet_snd() and +packet_notifier(). In the case of a bound socket, packet_notifier() +can drop the last reference to the net_device and {t,}packet_snd() +might end up suddenly sending a packet over a freed net_device. + +To avoid reverting 827d9780 and thus introducing a performance +regression compared to the current state of things, we decided to +hold a cached RCU protected pointer to the net device and maintain +it on write side via bind spin_lock protected register_prot_hook() +and __unregister_prot_hook() calls. + +In {t,}packet_snd() path, we access this pointer under rcu_read_lock +through packet_cached_dev_get() that holds reference to the device +to prevent it from being freed through packet_notifier() while +we're in send path. This is okay to do as dev_put()/dev_hold() are +per-cpu counters, so this should not be a performance issue. Also, +the code simplifies a bit as we don't need need_rls_dev anymore. + +Fixes: 827d978037d7 ("af-packet: Use existing netdev reference for bound sockets.") +Reported-by: Salam Noureddine +Signed-off-by: Daniel Borkmann +Signed-off-by: Salam Noureddine +Cc: Ben Greear +Cc: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/packet/af_packet.c | 60 ++++++++++++++++++++++++++++++------------------- + 1 file changed, 37 insertions(+), 23 deletions(-) + +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -294,6 +294,7 @@ struct packet_sock { + unsigned int tp_reserve; + unsigned int tp_loss:1; + unsigned int tp_tstamp; ++ struct net_device __rcu *cached_dev; + struct packet_type prot_hook ____cacheline_aligned_in_smp; + }; + +@@ -349,11 +350,15 @@ static void __fanout_link(struct sock *s + static void register_prot_hook(struct sock *sk) + { + struct packet_sock *po = pkt_sk(sk); ++ + if (!po->running) { +- if (po->fanout) ++ if (po->fanout) { + __fanout_link(sk, po); +- else ++ } else { + dev_add_pack(&po->prot_hook); ++ rcu_assign_pointer(po->cached_dev, po->prot_hook.dev); ++ } ++ + sock_hold(sk); + po->running = 1; + } +@@ -371,10 +376,13 @@ static void __unregister_prot_hook(struc + struct packet_sock *po = pkt_sk(sk); + + po->running = 0; +- if (po->fanout) ++ if (po->fanout) { + __fanout_unlink(sk, po); +- else ++ } else { + __dev_remove_pack(&po->prot_hook); ++ RCU_INIT_POINTER(po->cached_dev, NULL); ++ } ++ + __sock_put(sk); + + if (sync) { +@@ -2044,12 +2052,24 @@ static int tpacket_fill_skb(struct packe + return tp_len; + } + ++static struct net_device *packet_cached_dev_get(struct packet_sock *po) ++{ ++ struct net_device *dev; ++ ++ rcu_read_lock(); ++ dev = rcu_dereference(po->cached_dev); ++ if (dev) ++ dev_hold(dev); ++ rcu_read_unlock(); ++ ++ return dev; ++} ++ + static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) + { + struct sk_buff *skb; + struct net_device *dev; + __be16 proto; +- bool need_rls_dev = false; + int err, reserve = 0; + void *ph; + struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; +@@ -2063,7 +2083,7 @@ static int tpacket_snd(struct packet_soc + + err = -EBUSY; + if (saddr == NULL) { +- dev = po->prot_hook.dev; ++ dev = packet_cached_dev_get(po); + proto = po->num; + addr = NULL; + } else { +@@ -2077,19 +2097,17 @@ static int tpacket_snd(struct packet_soc + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); +- need_rls_dev = true; + } + + err = -ENXIO; + if (unlikely(dev == NULL)) + goto out; +- +- reserve = dev->hard_header_len; +- + err = -ENETDOWN; + if (unlikely(!(dev->flags & IFF_UP))) + goto out_put; + ++ reserve = dev->hard_header_len; ++ + size_max = po->tx_ring.frame_size + - (po->tp_hdrlen - sizeof(struct sockaddr_ll)); + +@@ -2166,8 +2184,7 @@ out_status: + __packet_set_status(po, ph, status); + kfree_skb(skb); + out_put: +- if (need_rls_dev) +- dev_put(dev); ++ dev_put(dev); + out: + mutex_unlock(&po->pg_vec_lock); + return err; +@@ -2205,7 +2222,6 @@ static int packet_snd(struct socket *soc + struct sk_buff *skb; + struct net_device *dev; + __be16 proto; +- bool need_rls_dev = false; + unsigned char *addr; + int err, reserve = 0; + struct virtio_net_hdr vnet_hdr = { 0 }; +@@ -2221,7 +2237,7 @@ static int packet_snd(struct socket *soc + */ + + if (saddr == NULL) { +- dev = po->prot_hook.dev; ++ dev = packet_cached_dev_get(po); + proto = po->num; + addr = NULL; + } else { +@@ -2233,19 +2249,17 @@ static int packet_snd(struct socket *soc + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); +- need_rls_dev = true; + } + + err = -ENXIO; +- if (dev == NULL) ++ if (unlikely(dev == NULL)) + goto out_unlock; +- if (sock->type == SOCK_RAW) +- reserve = dev->hard_header_len; +- + err = -ENETDOWN; +- if (!(dev->flags & IFF_UP)) ++ if (unlikely(!(dev->flags & IFF_UP))) + goto out_unlock; + ++ if (sock->type == SOCK_RAW) ++ reserve = dev->hard_header_len; + if (po->has_vnet_hdr) { + vnet_hdr_len = sizeof(vnet_hdr); + +@@ -2378,15 +2392,14 @@ static int packet_snd(struct socket *soc + if (err > 0 && (err = net_xmit_errno(err)) != 0) + goto out_unlock; + +- if (need_rls_dev) +- dev_put(dev); ++ dev_put(dev); + + return len; + + out_free: + kfree_skb(skb); + out_unlock: +- if (dev && need_rls_dev) ++ if (dev) + dev_put(dev); + out: + return err; +@@ -2603,6 +2616,7 @@ static int packet_create(struct net *net + po = pkt_sk(sk); + sk->sk_family = PF_PACKET; + po->num = proto; ++ RCU_INIT_POINTER(po->cached_dev, NULL); + + sk->sk_destruct = packet_sock_destruct; + sk_refcnt_debug_inc(sk); diff --git a/queue-3.4/pktgen-xfrm-update-ipv4-header-total-len-and-checksum-after-tranformation.patch b/queue-3.4/pktgen-xfrm-update-ipv4-header-total-len-and-checksum-after-tranformation.patch new file mode 100644 index 00000000000..8a5e06017d4 --- /dev/null +++ b/queue-3.4/pktgen-xfrm-update-ipv4-header-total-len-and-checksum-after-tranformation.patch @@ -0,0 +1,57 @@ +From 81925fd57f0ec863230e1b3247f6f193ce2953ac Mon Sep 17 00:00:00 2001 +From: "fan.du" +Date: Sun, 1 Dec 2013 16:28:48 +0800 +Subject: {pktgen, xfrm} Update IPv4 header total len and checksum after tranformation + +From: "fan.du" + +[ Upstream commit 3868204d6b89ea373a273e760609cb08020beb1a ] + +commit a553e4a6317b2cfc7659542c10fe43184ffe53da ("[PKTGEN]: IPSEC support") +tried to support IPsec ESP transport transformation for pktgen, but acctually +this doesn't work at all for two reasons(The orignal transformed packet has +bad IPv4 checksum value, as well as wrong auth value, reported by wireshark) + +- After transpormation, IPv4 header total length needs update, + because encrypted payload's length is NOT same as that of plain text. + +- After transformation, IPv4 checksum needs re-caculate because of payload + has been changed. + +With this patch, armmed pktgen with below cofiguration, Wireshark is able to +decrypted ESP packet generated by pktgen without any IPv4 checksum error or +auth value error. + +pgset "flag IPSEC" +pgset "flows 1" + +Signed-off-by: Fan Du +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/pktgen.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -2521,6 +2521,8 @@ static int process_ipsec(struct pktgen_d + if (x) { + int ret; + __u8 *eth; ++ struct iphdr *iph; ++ + nhead = x->props.header_len - skb_headroom(skb); + if (nhead > 0) { + ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); +@@ -2542,6 +2544,11 @@ static int process_ipsec(struct pktgen_d + eth = (__u8 *) skb_push(skb, ETH_HLEN); + memcpy(eth, pkt_dev->hh, 12); + *(u16 *) ð[12] = protocol; ++ ++ /* Update IPv4 header len as well as checksum value */ ++ iph = ip_hdr(skb); ++ iph->tot_len = htons(skb->len - ETH_HLEN); ++ ip_send_check(iph); + } + } + return 1; diff --git a/queue-3.4/random32-fix-off-by-one-in-seeding-requirement.patch b/queue-3.4/random32-fix-off-by-one-in-seeding-requirement.patch new file mode 100644 index 00000000000..87ab0e4debe --- /dev/null +++ b/queue-3.4/random32-fix-off-by-one-in-seeding-requirement.patch @@ -0,0 +1,96 @@ +From 02638b50e8249d902d2ac84477e80e501c7c31cc Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Mon, 11 Nov 2013 12:20:32 +0100 +Subject: random32: fix off-by-one in seeding requirement + +From: Daniel Borkmann + +[ Upstream commit 51c37a70aaa3f95773af560e6db3073520513912 ] + +For properly initialising the Tausworthe generator [1], we have +a strict seeding requirement, that is, s1 > 1, s2 > 7, s3 > 15. + +Commit 697f8d0348 ("random32: seeding improvement") introduced +a __seed() function that imposes boundary checks proposed by the +errata paper [2] to properly ensure above conditions. + +However, we're off by one, as the function is implemented as: +"return (x < m) ? x + m : x;", and called with __seed(X, 1), +__seed(X, 7), __seed(X, 15). Thus, an unwanted seed of 1, 7, 15 +would be possible, whereas the lower boundary should actually +be of at least 2, 8, 16, just as GSL does. Fix this, as otherwise +an initialization with an unwanted seed could have the effect +that Tausworthe's PRNG properties cannot not be ensured. + +Note that this PRNG is *not* used for cryptography in the kernel. + + [1] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + [2] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + +Joint work with Hannes Frederic Sowa. + +Fixes: 697f8d0348a6 ("random32: seeding improvement") +Cc: Stephen Hemminger +Cc: Florian Weimer +Cc: Theodore Ts'o +Signed-off-by: Daniel Borkmann +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/random.h | 6 +++--- + lib/random32.c | 14 +++++++------- + 2 files changed, 10 insertions(+), 10 deletions(-) + +--- a/include/linux/random.h ++++ b/include/linux/random.h +@@ -87,9 +87,9 @@ static inline void prandom32_seed(struct + { + u32 i = (seed >> 32) ^ (seed << 10) ^ seed; + +- state->s1 = __seed(i, 1); +- state->s2 = __seed(i, 7); +- state->s3 = __seed(i, 15); ++ state->s1 = __seed(i, 2); ++ state->s2 = __seed(i, 8); ++ state->s3 = __seed(i, 16); + } + + #ifdef CONFIG_ARCH_RANDOM +--- a/lib/random32.c ++++ b/lib/random32.c +@@ -92,7 +92,7 @@ void srandom32(u32 entropy) + */ + for_each_possible_cpu (i) { + struct rnd_state *state = &per_cpu(net_rand_state, i); +- state->s1 = __seed(state->s1 ^ entropy, 1); ++ state->s1 = __seed(state->s1 ^ entropy, 2); + } + } + EXPORT_SYMBOL(srandom32); +@@ -109,9 +109,9 @@ static int __init random32_init(void) + struct rnd_state *state = &per_cpu(net_rand_state,i); + + #define LCG(x) ((x) * 69069) /* super-duper LCG */ +- state->s1 = __seed(LCG(i + jiffies), 1); +- state->s2 = __seed(LCG(state->s1), 7); +- state->s3 = __seed(LCG(state->s2), 15); ++ state->s1 = __seed(LCG(i + jiffies), 2); ++ state->s2 = __seed(LCG(state->s1), 8); ++ state->s3 = __seed(LCG(state->s2), 16); + + /* "warm it up" */ + prandom32(state); +@@ -138,9 +138,9 @@ static int __init random32_reseed(void) + u32 seeds[3]; + + get_random_bytes(&seeds, sizeof(seeds)); +- state->s1 = __seed(seeds[0], 1); +- state->s2 = __seed(seeds[1], 7); +- state->s3 = __seed(seeds[2], 15); ++ state->s1 = __seed(seeds[0], 2); ++ state->s2 = __seed(seeds[1], 8); ++ state->s3 = __seed(seeds[2], 16); + + /* mix it in */ + prandom32(state); diff --git a/queue-3.4/series b/queue-3.4/series new file mode 100644 index 00000000000..b0365b64111 --- /dev/null +++ b/queue-3.4/series @@ -0,0 +1,24 @@ +net-fix-ip-rule-delete-table-256.patch +ipv6-use-rt6_get_dflt_router-to-get-default-router-in-rt6_route_rcv.patch +random32-fix-off-by-one-in-seeding-requirement.patch +bonding-don-t-permit-to-use-arp-monitoring-in-802.3ad.patch +6lowpan-uncompression-of-traffic-class-field-was-incorrect.patch +bonding-fix-two-race-conditions-in-bond_store_updelay-downdelay.patch +isdnloop-use-strlcpy-instead-of-strcpy.patch +connector-improved-unaligned-access-error-fix.patch +ipv4-fix-possible-seqlock-deadlock.patch +inet-prevent-leakage-of-uninitialized-memory-to-user-in-recv-syscalls.patch +net-rework-recvmsg-handler-msg_name-and-msg_namelen-logic.patch +net-add-bug_on-if-kernel-advertises-msg_namelen-sizeof-struct-sockaddr_storage.patch +inet-fix-addr_len-msg-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch +net-clamp-msg_namelen-instead-of-returning-an-error.patch +ipv6-fix-leaking-uninitialized-port-number-of-offender-sockaddr.patch +atm-idt77252-fix-dev-refcnt-leak.patch +net-core-always-propagate-flag-changes-to-interfaces.patch +bridge-flush-br-s-address-entry-in-fdb-when-remove-the-bridge-dev.patch +packet-fix-use-after-free-race-in-send-path-when-dev-is-released.patch +af_packet-block-bh-in-prb_shutdown_retire_blk_timer.patch +net-update-consumers-of-msg_more-to-recognize-msg_sendpage_notlast.patch +inet-fix-possible-seqlock-deadlocks.patch +ipv6-fix-possible-seqlock-deadlock-in-ip6_finish_output2.patch +pktgen-xfrm-update-ipv4-header-total-len-and-checksum-after-tranformation.patch