Commit ce3b7e1906ebbe96753fe090b36de6ffb8e0e0e7
Committed by
Trond Myklebust
1 parent
d1aa082573
Exists in
master
and in
20 other branches
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>
Showing 2 changed files with 77 additions and 30 deletions Side-by-side Diff
fs/nfs/super.c
... | ... | @@ -705,41 +705,79 @@ |
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)) | |
714 | + if (str_len <= INET_ADDRSTRLEN) { | |
715 | + dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | |
716 | + (int)str_len, string); | |
717 | + | |
718 | + sin->sin_family = AF_INET; | |
719 | + *addr_len = sizeof(*sin); | |
720 | + if (in4_pton(string, str_len, addr, '\0', NULL)) | |
727 | 721 | return; |
728 | - } else { | |
729 | - struct sockaddr_in *ap = (struct sockaddr_in *)sap; | |
730 | - u8 *addr = (u8 *)&ap->sin_addr.s_addr; | |
722 | + } | |
731 | 723 | |
732 | - ap->sin_family = AF_INET; | |
733 | - *len = sizeof(*ap); | |
734 | - if (in4_pton(value, -1, addr, '\0', NULL)) | |
724 | + sap->sa_family = AF_UNSPEC; | |
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)) | |
735 | 742 | return; |
736 | 743 | } |
737 | 744 | |
738 | 745 | sap->sa_family = AF_UNSPEC; |
739 | - *len = 0; | |
746 | + *addr_len = 0; | |
740 | 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 | |
741 | 756 | |
742 | 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); | |
778 | +} | |
779 | + | |
780 | +/* | |
743 | 781 | * Error-check and convert a string of mount options from user space into |
744 | 782 | * a data structure |
745 | 783 | */ |
... | ... | @@ -1070,9 +1108,10 @@ |
1070 | 1108 | string = match_strdup(args); |
1071 | 1109 | if (string == NULL) |
1072 | 1110 | goto out_nomem; |
1073 | - nfs_parse_server_address(string, (struct sockaddr *) | |
1074 | - &mnt->nfs_server.address, | |
1075 | - &mnt->nfs_server.addrlen); | |
1111 | + nfs_parse_ip_address(string, strlen(string), | |
1112 | + (struct sockaddr *) | |
1113 | + &mnt->nfs_server.address, | |
1114 | + &mnt->nfs_server.addrlen); | |
1076 | 1115 | kfree(string); |
1077 | 1116 | break; |
1078 | 1117 | case Opt_clientaddr: |
... | ... | @@ -1093,9 +1132,10 @@ |
1093 | 1132 | string = match_strdup(args); |
1094 | 1133 | if (string == NULL) |
1095 | 1134 | goto out_nomem; |
1096 | - nfs_parse_server_address(string, (struct sockaddr *) | |
1097 | - &mnt->mount_server.address, | |
1098 | - &mnt->mount_server.addrlen); | |
1135 | + nfs_parse_ip_address(string, strlen(string), | |
1136 | + (struct sockaddr *) | |
1137 | + &mnt->mount_server.address, | |
1138 | + &mnt->mount_server.addrlen); | |
1099 | 1139 | kfree(string); |
1100 | 1140 | break; |
1101 | 1141 |
include/linux/inet.h
... | ... | @@ -44,6 +44,13 @@ |
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); |