Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6

Conflicts:

	drivers/infiniband/core/iwcm.c
	drivers/net/chelsio/cxgb2.c
	drivers/net/wireless/bcm43xx/bcm43xx_main.c
	drivers/net/wireless/prism54/islpci_eth.c
	drivers/usb/core/hub.h
	drivers/usb/input/hid-core.c
	net/core/netpoll.c

Fix up merge failures with Linus's head and fix new compilation failures.

Signed-Off-By: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells
2006-12-05 14:37:56 +00:00
committed by David Howells
1476 changed files with 67646 additions and 41035 deletions

View File

@@ -58,12 +58,13 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf,
{
int num;
void *buf;
size_t size = maxnum * sizeof(struct __fdb_entry);
size_t size;
if (size > PAGE_SIZE) {
size = PAGE_SIZE;
/* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */
if (maxnum > PAGE_SIZE/sizeof(struct __fdb_entry))
maxnum = PAGE_SIZE/sizeof(struct __fdb_entry);
}
size = maxnum * sizeof(struct __fdb_entry);
buf = kmalloc(size, GFP_USER);
if (!buf)

View File

@@ -40,7 +40,6 @@
#include <net/route.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include "br_private.h"
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -381,7 +380,7 @@ static int check_hbh_len(struct sk_buff *skb)
case IPV6_TLV_JUMBO:
if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2)
goto bad;
pkt_len = ntohl(*(u32 *) (skb->nh.raw + off + 2));
pkt_len = ntohl(*(__be32 *) (skb->nh.raw + off + 2));
if (pkt_len <= IPV6_MAXPLEN ||
skb->nh.ipv6h->payload_len)
goto bad;

View File

@@ -15,6 +15,18 @@
#include <net/netlink.h>
#include "br_private.h"
static inline size_t br_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+ nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(4) /* IFLA_MTU */
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1); /* IFLA_PROTINFO */
}
/*
* Create one netlink message for one interface
* Contains port and master info as well as carrier and bridge state.
@@ -24,51 +36,43 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
{
const struct net_bridge *br = port->br;
const struct net_device *dev = port->dev;
struct ifinfomsg *r;
struct ifinfomsg *hdr;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
u32 mtu = dev->mtu;
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
u8 portstate = port->state;
pr_debug("br_fill_info event %d port %s master %s\n",
event, dev->name, br->dev->name);
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
r = NLMSG_DATA(nlh);
r->ifi_family = AF_BRIDGE;
r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev_get_flags(dev);
r->ifi_change = 0;
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
if (nlh == NULL)
return -ENOBUFS;
RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
hdr = nlmsg_data(nlh);
hdr->ifi_family = AF_BRIDGE;
hdr->__ifi_pad = 0;
hdr->ifi_type = dev->type;
hdr->ifi_index = dev->ifindex;
hdr->ifi_flags = dev_get_flags(dev);
hdr->ifi_change = 0;
RTA_PUT(skb, IFLA_MASTER, sizeof(int), &br->dev->ifindex);
NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex);
NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate);
if (dev->addr_len)
RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
if (dev->ifindex != dev->iflink)
RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink);
RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
if (event == RTM_NEWLINK)
RTA_PUT(skb, IFLA_PROTINFO, sizeof(portstate), &portstate);
NLA_PUT_U8(skb, IFLA_PROTINFO, port->state);
nlh->nlmsg_len = skb->tail - b;
return nlmsg_end(skb, nlh);
return skb->len;
nlmsg_failure:
rtattr_failure:
skb_trim(skb, b - skb->data);
return -EINVAL;
nla_put_failure:
return nlmsg_cancel(skb, nlh);
}
/*
@@ -77,19 +81,16 @@ rtattr_failure:
void br_ifinfo_notify(int event, struct net_bridge_port *port)
{
struct sk_buff *skb;
int payload = sizeof(struct ifinfomsg) + 128;
int err = -ENOBUFS;
pr_debug("bridge notify event=%d\n", event);
skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL)
goto errout;
err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
if (err < 0) {
kfree_skb(skb);
goto errout;
}
/* failure implies BUG in br_nlmsg_size() */
BUG_ON(err < 0);
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
errout:
@@ -104,25 +105,18 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net_device *dev;
int idx;
int s_idx = cb->args[0];
int err = 0;
read_lock(&dev_base_lock);
for (dev = dev_base, idx = 0; dev; dev = dev->next) {
struct net_bridge_port *p = dev->br_port;
/* not a bridge port */
if (!p)
continue;
if (dev->br_port == NULL || idx < cb->args[0])
goto skip;
if (idx < s_idx)
goto cont;
err = br_fill_ifinfo(skb, p, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
if (err <= 0)
if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK,
NLM_F_MULTI) < 0)
break;
cont:
skip:
++idx;
}
read_unlock(&dev_base_lock);
@@ -138,26 +132,27 @@ cont:
*/
static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
struct ifinfomsg *ifm;
struct nlattr *protinfo;
struct net_device *dev;
struct net_bridge_port *p;
u8 new_state;
if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL;
ifm = nlmsg_data(nlh);
if (ifm->ifi_family != AF_BRIDGE)
return -EPFNOSUPPORT;
/* Must pass valid state as PROTINFO */
if (rta[IFLA_PROTINFO-1]) {
u8 *pstate = RTA_DATA(rta[IFLA_PROTINFO-1]);
new_state = *pstate;
} else
protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
if (!protinfo || nla_len(protinfo) < sizeof(u8))
return -EINVAL;
new_state = nla_get_u8(protinfo);
if (new_state > BR_STATE_BLOCKING)
return -EINVAL;
/* Find bridge port */
dev = __dev_get_by_index(ifm->ifi_index);
if (!dev)
return -ENODEV;
@@ -170,10 +165,8 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (p->br->stp_enabled)
return -EBUSY;
if (!netif_running(dev))
return -ENETDOWN;
if (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)
if (!netif_running(dev) ||
(!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
return -ENETDOWN;
p->state = new_state;

View File

@@ -17,7 +17,7 @@ static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *
{
struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
__be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
if (info->bitmask & EBT_802_3_SAP) {
if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP))

View File

@@ -15,7 +15,7 @@
#include <linux/module.h>
static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
const char *mac, uint32_t ip)
const char *mac, __be32 ip)
{
/* You may be puzzled as to how this code works.
* Some tricks were used, refer to
@@ -70,7 +70,7 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
return 0;
}
static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
{
if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
struct iphdr _iph, *ih;
@@ -81,16 +81,16 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
*addr = ih->daddr;
} else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
struct arphdr _arph, *ah;
uint32_t buf, *bp;
__be32 buf, *bp;
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_pln != sizeof(__be32) ||
ah->ar_hln != ETH_ALEN)
return -1;
bp = skb_header_pointer(skb, sizeof(struct arphdr) +
2 * ETH_ALEN + sizeof(uint32_t),
sizeof(uint32_t), &buf);
2 * ETH_ALEN + sizeof(__be32),
sizeof(__be32), &buf);
if (bp == NULL)
return -1;
*addr = *bp;
@@ -98,7 +98,7 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
return 0;
}
static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
static int get_ip_src(const struct sk_buff *skb, __be32 *addr)
{
if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
struct iphdr _iph, *ih;
@@ -109,15 +109,15 @@ static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
*addr = ih->saddr;
} else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
struct arphdr _arph, *ah;
uint32_t buf, *bp;
__be32 buf, *bp;
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_pln != sizeof(__be32) ||
ah->ar_hln != ETH_ALEN)
return -1;
bp = skb_header_pointer(skb, sizeof(struct arphdr) +
ETH_ALEN, sizeof(uint32_t), &buf);
ETH_ALEN, sizeof(__be32), &buf);
if (bp == NULL)
return -1;
*addr = *bp;
@@ -133,7 +133,7 @@ static int ebt_filter_among(const struct sk_buff *skb,
struct ebt_among_info *info = (struct ebt_among_info *) data;
const char *dmac, *smac;
const struct ebt_mac_wormhash *wh_dst, *wh_src;
uint32_t dip = 0, sip = 0;
__be32 dip = 0, sip = 0;
wh_dst = ebt_among_wh_dst(info);
wh_src = ebt_among_wh_src(info);

View File

@@ -35,10 +35,10 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
return EBT_NOMATCH;
if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
uint32_t _addr, *ap;
__be32 _addr, *ap;
/* IPv4 addresses are always 4 bytes */
if (ah->ar_pln != sizeof(uint32_t))
if (ah->ar_pln != sizeof(__be32))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_IP) {
ap = skb_header_pointer(skb, sizeof(struct arphdr) +
@@ -53,7 +53,7 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
if (info->bitmask & EBT_ARP_DST_IP) {
ap = skb_header_pointer(skb, sizeof(struct arphdr) +
2*ah->ar_hln+sizeof(uint32_t),
2*ah->ar_hln+sizeof(__be32),
sizeof(_addr), &_addr);
if (ap == NULL)
return EBT_NOMATCH;

View File

@@ -20,8 +20,8 @@
#include <linux/module.h>
struct tcpudphdr {
uint16_t src;
uint16_t dst;
__be16 src;
__be16 dst;
};
static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,

View File

@@ -38,8 +38,8 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask,
struct tcpudphdr
{
uint16_t src;
uint16_t dst;
__be16 src;
__be16 dst;
};
struct arppayload
@@ -130,7 +130,7 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
* then log the ARP payload */
if (ah->ar_hrd == htons(1) &&
ah->ar_hln == ETH_ALEN &&
ah->ar_pln == sizeof(uint32_t)) {
ah->ar_pln == sizeof(__be32)) {
struct arppayload _arpp, *ap;
ap = skb_header_pointer(skb, sizeof(_arph),

View File

@@ -25,15 +25,15 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
int action = info->target & -16;
if (action == MARK_SET_VALUE)
(*pskb)->nfmark = info->mark;
(*pskb)->mark = info->mark;
else if (action == MARK_OR_VALUE)
(*pskb)->nfmark |= info->mark;
(*pskb)->mark |= info->mark;
else if (action == MARK_AND_VALUE)
(*pskb)->nfmark &= info->mark;
(*pskb)->mark &= info->mark;
else
(*pskb)->nfmark ^= info->mark;
(*pskb)->mark ^= info->mark;
return info->target | -16;
return info->target | ~EBT_VERDICT_BITS;
}
static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
@@ -44,13 +44,13 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
return -EINVAL;
tmp = info->target | -16;
tmp = info->target | ~EBT_VERDICT_BITS;
if (BASE_CHAIN && tmp == EBT_RETURN)
return -EINVAL;
CLEAR_BASE_CHAIN_BIT;
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
return -EINVAL;
tmp = info->target & -16;
tmp = info->target & ~EBT_VERDICT_BITS;
if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
return -EINVAL;

View File

@@ -19,8 +19,8 @@ static int ebt_filter_mark(const struct sk_buff *skb,
struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
if (info->bitmask & EBT_MARK_OR)
return !(!!(skb->nfmark & info->mask) ^ info->invert);
return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
return !(!!(skb->mark & info->mask) ^ info->invert);
return !(((skb->mark & info->mask) == info->mark) ^ info->invert);
}
static int ebt_mark_check(const char *tablename, unsigned int hookmask,

View File

@@ -12,6 +12,8 @@
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
#include <net/sock.h>
#include <linux/if_arp.h>
#include <net/arp.h>
static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
const struct net_device *in, const struct net_device *out,
@@ -31,24 +33,43 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
*pskb = nskb;
}
memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
return info->target;
if (!(info->target & NAT_ARP_BIT) &&
eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
struct arphdr _ah, *ap;
ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah);
if (ap == NULL)
return EBT_DROP;
if (ap->ar_hln != ETH_ALEN)
goto out;
if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN))
return EBT_DROP;
}
out:
return info->target | ~EBT_VERDICT_BITS;
}
static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
const struct ebt_entry *e, void *data, unsigned int datalen)
{
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
int tmp;
if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN)
tmp = info->target | ~EBT_VERDICT_BITS;
if (BASE_CHAIN && tmp == EBT_RETURN)
return -EINVAL;
CLEAR_BASE_CHAIN_BIT;
if (strcmp(tablename, "nat"))
return -EINVAL;
if (hookmask & ~(1 << NF_BR_POST_ROUTING))
return -EINVAL;
if (INVALID_TARGET)
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
return -EINVAL;
tmp = info->target | EBT_VERDICT_BITS;
if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT)
return -EINVAL;
return 0;
}

View File

@@ -168,7 +168,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
if (ub->qlen == 1)
skb_set_timestamp(ub->skb, &pm->stamp);
pm->data_len = copy_len;
pm->mark = skb->nfmark;
pm->mark = skb->mark;
pm->hook = hooknr;
if (uloginfo->prefix != NULL)
strcpy(pm->prefix, uloginfo->prefix);

View File

@@ -55,7 +55,7 @@ ebt_filter_vlan(const struct sk_buff *skb,
unsigned short id; /* VLAN ID, given from frame TCI */
unsigned char prio; /* user_priority, given from frame TCI */
/* VLAN encapsulated Type/Length field, given from orig frame */
unsigned short encap;
__be16 encap;
fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
if (fp == NULL)

View File

@@ -23,7 +23,7 @@ static struct ebt_entries initial_chain = {
.policy = EBT_ACCEPT,
};
static struct ebt_replace initial_table =
static struct ebt_replace_kernel initial_table =
{
.name = "broute",
.valid_hooks = 1 << NF_BR_BROUTING,

View File

@@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] =
},
};
static struct ebt_replace initial_table =
static struct ebt_replace_kernel initial_table =
{
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,

View File

@@ -30,7 +30,7 @@ static struct ebt_entries initial_chains[] =
}
};
static struct ebt_replace initial_table =
static struct ebt_replace_kernel initial_table =
{
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,

View File

@@ -338,10 +338,11 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
const char *name, unsigned int hookmask, unsigned int *cnt)
{
struct ebt_match *match;
size_t left = ((char *)e + e->watchers_offset) - (char *)m;
int ret;
if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
((char *)e) + e->watchers_offset)
if (left < sizeof(struct ebt_entry_match) ||
left - sizeof(struct ebt_entry_match) < m->match_size)
return -EINVAL;
match = find_match_lock(m->u.name, &ret, &ebt_mutex);
if (!match)
@@ -367,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
const char *name, unsigned int hookmask, unsigned int *cnt)
{
struct ebt_watcher *watcher;
size_t left = ((char *)e + e->target_offset) - (char *)w;
int ret;
if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
((char *)e) + e->target_offset)
if (left < sizeof(struct ebt_entry_watcher) ||
left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
return -EINVAL;
watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
if (!watcher)
@@ -391,35 +393,91 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
return 0;
}
static int ebt_verify_pointers(struct ebt_replace *repl,
struct ebt_table_info *newinfo)
{
unsigned int limit = repl->entries_size;
unsigned int valid_hooks = repl->valid_hooks;
unsigned int offset = 0;
int i;
for (i = 0; i < NF_BR_NUMHOOKS; i++)
newinfo->hook_entry[i] = NULL;
newinfo->entries_size = repl->entries_size;
newinfo->nentries = repl->nentries;
while (offset < limit) {
size_t left = limit - offset;
struct ebt_entry *e = (void *)newinfo->entries + offset;
if (left < sizeof(unsigned int))
break;
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if ((valid_hooks & (1 << i)) == 0)
continue;
if ((char __user *)repl->hook_entry[i] ==
repl->entries + offset)
break;
}
if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
if (e->bitmask != 0) {
/* we make userspace set this right,
so there is no misunderstanding */
BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
"in distinguisher\n");
return -EINVAL;
}
if (i != NF_BR_NUMHOOKS)
newinfo->hook_entry[i] = (struct ebt_entries *)e;
if (left < sizeof(struct ebt_entries))
break;
offset += sizeof(struct ebt_entries);
} else {
if (left < sizeof(struct ebt_entry))
break;
if (left < e->next_offset)
break;
offset += e->next_offset;
}
}
if (offset != limit) {
BUGPRINT("entries_size too small\n");
return -EINVAL;
}
/* check if all valid hooks have a chain */
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if (!newinfo->hook_entry[i] &&
(valid_hooks & (1 << i))) {
BUGPRINT("Valid hook without chain\n");
return -EINVAL;
}
}
return 0;
}
/*
* this one is very careful, as it is the first function
* to parse the userspace data
*/
static inline int
ebt_check_entry_size_and_hooks(struct ebt_entry *e,
struct ebt_table_info *newinfo, char *base, char *limit,
struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
struct ebt_table_info *newinfo,
unsigned int *n, unsigned int *cnt,
unsigned int *totalcnt, unsigned int *udc_cnt)
{
int i;
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if ((valid_hooks & (1 << i)) == 0)
continue;
if ( (char *)hook_entries[i] - base ==
(char *)e - newinfo->entries)
if ((void *)e == (void *)newinfo->hook_entry[i])
break;
}
/* beginning of a new chain
if i == NF_BR_NUMHOOKS it must be a user defined chain */
if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
/* we make userspace set this right,
so there is no misunderstanding */
BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
"in distinguisher\n");
return -EINVAL;
}
if (i != NF_BR_NUMHOOKS || !e->bitmask) {
/* this checks if the previous chain has as many entries
as it said it has */
if (*n != *cnt) {
@@ -427,12 +485,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
"in the chain\n");
return -EINVAL;
}
/* before we look at the struct, be sure it is not too big */
if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
> limit) {
BUGPRINT("entries_size too small\n");
return -EINVAL;
}
if (((struct ebt_entries *)e)->policy != EBT_DROP &&
((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
/* only RETURN from udc */
@@ -444,8 +496,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
}
if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
(*udc_cnt)++;
else
newinfo->hook_entry[i] = (struct ebt_entries *)e;
if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
BUGPRINT("counter_offset != totalcnt");
return -EINVAL;
@@ -466,7 +516,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
BUGPRINT("target size too small\n");
return -EINVAL;
}
(*cnt)++;
(*totalcnt)++;
return 0;
@@ -485,17 +534,14 @@ struct ebt_cl_stack
*/
static inline int
ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks,
struct ebt_cl_stack *udc)
unsigned int *n, struct ebt_cl_stack *udc)
{
int i;
/* we're only interested in chain starts */
if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
if (e->bitmask)
return 0;
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if ((valid_hooks & (1 << i)) == 0)
continue;
if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
break;
}
@@ -541,7 +587,7 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
{
struct ebt_entry_target *t;
if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
if (e->bitmask == 0)
return 0;
/* we're done */
if (cnt && (*cnt)-- == 0)
@@ -558,16 +604,17 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
static inline int
ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
const char *name, unsigned int *cnt, unsigned int valid_hooks,
const char *name, unsigned int *cnt,
struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
{
struct ebt_entry_target *t;
struct ebt_target *target;
unsigned int i, j, hook = 0, hookmask = 0;
size_t gap = e->next_offset - e->target_offset;
int ret;
/* don't mess with the struct ebt_entries */
if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
if (e->bitmask == 0)
return 0;
if (e->bitmask & ~EBT_F_MASK) {
@@ -584,7 +631,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
}
/* what hook do we belong to? */
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if ((valid_hooks & (1 << i)) == 0)
if (!newinfo->hook_entry[i])
continue;
if ((char *)newinfo->hook_entry[i] < (char *)e)
hook = i;
@@ -625,8 +672,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
t->u.target = target;
if (t->u.target == &ebt_standard_target) {
if (e->target_offset + sizeof(struct ebt_standard_target) >
e->next_offset) {
if (gap < sizeof(struct ebt_standard_target)) {
BUGPRINT("Standard target size too big\n");
ret = -EFAULT;
goto cleanup_watchers;
@@ -637,8 +683,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
ret = -EFAULT;
goto cleanup_watchers;
}
} else if ((e->target_offset + t->target_size +
sizeof(struct ebt_entry_target) > e->next_offset) ||
} else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
(t->u.target->check &&
t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
module_put(t->u.target->me);
@@ -708,7 +753,9 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
BUGPRINT("loop\n");
return -1;
}
/* this can't be 0, so the above test is correct */
if (cl_s[i].hookmask & (1 << hooknr))
goto letscontinue;
/* this can't be 0, so the loop test is correct */
cl_s[i].cs.n = pos + 1;
pos = 0;
cl_s[i].cs.e = ((void *)e + e->next_offset);
@@ -728,42 +775,35 @@ letscontinue:
}
/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
static int translate_table(struct ebt_replace *repl,
struct ebt_table_info *newinfo)
static int translate_table(char *name, struct ebt_table_info *newinfo)
{
unsigned int i, j, k, udc_cnt;
int ret;
struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
i = 0;
while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
i++;
if (i == NF_BR_NUMHOOKS) {
BUGPRINT("No valid hooks specified\n");
return -EINVAL;
}
if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
BUGPRINT("Chains don't start at beginning\n");
return -EINVAL;
}
/* make sure chains are ordered after each other in same order
as their corresponding hooks */
for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
if (!(repl->valid_hooks & (1 << j)))
if (!newinfo->hook_entry[j])
continue;
if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
BUGPRINT("Hook order must be followed\n");
return -EINVAL;
}
i = j;
}
for (i = 0; i < NF_BR_NUMHOOKS; i++)
newinfo->hook_entry[i] = NULL;
newinfo->entries_size = repl->entries_size;
newinfo->nentries = repl->nentries;
/* do some early checkings and initialize some things */
i = 0; /* holds the expected nr. of entries for the chain */
j = 0; /* holds the up to now counted entries for the chain */
@@ -771,9 +811,8 @@ static int translate_table(struct ebt_replace *repl,
newinfo->nentries afterwards */
udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_check_entry_size_and_hooks, newinfo, repl->entries,
repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
&udc_cnt, repl->valid_hooks);
ebt_check_entry_size_and_hooks, newinfo,
&i, &j, &k, &udc_cnt);
if (ret != 0)
return ret;
@@ -788,15 +827,6 @@ static int translate_table(struct ebt_replace *repl,
return -EINVAL;
}
/* check if all valid hooks have a chain */
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if (newinfo->hook_entry[i] == NULL &&
(repl->valid_hooks & (1 << i))) {
BUGPRINT("Valid hook without chain\n");
return -EINVAL;
}
}
/* get the location of the udc, put them in an array
while we're at it, allocate the chainstack */
if (udc_cnt) {
@@ -824,8 +854,7 @@ static int translate_table(struct ebt_replace *repl,
return -ENOMEM;
i = 0; /* the i'th udc */
EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_get_udc_positions, newinfo, repl->hook_entry, &i,
repl->valid_hooks, cl_s);
ebt_get_udc_positions, newinfo, &i, cl_s);
/* sanity check */
if (i != udc_cnt) {
BUGPRINT("i != udc_cnt\n");
@@ -836,7 +865,7 @@ static int translate_table(struct ebt_replace *repl,
/* Check for loops */
for (i = 0; i < NF_BR_NUMHOOKS; i++)
if (repl->valid_hooks & (1 << i))
if (newinfo->hook_entry[i])
if (check_chainloops(newinfo->hook_entry[i],
cl_s, udc_cnt, i, newinfo->entries)) {
vfree(cl_s);
@@ -856,8 +885,7 @@ static int translate_table(struct ebt_replace *repl,
/* used to know what we need to clean up if something goes wrong */
i = 0;
ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks,
cl_s, udc_cnt);
ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
if (ret != 0) {
EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_cleanup_entry, &i);
@@ -954,7 +982,11 @@ static int do_replace(void __user *user, unsigned int len)
/* this can get initialized by translate_table() */
newinfo->chainstack = NULL;
ret = translate_table(&tmp, newinfo);
ret = ebt_verify_pointers(&tmp, newinfo);
if (ret != 0)
goto free_counterstmp;
ret = translate_table(tmp.name, newinfo);
if (ret != 0)
goto free_counterstmp;
@@ -1125,35 +1157,47 @@ int ebt_register_table(struct ebt_table *table)
{
struct ebt_table_info *newinfo;
struct ebt_table *t;
struct ebt_replace_kernel *repl;
int ret, i, countersize;
void *p;
if (!table || !table->table ||!table->table->entries ||
table->table->entries_size == 0 ||
table->table->counters || table->private) {
if (!table || !(repl = table->table) || !repl->entries ||
repl->entries_size == 0 ||
repl->counters || table->private) {
BUGPRINT("Bad table data for ebt_register_table!!!\n");
return -EINVAL;
}
countersize = COUNTER_OFFSET(table->table->nentries) *
countersize = COUNTER_OFFSET(repl->nentries) *
(highest_possible_processor_id()+1);
newinfo = vmalloc(sizeof(*newinfo) + countersize);
ret = -ENOMEM;
if (!newinfo)
return -ENOMEM;
newinfo->entries = vmalloc(table->table->entries_size);
if (!(newinfo->entries))
p = vmalloc(repl->entries_size);
if (!p)
goto free_newinfo;
memcpy(newinfo->entries, table->table->entries,
table->table->entries_size);
memcpy(p, repl->entries, repl->entries_size);
newinfo->entries = p;
newinfo->entries_size = repl->entries_size;
newinfo->nentries = repl->nentries;
if (countersize)
memset(newinfo->counters, 0, countersize);
/* fill in newinfo and parse the entries */
newinfo->chainstack = NULL;
ret = translate_table(table->table, newinfo);
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if ((repl->valid_hooks & (1 << i)) == 0)
newinfo->hook_entry[i] = NULL;
else
newinfo->hook_entry[i] = p +
((char *)repl->hook_entry[i] - repl->entries);
}
ret = translate_table(repl->name, newinfo);
if (ret != 0) {
BUGPRINT("Translate_table failed\n");
goto free_chainstack;
@@ -1277,33 +1321,33 @@ free_tmp:
}
static inline int ebt_make_matchname(struct ebt_entry_match *m,
char *base, char *ubase)
char *base, char __user *ubase)
{
char *hlp = ubase - base + (char *)m;
char __user *hlp = ubase + ((char *)m - base);
if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
return -EFAULT;
return 0;
}
static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
char *base, char *ubase)
char *base, char __user *ubase)
{
char *hlp = ubase - base + (char *)w;
char __user *hlp = ubase + ((char *)w - base);
if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
return -EFAULT;
return 0;
}
static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
{
int ret;
char *hlp;
char __user *hlp;
struct ebt_entry_target *t;
if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
if (e->bitmask == 0)
return 0;
hlp = ubase - base + (char *)e + e->target_offset;
hlp = ubase + (((char *)e + e->target_offset) - base);
t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);