From d3dcd4efe2ad1ad1865b2fe5c863c1ebd9482a84 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 19 Jun 2006 23:39:45 -0700 Subject: [NETFILTER]: xt_sctp: fix endless loop caused by 0 chunk length Fix endless loop in the SCTP match similar to those already fixed in the SCTP conntrack helper (was CVE-2006-1527). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index b5110e5..9316c75 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -62,7 +62,7 @@ match_packet(const struct sk_buff *skb, do { sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); - if (sch == NULL) { + if (sch == NULL || sch->length == 0) { duprintf("Dropping invalid SCTP packet.\n"); *hotdrop = 1; return 0; -- cgit v0.10.2 From d6cc7f1a3b33c89c91b3dfce1ff053178893470e Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Mon, 19 Jun 2006 23:42:53 -0700 Subject: [CONNECTOR]: Initialize subsystem earlier. Attached patch declares connector init function as subsys_init() and returns -EAGAIN in case connector is not initialized yet. Signed-off-by: Evgeniy Polyakov Signed-off-by: David S. Miller diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 3589707..79d581c 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -308,6 +308,9 @@ int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *)) int err; struct cn_dev *dev = &cdev; + if (!cn_already_initialized) + return -EAGAIN; + err = cn_queue_add_callback(dev->cbdev, name, id, callback); if (err) return err; @@ -435,7 +438,7 @@ static void cn_callback(void *data) mutex_unlock(¬ify_lock); } -static int __init cn_init(void) +static int __devinit cn_init(void) { struct cn_dev *dev = &cdev; int err; @@ -456,21 +459,22 @@ static int __init cn_init(void) sock_release(dev->nls->sk_socket); return -EINVAL; } + + cn_already_initialized = 1; err = cn_add_callback(&dev->id, "connector", &cn_callback); if (err) { + cn_already_initialized = 0; cn_queue_free_dev(dev->cbdev); if (dev->nls->sk_socket) sock_release(dev->nls->sk_socket); return -EINVAL; } - cn_already_initialized = 1; - return 0; } -static void __exit cn_fini(void) +static void __devexit cn_fini(void) { struct cn_dev *dev = &cdev; @@ -482,7 +486,7 @@ static void __exit cn_fini(void) sock_release(dev->nls->sk_socket); } -module_init(cn_init); +subsys_initcall(cn_init); module_exit(cn_fini); EXPORT_SYMBOL_GPL(cn_add_callback); -- cgit v0.10.2 From 48d83325b61043e3bbd24dd37b9fe433744cf330 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 19 Jun 2006 23:57:59 -0700 Subject: [NET]: Prevent multiple qdisc runs Having two or more qdisc_run's contend against each other is bad because it can induce packet reordering if the packets have to be requeued. It appears that this is an unintended consequence of relinquinshing the queue lock while transmitting. That in turn is needed for devices that spend a lot of time in their transmit routine. There are no advantages to be had as devices with queues are inherently single-threaded (the loopback device is not but then it doesn't have a queue). Even if you were to add a queue to a parallel virtual device (e.g., bolt a tbf filter in front of an ipip tunnel device), you would still want to process the queue in sequence to ensure that the packets are ordered correctly. The solution here is to steal a bit from net_device to prevent this. BTW, as qdisc_restart is no longer used by anyone as a module inside the kernel (IIRC it used to with netif_wake_queue), I have not exported the new __qdisc_run function. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e432b74..39919c8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -233,6 +233,7 @@ enum netdev_state_t __LINK_STATE_RX_SCHED, __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, + __LINK_STATE_QDISC_RUNNING, }; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index b94d1ad..75b5b93 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab); extern void qdisc_put_rtab(struct qdisc_rate_table *tab); -extern int qdisc_restart(struct net_device *dev); +extern void __qdisc_run(struct net_device *dev); static inline void qdisc_run(struct net_device *dev) { - while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0) - /* NOTHING */; + if (!netif_queue_stopped(dev) && + !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) + __qdisc_run(dev); } extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index b1e4c5e..d7aca8e 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -90,7 +90,7 @@ void qdisc_unlock_tree(struct net_device *dev) NOTE: Called under dev->queue_lock with locally disabled BH. */ -int qdisc_restart(struct net_device *dev) +static inline int qdisc_restart(struct net_device *dev) { struct Qdisc *q = dev->qdisc; struct sk_buff *skb; @@ -179,6 +179,14 @@ requeue: return q->q.qlen; } +void __qdisc_run(struct net_device *dev) +{ + while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev)) + /* NOTHING */; + + clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); +} + static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -620,6 +628,5 @@ EXPORT_SYMBOL(qdisc_create_dflt); EXPORT_SYMBOL(qdisc_alloc); EXPORT_SYMBOL(qdisc_destroy); EXPORT_SYMBOL(qdisc_reset); -EXPORT_SYMBOL(qdisc_restart); EXPORT_SYMBOL(qdisc_lock_tree); EXPORT_SYMBOL(qdisc_unlock_tree); -- cgit v0.10.2 From 65fd28f743be6e3e3fd8eefa9a517656636fee42 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 00:07:52 -0700 Subject: [SCTP]: Fix unintentional change to SCTP_ASSERT when !SCTP_DEBUG A local debugging change slipped into a previous changeset. When SCTP_DEBUG is off SCTP_ASSERT should do nothing. Signed-off-by: David S. Miller diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index b2b40f9..aa6033c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -255,7 +255,7 @@ extern int sctp_debug_flag; #define SCTP_DEBUG_PRINTK_IPADDR(whatever...) #define SCTP_ENABLE_DEBUG #define SCTP_DISABLE_DEBUG -#define SCTP_ASSERT(expr, str, func) BUG_ON(!(expr)) +#define SCTP_ASSERT(expr, str, func) #endif /* SCTP_DEBUG */ -- cgit v0.10.2 From 8ca84481b69513f7bf341c7dd9897023a04d7d1d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 20 Jun 2006 03:26:14 -0700 Subject: [SCTP]: sctp_unpack_cookie() fix sizeof(pointer) != sizeof(array)... Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 5e0de3c..2a87736 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1402,14 +1402,14 @@ struct sctp_association *sctp_unpack_cookie( sg.length = bodysize; key = (char *)ep->secret_key[ep->current_key]; - memset(digest, 0x00, sizeof(digest)); + memset(digest, 0x00, SCTP_SIGNATURE_SIZE); sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Try the previous key. */ key = (char *)ep->secret_key[ep->last_key]; - memset(digest, 0x00, sizeof(digest)); + memset(digest, 0x00, SCTP_SIGNATURE_SIZE); sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); -- cgit v0.10.2 From ff7512e1a2a3504649d3716a757f43807b6d26ef Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 20 Jun 2006 03:27:27 -0700 Subject: [ATM]: fix broken uses of NIPQUAD in net/atm NIPQUAD expects an l-value of type __be32, _NOT_ a pointer to __be32. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/net/atm/mpc.c b/net/atm/mpc.c index c304ef1..a48a5d5 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -229,20 +229,15 @@ int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry) /* this is buggered - we need locking for qos_head */ void atm_mpoa_disp_qos(struct seq_file *m) { - unsigned char *ip; - char ipaddr[16]; struct atm_mpoa_qos *qos; qos = qos_head; seq_printf(m, "QoS entries for shortcuts:\n"); seq_printf(m, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n"); - ipaddr[sizeof(ipaddr)-1] = '\0'; while (qos != NULL) { - ip = (unsigned char *)&qos->ipaddr; - sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(ip)); seq_printf(m, "%u.%u.%u.%u\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", - NIPQUAD(ipaddr), + NIPQUAD(qos->ipaddr), qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu, qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu); qos = qos->next; @@ -1083,7 +1078,6 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry) { uint32_t dst_ip = msg->content.in_info.in_dst_ip; - unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip; struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); @@ -1097,7 +1091,7 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien entry->shortcut = eg_entry->shortcut; } if(entry->shortcut){ - dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(ip)); + dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(dst_ip)); client->eg_ops->put(eg_entry); return; } @@ -1123,8 +1117,7 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) uint32_t dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); - ip = (unsigned char *)&dst_ip; - dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(ip)); + dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip)); ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry); if(entry == NULL){ printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name); diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index 64ddebb..781ed1b 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -223,7 +223,6 @@ static void in_cache_remove_entry(in_cache_entry *entry, but an easy one... */ static void clear_count_and_expired(struct mpoa_client *client) { - unsigned char *ip; in_cache_entry *entry, *next_entry; struct timeval now; @@ -236,8 +235,7 @@ static void clear_count_and_expired(struct mpoa_client *client) next_entry = entry->next; if((now.tv_sec - entry->tv.tv_sec) > entry->ctrl_info.holding_time){ - ip = (unsigned char*)&entry->ctrl_info.in_dst_ip; - dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(ip)); + dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip)); client->in_ops->remove_entry(entry, client); } entry = next_entry; @@ -455,7 +453,6 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client) { - unsigned char *ip; eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL); if (entry == NULL) { @@ -463,8 +460,7 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli return NULL; } - ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip; - dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(ip)); + dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(msg->content.eg_info.eg_dst_ip)); memset(entry, 0, sizeof(eg_cache_entry)); atomic_set(&entry->use, 1); @@ -481,8 +477,8 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); - ip = (unsigned char *)&entry->ctrl_info.mps_ip; - dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", NIPQUAD(ip)); + dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", + NIPQUAD(entry->ctrl_info.mps_ip)); atomic_inc(&entry->use); write_unlock_irq(&client->egress_lock); -- cgit v0.10.2