From: Mostyn Bramley-Moore Date: Sat, 28 Dec 2024 23:36:01 +0000 (+0100) Subject: 7zip reader: add support for POWERPC filter for non-LZMA compressors (#2459) X-Git-Tag: v3.7.8~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3601017d68f4f1ad46f8ae8ecc1894404570aec4;p=thirdparty%2Flibarchive.git 7zip reader: add support for POWERPC filter for non-LZMA compressors (#2459) This new test archive contains a C hello world executable built like so on a ubuntu 24.04 machine: ``` #include int main(int argc, char *argv[]) { printf("hello, world\n"); return 0; } ``` `powerpc-linux-gnu-gcc hw.c -o hw-powerpc -Wall` The test archive that contains this executable was created like so, using 7-Zip 24.08: `7zz a -t7z -m0=deflate -mf=ppc libarchive/test/test_read_format_7zip_deflate_powerpc.7z hw-powerpc` This test fails in the first commit in this PR, and passes in the second commit. (cherry picked from commit 28cb5064d8dcd256237a736d7d6cbf7873de6671) --- diff --git a/Makefile.am b/Makefile.am index 092fdb9e4..cb994d6ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -788,6 +788,7 @@ libarchive_test_EXTRA_DIST=\ 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_deflate_powerpc.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 \ diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index 5ddc54a60..1707fe930 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -28,6 +28,9 @@ #ifdef HAVE_ERRNO_H #include #endif +#if HAVE_STDINT_H +#include +#endif #ifdef HAVE_STDLIB_H #include #endif @@ -436,6 +439,7 @@ 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); static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t); +static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t); int @@ -1111,6 +1115,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, coder2->codec != _7Z_X86_BCJ2 && coder2->codec != _7Z_ARM && coder2->codec != _7Z_ARM64 && + coder2->codec != _7Z_POWERPC && coder2->codec != _7Z_SPARC) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1712,6 +1717,8 @@ decompress(struct archive_read *a, struct _7zip *zip, *outbytes = arm64_Convert(zip, buff, *outbytes); } else if (zip->codec2 == _7Z_SPARC) { *outbytes = sparc_Convert(zip, buff, *outbytes); + } else if (zip->codec2 == _7Z_POWERPC) { + *outbytes = powerpc_Convert(zip, buff, *outbytes); } } @@ -4069,6 +4076,63 @@ sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size) return i; } +static size_t +powerpc_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t powerpc_code(void *simple, uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) + // in https://git.tukaani.org/xz.git + + /* + * Filter for PowerPC (big endian) binaries + * + * Authors: Igor Pavlov + * Lasse Collin + * + * Copyright (C) The XZ Utils authors and contributors + * + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + size &= ~(size_t)3; + + size_t i; + for (i = 0; i < size; i += 4) { + // PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) + if ((buf[i] >> 2) == 0x12 + && ((buf[i + 3] & 3) == 1)) { + + const uint32_t src + = (((uint32_t)(buf[i + 0]) & 3) << 24) + | ((uint32_t)(buf[i + 1]) << 16) + | ((uint32_t)(buf[i + 2]) << 8) + | ((uint32_t)(buf[i + 3]) & ~UINT32_C(3)); + + uint32_t dest = src - (zip->bcj_ip + (uint32_t)(i)); + + buf[i + 0] = 0x48 | ((dest >> 24) & 0x03); + buf[i + 1] = (dest >> 16); + buf[i + 2] = (dest >> 8); + buf[i + 3] &= 0x03; + buf[i + 3] |= dest; + } + } + + zip->bcj_ip += (uint32_t)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 c79a6e575..6cbcf79bc 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -1386,3 +1386,60 @@ DEFINE_TEST(test_read_format_7zip_zstd_sparc) assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } + +static void +test_powerpc_filter(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + size_t expected_entry_size = 68340; + char *buff = malloc(expected_entry_size); + uint32_t computed_crc = 0; + uint32_t expected_crc = 0x71fb03c9; + + assert((a = archive_read_new()) != NULL); + + extract_reference_file(refname); + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + 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-powerpc", archive_entry_pathname(ae)); + assertEqualInt(expected_entry_size, archive_entry_size(ae)); + assertEqualInt(expected_entry_size, archive_read_data(a, buff, expected_entry_size)); + + computed_crc = crc32(computed_crc, buff, expected_entry_size); + 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)); + + free(buff); +} + +DEFINE_TEST(test_read_format_7zip_deflate_powerpc) +{ + 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_powerpc_filter("test_read_format_7zip_deflate_powerpc.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/libarchive/test/test_read_format_7zip_deflate_powerpc.7z.uu b/libarchive/test/test_read_format_7zip_deflate_powerpc.7z.uu new file mode 100644 index 000000000..a7db07ca4 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_deflate_powerpc.7z.uu @@ -0,0 +1,55 @@ +begin 664 test_read_format_7zip_deflate_powerpc.7z +M-WJ\KR<<``2:7;DH@`@```````!R`````````#:LFQ3LU$MK$U$4P/$SDZB1 +M)#)*%$'1$0,JB&\D14M,?56J]8%N=)%6(QJ,5FW%(BD97XC@HN(#7(@K@QO! +MA6Y%-R*"7\$GKMQTX4*P.IX[*%#_!_U=.YMZYY][<5'/'LZ'I?AR2MI'2_G[/AO;S)NR8 +M8T.\*(PIHU'H1SQB/G]]]YPXM+M<8U7TO8[=I83B.7&H,1M3_^S!J7DVM+_% +M1#)6&_JR1[_*]VSHO?E1_!G?*Y.PZWLZON^?_65,)/6M;-0/KVS45@P.K%AM +M)MG[!7,NVWL/2->;^Z^F/4M_>]9U;/KU\&:^R;%2<:UQS7_. +MSVS:3W+2+S[W/)YDK[.3QJSXXOW3WV:[R4J.GD7.K#=39(94=^RN#@[5ZJ>J +MYP:/UN3TN:%!J5:ULB-ZN__L4/5D?_V4F+ZI<[ULW[FC:W-US8I5$ZVUZW3" +ML9,#I^R$:ER%UN28OZB>)Y-O7OSJ:UY@X;YG<=TN!"UW6B[ +MLVT[K6E).Z,Y4?OVHG"LF7';HXX4;KV43-<#F=)Z[;;+[\3=\.YG)E@0CJ\, +M1"K/)=,MZ8N!YC4SJ?9ES2TM$J\WB(^EN2P[O'^1K#?S1QZY[=+$VBFSMI3? +MBMN9-VN.O[[Z:/Q#MQYCG^8DL;'/F7.Z>66&AG/G?W/[[-YN?91<^8/G7B]+ +MT>1LTISD++HEU=_ABV/JO:?C42 +MT;U)J3[%TS,[H^O(R.*>X8Z6^$%6TM%:7\/QD?Y#P[I6M)].K>?B"),0ERX?>.$S].-Z>GVLWLP<+%&_H]?0<+R9Q)XS_/ +MP:2_MRO.\:.-QL!R__S`V48M>LKFI!_127]B3RTKE?=X1 +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````````````#PN]UJ +M!Y$:BJ(WF5E===2L_R\,..`_C!\4Q,+9CQ_PA^X*-CXSF[@3G$G6)*.[%B*B +MJ""B:*%6EEM:J+5@8R%BIZ4V%F*AH"(BCN?EW;CCD$8;FQPX\][)/;EY[[Z7 +MO,F0(4.&#!DR9,B0(4.&#!DR9/C?,"AO&)1[B:X&K@0+!NFOT7`+]`^TRJ?W6SR\&:1/H=^&^16BG0#]#.QT<`F>`!CB?%'*&3A+R +MMP3.`Z>""W'_0]E'*_-U@V5P&E@8E4FTUF>_U?J)^!C:EAPSVH_0'OT#D*^] +M#C?`V^`=0S]?0CN/.K"KKV];<=50M>E%S>*&3>8FL[Q^2S.6&\]MW&R6-Z_F +MRY0*U&60@!R1QMIFK;.^PCK'>H)UGO4SUET$R'JSGL+:8SV5]1CK;M9)OFFL +M'[*>SOHUZQE*YXJL"URC-ZQG*MU58#V+=>*?S7H[:X,`N8]8][#^P7I.LAZL +MY[+^R'I>K'5*XO-9)\]?P+K$>B$Q6,LZ:<3(4^L3FFZN=U%3]9Z#^:XC"37? +M91W^E8@?)T!7\=70-]KT=GZ/$GV(QZ-I:CS'DOEJ:KZ7Y+O7YK^9U$=3]7G0 +M_OR4\3Q"?:^QWR"@(_Y4[F..R_J\2.JKJ?J^2M:+U'J]E^\7Q^?)WP1SU%WK +M#%V-H1CGTY8G]3:4+B7[8XY.,Z'7L#^);^W(MY,81:6'#%UU>_387^7]E>^) +M]Y=V"O%5G&\A=)GWYV;D*T"?YO$D\0O\#N_F^&6.)_EOR?W.XYU!PT&TP?1) +M"*OJBL@:H1$_$G6KZM1E*(R:)TZ8PV0[@3/BAI$3B*@AANN^YX2XQ_;%2-VO +M6G5A1WX0"JLY1L-^8[3N1(YMEM,=XH3KN<(*`FM<.%X4C-.)P&HXPFXV&N.X +MI4T).*,_K+4S&(T0.P]5]@V(@?W]0I`XW%\1O97#`^CV']U?V;>G#XY=^X?$ +MP&XV[NX_1&+7W@.]E;WBP,Z=AP<&Q6"E=Z^\0]3=ZK`((RN(1,-RO1V[]N[I +M[1,;S4V;23BV%5D4#QA.*9231IM1F#CC>8XT?(^S"&D-?5&S/+OND-AS``'; +M]40S=&S"/&P8JF'(J>1#<6%P7Q_/)YXTD1F.-R*KBC8*5%M+>JZ'A1@ET_,C +MQQSQFF:UZ=;M]:[-ERJ]>];+I8QC-2NLD6F/>\@7M\BB(J>=('1][P\A$`N< +MNB6-W!NM1_*1+GXC9PR_LAR(^7%Q3*?&*U:S@TDE[TB63MW!?9G8:KC#>*J/ +M7"H'JD$F-DX#BTQ_@Z7\?=/5&2-),XG!,8D5X%3VV1232C2)/"EL:?-=(?Y. +MIOCZSK2GS,_>`,]CVCF'20U+FEL<<`CX`YYZ[./"G_+[!OC&)2N>.Y$F=EGWT3%),*[?-@?9'[O>KLE*02^^:W +M^:YS_BGJ&R-)_2GUNSWIRQ4IIO:$)F&0PKW$I[ZQDK0N)=]]]NGJVRE)/2F^ +MB39?D6+2LA3?XS;?=HI)@RD^.>998$Z=82#'&'GFS33]PO$\"^M1V^A'K;U8-(_4#^U^9U3MZ/:6!NTI>7/W=3GMOSIZ]+>KYW +M^GX!`00&``$)B(``!PL!``(#!`$(!`,#`@4!``S!]`K!]`H`"`H!R0/[<0`` +M!0$9#P```````````````````!$7`&@`=P`M`'``;P!W`&4`<@!P`&,````9 +;!``````4"@$`>7-\NFY9VP$5!@$`((#]@0`` +` +end