Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dm.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. * Support for decoding of DM_* ioctl commands.
  3. *
  4. * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
  5. * Copyright (c) 2016 Masatake Yamato <yamato@redhat.com>
  6. * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
  7. * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
  8. * Copyright (c) 2016-2018 The strace developers.
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. The name of the author may not be used to endorse or promote products
  20. * derived from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  23. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  24. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  25. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  27. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #include "defs.h"
  34. #ifdef HAVE_LINUX_DM_IOCTL_H
  35. # include "print_fields.h"
  36. # include <linux/dm-ioctl.h>
  37. # include <linux/ioctl.h>
  38. # if DM_VERSION_MAJOR == 4
  39. /* Definitions for command which have been added later */
  40. # ifndef DM_LIST_VERSIONS
  41. # define DM_LIST_VERSIONS _IOWR(DM_IOCTL, 0x0d, struct dm_ioctl)
  42. # endif
  43. # ifndef DM_TARGET_MSG
  44. # define DM_TARGET_MSG _IOWR(DM_IOCTL, 0x0e, struct dm_ioctl)
  45. # endif
  46. # ifndef DM_DEV_SET_GEOMETRY
  47. # define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0x0f, struct dm_ioctl)
  48. # endif
  49. # ifndef DM_DEV_ARM_POLL
  50. # define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, 0x10, struct dm_ioctl)
  51. # endif
  52. static void
  53. dm_decode_device(const unsigned int code, const struct dm_ioctl *ioc)
  54. {
  55. switch (code) {
  56. case DM_REMOVE_ALL:
  57. case DM_LIST_DEVICES:
  58. case DM_LIST_VERSIONS:
  59. break;
  60. default:
  61. if (ioc->dev)
  62. PRINT_FIELD_DEV(", ", *ioc, dev);
  63. if (ioc->name[0])
  64. PRINT_FIELD_CSTRING(", ", *ioc, name);
  65. if (ioc->uuid[0])
  66. PRINT_FIELD_CSTRING(", ", *ioc, uuid);
  67. break;
  68. }
  69. }
  70. static void
  71. dm_decode_values(struct tcb *tcp, const unsigned int code,
  72. const struct dm_ioctl *ioc)
  73. {
  74. if (entering(tcp)) {
  75. switch (code) {
  76. case DM_TABLE_LOAD:
  77. PRINT_FIELD_U(", ", *ioc, target_count);
  78. break;
  79. case DM_DEV_SUSPEND:
  80. if (ioc->flags & DM_SUSPEND_FLAG)
  81. break;
  82. ATTRIBUTE_FALLTHROUGH;
  83. case DM_DEV_RENAME:
  84. case DM_DEV_REMOVE:
  85. case DM_DEV_WAIT:
  86. PRINT_FIELD_U(", ", *ioc, event_nr);
  87. break;
  88. }
  89. } else if (!syserror(tcp)) {
  90. switch (code) {
  91. case DM_DEV_CREATE:
  92. case DM_DEV_RENAME:
  93. case DM_DEV_SUSPEND:
  94. case DM_DEV_STATUS:
  95. case DM_DEV_WAIT:
  96. case DM_TABLE_LOAD:
  97. case DM_TABLE_CLEAR:
  98. case DM_TABLE_DEPS:
  99. case DM_TABLE_STATUS:
  100. case DM_TARGET_MSG:
  101. PRINT_FIELD_U(", ", *ioc, target_count);
  102. PRINT_FIELD_U(", ", *ioc, open_count);
  103. PRINT_FIELD_U(", ", *ioc, event_nr);
  104. break;
  105. }
  106. }
  107. }
  108. #include "xlat/dm_flags.h"
  109. static void
  110. dm_decode_flags(const struct dm_ioctl *ioc)
  111. {
  112. PRINT_FIELD_FLAGS(", ", *ioc, flags, dm_flags, "DM_???");
  113. }
  114. static void
  115. dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
  116. const struct dm_ioctl *const ioc)
  117. {
  118. static const uint32_t target_spec_size =
  119. sizeof(struct dm_target_spec);
  120. uint32_t i;
  121. uint32_t offset = ioc->data_start;
  122. uint32_t offset_end = 0;
  123. if (abbrev(tcp)) {
  124. if (ioc->target_count)
  125. tprints(", ...");
  126. return;
  127. }
  128. for (i = 0; i < ioc->target_count; i++) {
  129. tprints(", ");
  130. if (i && offset <= offset_end)
  131. goto misplaced;
  132. offset_end = offset + target_spec_size;
  133. if (offset_end <= offset || offset_end > ioc->data_size)
  134. goto misplaced;
  135. if (i >= max_strlen) {
  136. tprints("...");
  137. break;
  138. }
  139. struct dm_target_spec s;
  140. if (umove_or_printaddr(tcp, addr + offset, &s))
  141. break;
  142. PRINT_FIELD_U("{", s, sector_start);
  143. PRINT_FIELD_U(", ", s, length);
  144. if (exiting(tcp))
  145. PRINT_FIELD_D(", ", s, status);
  146. PRINT_FIELD_CSTRING(", ", s, target_type);
  147. tprints(", string=");
  148. printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
  149. QUOTE_0_TERMINATED);
  150. tprints("}");
  151. if (entering(tcp))
  152. offset += s.next;
  153. else
  154. offset = ioc->data_start + s.next;
  155. }
  156. return;
  157. misplaced:
  158. tprints("???");
  159. tprints_comment("misplaced struct dm_target_spec");
  160. }
  161. bool
  162. dm_print_dev(struct tcb *tcp, void *dev_ptr, size_t dev_size, void *dummy)
  163. {
  164. uint64_t *dev = (uint64_t *) dev_ptr;
  165. print_dev_t(*dev);
  166. return 1;
  167. }
  168. static void
  169. dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ulong_t addr,
  170. const struct dm_ioctl *const ioc)
  171. {
  172. if (ioc->data_start == ioc->data_size)
  173. return;
  174. tprints(", ");
  175. if (abbrev(tcp)) {
  176. tprints("...");
  177. return;
  178. }
  179. static const uint32_t target_deps_dev_offs =
  180. offsetof(struct dm_target_deps, dev);
  181. uint64_t dev_buf;
  182. struct dm_target_deps s;
  183. uint32_t offset = ioc->data_start;
  184. uint32_t offset_end = offset + target_deps_dev_offs;
  185. uint32_t space;
  186. if (offset_end <= offset || offset_end > ioc->data_size)
  187. goto misplaced;
  188. if (umove_or_printaddr(tcp, addr + offset, &s))
  189. return;
  190. space = (ioc->data_size - offset_end) / sizeof(dev_buf);
  191. if (s.count > space)
  192. goto misplaced;
  193. PRINT_FIELD_U("{", s, count);
  194. tprints(", deps=");
  195. print_array(tcp, addr + offset_end, s.count, &dev_buf, sizeof(dev_buf),
  196. tfetch_mem, dm_print_dev, NULL);
  197. tprints("}");
  198. return;
  199. misplaced:
  200. tprints("???");
  201. tprints_comment("misplaced struct dm_target_deps");
  202. }
  203. static void
  204. dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
  205. const struct dm_ioctl *const ioc)
  206. {
  207. static const uint32_t name_list_name_offs =
  208. offsetof(struct dm_name_list, name);
  209. struct dm_name_list s;
  210. uint32_t offset = ioc->data_start;
  211. uint32_t offset_end = 0;
  212. uint32_t count;
  213. int rc;
  214. if (ioc->data_start == ioc->data_size)
  215. return;
  216. if (abbrev(tcp)) {
  217. tprints(", ...");
  218. return;
  219. }
  220. for (count = 0;; count++) {
  221. tprints(", ");
  222. if (count && offset <= offset_end)
  223. goto misplaced;
  224. offset_end = offset + name_list_name_offs;
  225. if (offset_end <= offset || offset_end > ioc->data_size)
  226. goto misplaced;
  227. if (count >= max_strlen) {
  228. tprints("...");
  229. break;
  230. }
  231. if (umove_or_printaddr(tcp, addr + offset, &s))
  232. break;
  233. PRINT_FIELD_DEV("{", s, dev);
  234. tprints(", name=");
  235. rc = printstr_ex(tcp, addr + offset_end,
  236. ioc->data_size - offset_end,
  237. QUOTE_0_TERMINATED);
  238. /*
  239. * In Linux v4.13-rc1~137^2~13 it has been decided to cram in
  240. * one more undocumented field after the device name, as if the
  241. * format decoding was not twisted enough already. So, we have
  242. * to check "next" now, and if it _looks like_ that there is
  243. * a space for one additional integer, let's print it. As if the
  244. * perversity with "name string going further than pointer to
  245. * the next one" wasn't enough. Moreover, the calculation was
  246. * broken for m32 on 64-bit kernels until v4.14-rc4~20^2~3, and
  247. * we have no ability to detect kernel bit-ness (on x86, at
  248. * least), so refrain from printing it for the DM versions below
  249. * 4.37 (the original version was also aligned differently than
  250. * now even on 64 bit).
  251. */
  252. if ((rc > 0) && ioc->version[1] >= 37) {
  253. kernel_ulong_t event_addr =
  254. (addr + offset_end + rc + 7) & ~7;
  255. uint32_t event_nr;
  256. if ((event_addr + sizeof(event_nr)) <=
  257. (addr + offset + s.next) &&
  258. !umove(tcp, event_addr, &event_nr))
  259. tprintf(", event_nr=%" PRIu32, event_nr);
  260. }
  261. tprints("}");
  262. if (!s.next)
  263. break;
  264. offset += s.next;
  265. }
  266. return;
  267. misplaced:
  268. tprints("???");
  269. tprints_comment("misplaced struct dm_name_list");
  270. }
  271. static void
  272. dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
  273. const struct dm_ioctl *const ioc)
  274. {
  275. static const uint32_t target_vers_name_offs =
  276. offsetof(struct dm_target_versions, name);
  277. struct dm_target_versions s;
  278. uint32_t offset = ioc->data_start;
  279. uint32_t offset_end = 0;
  280. uint32_t count;
  281. if (ioc->data_start == ioc->data_size)
  282. return;
  283. if (abbrev(tcp)) {
  284. tprints(", ...");
  285. return;
  286. }
  287. for (count = 0;; count++) {
  288. tprints(", ");
  289. if (count && offset <= offset_end)
  290. goto misplaced;
  291. offset_end = offset + target_vers_name_offs;
  292. if (offset_end <= offset || offset_end > ioc->data_size)
  293. goto misplaced;
  294. if (count >= max_strlen) {
  295. tprints("...");
  296. break;
  297. }
  298. if (umove_or_printaddr(tcp, addr + offset, &s))
  299. break;
  300. tprints("{name=");
  301. printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
  302. QUOTE_0_TERMINATED);
  303. tprintf(", version=%" PRIu32 ".%" PRIu32 ".%" PRIu32 "}",
  304. s.version[0], s.version[1], s.version[2]);
  305. if (!s.next)
  306. break;
  307. offset += s.next;
  308. }
  309. return;
  310. misplaced:
  311. tprints("???");
  312. tprints_comment("misplaced struct dm_target_versions");
  313. }
  314. static void
  315. dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ulong_t addr,
  316. const struct dm_ioctl *const ioc)
  317. {
  318. if (ioc->data_start == ioc->data_size)
  319. return;
  320. tprints(", ");
  321. if (abbrev(tcp)) {
  322. tprints("...");
  323. return;
  324. }
  325. static const uint32_t target_msg_message_offs =
  326. offsetof(struct dm_target_msg, message);
  327. uint32_t offset = ioc->data_start;
  328. uint32_t offset_end = offset + target_msg_message_offs;
  329. if (offset_end > offset && offset_end <= ioc->data_size) {
  330. struct dm_target_msg s;
  331. if (umove_or_printaddr(tcp, addr + offset, &s))
  332. return;
  333. PRINT_FIELD_U("{", s, sector);
  334. tprints(", message=");
  335. printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
  336. QUOTE_0_TERMINATED);
  337. tprints("}");
  338. } else {
  339. tprints("???");
  340. tprints_comment("misplaced struct dm_target_msg");
  341. }
  342. }
  343. static void
  344. dm_decode_string(struct tcb *const tcp, const kernel_ulong_t addr,
  345. const struct dm_ioctl *const ioc)
  346. {
  347. tprints(", ");
  348. if (abbrev(tcp)) {
  349. tprints("...");
  350. return;
  351. }
  352. uint32_t offset = ioc->data_start;
  353. if (offset <= ioc->data_size) {
  354. tprints("string=");
  355. printstr_ex(tcp, addr + offset, ioc->data_size - offset,
  356. QUOTE_0_TERMINATED);
  357. } else {
  358. tprints("???");
  359. tprints_comment("misplaced string");
  360. }
  361. }
  362. static inline bool
  363. dm_ioctl_has_params(const unsigned int code)
  364. {
  365. switch (code) {
  366. case DM_VERSION:
  367. case DM_REMOVE_ALL:
  368. case DM_DEV_CREATE:
  369. case DM_DEV_REMOVE:
  370. case DM_DEV_SUSPEND:
  371. case DM_DEV_STATUS:
  372. case DM_TABLE_CLEAR:
  373. case DM_DEV_ARM_POLL:
  374. return false;
  375. }
  376. return true;
  377. }
  378. static int
  379. dm_known_ioctl(struct tcb *const tcp, const unsigned int code,
  380. const kernel_ulong_t arg)
  381. {
  382. struct dm_ioctl *ioc = NULL;
  383. struct dm_ioctl *entering_ioc = NULL;
  384. bool ioc_changed = false;
  385. if (entering(tcp)) {
  386. ioc = malloc(sizeof(*ioc));
  387. if (!ioc)
  388. return 0;
  389. } else {
  390. ioc = alloca(sizeof(*ioc));
  391. }
  392. if ((umoven(tcp, arg, offsetof(struct dm_ioctl, data), ioc) < 0) ||
  393. (ioc->data_size < offsetof(struct dm_ioctl, data_size))) {
  394. if (entering(tcp))
  395. free(ioc);
  396. return 0;
  397. }
  398. if (entering(tcp))
  399. set_tcb_priv_data(tcp, ioc, free);
  400. else {
  401. entering_ioc = get_tcb_priv_data(tcp);
  402. /*
  403. * retrieve_status, __dev_status called only in case of success,
  404. * so it looks like there's no need to check open_count,
  405. * event_nr, target_count, dev fields for change (they are
  406. * printed only in case of absence of errors).
  407. */
  408. if (!entering_ioc ||
  409. (ioc->version[0] != entering_ioc->version[0]) ||
  410. (ioc->version[1] != entering_ioc->version[1]) ||
  411. (ioc->version[2] != entering_ioc->version[2]) ||
  412. (ioc->data_size != entering_ioc->data_size) ||
  413. (ioc->data_start != entering_ioc->data_start) ||
  414. (ioc->flags != entering_ioc->flags))
  415. ioc_changed = true;
  416. }
  417. if (exiting(tcp) && syserror(tcp) && !ioc_changed)
  418. return RVAL_IOCTL_DECODED;
  419. /*
  420. * device mapper code uses %d in some places and %u in another, but
  421. * fields themselves are declared as __u32.
  422. */
  423. tprintf("%s{version=%u.%u.%u", entering(tcp) ? ", " : " => ",
  424. ioc->version[0], ioc->version[1], ioc->version[2]);
  425. /*
  426. * if we use a different version of ABI, do not attempt to decode
  427. * ioctl fields
  428. */
  429. if (ioc->version[0] != DM_VERSION_MAJOR) {
  430. tprints_comment("unsupported device mapper ABI version");
  431. goto skip;
  432. }
  433. PRINT_FIELD_U(", ", *ioc, data_size);
  434. if (ioc->data_size < offsetof(struct dm_ioctl, data)) {
  435. tprints_comment("data_size too small");
  436. goto skip;
  437. }
  438. if (dm_ioctl_has_params(code))
  439. PRINT_FIELD_U(", ", *ioc, data_start);
  440. dm_decode_device(code, ioc);
  441. dm_decode_values(tcp, code, ioc);
  442. dm_decode_flags(ioc);
  443. switch (code) {
  444. case DM_DEV_WAIT:
  445. case DM_TABLE_STATUS:
  446. if (entering(tcp) || syserror(tcp))
  447. break;
  448. dm_decode_dm_target_spec(tcp, arg, ioc);
  449. break;
  450. case DM_TABLE_LOAD:
  451. if (exiting(tcp))
  452. break;
  453. dm_decode_dm_target_spec(tcp, arg, ioc);
  454. break;
  455. case DM_TABLE_DEPS:
  456. if (entering(tcp) || syserror(tcp))
  457. break;
  458. dm_decode_dm_target_deps(tcp, arg, ioc);
  459. break;
  460. case DM_LIST_DEVICES:
  461. if (entering(tcp) || syserror(tcp))
  462. break;
  463. dm_decode_dm_name_list(tcp, arg, ioc);
  464. break;
  465. case DM_LIST_VERSIONS:
  466. if (entering(tcp) || syserror(tcp))
  467. break;
  468. dm_decode_dm_target_versions(tcp, arg, ioc);
  469. break;
  470. case DM_TARGET_MSG:
  471. if (entering(tcp))
  472. dm_decode_dm_target_msg(tcp, arg, ioc);
  473. else if (!syserror(tcp) && ioc->flags & DM_DATA_OUT_FLAG)
  474. dm_decode_string(tcp, arg, ioc);
  475. break;
  476. case DM_DEV_RENAME:
  477. case DM_DEV_SET_GEOMETRY:
  478. if (exiting(tcp))
  479. break;
  480. dm_decode_string(tcp, arg, ioc);
  481. break;
  482. }
  483. skip:
  484. tprints("}");
  485. return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
  486. }
  487. int
  488. dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
  489. {
  490. switch (code) {
  491. case DM_VERSION:
  492. case DM_REMOVE_ALL:
  493. case DM_LIST_DEVICES:
  494. case DM_DEV_CREATE:
  495. case DM_DEV_REMOVE:
  496. case DM_DEV_RENAME:
  497. case DM_DEV_SUSPEND:
  498. case DM_DEV_STATUS:
  499. case DM_DEV_WAIT:
  500. case DM_TABLE_LOAD:
  501. case DM_TABLE_CLEAR:
  502. case DM_TABLE_DEPS:
  503. case DM_TABLE_STATUS:
  504. case DM_LIST_VERSIONS:
  505. case DM_TARGET_MSG:
  506. case DM_DEV_SET_GEOMETRY:
  507. case DM_DEV_ARM_POLL:
  508. return dm_known_ioctl(tcp, code, arg);
  509. default:
  510. return RVAL_DECODED;
  511. }
  512. }
  513. # else /* !(DM_VERSION_MAJOR == 4) */
  514. int
  515. dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
  516. {
  517. return RVAL_DECODED;
  518. }
  519. # endif /* DM_VERSION_MAJOR == 4 */
  520. #endif /* HAVE_LINUX_DM_IOCTL_H */