diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2009-06-17 21:02:14 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-06-17 21:02:14 -0400 |
commit | a5a16bae707cd5d2bc97d7bd1a30079f18113a77 (patch) | |
tree | dbd8012bbba334e92edae060806eebc73d4338ad | |
parent | d23c45fd84f79a3b84899dac053dcafe9d43ebc9 (diff) |
NFS: More "sloppy" parsing problems
Specifying "port=-5" with the kernel's current mount option parser
generates "unrecognized mount option". If "sloppy" is set, this
causes the mount to succeed and use the default values; the desired
behavior is that, since this is a valid option with an invalid value,
the mount should fail, even with "sloppy."
To properly handle "sloppy" parsing, we need to distinguish between
correct options with invalid values, and incorrect options. We will
need to parse integer values by hand, therefore, and not rely on
match_token().
For instance, these must all fail with "invalid value":
port=12345678
port=-5
port=samuel
and not with "unrecognized option," as they do currently.
Thus, for the sake of match_token() we need to treat the values for
these options as strings, and do the conversion to integers using
strict_strtol().
This is basically the same solution we used for the earlier "retry="
fix (commit ecbb3845), except in this case the kernel actually has to
parse the value, rather than ignore it.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/super.c | 142 |
1 files changed, 108 insertions, 34 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index a2b2805caf9d..b798ed1bd36d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -139,22 +139,22 @@ static const match_table_t nfs_mount_option_tokens = { | |||
139 | { Opt_fscache_uniq, "fsc=%s" }, | 139 | { Opt_fscache_uniq, "fsc=%s" }, |
140 | { Opt_nofscache, "nofsc" }, | 140 | { Opt_nofscache, "nofsc" }, |
141 | 141 | ||
142 | { Opt_port, "port=%u" }, | 142 | { Opt_port, "port=%s" }, |
143 | { Opt_rsize, "rsize=%u" }, | 143 | { Opt_rsize, "rsize=%s" }, |
144 | { Opt_wsize, "wsize=%u" }, | 144 | { Opt_wsize, "wsize=%s" }, |
145 | { Opt_bsize, "bsize=%u" }, | 145 | { Opt_bsize, "bsize=%s" }, |
146 | { Opt_timeo, "timeo=%u" }, | 146 | { Opt_timeo, "timeo=%s" }, |
147 | { Opt_retrans, "retrans=%u" }, | 147 | { Opt_retrans, "retrans=%s" }, |
148 | { Opt_acregmin, "acregmin=%u" }, | 148 | { Opt_acregmin, "acregmin=%s" }, |
149 | { Opt_acregmax, "acregmax=%u" }, | 149 | { Opt_acregmax, "acregmax=%s" }, |
150 | { Opt_acdirmin, "acdirmin=%u" }, | 150 | { Opt_acdirmin, "acdirmin=%s" }, |
151 | { Opt_acdirmax, "acdirmax=%u" }, | 151 | { Opt_acdirmax, "acdirmax=%s" }, |
152 | { Opt_actimeo, "actimeo=%u" }, | 152 | { Opt_actimeo, "actimeo=%s" }, |
153 | { Opt_namelen, "namlen=%u" }, | 153 | { Opt_namelen, "namlen=%s" }, |
154 | { Opt_mountport, "mountport=%u" }, | 154 | { Opt_mountport, "mountport=%s" }, |
155 | { Opt_mountvers, "mountvers=%u" }, | 155 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%u" }, | 156 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%u" }, | 157 | { Opt_nfsvers, "vers=%s" }, |
158 | 158 | ||
159 | { Opt_sec, "sec=%s" }, | 159 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 160 | { Opt_proto, "proto=%s" }, |
@@ -976,7 +976,8 @@ static int nfs_parse_mount_options(char *raw, | |||
976 | 976 | ||
977 | while ((p = strsep(&raw, ",")) != NULL) { | 977 | while ((p = strsep(&raw, ",")) != NULL) { |
978 | substring_t args[MAX_OPT_ARGS]; | 978 | substring_t args[MAX_OPT_ARGS]; |
979 | int option, token; | 979 | unsigned long option; |
980 | int token; | ||
980 | 981 | ||
981 | if (!*p) | 982 | if (!*p) |
982 | continue; | 983 | continue; |
@@ -1085,82 +1086,155 @@ static int nfs_parse_mount_options(char *raw, | |||
1085 | * options that take numeric values | 1086 | * options that take numeric values |
1086 | */ | 1087 | */ |
1087 | case Opt_port: | 1088 | case Opt_port: |
1088 | if (match_int(args, &option) || | 1089 | string = match_strdup(args); |
1089 | option < 0 || option > USHORT_MAX) | 1090 | if (string == NULL) |
1091 | goto out_nomem; | ||
1092 | rc = strict_strtoul(string, 10, &option); | ||
1093 | kfree(string); | ||
1094 | if (rc != 0 || option > USHORT_MAX) | ||
1090 | goto out_invalid_value; | 1095 | goto out_invalid_value; |
1091 | mnt->nfs_server.port = option; | 1096 | mnt->nfs_server.port = option; |
1092 | break; | 1097 | break; |
1093 | case Opt_rsize: | 1098 | case Opt_rsize: |
1094 | if (match_int(args, &option) || option < 0) | 1099 | string = match_strdup(args); |
1100 | if (string == NULL) | ||
1101 | goto out_nomem; | ||
1102 | rc = strict_strtoul(string, 10, &option); | ||
1103 | kfree(string); | ||
1104 | if (rc != 0) | ||
1095 | goto out_invalid_value; | 1105 | goto out_invalid_value; |
1096 | mnt->rsize = option; | 1106 | mnt->rsize = option; |
1097 | break; | 1107 | break; |
1098 | case Opt_wsize: | 1108 | case Opt_wsize: |
1099 | if (match_int(args, &option) || option < 0) | 1109 | string = match_strdup(args); |
1110 | if (string == NULL) | ||
1111 | goto out_nomem; | ||
1112 | rc = strict_strtoul(string, 10, &option); | ||
1113 | kfree(string); | ||
1114 | if (rc != 0) | ||
1100 | goto out_invalid_value; | 1115 | goto out_invalid_value; |
1101 | mnt->wsize = option; | 1116 | mnt->wsize = option; |
1102 | break; | 1117 | break; |
1103 | case Opt_bsize: | 1118 | case Opt_bsize: |
1104 | if (match_int(args, &option) || option < 0) | 1119 | string = match_strdup(args); |
1120 | if (string == NULL) | ||
1121 | goto out_nomem; | ||
1122 | rc = strict_strtoul(string, 10, &option); | ||
1123 | kfree(string); | ||
1124 | if (rc != 0) | ||
1105 | goto out_invalid_value; | 1125 | goto out_invalid_value; |
1106 | mnt->bsize = option; | 1126 | mnt->bsize = option; |
1107 | break; | 1127 | break; |
1108 | case Opt_timeo: | 1128 | case Opt_timeo: |
1109 | if (match_int(args, &option) || option <= 0) | 1129 | string = match_strdup(args); |
1130 | if (string == NULL) | ||
1131 | goto out_nomem; | ||
1132 | rc = strict_strtoul(string, 10, &option); | ||
1133 | kfree(string); | ||
1134 | if (rc != 0 || option == 0) | ||
1110 | goto out_invalid_value; | 1135 | goto out_invalid_value; |
1111 | mnt->timeo = option; | 1136 | mnt->timeo = option; |
1112 | break; | 1137 | break; |
1113 | case Opt_retrans: | 1138 | case Opt_retrans: |
1114 | if (match_int(args, &option) || option <= 0) | 1139 | string = match_strdup(args); |
1140 | if (string == NULL) | ||
1141 | goto out_nomem; | ||
1142 | rc = strict_strtoul(string, 10, &option); | ||
1143 | kfree(string); | ||
1144 | if (rc != 0 || option == 0) | ||
1115 | goto out_invalid_value; | 1145 | goto out_invalid_value; |
1116 | mnt->retrans = option; | 1146 | mnt->retrans = option; |
1117 | break; | 1147 | break; |
1118 | case Opt_acregmin: | 1148 | case Opt_acregmin: |
1119 | if (match_int(args, &option) || option < 0) | 1149 | string = match_strdup(args); |
1150 | if (string == NULL) | ||
1151 | goto out_nomem; | ||
1152 | rc = strict_strtoul(string, 10, &option); | ||
1153 | kfree(string); | ||
1154 | if (rc != 0) | ||
1120 | goto out_invalid_value; | 1155 | goto out_invalid_value; |
1121 | mnt->acregmin = option; | 1156 | mnt->acregmin = option; |
1122 | break; | 1157 | break; |
1123 | case Opt_acregmax: | 1158 | case Opt_acregmax: |
1124 | if (match_int(args, &option) || option < 0) | 1159 | string = match_strdup(args); |
1160 | if (string == NULL) | ||
1161 | goto out_nomem; | ||
1162 | rc = strict_strtoul(string, 10, &option); | ||
1163 | kfree(string); | ||
1164 | if (rc != 0) | ||
1125 | goto out_invalid_value; | 1165 | goto out_invalid_value; |
1126 | mnt->acregmax = option; | 1166 | mnt->acregmax = option; |
1127 | break; | 1167 | break; |
1128 | case Opt_acdirmin: | 1168 | case Opt_acdirmin: |
1129 | if (match_int(args, &option) || option < 0) | 1169 | string = match_strdup(args); |
1170 | if (string == NULL) | ||
1171 | goto out_nomem; | ||
1172 | rc = strict_strtoul(string, 10, &option); | ||
1173 | kfree(string); | ||
1174 | if (rc != 0) | ||
1130 | goto out_invalid_value; | 1175 | goto out_invalid_value; |
1131 | mnt->acdirmin = option; | 1176 | mnt->acdirmin = option; |
1132 | break; | 1177 | break; |
1133 | case Opt_acdirmax: | 1178 | case Opt_acdirmax: |
1134 | if (match_int(args, &option) || option < 0) | 1179 | string = match_strdup(args); |
1180 | if (string == NULL) | ||
1181 | goto out_nomem; | ||
1182 | rc = strict_strtoul(string, 10, &option); | ||
1183 | kfree(string); | ||
1184 | if (rc != 0) | ||
1135 | goto out_invalid_value; | 1185 | goto out_invalid_value; |
1136 | mnt->acdirmax = option; | 1186 | mnt->acdirmax = option; |
1137 | break; | 1187 | break; |
1138 | case Opt_actimeo: | 1188 | case Opt_actimeo: |
1139 | if (match_int(args, &option) || option < 0) | 1189 | string = match_strdup(args); |
1190 | if (string == NULL) | ||
1191 | goto out_nomem; | ||
1192 | rc = strict_strtoul(string, 10, &option); | ||
1193 | kfree(string); | ||
1194 | if (rc != 0) | ||
1140 | goto out_invalid_value; | 1195 | goto out_invalid_value; |
1141 | mnt->acregmin = mnt->acregmax = | 1196 | mnt->acregmin = mnt->acregmax = |
1142 | mnt->acdirmin = mnt->acdirmax = option; | 1197 | mnt->acdirmin = mnt->acdirmax = option; |
1143 | break; | 1198 | break; |
1144 | case Opt_namelen: | 1199 | case Opt_namelen: |
1145 | if (match_int(args, &option) || option < 0) | 1200 | string = match_strdup(args); |
1201 | if (string == NULL) | ||
1202 | goto out_nomem; | ||
1203 | rc = strict_strtoul(string, 10, &option); | ||
1204 | kfree(string); | ||
1205 | if (rc != 0) | ||
1146 | goto out_invalid_value; | 1206 | goto out_invalid_value; |
1147 | mnt->namlen = option; | 1207 | mnt->namlen = option; |
1148 | break; | 1208 | break; |
1149 | case Opt_mountport: | 1209 | case Opt_mountport: |
1150 | if (match_int(args, &option) || | 1210 | string = match_strdup(args); |
1151 | option < 0 || option > USHORT_MAX) | 1211 | if (string == NULL) |
1212 | goto out_nomem; | ||
1213 | rc = strict_strtoul(string, 10, &option); | ||
1214 | kfree(string); | ||
1215 | if (rc != 0 || option > USHORT_MAX) | ||
1152 | goto out_invalid_value; | 1216 | goto out_invalid_value; |
1153 | mnt->mount_server.port = option; | 1217 | mnt->mount_server.port = option; |
1154 | break; | 1218 | break; |
1155 | case Opt_mountvers: | 1219 | case Opt_mountvers: |
1156 | if (match_int(args, &option) || | 1220 | string = match_strdup(args); |
1221 | if (string == NULL) | ||
1222 | goto out_nomem; | ||
1223 | rc = strict_strtoul(string, 10, &option); | ||
1224 | kfree(string); | ||
1225 | if (rc != 0 || | ||
1157 | option < NFS_MNT_VERSION || | 1226 | option < NFS_MNT_VERSION || |
1158 | option > NFS_MNT3_VERSION) | 1227 | option > NFS_MNT3_VERSION) |
1159 | goto out_invalid_value; | 1228 | goto out_invalid_value; |
1160 | mnt->mount_server.version = option; | 1229 | mnt->mount_server.version = option; |
1161 | break; | 1230 | break; |
1162 | case Opt_nfsvers: | 1231 | case Opt_nfsvers: |
1163 | if (match_int(args, &option)) | 1232 | string = match_strdup(args); |
1233 | if (string == NULL) | ||
1234 | goto out_nomem; | ||
1235 | rc = strict_strtoul(string, 10, &option); | ||
1236 | kfree(string); | ||
1237 | if (rc != 0) | ||
1164 | goto out_invalid_value; | 1238 | goto out_invalid_value; |
1165 | switch (option) { | 1239 | switch (option) { |
1166 | case NFS2_VERSION: | 1240 | case NFS2_VERSION: |