test_evil.toml 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # Tests for recovering from conditions which shouldn't normally
  2. # happen during normal operation of littlefs
  3. # invalid pointer tests (outside of block_count)
  4. [cases.test_evil_invalid_tail_pointer]
  5. defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
  6. defines.INVALSET = [0x3, 0x1, 0x2]
  7. in = "lfs.c"
  8. code = '''
  9. // create littlefs
  10. lfs_t lfs;
  11. lfs_format(&lfs, cfg) => 0;
  12. // change tail-pointer to invalid pointers
  13. lfs_init(&lfs, cfg) => 0;
  14. lfs_mdir_t mdir;
  15. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  16. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  17. {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
  18. (lfs_block_t[2]){
  19. (INVALSET & 0x1) ? 0xcccccccc : 0,
  20. (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
  21. lfs_deinit(&lfs) => 0;
  22. // test that mount fails gracefully
  23. lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
  24. '''
  25. [cases.test_evil_invalid_dir_pointer]
  26. defines.INVALSET = [0x3, 0x1, 0x2]
  27. in = "lfs.c"
  28. code = '''
  29. // create littlefs
  30. lfs_t lfs;
  31. lfs_format(&lfs, cfg) => 0;
  32. // make a dir
  33. lfs_mount(&lfs, cfg) => 0;
  34. lfs_mkdir(&lfs, "dir_here") => 0;
  35. lfs_unmount(&lfs) => 0;
  36. // change the dir pointer to be invalid
  37. lfs_init(&lfs, cfg) => 0;
  38. lfs_mdir_t mdir;
  39. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  40. // make sure id 1 == our directory
  41. uint8_t buffer[1024];
  42. lfs_dir_get(&lfs, &mdir,
  43. LFS_MKTAG(0x700, 0x3ff, 0),
  44. LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer)
  45. => LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here"));
  46. assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0);
  47. // change dir pointer
  48. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  49. {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8),
  50. (lfs_block_t[2]){
  51. (INVALSET & 0x1) ? 0xcccccccc : 0,
  52. (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
  53. lfs_deinit(&lfs) => 0;
  54. // test that accessing our bad dir fails, note there's a number
  55. // of ways to access the dir, some can fail, but some don't
  56. lfs_mount(&lfs, cfg) => 0;
  57. struct lfs_info info;
  58. lfs_stat(&lfs, "dir_here", &info) => 0;
  59. assert(strcmp(info.name, "dir_here") == 0);
  60. assert(info.type == LFS_TYPE_DIR);
  61. lfs_dir_t dir;
  62. lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT;
  63. lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT;
  64. lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT;
  65. lfs_file_t file;
  66. lfs_file_open(&lfs, &file, "dir_here/file_here",
  67. LFS_O_RDONLY) => LFS_ERR_CORRUPT;
  68. lfs_file_open(&lfs, &file, "dir_here/file_here",
  69. LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT;
  70. lfs_unmount(&lfs) => 0;
  71. '''
  72. [cases.test_evil_invalid_file_pointer]
  73. in = "lfs.c"
  74. defines.SIZE = [10, 1000, 100000] # faked file size
  75. code = '''
  76. // create littlefs
  77. lfs_t lfs;
  78. lfs_format(&lfs, cfg) => 0;
  79. // make a file
  80. lfs_mount(&lfs, cfg) => 0;
  81. lfs_file_t file;
  82. lfs_file_open(&lfs, &file, "file_here",
  83. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  84. lfs_file_close(&lfs, &file) => 0;
  85. lfs_unmount(&lfs) => 0;
  86. // change the file pointer to be invalid
  87. lfs_init(&lfs, cfg) => 0;
  88. lfs_mdir_t mdir;
  89. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  90. // make sure id 1 == our file
  91. uint8_t buffer[1024];
  92. lfs_dir_get(&lfs, &mdir,
  93. LFS_MKTAG(0x700, 0x3ff, 0),
  94. LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
  95. => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
  96. assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
  97. // change file pointer
  98. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  99. {LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)),
  100. &(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0;
  101. lfs_deinit(&lfs) => 0;
  102. // test that accessing our bad file fails, note there's a number
  103. // of ways to access the dir, some can fail, but some don't
  104. lfs_mount(&lfs, cfg) => 0;
  105. struct lfs_info info;
  106. lfs_stat(&lfs, "file_here", &info) => 0;
  107. assert(strcmp(info.name, "file_here") == 0);
  108. assert(info.type == LFS_TYPE_REG);
  109. assert(info.size == SIZE);
  110. lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
  111. lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
  112. lfs_file_close(&lfs, &file) => 0;
  113. // any allocs that traverse CTZ must unfortunately must fail
  114. if (SIZE > 2*BLOCK_SIZE) {
  115. lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
  116. }
  117. lfs_unmount(&lfs) => 0;
  118. '''
  119. [cases.test_evil_invalid_ctz_pointer] # invalid pointer in CTZ skip-list test
  120. defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE']
  121. in = "lfs.c"
  122. code = '''
  123. // create littlefs
  124. lfs_t lfs;
  125. lfs_format(&lfs, cfg) => 0;
  126. // make a file
  127. lfs_mount(&lfs, cfg) => 0;
  128. lfs_file_t file;
  129. lfs_file_open(&lfs, &file, "file_here",
  130. LFS_O_WRONLY | LFS_O_CREAT) => 0;
  131. for (int i = 0; i < SIZE; i++) {
  132. char c = 'c';
  133. lfs_file_write(&lfs, &file, &c, 1) => 1;
  134. }
  135. lfs_file_close(&lfs, &file) => 0;
  136. lfs_unmount(&lfs) => 0;
  137. // change pointer in CTZ skip-list to be invalid
  138. lfs_init(&lfs, cfg) => 0;
  139. lfs_mdir_t mdir;
  140. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  141. // make sure id 1 == our file and get our CTZ structure
  142. uint8_t buffer[4*BLOCK_SIZE];
  143. lfs_dir_get(&lfs, &mdir,
  144. LFS_MKTAG(0x700, 0x3ff, 0),
  145. LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
  146. => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
  147. assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
  148. struct lfs_ctz ctz;
  149. lfs_dir_get(&lfs, &mdir,
  150. LFS_MKTAG(0x700, 0x3ff, 0),
  151. LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz)
  152. => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz));
  153. lfs_ctz_fromle32(&ctz);
  154. // rewrite block to contain bad pointer
  155. uint8_t bbuffer[BLOCK_SIZE];
  156. cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
  157. uint32_t bad = lfs_tole32(0xcccccccc);
  158. memcpy(&bbuffer[0], &bad, sizeof(bad));
  159. memcpy(&bbuffer[4], &bad, sizeof(bad));
  160. cfg->erase(cfg, ctz.head) => 0;
  161. cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
  162. lfs_deinit(&lfs) => 0;
  163. // test that accessing our bad file fails, note there's a number
  164. // of ways to access the dir, some can fail, but some don't
  165. lfs_mount(&lfs, cfg) => 0;
  166. struct lfs_info info;
  167. lfs_stat(&lfs, "file_here", &info) => 0;
  168. assert(strcmp(info.name, "file_here") == 0);
  169. assert(info.type == LFS_TYPE_REG);
  170. assert(info.size == SIZE);
  171. lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
  172. lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
  173. lfs_file_close(&lfs, &file) => 0;
  174. // any allocs that traverse CTZ must unfortunately must fail
  175. if (SIZE > 2*BLOCK_SIZE) {
  176. lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
  177. }
  178. lfs_unmount(&lfs) => 0;
  179. '''
  180. [cases.test_evil_invalid_gstate_pointer]
  181. defines.INVALSET = [0x3, 0x1, 0x2]
  182. in = "lfs.c"
  183. code = '''
  184. // create littlefs
  185. lfs_t lfs;
  186. lfs_format(&lfs, cfg) => 0;
  187. // create an invalid gstate
  188. lfs_init(&lfs, cfg) => 0;
  189. lfs_mdir_t mdir;
  190. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  191. lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
  192. (INVALSET & 0x1) ? 0xcccccccc : 0,
  193. (INVALSET & 0x2) ? 0xcccccccc : 0});
  194. lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
  195. lfs_deinit(&lfs) => 0;
  196. // test that mount fails gracefully
  197. // mount may not fail, but our first alloc should fail when
  198. // we try to fix the gstate
  199. lfs_mount(&lfs, cfg) => 0;
  200. lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT;
  201. lfs_unmount(&lfs) => 0;
  202. '''
  203. # cycle detection/recovery tests
  204. [cases.test_evil_mdir_loop] # metadata-pair threaded-list loop test
  205. in = "lfs.c"
  206. code = '''
  207. // create littlefs
  208. lfs_t lfs;
  209. lfs_format(&lfs, cfg) => 0;
  210. // change tail-pointer to point to ourself
  211. lfs_init(&lfs, cfg) => 0;
  212. lfs_mdir_t mdir;
  213. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  214. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  215. {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
  216. (lfs_block_t[2]){0, 1}})) => 0;
  217. lfs_deinit(&lfs) => 0;
  218. // test that mount fails gracefully
  219. lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
  220. '''
  221. [cases.test_evil_mdir_loop2] # metadata-pair threaded-list 2-length loop test
  222. in = "lfs.c"
  223. code = '''
  224. // create littlefs with child dir
  225. lfs_t lfs;
  226. lfs_format(&lfs, cfg) => 0;
  227. lfs_mount(&lfs, cfg) => 0;
  228. lfs_mkdir(&lfs, "child") => 0;
  229. lfs_unmount(&lfs) => 0;
  230. // find child
  231. lfs_init(&lfs, cfg) => 0;
  232. lfs_mdir_t mdir;
  233. lfs_block_t pair[2];
  234. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  235. lfs_dir_get(&lfs, &mdir,
  236. LFS_MKTAG(0x7ff, 0x3ff, 0),
  237. LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
  238. => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
  239. lfs_pair_fromle32(pair);
  240. // change tail-pointer to point to root
  241. lfs_dir_fetch(&lfs, &mdir, pair) => 0;
  242. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  243. {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
  244. (lfs_block_t[2]){0, 1}})) => 0;
  245. lfs_deinit(&lfs) => 0;
  246. // test that mount fails gracefully
  247. lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
  248. '''
  249. [cases.test_evil_mdir_loop_child] # metadata-pair threaded-list 1-length child loop test
  250. in = "lfs.c"
  251. code = '''
  252. // create littlefs with child dir
  253. lfs_t lfs;
  254. lfs_format(&lfs, cfg) => 0;
  255. lfs_mount(&lfs, cfg) => 0;
  256. lfs_mkdir(&lfs, "child") => 0;
  257. lfs_unmount(&lfs) => 0;
  258. // find child
  259. lfs_init(&lfs, cfg) => 0;
  260. lfs_mdir_t mdir;
  261. lfs_block_t pair[2];
  262. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  263. lfs_dir_get(&lfs, &mdir,
  264. LFS_MKTAG(0x7ff, 0x3ff, 0),
  265. LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
  266. => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
  267. lfs_pair_fromle32(pair);
  268. // change tail-pointer to point to ourself
  269. lfs_dir_fetch(&lfs, &mdir, pair) => 0;
  270. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  271. {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0;
  272. lfs_deinit(&lfs) => 0;
  273. // test that mount fails gracefully
  274. lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
  275. '''