Skip to content

Commit 680edfa

Browse files
authored
GH-3168: Restrict trusted packages in the parquet-avro module (#3169)
1 parent d639b06 commit 680edfa

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

parquet-avro/src/main/java/org/apache/parquet/avro/AvroConverters.java

+39
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.lang.reflect.Constructor;
2222
import java.lang.reflect.InvocationTargetException;
2323
import java.nio.ByteBuffer;
24+
import java.util.Arrays;
25+
import java.util.List;
2426
import org.apache.avro.Schema;
2527
import org.apache.avro.generic.GenericData;
2628
import org.apache.avro.util.Utf8;
@@ -34,6 +36,15 @@
3436

3537
public class AvroConverters {
3638

39+
public static final String[] SERIALIZABLE_PACKAGES;
40+
41+
static {
42+
SERIALIZABLE_PACKAGES = System.getProperty(
43+
"org.apache.parquet.avro.SERIALIZABLE_PACKAGES",
44+
"java.lang,java.math,java.io,java.net,org.apache.parquet.avro")
45+
.split(",");
46+
}
47+
3748
public abstract static class AvroGroupConverter extends GroupConverter {
3849
protected final ParentValueContainer parent;
3950

@@ -261,6 +272,7 @@ static final class FieldStringableConverter extends BinaryConverter<Object> {
261272

262273
public FieldStringableConverter(ParentValueContainer parent, Class<?> stringableClass) {
263274
super(parent);
275+
checkSecurity(stringableClass);
264276
stringableName = stringableClass.getName();
265277
try {
266278
this.ctor = stringableClass.getConstructor(String.class);
@@ -277,6 +289,33 @@ public Object convert(Binary binary) {
277289
throw new ParquetDecodingException("Cannot convert binary to " + stringableName, e);
278290
}
279291
}
292+
293+
private void checkSecurity(Class<?> clazz) throws SecurityException {
294+
List<String> trustedPackages = Arrays.asList(SERIALIZABLE_PACKAGES);
295+
296+
boolean trustAllPackages = trustedPackages.size() == 1 && "*".equals(trustedPackages.get(0));
297+
if (trustAllPackages || clazz.isPrimitive()) {
298+
return;
299+
}
300+
301+
boolean found = false;
302+
Package thePackage = clazz.getPackage();
303+
if (thePackage != null) {
304+
for (String trustedPackage : trustedPackages) {
305+
if (thePackage.getName().equals(trustedPackage)
306+
|| thePackage.getName().startsWith(trustedPackage + ".")) {
307+
found = true;
308+
break;
309+
}
310+
}
311+
if (!found) {
312+
throw new SecurityException("Forbidden " + clazz
313+
+ "! This class is not trusted to be included in Avro schema using java-class."
314+
+ " Please set org.apache.parquet.avro.SERIALIZABLE_PACKAGES system property"
315+
+ " with the packages you trust.");
316+
}
317+
}
318+
}
280319
}
281320

282321
static final class FieldEnumConverter extends BinaryConverter<Object> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.parquet;
20+
21+
public class UntrustedStringableClass {
22+
private final String value;
23+
24+
public UntrustedStringableClass(String value) {
25+
this.value = value;
26+
}
27+
28+
@Override
29+
public String toString() {
30+
return this.value;
31+
}
32+
}

parquet-avro/src/test/java/org/apache/parquet/avro/TestReflectReadWrite.java

+35
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.apache.avro.util.Utf8;
3838
import org.apache.hadoop.conf.Configuration;
3939
import org.apache.hadoop.fs.Path;
40+
import org.apache.parquet.UntrustedStringableClass;
4041
import org.apache.parquet.hadoop.ParquetReader;
4142
import org.apache.parquet.hadoop.ParquetWriter;
4243
import org.apache.parquet.hadoop.metadata.CompressionCodecName;
@@ -76,6 +77,40 @@ public void testWriteReflectReadGeneric() throws IOException {
7677
}
7778
}
7879

80+
@Test(expected = SecurityException.class)
81+
public void testUntrustedStringableClass() {
82+
new AvroConverters.FieldStringableConverter(
83+
new ParentValueContainer() {
84+
@Override
85+
public void add(Object value) {}
86+
87+
@Override
88+
public void addBoolean(boolean value) {}
89+
90+
@Override
91+
public void addInt(int value) {}
92+
93+
@Override
94+
public void addLong(long value) {}
95+
96+
@Override
97+
public void addFloat(float value) {}
98+
99+
@Override
100+
public void addDouble(double value) {}
101+
102+
@Override
103+
public void addChar(char value) {}
104+
105+
@Override
106+
public void addByte(byte value) {}
107+
108+
@Override
109+
public void addShort(short value) {}
110+
},
111+
UntrustedStringableClass.class);
112+
}
113+
79114
private GenericRecord getGenericPojoUtf8() {
80115
Schema schema = ReflectData.get().getSchema(Pojo.class);
81116
GenericData.Record record = new GenericData.Record(schema);

0 commit comments

Comments
 (0)