diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_if.c | 21 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 10 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 7 |
4 files changed, 29 insertions, 10 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ba442883e877..da687c8dc6ff 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p) | |||
104 | { | 104 | { |
105 | struct net_device *dev = p->dev; | 105 | struct net_device *dev = p->dev; |
106 | 106 | ||
107 | dev->br_port = NULL; | ||
107 | p->br = NULL; | 108 | p->br = NULL; |
108 | p->dev = NULL; | 109 | p->dev = NULL; |
109 | dev_put(dev); | 110 | dev_put(dev); |
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head) | |||
118 | destroy_nbp(p); | 119 | destroy_nbp(p); |
119 | } | 120 | } |
120 | 121 | ||
121 | /* called with RTNL */ | 122 | /* Delete port(interface) from bridge is done in two steps. |
123 | * via RCU. First step, marks device as down. That deletes | ||
124 | * all the timers and stops new packets from flowing through. | ||
125 | * | ||
126 | * Final cleanup doesn't occur until after all CPU's finished | ||
127 | * processing packets. | ||
128 | * | ||
129 | * Protected from multiple admin operations by RTNL mutex | ||
130 | */ | ||
122 | static void del_nbp(struct net_bridge_port *p) | 131 | static void del_nbp(struct net_bridge_port *p) |
123 | { | 132 | { |
124 | struct net_bridge *br = p->br; | 133 | struct net_bridge *br = p->br; |
125 | struct net_device *dev = p->dev; | 134 | struct net_device *dev = p->dev; |
126 | 135 | ||
127 | dev->br_port = NULL; | 136 | /* Race between RTNL notify and RCU callback */ |
137 | if (p->deleted) | ||
138 | return; | ||
139 | |||
128 | dev_set_promiscuity(dev, -1); | 140 | dev_set_promiscuity(dev, -1); |
129 | 141 | ||
130 | cancel_delayed_work(&p->carrier_check); | 142 | cancel_delayed_work(&p->carrier_check); |
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p) | |||
132 | 144 | ||
133 | spin_lock_bh(&br->lock); | 145 | spin_lock_bh(&br->lock); |
134 | br_stp_disable_port(p); | 146 | br_stp_disable_port(p); |
147 | p->deleted = 1; | ||
135 | spin_unlock_bh(&br->lock); | 148 | spin_unlock_bh(&br->lock); |
136 | 149 | ||
137 | br_fdb_delete_by_port(br, p); | 150 | br_fdb_delete_by_port(br, p); |
138 | 151 | ||
139 | list_del_rcu(&p->list); | 152 | list_del_rcu(&p->list); |
140 | 153 | ||
141 | del_timer_sync(&p->message_age_timer); | ||
142 | del_timer_sync(&p->forward_delay_timer); | ||
143 | del_timer_sync(&p->hold_timer); | ||
144 | |||
145 | call_rcu(&p->rcu, destroy_nbp_rcu); | 154 | call_rcu(&p->rcu, destroy_nbp_rcu); |
146 | } | 155 | } |
147 | 156 | ||
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c5bd631ffcd5..e330b17b6d81 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -68,6 +68,7 @@ struct net_bridge_port | |||
68 | /* STP */ | 68 | /* STP */ |
69 | u8 priority; | 69 | u8 priority; |
70 | u8 state; | 70 | u8 state; |
71 | u8 deleted; | ||
71 | u16 port_no; | 72 | u16 port_no; |
72 | unsigned char topology_change_ack; | 73 | unsigned char topology_change_ack; |
73 | unsigned char config_pending; | 74 | unsigned char config_pending; |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ce617b3dbbb8..802baf755ef4 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #define PRINTR(format, args...) do { if (net_ratelimit()) \ | 46 | #define PRINTR(format, args...) do { if (net_ratelimit()) \ |
47 | printk(format , ## args); } while (0) | 47 | printk(format , ## args); } while (0) |
48 | 48 | ||
49 | static unsigned int nlbufsiz = 4096; | 49 | static unsigned int nlbufsiz = NLMSG_GOODSIZE; |
50 | module_param(nlbufsiz, uint, 0600); | 50 | module_param(nlbufsiz, uint, 0600); |
51 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " | 51 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " |
52 | "(defaults to 4096)"); | 52 | "(defaults to 4096)"); |
@@ -98,12 +98,14 @@ static void ulog_timer(unsigned long data) | |||
98 | static struct sk_buff *ulog_alloc_skb(unsigned int size) | 98 | static struct sk_buff *ulog_alloc_skb(unsigned int size) |
99 | { | 99 | { |
100 | struct sk_buff *skb; | 100 | struct sk_buff *skb; |
101 | unsigned int n; | ||
101 | 102 | ||
102 | skb = alloc_skb(nlbufsiz, GFP_ATOMIC); | 103 | n = max(size, nlbufsiz); |
104 | skb = alloc_skb(n, GFP_ATOMIC); | ||
103 | if (!skb) { | 105 | if (!skb) { |
104 | PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " | 106 | PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " |
105 | "of size %ub!\n", nlbufsiz); | 107 | "of size %ub!\n", n); |
106 | if (size < nlbufsiz) { | 108 | if (n > size) { |
107 | /* try to allocate only as much as we need for | 109 | /* try to allocate only as much as we need for |
108 | * current packet */ | 110 | * current packet */ |
109 | skb = alloc_skb(size, GFP_ATOMIC); | 111 | skb = alloc_skb(size, GFP_ATOMIC); |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 00729b3604f8..cbd4020cc84d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -934,6 +934,13 @@ static int do_replace(void __user *user, unsigned int len) | |||
934 | BUGPRINT("Entries_size never zero\n"); | 934 | BUGPRINT("Entries_size never zero\n"); |
935 | return -EINVAL; | 935 | return -EINVAL; |
936 | } | 936 | } |
937 | /* overflow check */ | ||
938 | if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS - | ||
939 | SMP_CACHE_BYTES) / sizeof(struct ebt_counter)) | ||
940 | return -ENOMEM; | ||
941 | if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter)) | ||
942 | return -ENOMEM; | ||
943 | |||
937 | countersize = COUNTER_OFFSET(tmp.nentries) * | 944 | countersize = COUNTER_OFFSET(tmp.nentries) * |
938 | (highest_possible_processor_id()+1); | 945 | (highest_possible_processor_id()+1); |
939 | newinfo = (struct ebt_table_info *) | 946 | newinfo = (struct ebt_table_info *) |