aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2008-10-08 15:38:10 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-10-10 14:41:51 -0400
commit5e2e7721f04c11e6dc4a74b33f05a0e1c0381e2e (patch)
tree2eaa3154bae5232012e1f1aa8fd7f59f98f9a7e5 /fs
parent456018d791ff4ef03d610f72486c637056bcd749 (diff)
NFS: fix nfs_parse_ip_address() corner case
Bruce observed that nfs_parse_ip_address() will successfully parse an IPv6 address that looks like this: "::1%" A scope delimiter is present, but there is no scope ID following it. This is harmless, as it would simply set the scope ID to zero. However, in some cases we would like to flag this as an improperly formed address. We are now also careful to reject addresses where garbage follows the address (up to the length of the string), instead of ignoring the non-address characters; and where the scope ID is nonsense (not a valid device name, but also not numeric). Before, both of these cases would result in a harmless zero scope ID. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/super.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 20dc4ccdff56..d496e4016224 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -717,17 +717,21 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len,
717} 717}
718 718
719#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 719#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
720static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, 720static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
721 const char *delim, 721 const char *delim,
722 struct sockaddr_in6 *sin6) 722 struct sockaddr_in6 *sin6)
723{ 723{
724 char *p; 724 char *p;
725 size_t len; 725 size_t len;
726 726
727 if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 727 if ((string + str_len) == delim)
728 return ; 728 return 1;
729
729 if (*delim != IPV6_SCOPE_DELIMITER) 730 if (*delim != IPV6_SCOPE_DELIMITER)
730 return; 731 return 0;
732
733 if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
734 return 0;
731 735
732 len = (string + str_len) - delim - 1; 736 len = (string + str_len) - delim - 1;
733 p = kstrndup(delim + 1, len, GFP_KERNEL); 737 p = kstrndup(delim + 1, len, GFP_KERNEL);
@@ -740,14 +744,20 @@ static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
740 scope_id = dev->ifindex; 744 scope_id = dev->ifindex;
741 dev_put(dev); 745 dev_put(dev);
742 } else { 746 } else {
743 /* scope_id is set to zero on error */ 747 if (strict_strtoul(p, 10, &scope_id) == 0) {
744 strict_strtoul(p, 10, &scope_id); 748 kfree(p);
749 return 0;
750 }
745 } 751 }
746 752
747 kfree(p); 753 kfree(p);
754
748 sin6->sin6_scope_id = scope_id; 755 sin6->sin6_scope_id = scope_id;
749 dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); 756 dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
757 return 1;
750 } 758 }
759
760 return 0;
751} 761}
752 762
753static void nfs_parse_ipv6_address(char *string, size_t str_len, 763static void nfs_parse_ipv6_address(char *string, size_t str_len,
@@ -763,9 +773,11 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len,
763 773
764 sin6->sin6_family = AF_INET6; 774 sin6->sin6_family = AF_INET6;
765 *addr_len = sizeof(*sin6); 775 *addr_len = sizeof(*sin6);
766 if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { 776 if (in6_pton(string, str_len, addr,
767 nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); 777 IPV6_SCOPE_DELIMITER, &delim) != 0) {
768 return; 778 if (nfs_parse_ipv6_scope_id(string, str_len,
779 delim, sin6) != 0)
780 return;
769 } 781 }
770 } 782 }
771 783