diff --git a/CVE-2023-2976-pre.patch b/CVE-2023-2976-pre.patch new file mode 100644 index 0000000..28f161f --- /dev/null +++ b/CVE-2023-2976-pre.patch @@ -0,0 +1,186 @@ +From 364aed58e083e305f3f9ffc5bcacf9536f2472ab Mon Sep 17 00:00:00 2001 +From: cpovirk +Date: Tue, 25 Apr 2023 10:00:41 -0700 +Subject: [PATCH] Split the tests for `Files.createTempDir` into a separate + file. + +This makes it easier to run them a second time under a newer Android emulator in our internal tests. + +RELNOTES=n/a +PiperOrigin-RevId: 526998248 + +Origin: https://github.com/google/guava/commit/364aed58e083e305f3f9ffc5bcacf9536f2472ab + +--- + .../common/io/FilesCreateTempDirTest.java | 37 +++++++++++++++++ + .../test/com/google/common/io/FilesTest.java | 15 +++---- + .../common/annotations/J2ktIncompatible.java | 31 ++++++++++++++ + .../io/ElementTypesAreNonnullByDefault.java | 41 +++++++++++++++++++ + 4 files changed, 115 insertions(+), 9 deletions(-) + create mode 100644 guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java + create mode 100644 guava/src/com/google/common/annotations/J2ktIncompatible.java + create mode 100644 guava/src/com/google/common/io/ElementTypesAreNonnullByDefault.java + +diff --git a/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java b/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java +new file mode 100644 +index 0000000..557689e +--- /dev/null ++++ b/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (C) 2007 The Guava Authors ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.google.common.io; ++ ++import static com.google.common.truth.Truth.assertThat; ++ ++import java.io.File; ++ ++/** ++ * Unit test for {@link Files#createTempDir}. ++ * ++ * @author Chris Nokleberg ++ */ ++ ++public class FilesCreateTempDirTest extends IoTestCase { ++ public void testCreateTempDir() { ++ File temp = Files.createTempDir(); ++ assertTrue(temp.exists()); ++ assertTrue(temp.isDirectory()); ++ assertThat(temp.listFiles()).isEmpty(); ++ assertTrue(temp.delete()); ++ } ++} +diff --git a/guava-tests/test/com/google/common/io/FilesTest.java b/guava-tests/test/com/google/common/io/FilesTest.java +index e987f60..d552e0f 100644 +--- a/guava-tests/test/com/google/common/io/FilesTest.java ++++ b/guava-tests/test/com/google/common/io/FilesTest.java +@@ -43,7 +43,12 @@ import junit.framework.TestSuite; + /** + * Unit test for {@link Files}. + * +- *

Note: {@link Files#fileTraverser()} is tested in {@link FilesFileTraverserTest}. ++ *

Some methods are tested in separate files: ++ * ++ *

+ * + * @author Chris Nokleberg + */ +@@ -358,14 +363,6 @@ public class FilesTest extends IoTestCase { + } + } + +- public void testCreateTempDir() { +- File temp = Files.createTempDir(); +- assertTrue(temp.exists()); +- assertTrue(temp.isDirectory()); +- assertThat(temp.listFiles()).isEmpty(); +- assertTrue(temp.delete()); +- } +- + public void testMove() throws IOException { + File i18nFile = getTestFile("i18n.txt"); + File temp1 = createTempFile(); +diff --git a/guava/src/com/google/common/annotations/J2ktIncompatible.java b/guava/src/com/google/common/annotations/J2ktIncompatible.java +new file mode 100644 +index 0000000..6e28d02 +--- /dev/null ++++ b/guava/src/com/google/common/annotations/J2ktIncompatible.java +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2009 The Guava Authors ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except ++ * in compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software distributed under the License ++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express ++ * or implied. See the License for the specific language governing permissions and limitations under ++ * the License. ++ */ ++ ++package com.google.common.annotations; ++ ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++ ++/** ++ * The presence of this annotation on an API indicates that the method may not be used with ++ * J2kt. ++ * ++ * @since NEXT ++ */ ++@Retention(RetentionPolicy.CLASS) ++@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) ++@GwtCompatible ++public @interface J2ktIncompatible {} +diff --git a/guava/src/com/google/common/io/ElementTypesAreNonnullByDefault.java b/guava/src/com/google/common/io/ElementTypesAreNonnullByDefault.java +new file mode 100644 +index 0000000..48bc10f +--- /dev/null ++++ b/guava/src/com/google/common/io/ElementTypesAreNonnullByDefault.java +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (C) 2021 The Guava Authors ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.google.common.io; ++ ++import static java.lang.annotation.ElementType.FIELD; ++import static java.lang.annotation.ElementType.METHOD; ++import static java.lang.annotation.ElementType.PARAMETER; ++import static java.lang.annotation.ElementType.TYPE; ++import static java.lang.annotation.RetentionPolicy.RUNTIME; ++ ++import com.google.common.annotations.GwtCompatible; ++import java.lang.annotation.Retention; ++import java.lang.annotation.Target; ++import javax.annotation.Nonnull; ++import javax.annotation.meta.TypeQualifierDefault; ++ ++/** ++ * Marks all "top-level" types as non-null in a way that is recognized by Kotlin. Note that this ++ * unfortunately includes type-variable usages, so we also provide {@link ParametricNullness} to ++ * "undo" it as best we can. ++ */ ++@GwtCompatible ++@Retention(RUNTIME) ++@Target(TYPE) ++@TypeQualifierDefault({FIELD, METHOD, PARAMETER}) ++@Nonnull ++@interface ElementTypesAreNonnullByDefault {} +-- +2.33.0 + diff --git a/CVE-2023-2976.patch b/CVE-2023-2976.patch new file mode 100644 index 0000000..654728c --- /dev/null +++ b/CVE-2023-2976.patch @@ -0,0 +1,517 @@ +From feb83a1c8fd2e7670b244d5afd23cba5aca43284 Mon Sep 17 00:00:00 2001 +From: cpovirk +Date: Thu, 25 May 2023 13:18:00 -0700 +Subject: [PATCH] Restrict permissions when creating temporary files and + directories, or fail if that's not possible. + +(Also, check that the provided `fileThreshold` is non-negative.) + +- Fixes https://github.com/google/guava/issues/2575 +- Fixes https://github.com/google/guava/issues/4011 + +RELNOTES=Reimplemented `Files.createTempDir` and `FileBackedOutputStream` to further address [CVE-2020-8908](https://github.com/google/guava/issues/4011) and [Guava issue #2575](https://github.com/google/guava/issues/2575) (CVE forthcoming). +PiperOrigin-RevId: 535359233 + +Refer: https://github.com/google/guava/commit/feb83a1c8fd2e7670b244d5afd23cba5aca43284 + +--- + .../common/io/FileBackedOutputStreamTest.java | 27 +++ + .../common/io/FilesCreateTempDirTest.java | 41 +++- + .../common/io/FileBackedOutputStream.java | 16 +- + guava/src/com/google/common/io/Files.java | 48 ++--- + .../common/io/IgnoreJRERequirement.java | 30 +++ + .../com/google/common/io/TempFileCreator.java | 176 ++++++++++++++++++ + 6 files changed, 302 insertions(+), 36 deletions(-) + create mode 100644 guava/src/com/google/common/io/IgnoreJRERequirement.java + create mode 100644 guava/src/com/google/common/io/TempFileCreator.java + +diff --git a/guava-tests/test/com/google/common/io/FileBackedOutputStreamTest.java b/guava-tests/test/com/google/common/io/FileBackedOutputStreamTest.java +index 66558e9..db74f32 100644 +--- a/guava-tests/test/com/google/common/io/FileBackedOutputStreamTest.java ++++ b/guava-tests/test/com/google/common/io/FileBackedOutputStreamTest.java +@@ -16,10 +16,18 @@ + + package com.google.common.io; + ++import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; ++import static com.google.common.truth.Truth.assertThat; ++import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; ++import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; ++import static org.junit.Assert.assertThrows; ++ + import com.google.common.testing.GcFinalization; + import java.io.File; + import java.io.IOException; + import java.io.OutputStream; ++import java.nio.file.attribute.PosixFileAttributeView; ++import java.nio.file.attribute.PosixFileAttributes; + import java.util.Arrays; + + /** +@@ -59,10 +67,21 @@ public class FileBackedOutputStreamTest extends IoTestCase { + + // Write data to go over the threshold + if (chunk2 > 0) { ++ if (JAVA_IO_TMPDIR.value().equals("/sdcard")) { ++ assertThrows(IOException.class, () -> write(out, data, chunk1, chunk2, singleByte)); ++ return; ++ } + write(out, data, chunk1, chunk2, singleByte); + file = out.getFile(); + assertEquals(dataSize, file.length()); + assertTrue(file.exists()); ++ assertThat(file.getName()).contains("FileBackedOutputStream"); ++ if (!isAndroid()) { ++ PosixFileAttributes attributes = ++ java.nio.file.Files.getFileAttributeView(file.toPath(), PosixFileAttributeView.class) ++ .readAttributes(); ++ assertThat(attributes.permissions()).containsExactly(OWNER_READ, OWNER_WRITE); ++ } + } + out.close(); + +@@ -129,6 +148,10 @@ public class FileBackedOutputStreamTest extends IoTestCase { + FileBackedOutputStream out = new FileBackedOutputStream(50); + ByteSource source = out.asByteSource(); + ++ if (JAVA_IO_TMPDIR.value().equals("/sdcard")) { ++ assertThrows(IOException.class, () -> out.write(data)); ++ return; ++ } + out.write(data); + assertTrue(Arrays.equals(data, source.read())); + +@@ -160,4 +183,8 @@ public class FileBackedOutputStreamTest extends IoTestCase { + + out.close(); + } ++ ++ private static boolean isAndroid() { ++ return System.getProperty("java.runtime.name", "").contains("Android"); ++ } + } +diff --git a/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java b/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java +index 557689e..62098ef 100644 +--- a/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java ++++ b/guava-tests/test/com/google/common/io/FilesCreateTempDirTest.java +@@ -16,9 +16,18 @@ + + package com.google.common.io; + ++import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; + import static com.google.common.truth.Truth.assertThat; ++import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE; ++import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; ++import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; ++import static org.junit.Assert.assertThrows; + + import java.io.File; ++import java.io.IOException; ++import java.nio.file.attribute.PosixFileAttributeView; ++import java.nio.file.attribute.PosixFileAttributes; ++import junit.framework.TestCase; + + /** + * Unit test for {@link Files#createTempDir}. +@@ -26,12 +35,32 @@ import java.io.File; + * @author Chris Nokleberg + */ + +-public class FilesCreateTempDirTest extends IoTestCase { +- public void testCreateTempDir() { ++@SuppressWarnings("deprecation") // tests of a deprecated method ++public class FilesCreateTempDirTest extends TestCase { ++ public void testCreateTempDir() throws IOException { ++ if (JAVA_IO_TMPDIR.value().equals("/sdcard")) { ++ assertThrows(IllegalStateException.class, Files::createTempDir); ++ return; ++ } + File temp = Files.createTempDir(); +- assertTrue(temp.exists()); +- assertTrue(temp.isDirectory()); +- assertThat(temp.listFiles()).isEmpty(); +- assertTrue(temp.delete()); ++ try { ++ assertTrue(temp.exists()); ++ assertTrue(temp.isDirectory()); ++ assertThat(temp.listFiles()).isEmpty(); ++ ++ if (isAndroid()) { ++ return; ++ } ++ PosixFileAttributes attributes = ++ java.nio.file.Files.getFileAttributeView(temp.toPath(), PosixFileAttributeView.class) ++ .readAttributes(); ++ assertThat(attributes.permissions()).containsExactly(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE); ++ } finally { ++ assertTrue(temp.delete()); ++ } ++ } ++ ++ private static boolean isAndroid() { ++ return System.getProperty("java.runtime.name", "").contains("Android"); + } + } +diff --git a/guava/src/com/google/common/io/FileBackedOutputStream.java b/guava/src/com/google/common/io/FileBackedOutputStream.java +index b002561..23d427c 100644 +--- a/guava/src/com/google/common/io/FileBackedOutputStream.java ++++ b/guava/src/com/google/common/io/FileBackedOutputStream.java +@@ -14,6 +14,8 @@ + + package com.google.common.io; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import com.google.common.annotations.Beta; + import com.google.common.annotations.GwtIncompatible; + import com.google.common.annotations.VisibleForTesting; +@@ -31,6 +33,14 @@ import java.io.OutputStream; + * An {@link OutputStream} that starts buffering to a byte array, but switches to file buffering + * once the data reaches a configurable size. + * ++ *

When this stream creates a temporary file, it restricts the file's permissions to the current ++ * user or, in the case of Android, the current app. If that is not possible (as is the case under ++ * the very old Android Ice Cream Sandwich release), then this stream throws an exception instead of ++ * creating a file that would be more accessible. (This behavior is new in Guava 32.0.0. Previous ++ * versions would create a file that is more accessible, as discussed in Guava issue 2575. TODO: b/283778848 - Fill ++ * in CVE number once it's available.) ++ * + *

This class is thread-safe. + * + * @author Chris Nokleberg +@@ -70,6 +80,7 @@ public final class FileBackedOutputStream extends OutputStream { + * {@link ByteSource} returned by {@link #asByteSource} is finalized. + * + * @param fileThreshold the number of bytes before the stream should switch to buffering to a file ++ * @throws IllegalArgumentException if {@code fileThreshold} is negative + */ + public FileBackedOutputStream(int fileThreshold) { + this(fileThreshold, false); +@@ -82,8 +93,11 @@ public final class FileBackedOutputStream extends OutputStream { + * @param fileThreshold the number of bytes before the stream should switch to buffering to a file + * @param resetOnFinalize if true, the {@link #reset} method will be called when the {@link + * ByteSource} returned by {@link #asByteSource} is finalized ++ * @throws IllegalArgumentException if {@code fileThreshold} is negative + */ + public FileBackedOutputStream(int fileThreshold, boolean resetOnFinalize) { ++ checkArgument( ++ fileThreshold >= 0, "fileThreshold must be non-negative, but was %s", fileThreshold); + this.fileThreshold = fileThreshold; + this.resetOnFinalize = resetOnFinalize; + memory = new MemoryOutput(); +@@ -193,7 +207,7 @@ public final class FileBackedOutputStream extends OutputStream { + */ + private void update(int len) throws IOException { + if (file == null && (memory.getCount() + len > fileThreshold)) { +- File temp = File.createTempFile("FileBackedOutputStream", null); ++ File temp = TempFileCreator.INSTANCE.createTempFile("FileBackedOutputStream"); + if (resetOnFinalize) { + // Finalizers are not guaranteed to be called on system shutdown; + // this is insurance. +diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java +index b0c4390..a2ef1d0 100644 +--- a/guava/src/com/google/common/io/Files.java ++++ b/guava/src/com/google/common/io/Files.java +@@ -67,9 +67,6 @@ import java.util.List; + @GwtIncompatible + public final class Files { + +- /** Maximum loop count when creating temp directories. */ +- private static final int TEMP_DIR_ATTEMPTS = 10000; +- + private Files() {} + + /** +@@ -380,17 +377,19 @@ public final class Files { + * Atomically creates a new directory somewhere beneath the system's temporary directory (as + * defined by the {@code java.io.tmpdir} system property), and returns its name. + * ++ *

The temporary directory is created with permissions restricted to the current user or, in ++ * the case of Android, the current app. If that is not possible (as is the case under the very ++ * old Android Ice Cream Sandwich release), then this method throws an exception instead of ++ * creating a directory that would be more accessible. (This behavior is new in Guava 32.0.0. ++ * Previous versions would create a directory that is more accessible, as discussed in CVE-2020-8908.) ++ * + *

Use this method instead of {@link File#createTempFile(String, String)} when you wish to + * create a directory, not a regular file. A common pitfall is to call {@code createTempFile}, + * delete the file and create a directory in its place, but this leads a race condition which can + * be exploited to create security vulnerabilities, especially when executable files are to be + * written into the directory. + * +- *

Depending on the environmment that this code is run in, the system temporary directory (and +- * thus the directory this method creates) may be more visible that a program would like - files +- * written to this directory may be read or overwritten by hostile programs running on the same +- * machine. +- * + *

This method assumes that the temporary volume is writable, has free inodes and free blocks, + * and that it will not be called thousands of times per second. + * +@@ -399,33 +398,24 @@ public final class Files { + * + * @return the newly-created directory + * @throws IllegalStateException if the directory could not be created ++ * @throws UnsupportedOperationException if the system does not support creating temporary ++ * directories securely + * @deprecated For Android users, see the Data and File + * Storage overview to select an appropriate temporary directory (perhaps {@code +- * context.getCacheDir()}). For developers on Java 7 or later, use {@link +- * java.nio.file.Files#createTempDirectory}, transforming it to a {@link File} using {@link +- * java.nio.file.Path#toFile() toFile()} if needed. ++ * context.getCacheDir()}), and create your own directory under that. (For example, you might ++ * use {@code new File(context.getCacheDir(), "directoryname").mkdir()}, or, if you need an ++ * arbitrary number of temporary directories, you might have to generate multiple directory ++ * names in a loop until {@code mkdir()} returns {@code true}.) For developers on Java 7 or ++ * later, use {@link java.nio.file.Files#createTempDirectory}, transforming it to a {@link ++ * File} using {@link java.nio.file.Path#toFile() toFile()} if needed. To restrict permissions ++ * as this method does, pass {@code ++ * PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------"))} to your ++ * call to {@code createTempDirectory}. + */ + @Deprecated + public static File createTempDir() { +- File baseDir = new File(System.getProperty("java.io.tmpdir")); +- String baseName = System.currentTimeMillis() + "-"; +- +- for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { +- File tempDir = new File(baseDir, baseName + counter); +- if (tempDir.mkdir()) { +- return tempDir; +- } +- } +- throw new IllegalStateException( +- "Failed to create directory within " +- + TEMP_DIR_ATTEMPTS +- + " attempts (tried " +- + baseName +- + "0 to " +- + baseName +- + (TEMP_DIR_ATTEMPTS - 1) +- + ')'); ++ return TempFileCreator.INSTANCE.createTempDir(); + } + + /** +diff --git a/guava/src/com/google/common/io/IgnoreJRERequirement.java b/guava/src/com/google/common/io/IgnoreJRERequirement.java +new file mode 100644 +index 0000000..b1b8e10 +--- /dev/null ++++ b/guava/src/com/google/common/io/IgnoreJRERequirement.java +@@ -0,0 +1,30 @@ ++/* ++ * Copyright 2019 The Guava Authors ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except ++ * in compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software distributed under the License ++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express ++ * or implied. See the License for the specific language governing permissions and limitations under ++ * the License. ++ */ ++ ++package com.google.common.io; ++ ++import static java.lang.annotation.ElementType.CONSTRUCTOR; ++import static java.lang.annotation.ElementType.METHOD; ++import static java.lang.annotation.ElementType.TYPE; ++ ++import java.lang.annotation.Target; ++ ++/** ++ * Disables Animal Sniffer's checking of compatibility with older versions of Java/Android. ++ * ++ *

Each package's copy of this annotation needs to be listed in our {@code pom.xml}. ++ */ ++@Target({METHOD, CONSTRUCTOR, TYPE}) ++@ElementTypesAreNonnullByDefault ++@interface IgnoreJRERequirement {} +diff --git a/guava/src/com/google/common/io/TempFileCreator.java b/guava/src/com/google/common/io/TempFileCreator.java +new file mode 100644 +index 0000000..103427a +--- /dev/null ++++ b/guava/src/com/google/common/io/TempFileCreator.java +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (C) 2007 The Guava Authors ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except ++ * in compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software distributed under the License ++ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express ++ * or implied. See the License for the specific language governing permissions and limitations under ++ * the License. ++ */ ++ ++package com.google.common.io; ++ ++import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; ++ ++import com.google.common.annotations.GwtIncompatible; ++import com.google.common.annotations.J2ktIncompatible; ++import com.google.j2objc.annotations.J2ObjCIncompatible; ++import java.io.File; ++import java.io.IOException; ++import java.nio.file.Paths; ++import java.nio.file.attribute.FileAttribute; ++import java.nio.file.attribute.PosixFilePermission; ++import java.nio.file.attribute.PosixFilePermissions; ++import java.util.Set; ++ ++/** ++ * Creates temporary files and directories whose permissions are restricted to the current user or, ++ * in the case of Android, the current app. If that is not possible (as is the case under the very ++ * old Android Ice Cream Sandwich release), then this class throws an exception instead of creating ++ * a file or directory that would be more accessible. ++ */ ++@J2ktIncompatible ++@GwtIncompatible ++@J2ObjCIncompatible ++@ElementTypesAreNonnullByDefault ++abstract class TempFileCreator { ++ static final TempFileCreator INSTANCE = pickSecureCreator(); ++ ++ /** ++ * @throws IllegalStateException if the directory could not be created (to implement the contract ++ * of {@link Files#createTempDir()} ++ * @throws UnsupportedOperationException if the system does not support creating temporary ++ * directories securely ++ */ ++ abstract File createTempDir(); ++ ++ abstract File createTempFile(String prefix) throws IOException; ++ ++ private static TempFileCreator pickSecureCreator() { ++ try { ++ Class.forName("java.nio.file.Path"); ++ return new JavaNioCreator(); ++ } catch (ClassNotFoundException runningUnderAndroid) { ++ // Try another way. ++ } ++ ++ try { ++ int version = ((Integer) Class.forName("android.os.Build$VERSION").getField("SDK_INT").get(null)).intValue(); ++ int jellyBean = ++ ((Integer) Class.forName("android.os.Build$VERSION_CODES").getField("JELLY_BEAN").get(null)).intValue(); ++ /* ++ * I assume that this check can't fail because JELLY_BEAN will be present only if we're ++ * running under Jelly Bean or higher. But it seems safest to check. ++ */ ++ if (version < jellyBean) { ++ return new ThrowingCreator(); ++ } ++ ++ // Don't merge these catch() blocks, let alone use ReflectiveOperationException directly: ++ // b/65343391 ++ } catch (NoSuchFieldException e) { ++ // The JELLY_BEAN field doesn't exist because we're running on a version before Jelly Bean :) ++ return new ThrowingCreator(); ++ } catch (ClassNotFoundException e) { ++ // Should be impossible, but we want to return *something* so that class init succeeds. ++ return new ThrowingCreator(); ++ } catch (IllegalAccessException e) { ++ // ditto ++ return new ThrowingCreator(); ++ } ++ ++ // Android isolates apps' temporary directories since Jelly Bean: ++ // https://github.com/google/guava/issues/4011#issuecomment-770020802 ++ // So we can create files there with any permissions and still get security from the isolation. ++ return new JavaIoCreator(); ++ } ++ ++ @IgnoreJRERequirement // used only when Path is available ++ private static final class JavaNioCreator extends TempFileCreator { ++ private static final FileAttribute> RWX_USER_ONLY = ++ PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")); ++ private static final FileAttribute> RW_USER_ONLY = ++ PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")); ++ ++ @Override ++ File createTempDir() { ++ try { ++ return java.nio.file.Files.createTempDirectory( ++ Paths.get(JAVA_IO_TMPDIR.value()), /* prefix= */ null, RWX_USER_ONLY) ++ .toFile(); ++ } catch (IOException e) { ++ throw new IllegalStateException("Failed to create directory", e); ++ } ++ } ++ ++ @Override ++ File createTempFile(String prefix) throws IOException { ++ return java.nio.file.Files.createTempFile( ++ Paths.get(JAVA_IO_TMPDIR.value()), ++ /* prefix= */ prefix, ++ /* suffix= */ null, ++ RW_USER_ONLY) ++ .toFile(); ++ } ++ } ++ ++ private static final class JavaIoCreator extends TempFileCreator { ++ @Override ++ File createTempDir() { ++ File baseDir = new File(JAVA_IO_TMPDIR.value()); ++ @SuppressWarnings("GoodTime") // reading system time without TimeSource ++ String baseName = System.currentTimeMillis() + "-"; ++ ++ for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { ++ File tempDir = new File(baseDir, baseName + counter); ++ if (tempDir.mkdir()) { ++ return tempDir; ++ } ++ } ++ throw new IllegalStateException( ++ "Failed to create directory within " ++ + TEMP_DIR_ATTEMPTS ++ + " attempts (tried " ++ + baseName ++ + "0 to " ++ + baseName ++ + (TEMP_DIR_ATTEMPTS - 1) ++ + ')'); ++ } ++ ++ @Override ++ File createTempFile(String prefix) throws IOException { ++ return File.createTempFile( ++ /* prefix= */ prefix, ++ /* suffix= */ null, ++ /* directory= */ null /* defaults to java.io.tmpdir */); ++ } ++ ++ /** Maximum loop count when creating temp directories. */ ++ private static final int TEMP_DIR_ATTEMPTS = 10000; ++ } ++ ++ private static final class ThrowingCreator extends TempFileCreator { ++ private static final String MESSAGE = ++ "Guava cannot securely create temporary files or directories under SDK versions before" ++ + " Jelly Bean. You can create one yourself, either in the insecure default directory" ++ + " or in a more secure directory, such as context.getCacheDir(). For more information," ++ + " see the Javadoc for Files.createTempDir()."; ++ ++ @Override ++ File createTempDir() { ++ throw new IllegalStateException(MESSAGE); ++ } ++ ++ @Override ++ File createTempFile(String prefix) throws IOException { ++ throw new IOException(MESSAGE); ++ } ++ } ++ ++ private TempFileCreator() {} ++} +-- +2.33.0 + diff --git a/guava.spec b/guava.spec index d8a16ea..2285999 100644 --- a/guava.spec +++ b/guava.spec @@ -1,6 +1,6 @@ Name: guava Version: 25.0 -Release: 5 +Release: 6 Summary: Google Core Libraries for Java License: ASL 2.0 and CC0 URL: https://github.com/google/guava @@ -8,6 +8,8 @@ BuildArch: noarch Source0: https://github.com/google/guava/archive/v%{version}.tar.gz Patch0000: CVE-2020-8908.patch +Patch0001: CVE-2023-2976-pre.patch +Patch0002: CVE-2023-2976.patch BuildRequires: maven-local mvn(com.google.code.findbugs:jsr305) mvn(junit:junit) BuildRequires: mvn(org.apache.felix:maven-bundle-plugin) mvn(org.sonatype.oss:oss-parent:pom:) @@ -87,6 +89,9 @@ find -name '*.java' | xargs sed -ri \ %files testlib -f .mfiles-guava-testlib %changelog +* Tue Jul 04 2023 wangkai <13474090681@163.com> - 25.0-6 +- Fix CVE-2023-2976 + * Fri Feb 19 2021 wangxiao - 25.0-5 - Fix CVE-2020-8908