diff options
-rw-r--r-- | fs/nfs/client.c | 4 | ||||
-rw-r--r-- | fs/nfs/internal.h | 6 | ||||
-rw-r--r-- | fs/nfs/super.c | 54 |
3 files changed, 40 insertions, 24 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ba114faf195f..906613362a56 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -581,7 +581,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
581 | struct nfs_client_initdata cl_init = { | 581 | struct nfs_client_initdata cl_init = { |
582 | .hostname = data->nfs_server.hostname, | 582 | .hostname = data->nfs_server.hostname, |
583 | .addr = (const struct sockaddr *)&data->nfs_server.address, | 583 | .addr = (const struct sockaddr *)&data->nfs_server.address, |
584 | .addrlen = sizeof(data->nfs_server.address), | 584 | .addrlen = data->nfs_server.addrlen, |
585 | .rpc_ops = &nfs_v2_clientops, | 585 | .rpc_ops = &nfs_v2_clientops, |
586 | }; | 586 | }; |
587 | struct nfs_client *clp; | 587 | struct nfs_client *clp; |
@@ -1018,7 +1018,7 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1018 | error = nfs4_set_client(server, | 1018 | error = nfs4_set_client(server, |
1019 | data->nfs_server.hostname, | 1019 | data->nfs_server.hostname, |
1020 | (struct sockaddr *)&data->nfs_server.address, | 1020 | (struct sockaddr *)&data->nfs_server.address, |
1021 | sizeof(data->nfs_server.address), | 1021 | data->nfs_server.addrlen, |
1022 | data->client_address, | 1022 | data->client_address, |
1023 | data->auth_flavors[0], | 1023 | data->auth_flavors[0], |
1024 | data->nfs_server.protocol, | 1024 | data->nfs_server.protocol, |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 75dd4e252cae..a80621199086 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -42,7 +42,8 @@ struct nfs_parsed_mount_data { | |||
42 | char *client_address; | 42 | char *client_address; |
43 | 43 | ||
44 | struct { | 44 | struct { |
45 | struct sockaddr_in address; | 45 | struct sockaddr_storage address; |
46 | size_t addrlen; | ||
46 | char *hostname; | 47 | char *hostname; |
47 | unsigned int version; | 48 | unsigned int version; |
48 | unsigned short port; | 49 | unsigned short port; |
@@ -50,7 +51,8 @@ struct nfs_parsed_mount_data { | |||
50 | } mount_server; | 51 | } mount_server; |
51 | 52 | ||
52 | struct { | 53 | struct { |
53 | struct sockaddr_in address; | 54 | struct sockaddr_storage address; |
55 | size_t addrlen; | ||
54 | char *hostname; | 56 | char *hostname; |
55 | char *export_path; | 57 | char *export_path; |
56 | int protocol; | 58 | int protocol; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 041fe9e9b74d..7efc6a34b56b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -649,15 +649,18 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
649 | * to punt the mount. | 649 | * to punt the mount. |
650 | */ | 650 | */ |
651 | static void nfs_parse_server_address(char *value, | 651 | static void nfs_parse_server_address(char *value, |
652 | struct sockaddr *sap) | 652 | struct sockaddr *sap, |
653 | size_t *len) | ||
653 | { | 654 | { |
654 | struct sockaddr_in *ap = (void *)sap; | 655 | struct sockaddr_in *ap = (void *)sap; |
655 | 656 | ||
656 | ap->sin_family = AF_INET; | 657 | ap->sin_family = AF_INET; |
658 | *len = sizeof(*ap); | ||
657 | if (in4_pton(value, -1, (u8 *)&ap->sin_addr.s_addr, '\0', NULL)) | 659 | if (in4_pton(value, -1, (u8 *)&ap->sin_addr.s_addr, '\0', NULL)) |
658 | return; | 660 | return; |
659 | 661 | ||
660 | sap->sa_family = AF_UNSPEC; | 662 | sap->sa_family = AF_UNSPEC; |
663 | *len = 0; | ||
661 | } | 664 | } |
662 | 665 | ||
663 | /* | 666 | /* |
@@ -984,7 +987,8 @@ static int nfs_parse_mount_options(char *raw, | |||
984 | if (string == NULL) | 987 | if (string == NULL) |
985 | goto out_nomem; | 988 | goto out_nomem; |
986 | nfs_parse_server_address(string, (struct sockaddr *) | 989 | nfs_parse_server_address(string, (struct sockaddr *) |
987 | &mnt->nfs_server.address); | 990 | &mnt->nfs_server.address, |
991 | &mnt->nfs_server.addrlen); | ||
988 | kfree(string); | 992 | kfree(string); |
989 | break; | 993 | break; |
990 | case Opt_clientaddr: | 994 | case Opt_clientaddr: |
@@ -1004,7 +1008,8 @@ static int nfs_parse_mount_options(char *raw, | |||
1004 | if (string == NULL) | 1008 | if (string == NULL) |
1005 | goto out_nomem; | 1009 | goto out_nomem; |
1006 | nfs_parse_server_address(string, (struct sockaddr *) | 1010 | nfs_parse_server_address(string, (struct sockaddr *) |
1007 | &mnt->mount_server.address); | 1011 | &mnt->mount_server.address, |
1012 | &mnt->mount_server.addrlen); | ||
1008 | kfree(string); | 1013 | kfree(string); |
1009 | break; | 1014 | break; |
1010 | 1015 | ||
@@ -1049,9 +1054,9 @@ out_unknown: | |||
1049 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1054 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1050 | struct nfs_fh *root_fh) | 1055 | struct nfs_fh *root_fh) |
1051 | { | 1056 | { |
1052 | struct sockaddr_in sin; | 1057 | struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address; |
1053 | int status; | ||
1054 | char *hostname; | 1058 | char *hostname; |
1059 | int status; | ||
1055 | 1060 | ||
1056 | if (args->mount_server.version == 0) { | 1061 | if (args->mount_server.version == 0) { |
1057 | if (args->flags & NFS_MOUNT_VER3) | 1062 | if (args->flags & NFS_MOUNT_VER3) |
@@ -1068,21 +1073,23 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1068 | /* | 1073 | /* |
1069 | * Construct the mount server's address. | 1074 | * Construct the mount server's address. |
1070 | */ | 1075 | */ |
1071 | if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) | 1076 | if (args->mount_server.address.ss_family == AF_UNSPEC) { |
1072 | sin = args->mount_server.address; | 1077 | memcpy(sap, &args->nfs_server.address, |
1073 | else | 1078 | args->nfs_server.addrlen); |
1074 | sin = args->nfs_server.address; | 1079 | args->mount_server.addrlen = args->nfs_server.addrlen; |
1080 | } | ||
1081 | |||
1075 | /* | 1082 | /* |
1076 | * autobind will be used if mount_server.port == 0 | 1083 | * autobind will be used if mount_server.port == 0 |
1077 | */ | 1084 | */ |
1078 | nfs_set_port((struct sockaddr *)&sin, args->mount_server.port); | 1085 | nfs_set_port(sap, args->mount_server.port); |
1079 | 1086 | ||
1080 | /* | 1087 | /* |
1081 | * Now ask the mount server to map our export path | 1088 | * Now ask the mount server to map our export path |
1082 | * to a file handle. | 1089 | * to a file handle. |
1083 | */ | 1090 | */ |
1084 | status = nfs_mount((struct sockaddr *) &sin, | 1091 | status = nfs_mount(sap, |
1085 | sizeof(sin), | 1092 | args->mount_server.addrlen, |
1086 | hostname, | 1093 | hostname, |
1087 | args->nfs_server.export_path, | 1094 | args->nfs_server.export_path, |
1088 | args->mount_server.version, | 1095 | args->mount_server.version, |
@@ -1165,9 +1172,6 @@ static int nfs_validate_mount_data(void *options, | |||
1165 | memset(mntfh->data + mntfh->size, 0, | 1172 | memset(mntfh->data + mntfh->size, 0, |
1166 | sizeof(mntfh->data) - mntfh->size); | 1173 | sizeof(mntfh->data) - mntfh->size); |
1167 | 1174 | ||
1168 | if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) | ||
1169 | goto out_no_address; | ||
1170 | |||
1171 | /* | 1175 | /* |
1172 | * Translate to nfs_parsed_mount_data, which nfs_fill_super | 1176 | * Translate to nfs_parsed_mount_data, which nfs_fill_super |
1173 | * can deal with. | 1177 | * can deal with. |
@@ -1182,7 +1186,14 @@ static int nfs_validate_mount_data(void *options, | |||
1182 | args->acregmax = data->acregmax; | 1186 | args->acregmax = data->acregmax; |
1183 | args->acdirmin = data->acdirmin; | 1187 | args->acdirmin = data->acdirmin; |
1184 | args->acdirmax = data->acdirmax; | 1188 | args->acdirmax = data->acdirmax; |
1185 | args->nfs_server.address = data->addr; | 1189 | |
1190 | memcpy(&args->nfs_server.address, &data->addr, | ||
1191 | sizeof(data->addr)); | ||
1192 | args->nfs_server.addrlen = sizeof(data->addr); | ||
1193 | if (!nfs_verify_server_address((struct sockaddr *) | ||
1194 | &args->nfs_server.address)) | ||
1195 | goto out_no_address; | ||
1196 | |||
1186 | if (!(data->flags & NFS_MOUNT_TCP)) | 1197 | if (!(data->flags & NFS_MOUNT_TCP)) |
1187 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1198 | args->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1188 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1199 | /* N.B. caller will free nfs_server.hostname in all cases */ |
@@ -1655,6 +1666,7 @@ static int nfs4_validate_mount_data(void *options, | |||
1655 | struct nfs_parsed_mount_data *args, | 1666 | struct nfs_parsed_mount_data *args, |
1656 | const char *dev_name) | 1667 | const char *dev_name) |
1657 | { | 1668 | { |
1669 | struct sockaddr_in *ap; | ||
1658 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 1670 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
1659 | char *c; | 1671 | char *c; |
1660 | 1672 | ||
@@ -1675,11 +1687,13 @@ static int nfs4_validate_mount_data(void *options, | |||
1675 | 1687 | ||
1676 | switch (data->version) { | 1688 | switch (data->version) { |
1677 | case 1: | 1689 | case 1: |
1678 | if (data->host_addrlen != sizeof(args->nfs_server.address)) | 1690 | ap = (struct sockaddr_in *)&args->nfs_server.address; |
1691 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | ||
1692 | goto out_no_address; | ||
1693 | if (data->host_addrlen == 0) | ||
1679 | goto out_no_address; | 1694 | goto out_no_address; |
1680 | if (copy_from_user(&args->nfs_server.address, | 1695 | args->nfs_server.addrlen = data->host_addrlen; |
1681 | data->host_addr, | 1696 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) |
1682 | sizeof(args->nfs_server.address))) | ||
1683 | return -EFAULT; | 1697 | return -EFAULT; |
1684 | if (!nfs_verify_server_address((struct sockaddr *) | 1698 | if (!nfs_verify_server_address((struct sockaddr *) |
1685 | &args->nfs_server.address)) | 1699 | &args->nfs_server.address)) |