From eb2b5ad6e0ad875f3d543bda53c09beb49f28d42 Mon Sep 17 00:00:00 2001 From: Mostyn Bramley-Moore Date: Mon, 17 Jul 2023 13:00:23 +0200 Subject: [PATCH] 7zip reader: add support for ARM64 filter (#1918) 7-Zip 23.00 added a new ARM64 filter, which is also supported by recent versions of liblzma. This PR adds support for this filter for both lzma and non-lzma encoders. --- Makefile.am | 4 +- configure.ac | 13 +++ libarchive/archive_read_support_format_7zip.c | 80 ++++++++++++++++++- libarchive/test/test_read_format_7zip.c | 72 +++++++++++++++++ .../test_read_format_7zip_deflate_arm64.7z.uu | 64 +++++++++++++++ .../test_read_format_7zip_lzma2_arm64.7z.uu | 54 +++++++++++++ 6 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu create mode 100644 libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu diff --git a/Makefile.am b/Makefile.am index 4dd038829..7f0198a40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -768,6 +768,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_copy.7z.uu \ libarchive/test/test_read_format_7zip_copy_2.7z.uu \ libarchive/test/test_read_format_7zip_deflate.7z.uu \ + libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_delta4_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma2.7z.uu \ @@ -780,8 +781,9 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_lzma1_2.7z.uu \ libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu \ - libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu \ libarchive/test/test_read_format_7zip_lzma2.7z.uu \ + libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu \ + libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu \ libarchive/test/test_read_format_7zip_malformed.7z.uu \ libarchive/test/test_read_format_7zip_malformed2.7z.uu \ libarchive/test/test_read_format_7zip_packinfo_digests.7z.uu \ diff --git a/configure.ac b/configure.ac index a2a0a5c25..933fea59e 100644 --- a/configure.ac +++ b/configure.ac @@ -482,6 +482,19 @@ if test "x$with_lzma" != "xno"; then if test "x$ac_cv_lzma_has_mt" != xno; then AC_DEFINE([HAVE_LZMA_STREAM_ENCODER_MT], [1], [Define to 1 if you have the `lzma_stream_encoder_mt' function.]) fi + + AC_CACHE_CHECK( + [whether we have ARM64 filter support in lzma], + ac_cv_lzma_has_arm64, + [AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[#include ] + [#ifndef LZMA_FILTER_ARM64] + [#error unsupported] + [#endif]])], + [ac_cv_lzma_has_arm64=yes], [ac_cv_lzma_has_arm64=no])]) + if test "x$ac_cv_lzma_has_arm64" != xno; then + AC_DEFINE([HAVE_LZMA_FILTER_ARM64], [1], [Define to 1 if you have the `LZMA_FILTER_ARM64' macro.]) + fi fi AC_ARG_WITH([lzo2], diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index df6f035ed..bb595b3e4 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$"); #define _7Z_IA64 0x03030401 #define _7Z_ARM 0x03030501 #define _7Z_ARMTHUMB 0x03030701 +#define _7Z_ARM64 0xa #define _7Z_SPARC 0x03030805 #define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */ @@ -409,6 +410,7 @@ static void x86_Init(struct _7zip *); static size_t x86_Convert(struct _7zip *, uint8_t *, size_t); static void arm_Init(struct _7zip *); static size_t arm_Convert(struct _7zip *, uint8_t *, size_t); +static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t); static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t); @@ -1044,7 +1046,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, if (coder2 != NULL) { if (coder2->codec != _7Z_X86 && coder2->codec != _7Z_X86_BCJ2 && - coder2->codec != _7Z_ARM) { + coder2->codec != _7Z_ARM && + coder2->codec != _7Z_ARM64) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported filter %lx for %lx", @@ -1153,6 +1156,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip, filters[fi].id = LZMA_FILTER_ARMTHUMB; fi++; break; +#ifdef LZMA_FILTER_ARM64 + case _7Z_ARM64: + filters[fi].id = LZMA_FILTER_ARM64; + fi++; + break; +#endif case _7Z_SPARC: filters[fi].id = LZMA_FILTER_SPARC; fi++; @@ -1620,7 +1629,7 @@ decompress(struct archive_read *a, struct _7zip *zip, /* * Decord BCJ. */ - if (zip->codec != _7Z_LZMA2 && (zip->codec2 == _7Z_X86 || zip->codec2 == _7Z_ARM)) { + if (zip->codec != _7Z_LZMA2) { if (zip->codec2 == _7Z_X86) { size_t l = x86_Convert(zip, buff, *outbytes); @@ -1632,8 +1641,10 @@ decompress(struct archive_read *a, struct _7zip *zip, *outbytes = l; } else zip->odd_bcj_size = 0; - } else { // zip->codec2 == _7Z_ARM + } else if (zip->codec2 == _7Z_ARM) { *outbytes = arm_Convert(zip, buff, *outbytes); + } else if (zip->codec2 == _7Z_ARM64) { + *outbytes = arm64_Convert(zip, buff, *outbytes); } } @@ -3827,6 +3838,69 @@ arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size) return i; } +static size_t +arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size) + // in https://git.tukaani.org/xz-embedded.git + + /* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + + size_t i; + uint32_t instr; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = (uint32_t)buf[i] + | ((uint32_t)buf[i+1] << 8) + | ((uint32_t)buf[i+2] << 16) + | ((uint32_t)buf[i+3] << 24); + + if ((instr >> 26) == 0x25) { + /* BL instruction */ + addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2); + instr = 0x94000000 | (addr & 0x03FFFFFF); + + buf[i] = (uint8_t)instr; + buf[i+1] = (uint8_t)(instr >> 8); + buf[i+2] = (uint8_t)(instr >> 16); + buf[i+3] = (uint8_t)(instr >> 24); + } else if ((instr & 0x9F000000) == 0x90000000) { + /* ADRP instruction */ + addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC); + + /* Only convert values in the range +/-512 MiB. */ + if ((addr + 0x020000) & 0x1C0000) + continue; + + addr -= (zip->bcj_ip + (uint32_t)i) >> 12; + + instr &= 0x9000001F; + instr |= (addr & 3) << 29; + instr |= (addr & 0x03FFFC) << 3; + instr |= (0U - (addr & 0x020000)) & 0xE00000; + + buf[i] = (uint8_t)instr; + buf[i+1] = (uint8_t)(instr >> 8); + buf[i+2] = (uint8_t)(instr >> 16); + buf[i+3] = (uint8_t)(instr >> 24); + } + } + + zip->bcj_ip += i; + + return i; +} + /* * Brought from LZMA SDK. * diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index 5f97b6a0d..1eca3936e 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -1110,3 +1110,75 @@ DEFINE_TEST(test_read_format_7zip_ppmd) { test_ppmd(); } + +static void +test_arm64_filter(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + char buff[70368]; + uint32_t computed_crc = 0; + uint32_t expected_crc = 0xde97d594; + + assert((a = archive_read_new()) != NULL); + + extract_reference_file(refname); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0775), archive_entry_mode(ae)); + assertEqualString("hw-arm64", archive_entry_pathname(ae)); + assertEqualInt(sizeof(buff), archive_entry_size(ae)); + assertEqualInt(sizeof(buff), archive_read_data(a, buff, sizeof(buff))); + computed_crc = crc32(computed_crc, buff, sizeof(buff)); + assertEqualInt(computed_crc, expected_crc); + + assertEqualInt(1, archive_file_count(a)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_lzma2_arm64) +{ +#ifdef HAVE_LZMA_FILTER_ARM64 + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + test_arm64_filter("test_read_format_7zip_lzma2_arm64.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +#else + skipping("This version of liblzma does not support LZMA_FILTER_ARM64"); +#endif +} + +DEFINE_TEST(test_read_format_7zip_deflate_arm64) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_gzip(a)) { + skipping( + "7zip:deflate decoding is not supported on this platform"); + } else { + test_arm64_filter("test_read_format_7zip_deflate_arm64.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu b/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu new file mode 100644 index 000000000..e516ca5b4 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu @@ -0,0 +1,64 @@ +begin 664 libarchive/test/test_read_format_7zip_deflate_arm64.7z +M-WJ\KR<<``2V^52G)0H```````!:`````````.HY+B_LU5^(3%$

2.2T-J0XF&*!R-C_.Z=<^_9 +MV1\-3^RE>M;>QXU.A7.TUWJB)`<[&KZ8T]<]&O#7!73=1:O.CH8O%NQ0C7^[)' +MUEN-U>

HU&)4Q[IZH<^Z^V_Z?J?JI.[UJY8?;3]2E +MG^V0&G.LDQ:JD1\IK:%&/MG#^(D]S&_TD&_K/H]^`'NSK2H6D]N^/=::C6>R +ML=WQ9(MDMK?%8SN2+?%4O_K#7#6EZ]NC$+9GV^L<]Z[ +M@,[[^Z_T>$/R\N?J_!-/OH\G/RYDOB@=N'^M9*K\>4.=*AUX>/6!&7M9D%Q!;M/@9]'B +MH"-+\J'`N)?66*?9YU[*N4N5?KOI-_IZ7=*/["TVO\D_8:E[MQC +M5.[96&D?377]O1DN=HY7^4^RK@X9JWY$BZ:<"TH[*.L\*LW.?X\6P[(=/I3+ +M(V3=[AIE`YV0'X^\(;%>XE*EOCR0Q_Q>:NJ_1HMQJ2F8QG4EU[;JNHZO5^II +MPZ]#SY?U/WRL_M>RDP]E?*?41GY%BTUV;<"MK=S#>_8]_-9/%8?*'-LBX05A +M0\VSUUB(%G-28U\C&"[F9.V7I854;M.VB%KPK5^X6#KPZ*IW_6_D\SAS=HQ3 +M=]_+O-8V5]O&YMNE5DEMM:;Z#)WG9^A]NRN12J5#^]*95+,R1IF+YNOOJG._ +MR^4-$K]*;)8XNEPN6]\96R2V2[PA\::U_R0^]KR'QOY-*M@VUAC5?YR=&REM +MAY&9[?B+"^IO-[$[+>.6M?2FZU73LP=#YXP8R<#*Q_ +M]_;Y0*?.6M-W&>.\O[(+E)GKK5[]X.5``````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````#PIQUK"7$B"*(ULY_$__\O$M2#"@F; +M]2^"&_^"/S0*(MI,,K.;T62R3"::50\>!/6@B'A8!$'0@X('3^)1;QX4/`I> +M5-23@H(?5#36))79Z4EE=P_B:=[2>>G75=7=-36]F0D1(D2($"%"A`@1(D2( +M$"%"C`I[(U`'L4+=./%XXH<==9Y`_3-D/X?Z5W[7/>=1/TH\EWB0QN<'QK_^ +MJ19KXRK4T$'ZG;8Z=S;FI_&QU+]*/(YX-O$,D-'66%]5J;%*_0KQ=/_V$;.( +M>SID_6R[O.Y'Q&,"\R\`V>Y7M;X_A:0_U-]+\:K>>!V?J+^.QG]0OQW^+YYW +MC(YOXG4=#ND(L(C2E=BV:=.ZV)(#F;+EE&/)Y?'NKN[E7=W)E?%DN:9U+T4U +MT95(QAHCL25&I=^PS8)A.5I^:>QP02LYAAVST7OEVK5KXWW+>U?TZ/PEY6'P-G67TL +MUC&GCX.'K#X>GK/Z!.CIY/2)>`YP^B2XPNJ3X3:K3X%7K#[5.U=D?1H,LOIT +MN,GJ,_#^Y_29^*DR^BR8S.JS(0BE=F]^KH($.A>8.AGO^OCT&.DS`4%Y;HXS +M!;Y$&)W)\QQ^/5Y\QQ^?YE=]^G3)7JX33V>N>YR?UXOSI$6<"X$X*T98_Y7` +M^C=@4QD]1?HC-I\SZ?P90IKL(;">8]@47STH_CA,'9YP;1C]!L7?RUU'IL[O +M8E-(Y^HA&F7B,'7[9-CZG`2#$3[/Z0A?A[GHZ*Y7P_Y"P/X9-H5T&7RI-M]WIUO$.>_JS#JOM=C7+=2GJ,WWQ?T6^7GLVOO. +MG_;&[X86]J]:K/.2:^\[]U:0_JZ%_<<6>?Y!<1IUNX3T/[2OH/U8E<_#8M7- +M,_/_<7_6=I*)(BS600@M8PI'ZX/%%4#91#FKY?/BI*$=%[V6JUFH(96<Z$[1+@FMC`&+A?Z\X1AZHHNW +M$+VF90K-MK4!@;^![`'HM;6"(?1RH3"`+KZ>0$M',LV=Q-4(L75?:M<6L67W +M9B%`;#ZT.[5KQR:4M^T^(+9LI]'MF_>!V+9SS\;43K%GZ];]6](BG=JX5$IFSF];BIDY3:N"/NUE5M+*>5 +M>G@U4_=H?,?`6L',XJQ%C%6/@7F"!%:L^V,<_@7F85-\I]8: +MU6,:EZ&`C$78(C[_M"KSXJ;_.3)6!?PKJLRQ$?PW8_N&SVP-_T%5YOFD=WC/ +M03)VTS.MZCWWROR)]$YL;3[_V<0'25>]YVB9KXZ0OZ/8JK[UKVN7>7I@_6J` +MCV/[X_/?VRYSEV_]"K/_4Y33AO_9=ID?^>=G]G^._#=ZS_$R5WS^,QC_R[2N +M3N^]A\RS1[C^%QO^+9ZC^T'&9)!Q+>#?TRGS>@4D](",ZP'_,Q&9IX^P_IN! +M^^]*Q&/9OT7]W@GXWX[(O'Z$^1\$_%]%9+[7>GZO/B9B:Y/?2R'S]M$`/\4V +M:N]'B.G^5:C^/3^Y#E[3_GWOK8@;]3/\_.]E?U\F%9IG +M^/Q](*W-6Y=*K'#VJ,KX3%H7>)#\-=9?9A6:42&+GNC0>\44<_^.\=8NXV&T +M[K],'7[]4UKXOQE;M_P)P_O_!0$$!@`!"8HE``<+`0`"`P0!"`$*`0`,P>`2 +MP>`2``@*`935E]X```4!&0(``!$3`&@`=P`M`&$`<@!M`#8`-````!D`%`H! +3`#)5M-E?M]D!%08!`""`_8$````` +` +end diff --git a/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu b/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu new file mode 100644 index 000000000..3792a187f --- /dev/null +++ b/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu @@ -0,0 +1,54 @@ +begin 664 libarchive/test/test_read_format_7zip_lzma2_arm64.7z +M-WJ\KR<<``0W'TW>B^),$C`%""HM.8#>=`#! +MHGG`);CBW],\(2H/P+,[60V#BSUD@SPX?+]7UE`-G%X8-3UI(38JH=H'>(C4 +M.BHYW!+WO_VP/@H5V?EN8ESQEC<5V/WV[($3WNDOW%0OV?,5D(VX$W,9F]X6 +M$@+,!DJ9MCLG?+981]+>4RH&\+O6N:Z[J\UUAP1\;YX=FQG04]%"*WE/:)&N +M7]/;*`CB"$1/1LN;6/@^--#D_P_@^=I7&LU`$C*&]O)XY16O/YBAT\L2Q!M6 +MZ,^,_"DV_%G"4[;]`8E`Y>_4'B-G'SBG0\P#T504(#V)73,/E2#B3I7=S".' +MT?4S]U]05SC_GJUAE*!NK%8\&=\',!%JIL5J>;6'O[D[_5JVE7>4\(D]JBL8$[^!T?<88]&GF&D!J76?C\!TV:R8*BQ,2%*"NX6^-J!7;)H[ +M,VL2_VSHEIU&_VR#)=O81/7B?&1://2C9_O[-3*X(-,H(QI$N8$/CSMR0_PU +MF+&[-\:YPQ-V_/\D'K<+P1?:NF3DC@(W0X+$X,HG8*-0_+3@`07IT`9`RZO> +M=4MI;EB=PHN\-U*#KN5B^JX'^8EFYG-3'H?CITKDVRN+'.(ABHXGW.51@<$J +MTX]Z-:0Y]$8M))->TGEHM">WLYXA/P.=F-)"H)_M7B5FK,I=7R&:5F=A^H:\ +M"U3HG2Y>^C\3P&?0,F/>+S1<<,$W5!DW#+5:DT!&H>R]*HYAL;3=`9 +MG-6=ZO*O/-T<0GY[;.-GK`F4@EZ(HL.JR%:.V(7[VY:.`?"47U/P;N",R)G" +M%MX4UG$88O@.`;_;(1W&"==@<5,SMBD.R7>ITI@G5OR14O5NB?*E!["2KU6: +MH+P#/KA.)R4]DLK9W^<7&2RL#EF40DU1*VS`"A%7D5^"M`OB.0W5*_<#5K7* +MR'D05`R:?G3Q$`L;B5>KD\B"A%!FAV9F[BA2=I^AWD%J7`WFL7T,T%?%VI^; +M]0`QABMO4"3N3&-",I^)1E`Z61GN*(E7I&+P'2/Z$W,Q4^P3@1\Z01D"VYZ! +MZ]*!@]@/<"ZSHHN2'Z66_/Q1';U/W@:5/JY).$#*$JYEYOXW:DD&\7,"\NUZ +M*R7JO?D$*$NX)#AFK5F&$ZS`,HKM4&XRP,+WL+W:X2X98SA`L."UXPSOZY<".O^LP->K,4?Z-"*L#Z[P#"4,UW54G>W0KX/!21G-DW010]NZ54" +MT?"[+_BDNGN7B2'-)K$-,Q;L3<*/`/+A_EM-CG,CZT>TOP.1(>#99CO&/97= +MB[##0N[?U\)&U'1(]0CFGJ2>AXP_3RLI*,:V)B$I-<88"C66?>!/I0-YKR[, +M,(`W)51UA>T26X/6.,4;@!NGC*;0VLT(3KS2Z>(RX'MC'$C+I1BBR!)!)C1* +M!AZ7_:5Q_RI!L!3"6M0;8&NO0V2HYVA,"18X1IW+/I9?$B,06BS=Z#B<$J,U +M-GI\,NTS)(%MEW#FI%Q,1ZU30VDFO38M=_@*<2-HT`H>8VF^;V6!0,8*T'5/ +MS(?V9HD%DO;K^EOY8MB'_7J6P=+7MGT:AAH>E977IC9\\<$?0X0CKH-,^Y5$ +MPG(L?(8VYY=8"QMC)#MW)JL9?(`E$Q-65D_!\FG\A]NOX"3KECRR&I/I,-_L +MY&!L^F*E(.H&^C3[CL?KK2\S60UD3W[E,,NZ1Y^*&S@5U6J#BIL,-/Q?VP9< +M,5*R?(?<6J69T=K\E=)Y6T0$(RM!_S!38A6'S"CCI=F<`'?6/*5KS2L7ON'B +M:!)QKWUW%-N6`)K7@<="%O@E[$=W9+1;A, +M+'*KT@O#)$%J/;W$T,J!'NA?2G7F7GK88KT1(K\Q52<<(!S6;SKP4H#K%(SYK0`B,Y-/&7\3]CZ/'( +M0@61%II0K.Q,&R`2$K'#I8'B(J0'\20($ONEJ2AXW;-'V3AP;9ME^L7JBW46 +M!+9%;M7.G(>CLF;A8*'@X"+832%9%WXO^K*>?/(]*..3\@`!!`8``0F(```%`1D"```1$P!H`'<`+0!A +C`'(`;0`V`#0````9`!0*`0`R5;397[?9`14&`0`@@/V!```` +` +end -- 2.47.2