metadata.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /* fuzzer_metadata
  2. * Copyright (C) 2022-2023 Xiph.Org Foundation
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * - Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * - Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * - Neither the name of the Xiph.org Foundation nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include <cstdlib>
  32. #include <cstdio>
  33. #include <cstring> /* for memcpy */
  34. #include <unistd.h>
  35. #include "FLAC++/metadata.h"
  36. #include "common.h"
  37. #define CONFIG_LENGTH 2
  38. #define min(x,y) (x<y?x:y)
  39. static void run_tests_with_level_0_interface(char filename[]);
  40. static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size);
  41. static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size);
  42. extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
  43. {
  44. uint8_t command_length;
  45. char filename[] = "/tmp/tmpXXXXXX.flac";
  46. FLAC__bool init_bools[4];
  47. /* Use first byte for configuration, leave at least one byte of input */
  48. if(size < 1 + CONFIG_LENGTH){
  49. return 0;
  50. }
  51. /* First 4 bits for configuration bools, next 4 for length of command section */
  52. for(int i = 0; i < 4; i++)
  53. init_bools[i] = data[i/8] & (1 << (i % 8));
  54. command_length = data[0] >> 4;
  55. if(0)//data[1] < 128) /* Use MSB as on/off */
  56. alloc_check_threshold = data[1];
  57. else
  58. alloc_check_threshold = INT32_MAX;
  59. alloc_check_counter = 0;
  60. /* Leave at least one byte as input */
  61. if(command_length >= size - 1 - CONFIG_LENGTH)
  62. command_length = size - 1 - CONFIG_LENGTH;
  63. /* Dump input to file */
  64. {
  65. int file_to_fuzz = mkstemps(filename, 5);
  66. if (file_to_fuzz < 0)
  67. abort();
  68. write(file_to_fuzz,data+CONFIG_LENGTH+command_length,size-CONFIG_LENGTH-command_length);
  69. close(file_to_fuzz);
  70. }
  71. run_tests_with_level_0_interface(filename);
  72. run_tests_with_level_1_interface(filename, init_bools[1], init_bools[2], data+CONFIG_LENGTH, command_length/2);
  73. /* Dump input to file, to start fresh for level 2 */
  74. if(!init_bools[1]){
  75. FILE * file_to_fuzz = fopen(filename,"w");
  76. fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_fuzz);
  77. fclose(file_to_fuzz);
  78. }
  79. run_tests_with_level_2_interface(filename, init_bools[0], init_bools[3], data+command_length/2+CONFIG_LENGTH, command_length/2);
  80. remove(filename);
  81. return 0;
  82. }
  83. static void run_tests_with_level_0_interface(char filename[]) {
  84. FLAC::Metadata::StreamInfo streaminfo;
  85. FLAC::Metadata::VorbisComment vorbis_comment;
  86. FLAC::Metadata::CueSheet cue_sheet;
  87. FLAC::Metadata::Picture picture;
  88. FLAC::Metadata::get_streaminfo(filename,streaminfo);
  89. FLAC::Metadata::get_tags(filename,vorbis_comment);
  90. FLAC::Metadata::get_cuesheet(filename,cue_sheet);
  91. FLAC::Metadata::get_picture(filename,picture, (FLAC__StreamMetadata_Picture_Type)(1), NULL, NULL, -1, -1, -1, -1);
  92. }
  93. static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size) {
  94. FLAC::Metadata::SimpleIterator iterator;
  95. FLAC::Metadata::Prototype *metadata_block = nullptr;
  96. uint8_t id[4] = {0};
  97. if(!iterator.is_valid())
  98. return;
  99. if(!iterator.init(filename,readonly,preservestats))
  100. return;
  101. for(size_t i = 0; i < size && iterator.status() == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; i++) {
  102. switch(data[i] & 7) {
  103. case 0:
  104. iterator.get_block_type();
  105. iterator.get_block_offset();
  106. iterator.get_block_length();
  107. iterator.get_application_id(id);
  108. break;
  109. case 1:
  110. iterator.next();
  111. break;
  112. case 2:
  113. iterator.prev();
  114. break;
  115. case 3:
  116. iterator.delete_block(data[i] & 8);
  117. break;
  118. case 4:
  119. if(metadata_block != 0) {
  120. delete metadata_block;
  121. metadata_block = nullptr;
  122. }
  123. metadata_block = iterator.get_block();
  124. break;
  125. case 5:
  126. if(metadata_block != 0)
  127. iterator.set_block(metadata_block,data[i] & 8);
  128. break;
  129. case 6:
  130. if(metadata_block != 0)
  131. iterator.insert_block_after(metadata_block, data[i] & 8);
  132. break;
  133. case 7:
  134. iterator.status();
  135. iterator.is_last();
  136. iterator.is_writable();
  137. break;
  138. }
  139. }
  140. if(metadata_block != 0) {
  141. delete metadata_block;
  142. metadata_block = nullptr;
  143. }
  144. }
  145. static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size) {
  146. FLAC::Metadata::Chain chain;
  147. FLAC::Metadata::Iterator iterator;
  148. FLAC::Metadata::Prototype *metadata_block_get = nullptr;
  149. FLAC::Metadata::Prototype *metadata_block_transfer = nullptr;
  150. FLAC::Metadata::Prototype *metadata_block_put = nullptr;
  151. if(!chain.is_valid())
  152. return;
  153. if(!chain.read(filename, ogg))
  154. return;
  155. iterator.init(chain);
  156. for(size_t i = 0; i < size; i++) {
  157. switch(data[i] & 15) {
  158. case 0:
  159. iterator.get_block_type();
  160. break;
  161. case 1:
  162. iterator.next();
  163. break;
  164. case 2:
  165. iterator.prev();
  166. break;
  167. case 3:
  168. iterator.delete_block(data[i] & 16);
  169. break;
  170. case 4:
  171. metadata_block_get = iterator.get_block();
  172. if(metadata_block_get != 0 && metadata_block_get->is_valid()) {
  173. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  174. if(metadata_block_transfer != metadata_block_get) {
  175. delete metadata_block_transfer;
  176. metadata_block_transfer = nullptr;
  177. metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
  178. }
  179. }
  180. else {
  181. metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
  182. }
  183. }
  184. delete metadata_block_get;
  185. break;
  186. case 5:
  187. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  188. metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
  189. if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
  190. if(!iterator.insert_block_before(metadata_block_put))
  191. delete metadata_block_put;
  192. }
  193. else
  194. if(metadata_block_put != 0)
  195. delete metadata_block_put;
  196. }
  197. break;
  198. case 6:
  199. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  200. metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
  201. if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
  202. if(!iterator.insert_block_after(metadata_block_put))
  203. delete metadata_block_put;
  204. }
  205. else
  206. if(metadata_block_put != 0)
  207. delete metadata_block_put;
  208. }
  209. break;
  210. case 7:
  211. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  212. metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
  213. if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
  214. if(!iterator.set_block(metadata_block_put))
  215. delete metadata_block_put;
  216. }
  217. else
  218. if(metadata_block_put != 0)
  219. delete metadata_block_put;
  220. }
  221. break;
  222. case 8: /* Examine block */
  223. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  224. switch(metadata_block_transfer->get_type()) {
  225. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  226. {
  227. uint32_t num_comments;
  228. ::FLAC__StreamMetadata_VorbisComment_Entry entry;
  229. FLAC::Metadata::VorbisComment::Entry entry_cpp;
  230. FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
  231. const ::FLAC__StreamMetadata * metadata_c = *metadata_block_transfer;
  232. if(vorbiscomment == 0)
  233. abort();
  234. vorbiscomment->get_vendor_string();
  235. num_comments = vorbiscomment->get_num_comments();
  236. if(num_comments > 0) {
  237. entry = metadata_c->data.vorbis_comment.comments[min(data[i]>>4,num_comments-1)];
  238. if(entry.entry == 0)
  239. abort();
  240. if(vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)).is_valid()) {
  241. entry_cpp = vorbiscomment->get_comment(min(data[i]>>4,num_comments-1));
  242. if(entry_cpp.is_valid() && entry_cpp.get_field() == 0)
  243. abort();
  244. vorbiscomment->find_entry_from(0,"TEST");
  245. }
  246. }
  247. }
  248. break;
  249. case FLAC__METADATA_TYPE_CUESHEET:
  250. {
  251. uint32_t num_tracks, num_indices;
  252. FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
  253. if(cuesheet == 0 || !cuesheet->is_legal())
  254. break;
  255. cuesheet->is_legal(true); /* check CDDA subset */
  256. cuesheet->calculate_cddb_id();
  257. cuesheet->get_media_catalog_number();
  258. cuesheet->get_lead_in();
  259. cuesheet->get_is_cd();
  260. num_tracks = cuesheet->get_num_tracks();
  261. if(num_tracks > 0) {
  262. FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
  263. track.get_offset();
  264. track.get_number();
  265. track.get_isrc();
  266. track.get_pre_emphasis();
  267. num_indices = track.get_num_indices();
  268. if(num_indices > 0) {
  269. FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
  270. (void)index;
  271. }
  272. }
  273. }
  274. break;
  275. case FLAC__METADATA_TYPE_PICTURE:
  276. {
  277. char * violation = nullptr;
  278. FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
  279. if(picture == 0 || !picture->is_legal((const char **)&violation))
  280. break;
  281. picture->get_data();
  282. }
  283. break;
  284. default:
  285. break;
  286. }
  287. }
  288. break;
  289. case 9: /* Replace or add in block */
  290. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  291. switch(metadata_block_transfer->get_type()) {
  292. case FLAC__METADATA_TYPE_SEEKTABLE:
  293. {
  294. uint32_t num_seekpoints;
  295. FLAC__StreamMetadata_SeekPoint seekpoint;
  296. FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
  297. if(seektable == 0)
  298. break;
  299. if(seektable->is_valid() && seektable->is_legal()) {
  300. num_seekpoints = seektable->get_num_points();
  301. if(num_seekpoints > 0) {
  302. seekpoint = seektable->get_point(min(data[i]>>5,num_seekpoints-1));
  303. seektable->set_point(0,seekpoint);
  304. seektable->insert_point(min(data[i]>>5,num_seekpoints-1),seekpoint);
  305. }
  306. seektable->template_append_placeholders(4);
  307. seektable->template_append_point(111111);
  308. seektable->template_append_points((FLAC__uint64[]){222222, 333333, 444444}, 3);
  309. seektable->template_append_spaced_points(data[i]>>5, 1234567);
  310. seektable->template_append_spaced_points_by_samples(data[i]>>5, 2468000);
  311. seektable->template_sort(data[i] & 16);
  312. }
  313. }
  314. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  315. {
  316. uint32_t num_comments;
  317. FLAC::Metadata::VorbisComment::Entry entry;
  318. FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
  319. if(vorbiscomment == 0)
  320. break;
  321. num_comments = vorbiscomment->get_num_comments();
  322. if(num_comments > 0 && entry.is_valid()) {
  323. if(vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)).is_valid()) {
  324. entry = vorbiscomment->get_comment(min(data[i]>>5,num_comments-1));
  325. if(entry.is_valid()) {
  326. vorbiscomment->replace_comment(entry,data[i] & 16);
  327. vorbiscomment->set_comment(0,entry);
  328. vorbiscomment->append_comment(entry);
  329. vorbiscomment->insert_comment(0,entry);
  330. }
  331. }
  332. }
  333. }
  334. break;
  335. case FLAC__METADATA_TYPE_CUESHEET:
  336. {
  337. uint32_t num_tracks, num_indices;
  338. FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
  339. if(cuesheet == 0 || !cuesheet->is_legal())
  340. break;
  341. num_tracks = cuesheet->get_num_tracks();
  342. if(num_tracks > 0) {
  343. FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
  344. num_indices = track.get_num_indices();
  345. if(num_indices > 0) {
  346. FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
  347. track.set_index(0,index);
  348. cuesheet->insert_index(0,0,index);
  349. cuesheet->insert_blank_index(0,0);
  350. }
  351. cuesheet->insert_blank_track(0);
  352. cuesheet->insert_track(0,track);
  353. cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
  354. }
  355. }
  356. break;
  357. case FLAC__METADATA_TYPE_PICTURE:
  358. {
  359. FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
  360. const char testtext[] = "TEST";
  361. if(picture == 0 || !picture->is_legal(NULL))
  362. break;
  363. picture->set_description((FLAC__byte *)&testtext);
  364. picture->set_mime_type((const char *)&testtext);
  365. picture->set_data((FLAC__byte *)&testtext,4);
  366. }
  367. break;
  368. default:
  369. break;
  370. }
  371. }
  372. break;
  373. case 10: /* Delete from block */
  374. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  375. switch(metadata_block_transfer->get_type()) {
  376. case FLAC__METADATA_TYPE_SEEKTABLE:
  377. {
  378. uint32_t num_seekpoints;
  379. FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
  380. if(seektable == 0)
  381. break;
  382. if(seektable->is_valid() && seektable->is_legal()) {
  383. num_seekpoints = seektable->get_num_points();
  384. if(num_seekpoints > 0)
  385. seektable->delete_point(min(data[i]>>4,num_seekpoints-1));
  386. }
  387. }
  388. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  389. {
  390. uint32_t num_comments;
  391. FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
  392. if(vorbiscomment == 0)
  393. break;
  394. num_comments = vorbiscomment->get_num_comments();
  395. if(num_comments > 0)
  396. vorbiscomment->delete_comment(min(data[i]>>4,num_comments-1));
  397. vorbiscomment->remove_entry_matching("TEST");
  398. vorbiscomment->remove_entries_matching("TEST");
  399. }
  400. break;
  401. case FLAC__METADATA_TYPE_CUESHEET:
  402. {
  403. uint32_t num_tracks;
  404. FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
  405. if(cuesheet == 0 || !cuesheet->is_legal())
  406. break;
  407. num_tracks = cuesheet->get_num_tracks();
  408. if(num_tracks > 0) {
  409. FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
  410. if(track.get_num_indices() > 0)
  411. cuesheet->delete_index(min(data[i]>>4,num_tracks-1),0);
  412. cuesheet->delete_track(0);
  413. }
  414. }
  415. break;
  416. default:
  417. break;
  418. }
  419. }
  420. break;
  421. case 11: /* Resize block */
  422. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  423. switch(metadata_block_transfer->get_type()) {
  424. case FLAC__METADATA_TYPE_PADDING:
  425. {
  426. FLAC::Metadata::Padding * padding = dynamic_cast<FLAC::Metadata::Padding *>(metadata_block_transfer);
  427. if(padding == 0)
  428. break;
  429. padding->set_length(data[i]>>4);
  430. }
  431. break;
  432. case FLAC__METADATA_TYPE_SEEKTABLE:
  433. {
  434. FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
  435. if(seektable == 0)
  436. break;
  437. seektable->resize_points(data[i]>>4);
  438. }
  439. break;
  440. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  441. {
  442. FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
  443. if(vorbiscomment == 0)
  444. break;
  445. vorbiscomment->resize_comments(data[i]>>4);
  446. }
  447. break;
  448. case FLAC__METADATA_TYPE_CUESHEET:
  449. {
  450. uint32_t num_tracks;
  451. FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
  452. if(cuesheet == 0 || !cuesheet->is_legal())
  453. break;
  454. num_tracks = cuesheet->get_num_tracks();
  455. if(num_tracks > 0) {
  456. cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
  457. }
  458. cuesheet->resize_tracks(data[i]<<4);
  459. }
  460. break;
  461. default:
  462. break;
  463. }
  464. }
  465. break;
  466. case 12: /* Prototype functions */
  467. if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
  468. const ::FLAC__StreamMetadata * metadata_compare = *metadata_block_transfer;
  469. metadata_block_transfer->get_is_last();
  470. metadata_block_transfer->get_length();
  471. metadata_block_transfer->set_is_last(data[i] & 16);
  472. FLAC__metadata_object_is_equal(metadata_compare, metadata_compare);
  473. }
  474. break;
  475. }
  476. }
  477. if(metadata_block_transfer != 0) {
  478. delete metadata_block_transfer;
  479. metadata_block_transfer = nullptr;
  480. }
  481. chain.status();
  482. chain.sort_padding();
  483. chain.merge_padding();
  484. chain.check_if_tempfile_needed(!use_padding);
  485. chain.write(use_padding);
  486. }