diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 21:42:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-30 21:42:58 -0400 |
commit | 3985c7ce85039adacdf882904ca096f091d39346 (patch) | |
tree | afaf4161c4c3d9516cc09295eb30c0e22a8c3008 /net | |
parent | fcf744a96c66ca6ad7301a372034b771e57f30c4 (diff) | |
parent | ce384d91cd7a4269a1ed5d4307a70aa4c6fa14f2 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
isdn: mISDN: socket: fix information leak to userland
netdev: can: Change mail address of Hans J. Koch
pcnet_cs: add new_id
net: Truncate recvfrom and sendto length to INT_MAX.
RDS: Let rds_message_alloc_sgs() return NULL
RDS: Copy rds_iovecs into kernel memory instead of rereading from userspace
RDS: Clean up error handling in rds_cmsg_rdma_args
RDS: Return -EINVAL if rds_rdma_pages returns an error
net: fix rds_iovec page count overflow
can: pch_can: fix section mismatch warning by using a whitelisted name
can: pch_can: fix sparse warning
netxen_nic: Fix the tx queue manipulation bug in netxen_nic_probe
ip_gre: fix fallback tunnel setup
vmxnet: trivial annotation of protocol constant
vmxnet3: remove unnecessary byteswapping in BAR writing macros
ipv6/udp: report SndbufErrors and RcvbufErrors
phy/marvell: rename 88ec048 to 88e1318s and fix mscr1 addr
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_gre.c | 6 | ||||
-rw-r--r-- | net/ipv6/proc.c | 4 | ||||
-rw-r--r-- | net/rds/message.c | 5 | ||||
-rw-r--r-- | net/rds/rdma.c | 126 | ||||
-rw-r--r-- | net/rds/send.c | 4 | ||||
-rw-r--r-- | net/socket.c | 4 |
6 files changed, 104 insertions, 45 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 01087e035b7d..70ff77f02eee 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -1325,7 +1325,6 @@ static void ipgre_fb_tunnel_init(struct net_device *dev) | |||
1325 | { | 1325 | { |
1326 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1326 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1327 | struct iphdr *iph = &tunnel->parms.iph; | 1327 | struct iphdr *iph = &tunnel->parms.iph; |
1328 | struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id); | ||
1329 | 1328 | ||
1330 | tunnel->dev = dev; | 1329 | tunnel->dev = dev; |
1331 | strcpy(tunnel->parms.name, dev->name); | 1330 | strcpy(tunnel->parms.name, dev->name); |
@@ -1336,7 +1335,6 @@ static void ipgre_fb_tunnel_init(struct net_device *dev) | |||
1336 | tunnel->hlen = sizeof(struct iphdr) + 4; | 1335 | tunnel->hlen = sizeof(struct iphdr) + 4; |
1337 | 1336 | ||
1338 | dev_hold(dev); | 1337 | dev_hold(dev); |
1339 | rcu_assign_pointer(ign->tunnels_wc[0], tunnel); | ||
1340 | } | 1338 | } |
1341 | 1339 | ||
1342 | 1340 | ||
@@ -1383,10 +1381,12 @@ static int __net_init ipgre_init_net(struct net *net) | |||
1383 | if ((err = register_netdev(ign->fb_tunnel_dev))) | 1381 | if ((err = register_netdev(ign->fb_tunnel_dev))) |
1384 | goto err_reg_dev; | 1382 | goto err_reg_dev; |
1385 | 1383 | ||
1384 | rcu_assign_pointer(ign->tunnels_wc[0], | ||
1385 | netdev_priv(ign->fb_tunnel_dev)); | ||
1386 | return 0; | 1386 | return 0; |
1387 | 1387 | ||
1388 | err_reg_dev: | 1388 | err_reg_dev: |
1389 | free_netdev(ign->fb_tunnel_dev); | 1389 | ipgre_dev_free(ign->fb_tunnel_dev); |
1390 | err_alloc_dev: | 1390 | err_alloc_dev: |
1391 | return err; | 1391 | return err; |
1392 | } | 1392 | } |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index d082eaeefa25..24b3558b8e67 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -126,6 +126,8 @@ static const struct snmp_mib snmp6_udp6_list[] = { | |||
126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), | 126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), |
127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), | 127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), |
128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
129 | SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
130 | SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
129 | SNMP_MIB_SENTINEL | 131 | SNMP_MIB_SENTINEL |
130 | }; | 132 | }; |
131 | 133 | ||
@@ -134,6 +136,8 @@ static const struct snmp_mib snmp6_udplite6_list[] = { | |||
134 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | 136 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), |
135 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | 137 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), |
136 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 138 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
139 | SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
140 | SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
137 | SNMP_MIB_SENTINEL | 141 | SNMP_MIB_SENTINEL |
138 | }; | 142 | }; |
139 | 143 | ||
diff --git a/net/rds/message.c b/net/rds/message.c index a84545dae370..848cff45183b 100644 --- a/net/rds/message.c +++ b/net/rds/message.c | |||
@@ -224,6 +224,9 @@ struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents) | |||
224 | WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs); | 224 | WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs); |
225 | WARN_ON(!nents); | 225 | WARN_ON(!nents); |
226 | 226 | ||
227 | if (rm->m_used_sgs + nents > rm->m_total_sgs) | ||
228 | return NULL; | ||
229 | |||
227 | sg_ret = &sg_first[rm->m_used_sgs]; | 230 | sg_ret = &sg_first[rm->m_used_sgs]; |
228 | sg_init_table(sg_ret, nents); | 231 | sg_init_table(sg_ret, nents); |
229 | rm->m_used_sgs += nents; | 232 | rm->m_used_sgs += nents; |
@@ -246,6 +249,8 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in | |||
246 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); | 249 | rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); |
247 | rm->data.op_nents = ceil(total_len, PAGE_SIZE); | 250 | rm->data.op_nents = ceil(total_len, PAGE_SIZE); |
248 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); | 251 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); |
252 | if (!rm->data.op_sg) | ||
253 | return ERR_PTR(-ENOMEM); | ||
249 | 254 | ||
250 | for (i = 0; i < rm->data.op_nents; ++i) { | 255 | for (i = 0; i < rm->data.op_nents; ++i) { |
251 | sg_set_page(&rm->data.op_sg[i], | 256 | sg_set_page(&rm->data.op_sg[i], |
diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 1a41debca1ce..8920f2a83327 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c | |||
@@ -479,13 +479,38 @@ void rds_atomic_free_op(struct rm_atomic_op *ao) | |||
479 | 479 | ||
480 | 480 | ||
481 | /* | 481 | /* |
482 | * Count the number of pages needed to describe an incoming iovec. | 482 | * Count the number of pages needed to describe an incoming iovec array. |
483 | */ | 483 | */ |
484 | static int rds_rdma_pages(struct rds_rdma_args *args) | 484 | static int rds_rdma_pages(struct rds_iovec iov[], int nr_iovecs) |
485 | { | ||
486 | int tot_pages = 0; | ||
487 | unsigned int nr_pages; | ||
488 | unsigned int i; | ||
489 | |||
490 | /* figure out the number of pages in the vector */ | ||
491 | for (i = 0; i < nr_iovecs; i++) { | ||
492 | nr_pages = rds_pages_in_vec(&iov[i]); | ||
493 | if (nr_pages == 0) | ||
494 | return -EINVAL; | ||
495 | |||
496 | tot_pages += nr_pages; | ||
497 | |||
498 | /* | ||
499 | * nr_pages for one entry is limited to (UINT_MAX>>PAGE_SHIFT)+1, | ||
500 | * so tot_pages cannot overflow without first going negative. | ||
501 | */ | ||
502 | if (tot_pages < 0) | ||
503 | return -EINVAL; | ||
504 | } | ||
505 | |||
506 | return tot_pages; | ||
507 | } | ||
508 | |||
509 | int rds_rdma_extra_size(struct rds_rdma_args *args) | ||
485 | { | 510 | { |
486 | struct rds_iovec vec; | 511 | struct rds_iovec vec; |
487 | struct rds_iovec __user *local_vec; | 512 | struct rds_iovec __user *local_vec; |
488 | unsigned int tot_pages = 0; | 513 | int tot_pages = 0; |
489 | unsigned int nr_pages; | 514 | unsigned int nr_pages; |
490 | unsigned int i; | 515 | unsigned int i; |
491 | 516 | ||
@@ -502,14 +527,16 @@ static int rds_rdma_pages(struct rds_rdma_args *args) | |||
502 | return -EINVAL; | 527 | return -EINVAL; |
503 | 528 | ||
504 | tot_pages += nr_pages; | 529 | tot_pages += nr_pages; |
505 | } | ||
506 | 530 | ||
507 | return tot_pages; | 531 | /* |
508 | } | 532 | * nr_pages for one entry is limited to (UINT_MAX>>PAGE_SHIFT)+1, |
533 | * so tot_pages cannot overflow without first going negative. | ||
534 | */ | ||
535 | if (tot_pages < 0) | ||
536 | return -EINVAL; | ||
537 | } | ||
509 | 538 | ||
510 | int rds_rdma_extra_size(struct rds_rdma_args *args) | 539 | return tot_pages * sizeof(struct scatterlist); |
511 | { | ||
512 | return rds_rdma_pages(args) * sizeof(struct scatterlist); | ||
513 | } | 540 | } |
514 | 541 | ||
515 | /* | 542 | /* |
@@ -520,13 +547,12 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
520 | struct cmsghdr *cmsg) | 547 | struct cmsghdr *cmsg) |
521 | { | 548 | { |
522 | struct rds_rdma_args *args; | 549 | struct rds_rdma_args *args; |
523 | struct rds_iovec vec; | ||
524 | struct rm_rdma_op *op = &rm->rdma; | 550 | struct rm_rdma_op *op = &rm->rdma; |
525 | int nr_pages; | 551 | int nr_pages; |
526 | unsigned int nr_bytes; | 552 | unsigned int nr_bytes; |
527 | struct page **pages = NULL; | 553 | struct page **pages = NULL; |
528 | struct rds_iovec __user *local_vec; | 554 | struct rds_iovec iovstack[UIO_FASTIOV], *iovs = iovstack; |
529 | unsigned int nr; | 555 | int iov_size; |
530 | unsigned int i, j; | 556 | unsigned int i, j; |
531 | int ret = 0; | 557 | int ret = 0; |
532 | 558 | ||
@@ -546,9 +572,26 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
546 | goto out; | 572 | goto out; |
547 | } | 573 | } |
548 | 574 | ||
549 | nr_pages = rds_rdma_pages(args); | 575 | /* Check whether to allocate the iovec area */ |
550 | if (nr_pages < 0) | 576 | iov_size = args->nr_local * sizeof(struct rds_iovec); |
577 | if (args->nr_local > UIO_FASTIOV) { | ||
578 | iovs = sock_kmalloc(rds_rs_to_sk(rs), iov_size, GFP_KERNEL); | ||
579 | if (!iovs) { | ||
580 | ret = -ENOMEM; | ||
581 | goto out; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | if (copy_from_user(iovs, (struct rds_iovec __user *)(unsigned long) args->local_vec_addr, iov_size)) { | ||
586 | ret = -EFAULT; | ||
587 | goto out; | ||
588 | } | ||
589 | |||
590 | nr_pages = rds_rdma_pages(iovs, args->nr_local); | ||
591 | if (nr_pages < 0) { | ||
592 | ret = -EINVAL; | ||
551 | goto out; | 593 | goto out; |
594 | } | ||
552 | 595 | ||
553 | pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); | 596 | pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); |
554 | if (!pages) { | 597 | if (!pages) { |
@@ -564,6 +607,10 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
564 | op->op_recverr = rs->rs_recverr; | 607 | op->op_recverr = rs->rs_recverr; |
565 | WARN_ON(!nr_pages); | 608 | WARN_ON(!nr_pages); |
566 | op->op_sg = rds_message_alloc_sgs(rm, nr_pages); | 609 | op->op_sg = rds_message_alloc_sgs(rm, nr_pages); |
610 | if (!op->op_sg) { | ||
611 | ret = -ENOMEM; | ||
612 | goto out; | ||
613 | } | ||
567 | 614 | ||
568 | if (op->op_notify || op->op_recverr) { | 615 | if (op->op_notify || op->op_recverr) { |
569 | /* We allocate an uninitialized notifier here, because | 616 | /* We allocate an uninitialized notifier here, because |
@@ -597,50 +644,40 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
597 | (unsigned long long)args->remote_vec.addr, | 644 | (unsigned long long)args->remote_vec.addr, |
598 | op->op_rkey); | 645 | op->op_rkey); |
599 | 646 | ||
600 | local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr; | ||
601 | |||
602 | for (i = 0; i < args->nr_local; i++) { | 647 | for (i = 0; i < args->nr_local; i++) { |
603 | if (copy_from_user(&vec, &local_vec[i], | 648 | struct rds_iovec *iov = &iovs[i]; |
604 | sizeof(struct rds_iovec))) { | 649 | /* don't need to check, rds_rdma_pages() verified nr will be +nonzero */ |
605 | ret = -EFAULT; | 650 | unsigned int nr = rds_pages_in_vec(iov); |
606 | goto out; | ||
607 | } | ||
608 | |||
609 | nr = rds_pages_in_vec(&vec); | ||
610 | if (nr == 0) { | ||
611 | ret = -EINVAL; | ||
612 | goto out; | ||
613 | } | ||
614 | 651 | ||
615 | rs->rs_user_addr = vec.addr; | 652 | rs->rs_user_addr = iov->addr; |
616 | rs->rs_user_bytes = vec.bytes; | 653 | rs->rs_user_bytes = iov->bytes; |
617 | 654 | ||
618 | /* If it's a WRITE operation, we want to pin the pages for reading. | 655 | /* If it's a WRITE operation, we want to pin the pages for reading. |
619 | * If it's a READ operation, we need to pin the pages for writing. | 656 | * If it's a READ operation, we need to pin the pages for writing. |
620 | */ | 657 | */ |
621 | ret = rds_pin_pages(vec.addr, nr, pages, !op->op_write); | 658 | ret = rds_pin_pages(iov->addr, nr, pages, !op->op_write); |
622 | if (ret < 0) | 659 | if (ret < 0) |
623 | goto out; | 660 | goto out; |
624 | 661 | ||
625 | rdsdebug("RDS: nr_bytes %u nr %u vec.bytes %llu vec.addr %llx\n", | 662 | rdsdebug("RDS: nr_bytes %u nr %u iov->bytes %llu iov->addr %llx\n", |
626 | nr_bytes, nr, vec.bytes, vec.addr); | 663 | nr_bytes, nr, iov->bytes, iov->addr); |
627 | 664 | ||
628 | nr_bytes += vec.bytes; | 665 | nr_bytes += iov->bytes; |
629 | 666 | ||
630 | for (j = 0; j < nr; j++) { | 667 | for (j = 0; j < nr; j++) { |
631 | unsigned int offset = vec.addr & ~PAGE_MASK; | 668 | unsigned int offset = iov->addr & ~PAGE_MASK; |
632 | struct scatterlist *sg; | 669 | struct scatterlist *sg; |
633 | 670 | ||
634 | sg = &op->op_sg[op->op_nents + j]; | 671 | sg = &op->op_sg[op->op_nents + j]; |
635 | sg_set_page(sg, pages[j], | 672 | sg_set_page(sg, pages[j], |
636 | min_t(unsigned int, vec.bytes, PAGE_SIZE - offset), | 673 | min_t(unsigned int, iov->bytes, PAGE_SIZE - offset), |
637 | offset); | 674 | offset); |
638 | 675 | ||
639 | rdsdebug("RDS: sg->offset %x sg->len %x vec.addr %llx vec.bytes %llu\n", | 676 | rdsdebug("RDS: sg->offset %x sg->len %x iov->addr %llx iov->bytes %llu\n", |
640 | sg->offset, sg->length, vec.addr, vec.bytes); | 677 | sg->offset, sg->length, iov->addr, iov->bytes); |
641 | 678 | ||
642 | vec.addr += sg->length; | 679 | iov->addr += sg->length; |
643 | vec.bytes -= sg->length; | 680 | iov->bytes -= sg->length; |
644 | } | 681 | } |
645 | 682 | ||
646 | op->op_nents += nr; | 683 | op->op_nents += nr; |
@@ -655,13 +692,14 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, | |||
655 | } | 692 | } |
656 | op->op_bytes = nr_bytes; | 693 | op->op_bytes = nr_bytes; |
657 | 694 | ||
658 | ret = 0; | ||
659 | out: | 695 | out: |
696 | if (iovs != iovstack) | ||
697 | sock_kfree_s(rds_rs_to_sk(rs), iovs, iov_size); | ||
660 | kfree(pages); | 698 | kfree(pages); |
661 | if (ret) | 699 | if (ret) |
662 | rds_rdma_free_op(op); | 700 | rds_rdma_free_op(op); |
663 | 701 | else | |
664 | rds_stats_inc(s_send_rdma); | 702 | rds_stats_inc(s_send_rdma); |
665 | 703 | ||
666 | return ret; | 704 | return ret; |
667 | } | 705 | } |
@@ -773,6 +811,10 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm, | |||
773 | rm->atomic.op_active = 1; | 811 | rm->atomic.op_active = 1; |
774 | rm->atomic.op_recverr = rs->rs_recverr; | 812 | rm->atomic.op_recverr = rs->rs_recverr; |
775 | rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1); | 813 | rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1); |
814 | if (!rm->atomic.op_sg) { | ||
815 | ret = -ENOMEM; | ||
816 | goto err; | ||
817 | } | ||
776 | 818 | ||
777 | /* verify 8 byte-aligned */ | 819 | /* verify 8 byte-aligned */ |
778 | if (args->local_addr & 0x7) { | 820 | if (args->local_addr & 0x7) { |
diff --git a/net/rds/send.c b/net/rds/send.c index 0bc9db17a87d..35b9c2e9caf1 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
@@ -973,6 +973,10 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | |||
973 | /* Attach data to the rm */ | 973 | /* Attach data to the rm */ |
974 | if (payload_len) { | 974 | if (payload_len) { |
975 | rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE)); | 975 | rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE)); |
976 | if (!rm->data.op_sg) { | ||
977 | ret = -ENOMEM; | ||
978 | goto out; | ||
979 | } | ||
976 | ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len); | 980 | ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len); |
977 | if (ret) | 981 | if (ret) |
978 | goto out; | 982 | goto out; |
diff --git a/net/socket.c b/net/socket.c index 5247ae10f374..3ca2fd9e3720 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1652,6 +1652,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, | |||
1652 | struct iovec iov; | 1652 | struct iovec iov; |
1653 | int fput_needed; | 1653 | int fput_needed; |
1654 | 1654 | ||
1655 | if (len > INT_MAX) | ||
1656 | len = INT_MAX; | ||
1655 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1657 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1656 | if (!sock) | 1658 | if (!sock) |
1657 | goto out; | 1659 | goto out; |
@@ -1709,6 +1711,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, | |||
1709 | int err, err2; | 1711 | int err, err2; |
1710 | int fput_needed; | 1712 | int fput_needed; |
1711 | 1713 | ||
1714 | if (size > INT_MAX) | ||
1715 | size = INT_MAX; | ||
1712 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1716 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1713 | if (!sock) | 1717 | if (!sock) |
1714 | goto out; | 1718 | goto out; |