Skip to content

Commit 4a11b61

Browse files
authored
Merge pull request #22998 from protocolbuffers/gberg-cp-32
Restore compatibility of runtime with pre-3.22.x gencode impacted by …
2 parents 72abf95 + adf556f commit 4a11b61

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

java/core/src/main/java/com/google/protobuf/GeneratedMessage.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@
3030
import java.util.ArrayList;
3131
import java.util.Arrays;
3232
import java.util.Collections;
33+
import java.util.HashSet;
3334
import java.util.Iterator;
3435
import java.util.List;
3536
import java.util.Map;
37+
import java.util.Set;
3638
import java.util.SortedMap;
3739
import java.util.TreeMap;
40+
import java.util.logging.Logger;
3841

3942
/**
4043
* All generated protocol message classes extend this class. This class implements most of the
@@ -52,6 +55,8 @@
5255
public abstract class GeneratedMessage extends AbstractMessage implements Serializable {
5356
private static final long serialVersionUID = 1L;
5457

58+
private static final Logger logger = Logger.getLogger(GeneratedMessage.class.getName());
59+
5560
/**
5661
* For testing. Allows a test to disable the optimization that avoids using field builders for
5762
* nested messages until they are requested. By disabling this optimization, existing tests can be
@@ -394,6 +399,59 @@ protected static IntList emptyIntList() {
394399
return IntArrayList.emptyList();
395400
}
396401

402+
static final String PRE22_GENCODE_SILENCE_PROPERTY =
403+
"com.google.protobuf.use_unsafe_pre22_gencode";
404+
static final String PRE22_GENCODE_ERROR_PROPERTY =
405+
"com.google.protobuf.error_on_unsafe_pre22_gencode";
406+
407+
static final String PRE22_GENCODE_VULNERABILITY_MESSAGE =
408+
"As of 2022/09/29 (release 21.7) makeExtensionsImmutable should not be called from protobuf"
409+
+ " gencode. If you are seeing this message, your gencode is vulnerable to a denial of"
410+
+ " service attack. You should regenerate your code using protobuf 25.6 or later. Use the"
411+
+ " latest version that meets your needs. However, if you understand the risks and wish"
412+
+ " to continue with vulnerable gencode, you can set the system property"
413+
+ " `-Dcom.google.protobuf.use_unsafe_pre22_gencode` on the command line to silence this"
414+
+ " warning. You also can set"
415+
+ " `-Dcom.google.protobuf.error_on_unsafe_pre22_gencode` to throw an error instead. See"
416+
+ " security vulnerability:"
417+
+ " https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-h4h5-3hr4-j3g2";
418+
419+
protected static final Set<String> loggedPre22TypeNames =
420+
Collections.synchronizedSet(new HashSet<String>());
421+
422+
static void warnPre22Gencode(Class<?> messageClass) {
423+
if (System.getProperty(PRE22_GENCODE_SILENCE_PROPERTY) != null) {
424+
return;
425+
}
426+
String messageName = messageClass.getName();
427+
String vulnerabilityMessage =
428+
"Vulnerable protobuf generated type in use: "
429+
+ messageName
430+
+ "\n"
431+
+ PRE22_GENCODE_VULNERABILITY_MESSAGE;
432+
433+
if (System.getProperty(PRE22_GENCODE_ERROR_PROPERTY) != null) {
434+
throw new UnsupportedOperationException(vulnerabilityMessage);
435+
}
436+
437+
if (!loggedPre22TypeNames.add(messageName)) {
438+
return;
439+
}
440+
441+
logger.warning(vulnerabilityMessage);
442+
}
443+
444+
/**
445+
* This method only exists as a shim for pre-22 gencode. This function is a no-op other than
446+
* warning or throwing an error for messages that are not extendable.
447+
*
448+
* @throws UnsupportedOperationException if the {@link #PRE22_GENCODE_ERROR_PROPERTY} system
449+
* property is set.
450+
*/
451+
protected void makeExtensionsImmutable() {
452+
warnPre22Gencode(getClass());
453+
}
454+
397455
protected static LongList emptyLongList() {
398456
return LongArrayList.emptyList();
399457
}
@@ -1037,6 +1095,16 @@ public boolean isInitialized() {
10371095
return super.isInitialized() && extensionsAreInitialized();
10381096
}
10391097

1098+
/**
1099+
* This method only exists as a shim for pre-22 gencode (see {@link
1100+
* GeneratedMessage.warnPre22Gencode}.
1101+
*/
1102+
@Override
1103+
protected void makeExtensionsImmutable() {
1104+
GeneratedMessage.warnPre22Gencode(getClass());
1105+
extensions.makeImmutable();
1106+
}
1107+
10401108
/**
10411109
* Used by subclasses to serialize extensions. Extension ranges may be interleaved with field
10421110
* numbers, but we must write them in canonical (sorted by field number) order.

java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,4 +1976,104 @@ public void getAllFields_repeatedFieldsAreNotMutable() {
19761976
builder.clearField(repeatedMsgField);
19771977
assertThat(list).hasSize(1);
19781978
}
1979+
1980+
private TestUtil.TestLogHandler setupLogger() {
1981+
TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
1982+
Logger logger = Logger.getLogger(GeneratedMessage.class.getName());
1983+
logger.addHandler(logHandler);
1984+
logHandler.setLevel(Level.ALL);
1985+
return logHandler;
1986+
}
1987+
1988+
static class TestMessageBaseForPre22WarningsTests extends GeneratedMessage {
1989+
@Override
1990+
protected FieldAccessorTable internalGetFieldAccessorTable() {
1991+
return null;
1992+
}
1993+
1994+
@Override
1995+
protected Message.Builder newBuilderForType(BuilderParent parent) {
1996+
return null;
1997+
}
1998+
1999+
@Override
2000+
public Message.Builder newBuilderForType() {
2001+
return null;
2002+
}
2003+
2004+
@Override
2005+
public Message.Builder toBuilder() {
2006+
return null;
2007+
}
2008+
2009+
@Override
2010+
public Message getDefaultInstanceForType() {
2011+
return null;
2012+
}
2013+
}
2014+
2015+
@Test
2016+
public void generatedMessage_makeExtensionsImmutableShouldLog() {
2017+
TestUtil.TestLogHandler logHandler = setupLogger();
2018+
GeneratedMessage.loggedPre22TypeNames.clear();
2019+
2020+
class TestMessage1 extends TestMessageBaseForPre22WarningsTests {}
2021+
class TestMessage2 extends TestMessageBaseForPre22WarningsTests {}
2022+
2023+
TestMessage1 msg = new TestMessage1();
2024+
TestMessage2 msg2 = new TestMessage2();
2025+
2026+
msg.makeExtensionsImmutable();
2027+
List<LogRecord> logs = logHandler.getStoredLogRecords();
2028+
assertThat(logs).hasSize(1);
2029+
String message = logs.get(0).getMessage();
2030+
// The generated type
2031+
assertThat(message)
2032+
.contains(
2033+
"Vulnerable protobuf generated type in use: "
2034+
+ "com.google.protobuf.GeneratedMessageTest$1TestMessage1");
2035+
assertThat(message).contains(GeneratedMessage.PRE22_GENCODE_VULNERABILITY_MESSAGE);
2036+
assertThat(message).contains(GeneratedMessage.PRE22_GENCODE_SILENCE_PROPERTY);
2037+
2038+
// Subsequent calls for the same type do not log again.
2039+
msg.makeExtensionsImmutable();
2040+
assertThat(logHandler.getStoredLogRecords()).hasSize(1);
2041+
2042+
// A call on a second type does log for that type.
2043+
msg2.makeExtensionsImmutable();
2044+
assertThat(logHandler.getStoredLogRecords()).hasSize(2);
2045+
// And not again (only once per type).
2046+
msg2.makeExtensionsImmutable();
2047+
assertThat(logHandler.getStoredLogRecords()).hasSize(2);
2048+
}
2049+
2050+
@Test
2051+
public void extendableMessage_makeExtensionsImmutableShouldThrowWhenOptedIn() {
2052+
System.setProperty("com.google.protobuf.error_on_unsafe_pre22_gencode", "true");
2053+
GeneratedMessage.loggedPre22TypeNames.clear();
2054+
2055+
class TestMessage3 extends TestMessageBaseForPre22WarningsTests {}
2056+
TestMessage3 msg = new TestMessage3();
2057+
assertThrows(UnsupportedOperationException.class, msg::makeExtensionsImmutable);
2058+
2059+
// When opting into throwing, it should throw every time, not just the first time.
2060+
assertThrows(UnsupportedOperationException.class, msg::makeExtensionsImmutable);
2061+
assertThrows(UnsupportedOperationException.class, msg::makeExtensionsImmutable);
2062+
2063+
System.clearProperty("com.google.protobuf.error_on_unsafe_pre22_gencode");
2064+
}
2065+
2066+
@Test
2067+
public void extendableMessage_makeExtensionsImmutableShouldBeSilentWhenOptedIn() {
2068+
System.setProperty("com.google.protobuf.use_unsafe_pre22_gencode", "true");
2069+
TestUtil.TestLogHandler logHandler = setupLogger();
2070+
GeneratedMessage.loggedPre22TypeNames.clear();
2071+
2072+
class TestMessage4 extends TestMessageBaseForPre22WarningsTests {}
2073+
TestMessage4 msg = new TestMessage4();
2074+
msg.makeExtensionsImmutable();
2075+
assertThat(logHandler.getStoredLogRecords()).isEmpty();
2076+
2077+
System.clearProperty("com.google.protobuf.use_unsafe_pre22_gencode");
2078+
}
19792079
}

0 commit comments

Comments
 (0)