aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs2xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs2xdr.c')
-rw-r--r--fs/nfs/nfs2xdr.c564
1 files changed, 556 insertions, 8 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 2da9824d432..827d1b8ad55 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -77,6 +77,16 @@ static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
78} 78}
79 79
80/*
81 * Handle decode buffer overflows out-of-line.
82 */
83static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
84{
85 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
86 "Remaining buffer length is %tu words.\n",
87 func, xdr->end - xdr->p);
88}
89
80 90
81/* 91/*
82 * Common NFS XDR functions as inlines 92 * Common NFS XDR functions as inlines
@@ -139,6 +149,74 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
139 */ 149 */
140 150
141/* 151/*
152 * typedef opaque nfsdata<>;
153 */
154static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
155{
156 u32 recvd, count;
157 size_t hdrlen;
158 __be32 *p;
159
160 p = xdr_inline_decode(xdr, 4);
161 if (unlikely(p == NULL))
162 goto out_overflow;
163 count = be32_to_cpup(p);
164 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
165 recvd = xdr->buf->len - hdrlen;
166 if (unlikely(count > recvd))
167 goto out_cheating;
168out:
169 xdr_read_pages(xdr, count);
170 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
171 result->count = count;
172 return count;
173out_cheating:
174 dprintk("NFS: server cheating in read result: "
175 "count %u > recvd %u\n", count, recvd);
176 count = recvd;
177 goto out;
178out_overflow:
179 print_overflow_msg(__func__, xdr);
180 return -EIO;
181}
182
183/*
184 * enum stat {
185 * NFS_OK = 0,
186 * NFSERR_PERM = 1,
187 * NFSERR_NOENT = 2,
188 * NFSERR_IO = 5,
189 * NFSERR_NXIO = 6,
190 * NFSERR_ACCES = 13,
191 * NFSERR_EXIST = 17,
192 * NFSERR_NODEV = 19,
193 * NFSERR_NOTDIR = 20,
194 * NFSERR_ISDIR = 21,
195 * NFSERR_FBIG = 27,
196 * NFSERR_NOSPC = 28,
197 * NFSERR_ROFS = 30,
198 * NFSERR_NAMETOOLONG = 63,
199 * NFSERR_NOTEMPTY = 66,
200 * NFSERR_DQUOT = 69,
201 * NFSERR_STALE = 70,
202 * NFSERR_WFLUSH = 99
203 * };
204 */
205static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
206{
207 __be32 *p;
208
209 p = xdr_inline_decode(xdr, 4);
210 if (unlikely(p == NULL))
211 goto out_overflow;
212 *status = be32_to_cpup(p);
213 return 0;
214out_overflow:
215 print_overflow_msg(__func__, xdr);
216 return -EIO;
217}
218
219/*
142 * 2.3.3. fhandle 220 * 2.3.3. fhandle
143 * 221 *
144 * typedef opaque fhandle[FHSIZE]; 222 * typedef opaque fhandle[FHSIZE];
@@ -152,6 +230,21 @@ static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
152 memcpy(p, fh->data, NFS2_FHSIZE); 230 memcpy(p, fh->data, NFS2_FHSIZE);
153} 231}
154 232
233static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
234{
235 __be32 *p;
236
237 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
238 if (unlikely(p == NULL))
239 goto out_overflow;
240 fh->size = NFS2_FHSIZE;
241 memcpy(fh->data, p, NFS2_FHSIZE);
242 return 0;
243out_overflow:
244 print_overflow_msg(__func__, xdr);
245 return -EIO;
246}
247
155/* 248/*
156 * 2.3.4. timeval 249 * 2.3.4. timeval
157 * 250 *
@@ -186,6 +279,41 @@ static __be32 *xdr_encode_current_server_time(__be32 *p,
186} 279}
187 280
188/* 281/*
282 * 2.3.5. fattr
283 *
284 * struct fattr {
285 * ftype type;
286 * unsigned int mode;
287 * unsigned int nlink;
288 * unsigned int uid;
289 * unsigned int gid;
290 * unsigned int size;
291 * unsigned int blocksize;
292 * unsigned int rdev;
293 * unsigned int blocks;
294 * unsigned int fsid;
295 * unsigned int fileid;
296 * timeval atime;
297 * timeval mtime;
298 * timeval ctime;
299 * };
300 *
301 */
302static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
303{
304 __be32 *p;
305
306 p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
307 if (unlikely(p == NULL))
308 goto out_overflow;
309 xdr_decode_fattr(p, fattr);
310 return 0;
311out_overflow:
312 print_overflow_msg(__func__, xdr);
313 return -EIO;
314}
315
316/*
189 * 2.3.6. sattr 317 * 2.3.6. sattr
190 * 318 *
191 * struct sattr { 319 * struct sattr {
@@ -259,6 +387,32 @@ static void encode_filename(struct xdr_stream *xdr,
259 xdr_encode_opaque(p, name, length); 387 xdr_encode_opaque(p, name, length);
260} 388}
261 389
390static int decode_filename_inline(struct xdr_stream *xdr,
391 const char **name, u32 *length)
392{
393 __be32 *p;
394 u32 count;
395
396 p = xdr_inline_decode(xdr, 4);
397 if (unlikely(p == NULL))
398 goto out_overflow;
399 count = be32_to_cpup(p);
400 if (count > NFS3_MAXNAMLEN)
401 goto out_nametoolong;
402 p = xdr_inline_decode(xdr, count);
403 if (unlikely(p == NULL))
404 goto out_overflow;
405 *name = (const char *)p;
406 *length = count;
407 return 0;
408out_nametoolong:
409 dprintk("NFS: returned filename too long: %u\n", count);
410 return -ENAMETOOLONG;
411out_overflow:
412 print_overflow_msg(__func__, xdr);
413 return -EIO;
414}
415
262/* 416/*
263 * 2.3.8. path 417 * 2.3.8. path
264 * 418 *
@@ -274,6 +428,65 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
274 xdr_write_pages(xdr, pages, 0, length); 428 xdr_write_pages(xdr, pages, 0, length);
275} 429}
276 430
431static int decode_path(struct xdr_stream *xdr)
432{
433 u32 length, recvd;
434 size_t hdrlen;
435 __be32 *p;
436
437 p = xdr_inline_decode(xdr, 4);
438 if (unlikely(p == NULL))
439 goto out_overflow;
440 length = be32_to_cpup(p);
441 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
442 goto out_size;
443 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
444 recvd = xdr->buf->len - hdrlen;
445 if (unlikely(length > recvd))
446 goto out_cheating;
447
448 xdr_read_pages(xdr, length);
449 xdr_terminate_string(xdr->buf, length);
450 return 0;
451out_size:
452 dprintk("NFS: returned pathname too long: %u\n", length);
453 return -ENAMETOOLONG;
454out_cheating:
455 dprintk("NFS: server cheating in pathname result: "
456 "length %u > received %u\n", length, recvd);
457 return -EIO;
458out_overflow:
459 print_overflow_msg(__func__, xdr);
460 return -EIO;
461}
462
463/*
464 * 2.3.9. attrstat
465 *
466 * union attrstat switch (stat status) {
467 * case NFS_OK:
468 * fattr attributes;
469 * default:
470 * void;
471 * };
472 */
473static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
474{
475 enum nfs_stat status;
476 int error;
477
478 error = decode_stat(xdr, &status);
479 if (unlikely(error))
480 goto out;
481 if (status != NFS_OK)
482 goto out_default;
483 error = decode_fattr(xdr, result);
484out:
485 return error;
486out_default:
487 return nfs_stat_to_errno(status);
488}
489
277/* 490/*
278 * 2.3.10. diropargs 491 * 2.3.10. diropargs
279 * 492 *
@@ -289,6 +502,48 @@ static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
289 encode_filename(xdr, name, length); 502 encode_filename(xdr, name, length);
290} 503}
291 504
505/*
506 * 2.3.11. diropres
507 *
508 * union diropres switch (stat status) {
509 * case NFS_OK:
510 * struct {
511 * fhandle file;
512 * fattr attributes;
513 * } diropok;
514 * default:
515 * void;
516 * };
517 */
518static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
519{
520 int error;
521
522 error = decode_fhandle(xdr, result->fh);
523 if (unlikely(error))
524 goto out;
525 error = decode_fattr(xdr, result->fattr);
526out:
527 return error;
528}
529
530static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
531{
532 enum nfs_stat status;
533 int error;
534
535 error = decode_stat(xdr, &status);
536 if (unlikely(error))
537 goto out;
538 if (status != NFS_OK)
539 goto out_default;
540 error = decode_diropok(xdr, result);
541out:
542 return error;
543out_default:
544 return nfs_stat_to_errno(status);
545}
546
292 547
293/* 548/*
294 * NFSv2 XDR encode functions 549 * NFSv2 XDR encode functions
@@ -630,13 +885,6 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
630 return pglen; 885 return pglen;
631} 886}
632 887
633static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
634{
635 dprintk("nfs: %s: prematurely hit end of receive buffer. "
636 "Remaining buffer length is %tu words.\n",
637 func, xdr->end - xdr->p);
638}
639
640__be32 * 888__be32 *
641nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) 889nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
642{ 890{
@@ -700,6 +948,25 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
700 return status; 948 return status;
701} 949}
702 950
951static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p,
952 void *__unused)
953{
954 struct xdr_stream xdr;
955 enum nfs_stat status;
956 int error;
957
958 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
959 error = decode_stat(&xdr, &status);
960 if (unlikely(error))
961 goto out;
962 if (status != NFS_OK)
963 goto out_default;
964out:
965 return error;
966out_default:
967 return nfs_stat_to_errno(status);
968}
969
703/* 970/*
704 * Decode attrstat reply 971 * Decode attrstat reply
705 * GETATTR, SETATTR, WRITE 972 * GETATTR, SETATTR, WRITE
@@ -715,6 +982,15 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
715 return 0; 982 return 0;
716} 983}
717 984
985static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p,
986 struct nfs_fattr *result)
987{
988 struct xdr_stream xdr;
989
990 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
991 return decode_attrstat(&xdr, result);
992}
993
718/* 994/*
719 * Decode diropres reply 995 * Decode diropres reply
720 * LOOKUP, CREATE, MKDIR 996 * LOOKUP, CREATE, MKDIR
@@ -731,6 +1007,15 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
731 return 0; 1007 return 0;
732} 1008}
733 1009
1010static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p,
1011 struct nfs_diropok *result)
1012{
1013 struct xdr_stream xdr;
1014
1015 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1016 return decode_diropres(&xdr, result);
1017}
1018
734/* 1019/*
735 * Decode READLINK reply 1020 * Decode READLINK reply
736 */ 1021 */
@@ -772,6 +1057,70 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
772} 1057}
773 1058
774/* 1059/*
1060 * 2.2.6. readlinkres
1061 *
1062 * union readlinkres switch (stat status) {
1063 * case NFS_OK:
1064 * path data;
1065 * default:
1066 * void;
1067 * };
1068 */
1069static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p,
1070 void *__unused)
1071{
1072 struct xdr_stream xdr;
1073 enum nfs_stat status;
1074 int error;
1075
1076 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1077 error = decode_stat(&xdr, &status);
1078 if (unlikely(error))
1079 goto out;
1080 if (status != NFS_OK)
1081 goto out_default;
1082 error = decode_path(&xdr);
1083out:
1084 return error;
1085out_default:
1086 return nfs_stat_to_errno(status);
1087}
1088
1089/*
1090 * 2.2.7. readres
1091 *
1092 * union readres switch (stat status) {
1093 * case NFS_OK:
1094 * fattr attributes;
1095 * nfsdata data;
1096 * default:
1097 * void;
1098 * };
1099 */
1100static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p,
1101 struct nfs_readres *result)
1102{
1103 struct xdr_stream xdr;
1104 enum nfs_stat status;
1105 int error;
1106
1107 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1108 error = decode_stat(&xdr, &status);
1109 if (unlikely(error))
1110 goto out;
1111 if (status != NFS_OK)
1112 goto out_default;
1113 error = decode_fattr(&xdr, result->fattr);
1114 if (unlikely(error))
1115 goto out;
1116 error = decode_nfsdata(&xdr, result);
1117out:
1118 return error;
1119out_default:
1120 return nfs_stat_to_errno(status);
1121}
1122
1123/*
775 * Decode WRITE reply 1124 * Decode WRITE reply
776 */ 1125 */
777static int 1126static int
@@ -781,6 +1130,150 @@ nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
781 return nfs_xdr_attrstat(req, p, res->fattr); 1130 return nfs_xdr_attrstat(req, p, res->fattr);
782} 1131}
783 1132
1133static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p,
1134 struct nfs_writeres *result)
1135{
1136 struct xdr_stream xdr;
1137
1138 /* All NFSv2 writes are "file sync" writes */
1139 result->verf->committed = NFS_FILE_SYNC;
1140
1141 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1142 return decode_attrstat(&xdr, result->fattr);
1143}
1144
1145/**
1146 * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
1147 * the local page cache.
1148 * @xdr: XDR stream where entry resides
1149 * @entry: buffer to fill in with entry data
1150 * @server: nfs_server data for this directory
1151 * @plus: boolean indicating whether this should be a readdirplus entry
1152 *
1153 * Returns the position of the next item in the buffer, or an ERR_PTR.
1154 *
1155 * This function is not invoked during READDIR reply decoding, but
1156 * rather whenever an application invokes the getdents(2) system call
1157 * on a directory already in our cache.
1158 *
1159 * 2.2.17. entry
1160 *
1161 * struct entry {
1162 * unsigned fileid;
1163 * filename name;
1164 * nfscookie cookie;
1165 * entry *nextentry;
1166 * };
1167 */
1168__be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1169 struct nfs_server *server, int plus)
1170{
1171 __be32 *p;
1172 int error;
1173
1174 p = xdr_inline_decode(xdr, 4);
1175 if (unlikely(p == NULL))
1176 goto out_overflow;
1177 if (*p++ == xdr_zero) {
1178 p = xdr_inline_decode(xdr, 4);
1179 if (unlikely(p == NULL))
1180 goto out_overflow;
1181 if (*p++ == xdr_zero)
1182 return ERR_PTR(-EAGAIN);
1183 entry->eof = 1;
1184 return ERR_PTR(-EBADCOOKIE);
1185 }
1186
1187 p = xdr_inline_decode(xdr, 4);
1188 if (unlikely(p == NULL))
1189 goto out_overflow;
1190 entry->ino = be32_to_cpup(p);
1191
1192 error = decode_filename_inline(xdr, &entry->name, &entry->len);
1193 if (unlikely(error))
1194 return ERR_PTR(error);
1195
1196 /*
1197 * The type (size and byte order) of nfscookie isn't defined in
1198 * RFC 1094. This implementation assumes that it's an XDR uint32.
1199 */
1200 entry->prev_cookie = entry->cookie;
1201 p = xdr_inline_decode(xdr, 4);
1202 if (unlikely(p == NULL))
1203 goto out_overflow;
1204 entry->cookie = be32_to_cpup(p);
1205
1206 entry->d_type = DT_UNKNOWN;
1207
1208 /* Peek at the next entry to see if we're at EOD */
1209 p = xdr_inline_peek(xdr, 4 + 4);
1210 entry->eof = 0;
1211 if (p != NULL)
1212 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
1213 return p;
1214
1215out_overflow:
1216 print_overflow_msg(__func__, xdr);
1217 return ERR_PTR(-EAGAIN);
1218}
1219
1220/*
1221 * 2.2.17. readdirres
1222 *
1223 * union readdirres switch (stat status) {
1224 * case NFS_OK:
1225 * struct {
1226 * entry *entries;
1227 * bool eof;
1228 * } readdirok;
1229 * default:
1230 * void;
1231 * };
1232 *
1233 * Read the directory contents into the page cache, but don't
1234 * touch them. The actual decoding is done by nfs2_decode_dirent()
1235 * during subsequent nfs_readdir() calls.
1236 */
1237static int decode_readdirok(struct xdr_stream *xdr)
1238{
1239 u32 recvd, pglen;
1240 size_t hdrlen;
1241
1242 pglen = xdr->buf->page_len;
1243 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1244 recvd = xdr->buf->len - hdrlen;
1245 if (unlikely(pglen > recvd))
1246 goto out_cheating;
1247out:
1248 xdr_read_pages(xdr, pglen);
1249 return pglen;
1250out_cheating:
1251 dprintk("NFS: server cheating in readdir result: "
1252 "pglen %u > recvd %u\n", pglen, recvd);
1253 pglen = recvd;
1254 goto out;
1255}
1256
1257static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p,
1258 void *__unused)
1259{
1260 struct xdr_stream xdr;
1261 enum nfs_stat status;
1262 int error;
1263
1264 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1265 error = decode_stat(&xdr, &status);
1266 if (unlikely(error))
1267 goto out;
1268 if (status != NFS_OK)
1269 goto out_default;
1270 error = decode_readdirok(&xdr);
1271out:
1272 return error;
1273out_default:
1274 return nfs_stat_to_errno(status);
1275}
1276
784/* 1277/*
785 * Decode STATFS reply 1278 * Decode STATFS reply
786 */ 1279 */
@@ -801,6 +1294,61 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
801} 1294}
802 1295
803/* 1296/*
1297 * 2.2.18. statfsres
1298 *
1299 * union statfsres (stat status) {
1300 * case NFS_OK:
1301 * struct {
1302 * unsigned tsize;
1303 * unsigned bsize;
1304 * unsigned blocks;
1305 * unsigned bfree;
1306 * unsigned bavail;
1307 * } info;
1308 * default:
1309 * void;
1310 * };
1311 */
1312static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1313{
1314 __be32 *p;
1315
1316 p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1317 if (unlikely(p == NULL))
1318 goto out_overflow;
1319 result->tsize = be32_to_cpup(p++);
1320 result->bsize = be32_to_cpup(p++);
1321 result->blocks = be32_to_cpup(p++);
1322 result->bfree = be32_to_cpup(p++);
1323 result->bavail = be32_to_cpup(p);
1324 return 0;
1325out_overflow:
1326 print_overflow_msg(__func__, xdr);
1327 return -EIO;
1328}
1329
1330static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p,
1331 struct nfs2_fsstat *result)
1332{
1333 struct xdr_stream xdr;
1334 enum nfs_stat status;
1335 int error;
1336
1337 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1338 error = decode_stat(&xdr, &status);
1339 if (unlikely(error))
1340 goto out;
1341 if (status != NFS_OK)
1342 goto out_default;
1343 error = decode_info(&xdr, result);
1344out:
1345 return error;
1346out_default:
1347 return nfs_stat_to_errno(status);
1348}
1349
1350
1351/*
804 * We need to translate between nfs status return values and 1352 * We need to translate between nfs status return values and
805 * the local errno values which may not be the same. 1353 * the local errno values which may not be the same.
806 */ 1354 */
@@ -867,7 +1415,7 @@ int nfs_stat_to_errno(enum nfs_stat status)
867[NFSPROC_##proc] = { \ 1415[NFSPROC_##proc] = { \
868 .p_proc = NFSPROC_##proc, \ 1416 .p_proc = NFSPROC_##proc, \
869 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \ 1417 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
870 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ 1418 .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \
871 .p_arglen = NFS_##argtype##_sz, \ 1419 .p_arglen = NFS_##argtype##_sz, \
872 .p_replen = NFS_##restype##_sz, \ 1420 .p_replen = NFS_##restype##_sz, \
873 .p_timer = timer, \ 1421 .p_timer = timer, \