Commit 0fb375fb authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

[AF_PACKET]: Allow for > 8 byte hardware addresses.

The convention is that longer addresses will simply extend
the hardeware address byte arrays at the end of sockaddr_ll and
packet_mreq.

In making this change a small information leak was also closed.
The code only initializes the hardware address bytes that are
used, but all of struct sockaddr_ll was copied to userspace.
Now we just copy sockaddr_ll to the last byte of the hardware
address used.

For error checking larger structures than our internal
maximums continue to be allowed but an error is signaled if we can
not fit the hardware address into our internal structure.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6d67e34d
...@@ -36,6 +36,11 @@ ...@@ -36,6 +36,11 @@
* Michal Ostrowski : Module initialization cleanup. * Michal Ostrowski : Module initialization cleanup.
* Ulises Alonso : Frame number limit removal and * Ulises Alonso : Frame number limit removal and
* packet_set_ring memory leak. * packet_set_ring memory leak.
* Eric Biederman : Allow for > 8 byte hardware addresses.
* The convention is that longer addresses
* will simply extend the hardware address
* byte arrays at the end of sockaddr_ll
* and packet_mreq.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -161,7 +166,17 @@ struct packet_mclist ...@@ -161,7 +166,17 @@ struct packet_mclist
int count; int count;
unsigned short type; unsigned short type;
unsigned short alen; unsigned short alen;
unsigned char addr[8]; unsigned char addr[MAX_ADDR_LEN];
};
/* identical to struct packet_mreq except it has
* a longer address field.
*/
struct packet_mreq_max
{
int mr_ifindex;
unsigned short mr_type;
unsigned short mr_alen;
unsigned char mr_address[MAX_ADDR_LEN];
}; };
#endif #endif
#ifdef CONFIG_PACKET_MMAP #ifdef CONFIG_PACKET_MMAP
...@@ -716,6 +731,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -716,6 +731,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
err = -EINVAL; err = -EINVAL;
if (msg->msg_namelen < sizeof(struct sockaddr_ll)) if (msg->msg_namelen < sizeof(struct sockaddr_ll))
goto out; goto out;
if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr)))
goto out;
ifindex = saddr->sll_ifindex; ifindex = saddr->sll_ifindex;
proto = saddr->sll_protocol; proto = saddr->sll_protocol;
addr = saddr->sll_addr; addr = saddr->sll_addr;
...@@ -744,6 +761,12 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -744,6 +761,12 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
if (dev->hard_header) { if (dev->hard_header) {
int res; int res;
err = -EINVAL; err = -EINVAL;
if (saddr) {
if (saddr->sll_halen != dev->addr_len)
goto out_free;
if (saddr->sll_hatype != dev->type)
goto out_free;
}
res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
if (sock->type != SOCK_DGRAM) { if (sock->type != SOCK_DGRAM) {
skb->tail = skb->data; skb->tail = skb->data;
...@@ -1045,6 +1068,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1045,6 +1068,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
int copied, err; int copied, err;
struct sockaddr_ll *sll;
err = -EINVAL; err = -EINVAL;
if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
...@@ -1056,16 +1080,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1056,16 +1080,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
return -ENODEV; return -ENODEV;
#endif #endif
/*
* 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
msg->msg_namelen = sizeof(struct sockaddr_ll);
/* /*
* Call the generic datagram receiver. This handles all sorts * Call the generic datagram receiver. This handles all sorts
* of horrible races and re-entrancy so we can forget about it * of horrible races and re-entrancy so we can forget about it
...@@ -1086,6 +1100,17 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1086,6 +1100,17 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
if(skb==NULL) if(skb==NULL)
goto out; goto out;
/*
* If the address length field is there to be filled in, we fill
* it in now.
*/
sll = (struct sockaddr_ll*)skb->cb;
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 * You lose any data beyond the buffer you gave. If it worries a
* user program they can ask the device for its MTU anyway. * user program they can ask the device for its MTU anyway.
...@@ -1166,7 +1191,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -1166,7 +1191,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */
sll->sll_halen = 0; sll->sll_halen = 0;
} }
*uaddr_len = sizeof(*sll); *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen;
return 0; return 0;
} }
...@@ -1199,7 +1224,7 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i ...@@ -1199,7 +1224,7 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i
} }
} }
static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq) static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq)
{ {
struct packet_sock *po = pkt_sk(sk); struct packet_sock *po = pkt_sk(sk);
struct packet_mclist *ml, *i; struct packet_mclist *ml, *i;
...@@ -1249,7 +1274,7 @@ done: ...@@ -1249,7 +1274,7 @@ done:
return err; return err;
} }
static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
{ {
struct packet_mclist *ml, **mlp; struct packet_mclist *ml, **mlp;
...@@ -1315,11 +1340,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv ...@@ -1315,11 +1340,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
case PACKET_ADD_MEMBERSHIP: case PACKET_ADD_MEMBERSHIP:
case PACKET_DROP_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP:
{ {
struct packet_mreq mreq; struct packet_mreq_max mreq;
if (optlen<sizeof(mreq)) int len = optlen;
memset(&mreq, 0, sizeof(mreq));
if (len < sizeof(struct packet_mreq))
return -EINVAL; return -EINVAL;
if (copy_from_user(&mreq,optval,sizeof(mreq))) if (len > sizeof(mreq))
len = sizeof(mreq);
if (copy_from_user(&mreq,optval,len))
return -EFAULT; return -EFAULT;
if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
return -EINVAL;
if (optname == PACKET_ADD_MEMBERSHIP) if (optname == PACKET_ADD_MEMBERSHIP)
ret = packet_mc_add(sk, &mreq); ret = packet_mc_add(sk, &mreq);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment