Commit ce3b7e1906ebbe96753fe090b36de6ffb8e0e0e7

Authored by Chuck Lever
Committed by Trond Myklebust
1 parent d1aa082573

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

... ... @@ -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);