clntxdr.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/fs/lockd/clntxdr.c
  4. *
  5. * XDR functions to encode/decode NLM version 3 RPC arguments and results.
  6. * NLM version 3 is backwards compatible with NLM versions 1 and 2.
  7. *
  8. * NLM client-side only.
  9. *
  10. * Copyright (C) 2010, Oracle. All rights reserved.
  11. */
  12. #include <linux/types.h>
  13. #include <linux/sunrpc/xdr.h>
  14. #include <linux/sunrpc/clnt.h>
  15. #include <linux/sunrpc/stats.h>
  16. #include <linux/lockd/lockd.h>
  17. #include <uapi/linux/nfs2.h>
  18. #define NLMDBG_FACILITY NLMDBG_XDR
  19. #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
  20. # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
  21. #endif
  22. /*
  23. * Declare the space requirements for NLM arguments and replies as
  24. * number of 32bit-words
  25. */
  26. #define NLM_cookie_sz (1+(NLM_MAXCOOKIELEN>>2))
  27. #define NLM_caller_sz (1+(NLMCLNT_OHSIZE>>2))
  28. #define NLM_owner_sz (1+(NLMCLNT_OHSIZE>>2))
  29. #define NLM_fhandle_sz (1+(NFS2_FHSIZE>>2))
  30. #define NLM_lock_sz (3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz)
  31. #define NLM_holder_sz (4+NLM_owner_sz)
  32. #define NLM_testargs_sz (NLM_cookie_sz+1+NLM_lock_sz)
  33. #define NLM_lockargs_sz (NLM_cookie_sz+4+NLM_lock_sz)
  34. #define NLM_cancargs_sz (NLM_cookie_sz+2+NLM_lock_sz)
  35. #define NLM_unlockargs_sz (NLM_cookie_sz+NLM_lock_sz)
  36. #define NLM_testres_sz (NLM_cookie_sz+1+NLM_holder_sz)
  37. #define NLM_res_sz (NLM_cookie_sz+1)
  38. #define NLM_norep_sz (0)
  39. static s32 loff_t_to_s32(loff_t offset)
  40. {
  41. s32 res;
  42. if (offset >= NLM_OFFSET_MAX)
  43. res = NLM_OFFSET_MAX;
  44. else if (offset <= -NLM_OFFSET_MAX)
  45. res = -NLM_OFFSET_MAX;
  46. else
  47. res = offset;
  48. return res;
  49. }
  50. static void nlm_compute_offsets(const struct nlm_lock *lock,
  51. u32 *l_offset, u32 *l_len)
  52. {
  53. const struct file_lock *fl = &lock->fl;
  54. *l_offset = loff_t_to_s32(fl->fl_start);
  55. if (fl->fl_end == OFFSET_MAX)
  56. *l_len = 0;
  57. else
  58. *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
  59. }
  60. /*
  61. * Handle decode buffer overflows out-of-line.
  62. */
  63. static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
  64. {
  65. dprintk("lockd: %s prematurely hit the end of our receive buffer. "
  66. "Remaining buffer length is %tu words.\n",
  67. func, xdr->end - xdr->p);
  68. }
  69. /*
  70. * Encode/decode NLMv3 basic data types
  71. *
  72. * Basic NLMv3 data types are not defined in an IETF standards
  73. * document. X/Open has a description of these data types that
  74. * is useful. See Chapter 10 of "Protocols for Interworking:
  75. * XNFS, Version 3W".
  76. *
  77. * Not all basic data types have their own encoding and decoding
  78. * functions. For run-time efficiency, some data types are encoded
  79. * or decoded inline.
  80. */
  81. static void encode_bool(struct xdr_stream *xdr, const int value)
  82. {
  83. __be32 *p;
  84. p = xdr_reserve_space(xdr, 4);
  85. *p = value ? xdr_one : xdr_zero;
  86. }
  87. static void encode_int32(struct xdr_stream *xdr, const s32 value)
  88. {
  89. __be32 *p;
  90. p = xdr_reserve_space(xdr, 4);
  91. *p = cpu_to_be32(value);
  92. }
  93. /*
  94. * typedef opaque netobj<MAXNETOBJ_SZ>
  95. */
  96. static void encode_netobj(struct xdr_stream *xdr,
  97. const u8 *data, const unsigned int length)
  98. {
  99. __be32 *p;
  100. p = xdr_reserve_space(xdr, 4 + length);
  101. xdr_encode_opaque(p, data, length);
  102. }
  103. static int decode_netobj(struct xdr_stream *xdr,
  104. struct xdr_netobj *obj)
  105. {
  106. ssize_t ret;
  107. ret = xdr_stream_decode_opaque_inline(xdr, (void *)&obj->data,
  108. XDR_MAX_NETOBJ);
  109. if (unlikely(ret < 0))
  110. return -EIO;
  111. obj->len = ret;
  112. return 0;
  113. }
  114. /*
  115. * netobj cookie;
  116. */
  117. static void encode_cookie(struct xdr_stream *xdr,
  118. const struct nlm_cookie *cookie)
  119. {
  120. encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
  121. }
  122. static int decode_cookie(struct xdr_stream *xdr,
  123. struct nlm_cookie *cookie)
  124. {
  125. u32 length;
  126. __be32 *p;
  127. p = xdr_inline_decode(xdr, 4);
  128. if (unlikely(p == NULL))
  129. goto out_overflow;
  130. length = be32_to_cpup(p++);
  131. /* apparently HPUX can return empty cookies */
  132. if (length == 0)
  133. goto out_hpux;
  134. if (length > NLM_MAXCOOKIELEN)
  135. goto out_size;
  136. p = xdr_inline_decode(xdr, length);
  137. if (unlikely(p == NULL))
  138. goto out_overflow;
  139. cookie->len = length;
  140. memcpy(cookie->data, p, length);
  141. return 0;
  142. out_hpux:
  143. cookie->len = 4;
  144. memset(cookie->data, 0, 4);
  145. return 0;
  146. out_size:
  147. dprintk("NFS: returned cookie was too long: %u\n", length);
  148. return -EIO;
  149. out_overflow:
  150. print_overflow_msg(__func__, xdr);
  151. return -EIO;
  152. }
  153. /*
  154. * netobj fh;
  155. */
  156. static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
  157. {
  158. encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
  159. }
  160. /*
  161. * enum nlm_stats {
  162. * LCK_GRANTED = 0,
  163. * LCK_DENIED = 1,
  164. * LCK_DENIED_NOLOCKS = 2,
  165. * LCK_BLOCKED = 3,
  166. * LCK_DENIED_GRACE_PERIOD = 4
  167. * };
  168. *
  169. *
  170. * struct nlm_stat {
  171. * nlm_stats stat;
  172. * };
  173. *
  174. * NB: we don't swap bytes for the NLM status values. The upper
  175. * layers deal directly with the status value in network byte
  176. * order.
  177. */
  178. static void encode_nlm_stat(struct xdr_stream *xdr,
  179. const __be32 stat)
  180. {
  181. __be32 *p;
  182. WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD);
  183. p = xdr_reserve_space(xdr, 4);
  184. *p = stat;
  185. }
  186. static int decode_nlm_stat(struct xdr_stream *xdr,
  187. __be32 *stat)
  188. {
  189. __be32 *p;
  190. p = xdr_inline_decode(xdr, 4);
  191. if (unlikely(p == NULL))
  192. goto out_overflow;
  193. if (unlikely(ntohl(*p) > ntohl(nlm_lck_denied_grace_period)))
  194. goto out_enum;
  195. *stat = *p;
  196. return 0;
  197. out_enum:
  198. dprintk("%s: server returned invalid nlm_stats value: %u\n",
  199. __func__, be32_to_cpup(p));
  200. return -EIO;
  201. out_overflow:
  202. print_overflow_msg(__func__, xdr);
  203. return -EIO;
  204. }
  205. /*
  206. * struct nlm_holder {
  207. * bool exclusive;
  208. * int uppid;
  209. * netobj oh;
  210. * unsigned l_offset;
  211. * unsigned l_len;
  212. * };
  213. */
  214. static void encode_nlm_holder(struct xdr_stream *xdr,
  215. const struct nlm_res *result)
  216. {
  217. const struct nlm_lock *lock = &result->lock;
  218. u32 l_offset, l_len;
  219. __be32 *p;
  220. encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
  221. encode_int32(xdr, lock->svid);
  222. encode_netobj(xdr, lock->oh.data, lock->oh.len);
  223. p = xdr_reserve_space(xdr, 4 + 4);
  224. nlm_compute_offsets(lock, &l_offset, &l_len);
  225. *p++ = cpu_to_be32(l_offset);
  226. *p = cpu_to_be32(l_len);
  227. }
  228. static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
  229. {
  230. struct nlm_lock *lock = &result->lock;
  231. struct file_lock *fl = &lock->fl;
  232. u32 exclusive, l_offset, l_len;
  233. int error;
  234. __be32 *p;
  235. s32 end;
  236. memset(lock, 0, sizeof(*lock));
  237. locks_init_lock(fl);
  238. p = xdr_inline_decode(xdr, 4 + 4);
  239. if (unlikely(p == NULL))
  240. goto out_overflow;
  241. exclusive = be32_to_cpup(p++);
  242. lock->svid = be32_to_cpup(p);
  243. fl->fl_pid = (pid_t)lock->svid;
  244. error = decode_netobj(xdr, &lock->oh);
  245. if (unlikely(error))
  246. goto out;
  247. p = xdr_inline_decode(xdr, 4 + 4);
  248. if (unlikely(p == NULL))
  249. goto out_overflow;
  250. fl->fl_flags = FL_POSIX;
  251. fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK;
  252. l_offset = be32_to_cpup(p++);
  253. l_len = be32_to_cpup(p);
  254. end = l_offset + l_len - 1;
  255. fl->fl_start = (loff_t)l_offset;
  256. if (l_len == 0 || end < 0)
  257. fl->fl_end = OFFSET_MAX;
  258. else
  259. fl->fl_end = (loff_t)end;
  260. error = 0;
  261. out:
  262. return error;
  263. out_overflow:
  264. print_overflow_msg(__func__, xdr);
  265. return -EIO;
  266. }
  267. /*
  268. * string caller_name<LM_MAXSTRLEN>;
  269. */
  270. static void encode_caller_name(struct xdr_stream *xdr, const char *name)
  271. {
  272. /* NB: client-side does not set lock->len */
  273. u32 length = strlen(name);
  274. __be32 *p;
  275. p = xdr_reserve_space(xdr, 4 + length);
  276. xdr_encode_opaque(p, name, length);
  277. }
  278. /*
  279. * struct nlm_lock {
  280. * string caller_name<LM_MAXSTRLEN>;
  281. * netobj fh;
  282. * netobj oh;
  283. * int uppid;
  284. * unsigned l_offset;
  285. * unsigned l_len;
  286. * };
  287. */
  288. static void encode_nlm_lock(struct xdr_stream *xdr,
  289. const struct nlm_lock *lock)
  290. {
  291. u32 l_offset, l_len;
  292. __be32 *p;
  293. encode_caller_name(xdr, lock->caller);
  294. encode_fh(xdr, &lock->fh);
  295. encode_netobj(xdr, lock->oh.data, lock->oh.len);
  296. p = xdr_reserve_space(xdr, 4 + 4 + 4);
  297. *p++ = cpu_to_be32(lock->svid);
  298. nlm_compute_offsets(lock, &l_offset, &l_len);
  299. *p++ = cpu_to_be32(l_offset);
  300. *p = cpu_to_be32(l_len);
  301. }
  302. /*
  303. * NLMv3 XDR encode functions
  304. *
  305. * NLMv3 argument types are defined in Chapter 10 of The Open Group's
  306. * "Protocols for Interworking: XNFS, Version 3W".
  307. */
  308. /*
  309. * struct nlm_testargs {
  310. * netobj cookie;
  311. * bool exclusive;
  312. * struct nlm_lock alock;
  313. * };
  314. */
  315. static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
  316. struct xdr_stream *xdr,
  317. const void *data)
  318. {
  319. const struct nlm_args *args = data;
  320. const struct nlm_lock *lock = &args->lock;
  321. encode_cookie(xdr, &args->cookie);
  322. encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
  323. encode_nlm_lock(xdr, lock);
  324. }
  325. /*
  326. * struct nlm_lockargs {
  327. * netobj cookie;
  328. * bool block;
  329. * bool exclusive;
  330. * struct nlm_lock alock;
  331. * bool reclaim;
  332. * int state;
  333. * };
  334. */
  335. static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
  336. struct xdr_stream *xdr,
  337. const void *data)
  338. {
  339. const struct nlm_args *args = data;
  340. const struct nlm_lock *lock = &args->lock;
  341. encode_cookie(xdr, &args->cookie);
  342. encode_bool(xdr, args->block);
  343. encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
  344. encode_nlm_lock(xdr, lock);
  345. encode_bool(xdr, args->reclaim);
  346. encode_int32(xdr, args->state);
  347. }
  348. /*
  349. * struct nlm_cancargs {
  350. * netobj cookie;
  351. * bool block;
  352. * bool exclusive;
  353. * struct nlm_lock alock;
  354. * };
  355. */
  356. static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
  357. struct xdr_stream *xdr,
  358. const void *data)
  359. {
  360. const struct nlm_args *args = data;
  361. const struct nlm_lock *lock = &args->lock;
  362. encode_cookie(xdr, &args->cookie);
  363. encode_bool(xdr, args->block);
  364. encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
  365. encode_nlm_lock(xdr, lock);
  366. }
  367. /*
  368. * struct nlm_unlockargs {
  369. * netobj cookie;
  370. * struct nlm_lock alock;
  371. * };
  372. */
  373. static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
  374. struct xdr_stream *xdr,
  375. const void *data)
  376. {
  377. const struct nlm_args *args = data;
  378. const struct nlm_lock *lock = &args->lock;
  379. encode_cookie(xdr, &args->cookie);
  380. encode_nlm_lock(xdr, lock);
  381. }
  382. /*
  383. * struct nlm_res {
  384. * netobj cookie;
  385. * nlm_stat stat;
  386. * };
  387. */
  388. static void nlm_xdr_enc_res(struct rpc_rqst *req,
  389. struct xdr_stream *xdr,
  390. const void *data)
  391. {
  392. const struct nlm_res *result = data;
  393. encode_cookie(xdr, &result->cookie);
  394. encode_nlm_stat(xdr, result->status);
  395. }
  396. /*
  397. * union nlm_testrply switch (nlm_stats stat) {
  398. * case LCK_DENIED:
  399. * struct nlm_holder holder;
  400. * default:
  401. * void;
  402. * };
  403. *
  404. * struct nlm_testres {
  405. * netobj cookie;
  406. * nlm_testrply test_stat;
  407. * };
  408. */
  409. static void encode_nlm_testrply(struct xdr_stream *xdr,
  410. const struct nlm_res *result)
  411. {
  412. if (result->status == nlm_lck_denied)
  413. encode_nlm_holder(xdr, result);
  414. }
  415. static void nlm_xdr_enc_testres(struct rpc_rqst *req,
  416. struct xdr_stream *xdr,
  417. const void *data)
  418. {
  419. const struct nlm_res *result = data;
  420. encode_cookie(xdr, &result->cookie);
  421. encode_nlm_stat(xdr, result->status);
  422. encode_nlm_testrply(xdr, result);
  423. }
  424. /*
  425. * NLMv3 XDR decode functions
  426. *
  427. * NLMv3 result types are defined in Chapter 10 of The Open Group's
  428. * "Protocols for Interworking: XNFS, Version 3W".
  429. */
  430. /*
  431. * union nlm_testrply switch (nlm_stats stat) {
  432. * case LCK_DENIED:
  433. * struct nlm_holder holder;
  434. * default:
  435. * void;
  436. * };
  437. *
  438. * struct nlm_testres {
  439. * netobj cookie;
  440. * nlm_testrply test_stat;
  441. * };
  442. */
  443. static int decode_nlm_testrply(struct xdr_stream *xdr,
  444. struct nlm_res *result)
  445. {
  446. int error;
  447. error = decode_nlm_stat(xdr, &result->status);
  448. if (unlikely(error))
  449. goto out;
  450. if (result->status == nlm_lck_denied)
  451. error = decode_nlm_holder(xdr, result);
  452. out:
  453. return error;
  454. }
  455. static int nlm_xdr_dec_testres(struct rpc_rqst *req,
  456. struct xdr_stream *xdr,
  457. void *data)
  458. {
  459. struct nlm_res *result = data;
  460. int error;
  461. error = decode_cookie(xdr, &result->cookie);
  462. if (unlikely(error))
  463. goto out;
  464. error = decode_nlm_testrply(xdr, result);
  465. out:
  466. return error;
  467. }
  468. /*
  469. * struct nlm_res {
  470. * netobj cookie;
  471. * nlm_stat stat;
  472. * };
  473. */
  474. static int nlm_xdr_dec_res(struct rpc_rqst *req,
  475. struct xdr_stream *xdr,
  476. void *data)
  477. {
  478. struct nlm_res *result = data;
  479. int error;
  480. error = decode_cookie(xdr, &result->cookie);
  481. if (unlikely(error))
  482. goto out;
  483. error = decode_nlm_stat(xdr, &result->status);
  484. out:
  485. return error;
  486. }
  487. /*
  488. * For NLM, a void procedure really returns nothing
  489. */
  490. #define nlm_xdr_dec_norep NULL
  491. #define PROC(proc, argtype, restype) \
  492. [NLMPROC_##proc] = { \
  493. .p_proc = NLMPROC_##proc, \
  494. .p_encode = nlm_xdr_enc_##argtype, \
  495. .p_decode = nlm_xdr_dec_##restype, \
  496. .p_arglen = NLM_##argtype##_sz, \
  497. .p_replen = NLM_##restype##_sz, \
  498. .p_statidx = NLMPROC_##proc, \
  499. .p_name = #proc, \
  500. }
  501. static const struct rpc_procinfo nlm_procedures[] = {
  502. PROC(TEST, testargs, testres),
  503. PROC(LOCK, lockargs, res),
  504. PROC(CANCEL, cancargs, res),
  505. PROC(UNLOCK, unlockargs, res),
  506. PROC(GRANTED, testargs, res),
  507. PROC(TEST_MSG, testargs, norep),
  508. PROC(LOCK_MSG, lockargs, norep),
  509. PROC(CANCEL_MSG, cancargs, norep),
  510. PROC(UNLOCK_MSG, unlockargs, norep),
  511. PROC(GRANTED_MSG, testargs, norep),
  512. PROC(TEST_RES, testres, norep),
  513. PROC(LOCK_RES, res, norep),
  514. PROC(CANCEL_RES, res, norep),
  515. PROC(UNLOCK_RES, res, norep),
  516. PROC(GRANTED_RES, res, norep),
  517. };
  518. static unsigned int nlm_version1_counts[ARRAY_SIZE(nlm_procedures)];
  519. static const struct rpc_version nlm_version1 = {
  520. .number = 1,
  521. .nrprocs = ARRAY_SIZE(nlm_procedures),
  522. .procs = nlm_procedures,
  523. .counts = nlm_version1_counts,
  524. };
  525. static unsigned int nlm_version3_counts[ARRAY_SIZE(nlm_procedures)];
  526. static const struct rpc_version nlm_version3 = {
  527. .number = 3,
  528. .nrprocs = ARRAY_SIZE(nlm_procedures),
  529. .procs = nlm_procedures,
  530. .counts = nlm_version3_counts,
  531. };
  532. static const struct rpc_version *nlm_versions[] = {
  533. [1] = &nlm_version1,
  534. [3] = &nlm_version3,
  535. #ifdef CONFIG_LOCKD_V4
  536. [4] = &nlm_version4,
  537. #endif
  538. };
  539. static struct rpc_stat nlm_rpc_stats;
  540. const struct rpc_program nlm_program = {
  541. .name = "lockd",
  542. .number = NLM_PROGRAM,
  543. .nrvers = ARRAY_SIZE(nlm_versions),
  544. .version = nlm_versions,
  545. .stats = &nlm_rpc_stats,
  546. };