aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2014-05-15 11:28:07 -0400
committerBen Hutchings <ben@decadent.org.uk>2014-06-02 21:43:16 -0400
commitf062a3844845d267e3716cbc188ad502a15898b7 (patch)
tree964e372f604b5df8884f941a4f5c152fcfce5fbe /net
parentfe62d001372388abb15a324148c913f9b43722a8 (diff)
ethtool: Check that reserved fields of struct ethtool_rxfh are 0
We should fail rather than silently ignoring use of these extensions. Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'net')
-rw-r--r--net/core/ethtool.c89
1 files changed, 36 insertions, 53 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 8ae452afb545..17cb912793fa 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -681,11 +681,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
681{ 681{
682 int ret; 682 int ret;
683 const struct ethtool_ops *ops = dev->ethtool_ops; 683 const struct ethtool_ops *ops = dev->ethtool_ops;
684 u32 user_indir_size = 0, user_key_size = 0; 684 u32 user_indir_size, user_key_size;
685 u32 dev_indir_size = 0, dev_key_size = 0; 685 u32 dev_indir_size = 0, dev_key_size = 0;
686 struct ethtool_rxfh rxfh;
686 u32 total_size; 687 u32 total_size;
687 u32 indir_offset, indir_bytes; 688 u32 indir_bytes;
688 u32 key_offset;
689 u32 *indir = NULL; 689 u32 *indir = NULL;
690 u8 *hkey = NULL; 690 u8 *hkey = NULL;
691 u8 *rss_config; 691 u8 *rss_config;
@@ -697,33 +697,24 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
697 697
698 if (ops->get_rxfh_indir_size) 698 if (ops->get_rxfh_indir_size)
699 dev_indir_size = ops->get_rxfh_indir_size(dev); 699 dev_indir_size = ops->get_rxfh_indir_size(dev);
700
701 indir_offset = offsetof(struct ethtool_rxfh, indir_size);
702
703 if (copy_from_user(&user_indir_size,
704 useraddr + indir_offset,
705 sizeof(user_indir_size)))
706 return -EFAULT;
707
708 if (copy_to_user(useraddr + indir_offset,
709 &dev_indir_size, sizeof(dev_indir_size)))
710 return -EFAULT;
711
712 if (ops->get_rxfh_key_size) 700 if (ops->get_rxfh_key_size)
713 dev_key_size = ops->get_rxfh_key_size(dev); 701 dev_key_size = ops->get_rxfh_key_size(dev);
714 702
715 if ((dev_key_size + dev_indir_size) == 0) 703 if ((dev_key_size + dev_indir_size) == 0)
716 return -EOPNOTSUPP; 704 return -EOPNOTSUPP;
717 705
718 key_offset = offsetof(struct ethtool_rxfh, key_size); 706 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
719
720 if (copy_from_user(&user_key_size,
721 useraddr + key_offset,
722 sizeof(user_key_size)))
723 return -EFAULT; 707 return -EFAULT;
708 user_indir_size = rxfh.indir_size;
709 user_key_size = rxfh.key_size;
724 710
725 if (copy_to_user(useraddr + key_offset, 711 /* Check that reserved fields are 0 for now */
726 &dev_key_size, sizeof(dev_key_size))) 712 if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
713 return -EINVAL;
714
715 rxfh.indir_size = dev_indir_size;
716 rxfh.key_size = dev_key_size;
717 if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
727 return -EFAULT; 718 return -EFAULT;
728 719
729 /* If the user buffer size is 0, this is just a query for the 720 /* If the user buffer size is 0, this is just a query for the
@@ -768,12 +759,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
768 int ret; 759 int ret;
769 const struct ethtool_ops *ops = dev->ethtool_ops; 760 const struct ethtool_ops *ops = dev->ethtool_ops;
770 struct ethtool_rxnfc rx_rings; 761 struct ethtool_rxnfc rx_rings;
771 u32 user_indir_size = 0, dev_indir_size = 0, i; 762 struct ethtool_rxfh rxfh;
772 u32 user_key_size = 0, dev_key_size = 0; 763 u32 dev_indir_size = 0, dev_key_size = 0, i;
773 u32 *indir = NULL, indir_bytes = 0; 764 u32 *indir = NULL, indir_bytes = 0;
774 u8 *hkey = NULL; 765 u8 *hkey = NULL;
775 u8 *rss_config; 766 u8 *rss_config;
776 u32 indir_offset, key_offset;
777 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); 767 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
778 768
779 if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || 769 if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) ||
@@ -782,40 +772,33 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
782 772
783 if (ops->get_rxfh_indir_size) 773 if (ops->get_rxfh_indir_size)
784 dev_indir_size = ops->get_rxfh_indir_size(dev); 774 dev_indir_size = ops->get_rxfh_indir_size(dev);
785
786 indir_offset = offsetof(struct ethtool_rxfh, indir_size);
787 if (copy_from_user(&user_indir_size,
788 useraddr + indir_offset,
789 sizeof(user_indir_size)))
790 return -EFAULT;
791
792 if (ops->get_rxfh_key_size) 775 if (ops->get_rxfh_key_size)
793 dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); 776 dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
794
795 if ((dev_key_size + dev_indir_size) == 0) 777 if ((dev_key_size + dev_indir_size) == 0)
796 return -EOPNOTSUPP; 778 return -EOPNOTSUPP;
797 779
798 key_offset = offsetof(struct ethtool_rxfh, key_size); 780 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
799 if (copy_from_user(&user_key_size,
800 useraddr + key_offset,
801 sizeof(user_key_size)))
802 return -EFAULT; 781 return -EFAULT;
803 782
783 /* Check that reserved fields are 0 for now */
784 if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
785 return -EINVAL;
786
804 /* If either indir or hash key is valid, proceed further. 787 /* If either indir or hash key is valid, proceed further.
805 * It is not valid to request that both be unchanged. 788 * It is not valid to request that both be unchanged.
806 */ 789 */
807 if ((user_indir_size && 790 if ((rxfh.indir_size &&
808 user_indir_size != ETH_RXFH_INDIR_NO_CHANGE && 791 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
809 user_indir_size != dev_indir_size) || 792 rxfh.indir_size != dev_indir_size) ||
810 (user_key_size && (user_key_size != dev_key_size)) || 793 (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
811 (user_indir_size == ETH_RXFH_INDIR_NO_CHANGE && 794 (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
812 user_key_size == 0)) 795 rxfh.key_size == 0))
813 return -EINVAL; 796 return -EINVAL;
814 797
815 if (user_indir_size != ETH_RXFH_INDIR_NO_CHANGE) 798 if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
816 indir_bytes = dev_indir_size * sizeof(indir[0]); 799 indir_bytes = dev_indir_size * sizeof(indir[0]);
817 800
818 rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); 801 rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
819 if (!rss_config) 802 if (!rss_config)
820 return -ENOMEM; 803 return -ENOMEM;
821 804
@@ -824,29 +807,29 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
824 if (ret) 807 if (ret)
825 goto out; 808 goto out;
826 809
827 /* user_indir_size == 0 means reset the indir table to default. 810 /* rxfh.indir_size == 0 means reset the indir table to default.
828 * user_indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. 811 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
829 */ 812 */
830 if (user_indir_size && 813 if (rxfh.indir_size &&
831 user_indir_size != ETH_RXFH_INDIR_NO_CHANGE) { 814 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
832 indir = (u32 *)rss_config; 815 indir = (u32 *)rss_config;
833 ret = ethtool_copy_validate_indir(indir, 816 ret = ethtool_copy_validate_indir(indir,
834 useraddr + rss_cfg_offset, 817 useraddr + rss_cfg_offset,
835 &rx_rings, 818 &rx_rings,
836 user_indir_size); 819 rxfh.indir_size);
837 if (ret) 820 if (ret)
838 goto out; 821 goto out;
839 } else if (user_indir_size == 0) { 822 } else if (rxfh.indir_size == 0) {
840 indir = (u32 *)rss_config; 823 indir = (u32 *)rss_config;
841 for (i = 0; i < dev_indir_size; i++) 824 for (i = 0; i < dev_indir_size; i++)
842 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); 825 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
843 } 826 }
844 827
845 if (user_key_size) { 828 if (rxfh.key_size) {
846 hkey = rss_config + indir_bytes; 829 hkey = rss_config + indir_bytes;
847 if (copy_from_user(hkey, 830 if (copy_from_user(hkey,
848 useraddr + rss_cfg_offset + indir_bytes, 831 useraddr + rss_cfg_offset + indir_bytes,
849 user_key_size)) { 832 rxfh.key_size)) {
850 ret = -EFAULT; 833 ret = -EFAULT;
851 goto out; 834 goto out;
852 } 835 }