This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push:
new 63c4c5e64 COMPRESS-632: Fixes and tests for ArInputStream (#440)
63c4c5e64 is described below
commit 63c4c5e6468c0faa0d9af05d563ba3fdccf32c21
Author: Yakov Shafranovich <[email protected]>
AuthorDate: Tue Nov 14 16:38:35 2023 -0500
COMPRESS-632: Fixes and tests for ArInputStream (#440)
* Fixes and tests for AR parsing issues
* added another test
* another test
---------
Co-authored-by: Yakov Shafranovich <[email protected]>
---
.../archivers/ar/ArArchiveInputStream.java | 60 ++++++++++++++++-----
.../archivers/ar/ArArchiveInputStreamTest.java | 29 ++++++++++
.../compress/ar/number_parsing/bad_group.ar | 8 +++
.../compress/ar/number_parsing/bad_length.ar | 8 +++
.../ar/number_parsing/bad_long_namelen_bsd.ar | 5 ++
.../ar/number_parsing/bad_long_namelen_gnu1.ar | 8 +++
.../ar/number_parsing/bad_long_namelen_gnu2.ar | 6 +++
.../ar/number_parsing/bad_long_namelen_gnu3.ar | Bin 0 -> 274 bytes
.../compress/ar/number_parsing/bad_modified.ar | 8 +++
.../ar/number_parsing/bad_table_length_gnu.ar | 8 +++
.../commons/compress/ar/number_parsing/bad_user.ar | 8 +++
11 files changed, 135 insertions(+), 13 deletions(-)
diff --git
a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java
b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java
index ddb9e6c6c..aba0f155a 100644
---
a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java
+++
b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java
@@ -205,8 +205,13 @@ public class ArArchiveInputStream extends
ArchiveInputStream<ArArchiveEntry> {
* @since 1.3
*/
private String getBSDLongName(final String bsdLongName) throws IOException
{
- final int nameLen =
- Integer.parseInt(bsdLongName.substring(BSD_LONGNAME_PREFIX_LEN));
+ final int nameLen;
+ try {
+ nameLen =
Integer.parseInt(bsdLongName.substring(BSD_LONGNAME_PREFIX_LEN));
+ } catch (NumberFormatException ex) {
+ throw new IOException("Broken archive, unable to parse BSD long
name length field as a number", ex);
+ }
+
final byte[] name = IOUtils.readRange(input, nameLen);
final int read = name.length;
trackReadBytes(read);
@@ -229,10 +234,19 @@ public class ArArchiveInputStream extends
ArchiveInputStream<ArArchiveEntry> {
}
for (int i = offset; i < namebuffer.length; i++) {
if (namebuffer[i] == '\012' || namebuffer[i] == 0) {
- if (namebuffer[i - 1] == '/') {
+ // Avoid array errors
+ if (i == 0) {
+ break;
+ } else if (namebuffer[i - 1] == '/') {
i--; // drop trailing /
}
- return ArchiveUtils.toAsciiString(namebuffer, offset, i -
offset);
+
+ // Check there is a something to return, otherwise break out
of the loop
+ if (i - offset > 0) {
+ return ArchiveUtils.toAsciiString(namebuffer, offset, i -
offset);
+ } else {
+ break;
+ }
}
}
throw new IOException("Failed to read entry: " + offset);
@@ -311,11 +325,21 @@ public class ArArchiveInputStream extends
ArchiveInputStream<ArArchiveEntry> {
return getNextArEntry();
}
- long len = asLong(metaData, LENGTH_OFFSET, LENGTH_LEN);
+ long len;
+ try {
+ len = asLong(metaData, LENGTH_OFFSET, LENGTH_LEN);
+ } catch (NumberFormatException ex) {
+ throw new IOException("Broken archive, unable to parse ar_size
field as a number", ex);
+ }
if (temp.endsWith("/")) { // GNU terminator
temp = temp.substring(0, temp.length() - 1);
} else if (isGNULongName(temp)) {
- final int off = Integer.parseInt(temp.substring(1));// get the
offset
+ int off;
+ try {
+ off = Integer.parseInt(temp.substring(1));// get the offset
+ } catch (NumberFormatException ex) {
+ throw new IOException("Broken archive, unable to parse GNU
long name offset field as a number", ex);
+ }
temp = getExtendedName(off); // convert to the long name
} else if (isBSDLongName(temp)) {
temp = getBSDLongName(temp);
@@ -331,12 +355,16 @@ public class ArArchiveInputStream extends
ArchiveInputStream<ArArchiveEntry> {
throw new IOException("broken archive, entry with negative size");
}
- currentEntry = new ArArchiveEntry(temp, len,
- asInt(metaData, USER_ID_OFFSET,
USER_ID_LEN, true),
- asInt(metaData, GROUP_ID_OFFSET,
GROUP_ID_LEN, true),
- asInt(metaData, FILE_MODE_OFFSET,
FILE_MODE_LEN, 8),
- asLong(metaData,
LAST_MODIFIED_OFFSET, LAST_MODIFIED_LEN));
- return currentEntry;
+ try {
+ currentEntry = new ArArchiveEntry(temp, len,
+ asInt(metaData, USER_ID_OFFSET, USER_ID_LEN, true),
+ asInt(metaData, GROUP_ID_OFFSET, GROUP_ID_LEN, true),
+ asInt(metaData, FILE_MODE_OFFSET, FILE_MODE_LEN, 8),
+ asLong(metaData, LAST_MODIFIED_OFFSET, LAST_MODIFIED_LEN));
+ return currentEntry;
+ } catch (final NumberFormatException ex) {
+ throw new IOException("Broken archive, unable to parse entry
metadata fields as numbers", ex);
+ }
}
/*
@@ -389,7 +417,13 @@ public class ArArchiveInputStream extends
ArchiveInputStream<ArArchiveEntry> {
* @see #isGNUStringTable
*/
private ArArchiveEntry readGNUStringTable(final byte[] length, final int
offset, final int len) throws IOException {
- final int bufflen = asInt(length, offset, len); // Assume length will
fit in an int
+ int bufflen;
+ try {
+ bufflen = asInt(length, offset, len); // Assume length will fit in
an int
+ } catch (NumberFormatException ex) {
+ throw new IOException("Broken archive, unable to parse GNU string
table length field as a number", ex);
+ }
+
namebuffer = IOUtils.readRange(input, bufflen);
final int read = namebuffer.length;
trackReadBytes(read);
diff --git
a/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java
b/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java
index ae86a45c1..2b2bd7d3e 100644
---
a/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java
+++
b/src/test/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStreamTest.java
@@ -34,6 +34,8 @@ import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.utils.ArchiveUtils;
import org.apache.commons.compress.utils.IOUtils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
public class ArArchiveInputStreamTest extends AbstractTest {
@@ -134,4 +136,31 @@ public class ArArchiveInputStreamTest extends AbstractTest
{
assertEquals(-1, archive.read());
}
}
+
+ @ParameterizedTest
+ @ValueSource(strings = {"bad_group.ar", "bad_length.ar",
"bad_modified.ar", "bad_user.ar"})
+ public void testInvalidNumericFields(final String testFileName) throws
Exception {
+ try (InputStream in =
newInputStream("org/apache/commons/compress/ar/number_parsing/" + testFileName);
+ ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
+ assertThrows(IOException.class, archive::getNextEntry);
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"bad_long_namelen_bsd.ar",
"bad_long_namelen_gnu1.ar", "bad_long_namelen_gnu2.ar",
"bad_long_namelen_gnu3.ar", "bad_table_length_gnu.ar"})
+ public void testInvalidLongNameLength(final String testFileName) throws
Exception {
+ try (InputStream in =
newInputStream("org/apache/commons/compress/ar/number_parsing/" + testFileName);
+ ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
+ assertThrows(IOException.class, archive::getNextEntry);
+ }
+ }
+
+ @Test
+ public void testInvalidBadTableLength() throws Exception {
+ try (InputStream in =
newInputStream("org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu.ar");
+ ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
+ assertThrows(IOException.class, archive::getNextEntry);
+ }
+ }
+
}
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_group.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_group.ar
new file mode 100644
index 000000000..1cffcf1b3
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_group.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/0 1454693980 1000 1.23 100664 14 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_length.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_length.ar
new file mode 100644
index 000000000..259991876
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_length.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/0 1454693980 1000 1000 100664 1.23 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_bsd.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_bsd.ar
new file mode 100644
index 000000000..cd0f3b334
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_bsd.ar
@@ -0,0 +1,5 @@
+!<arch>
+#1/123456789012 1311256511 1000 1000 100644 42 `
+this_is_a_long_file_name.txtHello, world!
+#1/36 1454694016 1000 1000 100664 40 `
+this_is_a_long_file_name_as_well.txtBye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu1.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu1.ar
new file mode 100644
index 000000000..5779e549e
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu1.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/9999999999 1454693980 1000 1000 100664 14 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu2.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu2.ar
new file mode 100644
index 000000000..51e998d1f
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu2.ar
@@ -0,0 +1,6 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/29 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu3.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu3.ar
new file mode 100644
index 000000000..81a31e6db
Binary files /dev/null and
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_long_namelen_gnu3.ar
differ
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_modified.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_modified.ar
new file mode 100644
index 000000000..f4e12bbcd
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_modified.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/0 9e99999999 1000 1000 100664 14 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu.ar
new file mode 100644
index 000000000..9fd61f458
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 1.23 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/0 1454693980 1000 1000 100664 14 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye
diff --git
a/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_user.ar
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_user.ar
new file mode 100644
index 000000000..fc46fed87
--- /dev/null
+++
b/src/test/resources/org/apache/commons/compress/ar/number_parsing/bad_user.ar
@@ -0,0 +1,8 @@
+!<arch>
+// 68 `
+this_is_a_long_file_name.txt/
+this_is_a_long_file_name_as_well.txt/
+/0 1454693980 9e99 1000 100664 14 `
+Hello, world!
+/30 1454694016 1000 1000 100664 4 `
+Bye