Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Add string length argument to nfs_parse_server_address

To make nfs_parse_server_address() more generally useful, allow it to
accept input strings that are not terminated with '\0'.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Chuck Lever and committed by
Trond Myklebust
ce3b7e19 d1aa0825

+78 -31
+71 -31
fs/nfs/super.c
··· 705 705 return 0; 706 706 } 707 707 708 - /* 709 - * Parse string addresses passed in via a mount option, 710 - * and construct a sockaddr based on the result. 711 - * 712 - * If address parsing fails, set the sockaddr's address 713 - * family to AF_UNSPEC to force nfs_verify_server_address() 714 - * to punt the mount. 715 - */ 716 - static void nfs_parse_server_address(char *value, 717 - struct sockaddr *sap, 718 - size_t *len) 708 + static void nfs_parse_ipv4_address(char *string, size_t str_len, 709 + struct sockaddr *sap, size_t *addr_len) 719 710 { 720 - if (strchr(value, ':')) { 721 - struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; 722 - u8 *addr = (u8 *)&ap->sin6_addr.in6_u; 711 + struct sockaddr_in *sin = (struct sockaddr_in *)sap; 712 + u8 *addr = (u8 *)&sin->sin_addr.s_addr; 723 713 724 - ap->sin6_family = AF_INET6; 725 - *len = sizeof(*ap); 726 - if (in6_pton(value, -1, addr, '\0', NULL)) 727 - return; 728 - } else { 729 - struct sockaddr_in *ap = (struct sockaddr_in *)sap; 730 - u8 *addr = (u8 *)&ap->sin_addr.s_addr; 714 + if (str_len <= INET_ADDRSTRLEN) { 715 + dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", 716 + (int)str_len, string); 731 717 732 - ap->sin_family = AF_INET; 733 - *len = sizeof(*ap); 734 - if (in4_pton(value, -1, addr, '\0', NULL)) 718 + sin->sin_family = AF_INET; 719 + *addr_len = sizeof(*sin); 720 + if (in4_pton(string, str_len, addr, '\0', NULL)) 735 721 return; 736 722 } 737 723 738 724 sap->sa_family = AF_UNSPEC; 739 - *len = 0; 725 + *addr_len = 0; 726 + } 727 + 728 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 729 + static void nfs_parse_ipv6_address(char *string, size_t str_len, 730 + struct sockaddr *sap, size_t *addr_len) 731 + { 732 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 733 + u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; 734 + 735 + if (str_len <= INET6_ADDRSTRLEN) { 736 + dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", 737 + (int)str_len, string); 738 + 739 + sin6->sin6_family = AF_INET6; 740 + *addr_len = sizeof(*sin6); 741 + if (in6_pton(string, str_len, addr, '\0', NULL)) 742 + return; 743 + } 744 + 745 + sap->sa_family = AF_UNSPEC; 746 + *addr_len = 0; 747 + } 748 + #else 749 + static void nfs_parse_ipv6_address(char *string, size_t str_len, 750 + struct sockaddr *sap, size_t *addr_len) 751 + { 752 + sap->sa_family = AF_UNSPEC; 753 + *addr_len = 0; 754 + } 755 + #endif 756 + 757 + /* 758 + * Construct a sockaddr based on the contents of a string that contains 759 + * an IP address in presentation format. 760 + * 761 + * If there is a problem constructing the new sockaddr, set the address 762 + * family to AF_UNSPEC. 763 + */ 764 + static void nfs_parse_ip_address(char *string, size_t str_len, 765 + struct sockaddr *sap, size_t *addr_len) 766 + { 767 + unsigned int i, colons; 768 + 769 + colons = 0; 770 + for (i = 0; i < str_len; i++) 771 + if (string[i] == ':') 772 + colons++; 773 + 774 + if (colons >= 2) 775 + nfs_parse_ipv6_address(string, str_len, sap, addr_len); 776 + else 777 + nfs_parse_ipv4_address(string, str_len, sap, addr_len); 740 778 } 741 779 742 780 /* ··· 1108 1070 string = match_strdup(args); 1109 1071 if (string == NULL) 1110 1072 goto out_nomem; 1111 - nfs_parse_server_address(string, (struct sockaddr *) 1112 - &mnt->nfs_server.address, 1113 - &mnt->nfs_server.addrlen); 1073 + nfs_parse_ip_address(string, strlen(string), 1074 + (struct sockaddr *) 1075 + &mnt->nfs_server.address, 1076 + &mnt->nfs_server.addrlen); 1114 1077 kfree(string); 1115 1078 break; 1116 1079 case Opt_clientaddr: ··· 1132 1093 string = match_strdup(args); 1133 1094 if (string == NULL) 1134 1095 goto out_nomem; 1135 - nfs_parse_server_address(string, (struct sockaddr *) 1136 - &mnt->mount_server.address, 1137 - &mnt->mount_server.addrlen); 1096 + nfs_parse_ip_address(string, strlen(string), 1097 + (struct sockaddr *) 1098 + &mnt->mount_server.address, 1099 + &mnt->mount_server.addrlen); 1138 1100 kfree(string); 1139 1101 break; 1140 1102
+7
include/linux/inet.h
··· 44 44 45 45 #include <linux/types.h> 46 46 47 + /* 48 + * These mimic similar macros defined in user-space for inet_ntop(3). 49 + * See /usr/include/netinet/in.h . 50 + */ 51 + #define INET_ADDRSTRLEN (16) 52 + #define INET6_ADDRSTRLEN (48) 53 + 47 54 extern __be32 in_aton(const char *str); 48 55 extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); 49 56 extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);