Otavio Goncalves de Santana created JOHNZON-190: ---------------------------------------------------
Summary: Issues when call close method more than twice using Queue as buffer strategy. Key: JOHNZON-190 URL: https://issues.apache.org/jira/browse/JOHNZON-190 Project: Johnzon Issue Type: Bug Components: JSON-B Affects Versions: 1.1.10 Reporter: Otavio Goncalves de Santana Title: Issues when calling the close method more than twice using Queue as a buffer strategy. Hello everyone. I would like to report a bug within JsonGeneratorImpl. In the JsonGeneratorImpl has the BufferStrategy.BufferProvider<char[]> as an attribute. This BufferStrategy.BufferProvider either [put the buffer in the Queue|https://github.com/apache/johnzon/blob/d7a4a2f9de8c39b84fbb8b73b13c6f7f6514a9cf/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java#L466], whose uses the release *method*, and [feed|https://github.com/apache/johnzon/blob/d7a4a2f9de8c39b84fbb8b73b13c6f7f6514a9cf/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java#L72] the buffer using the *newBuffer* method. As consequences of this behavior there are two failures: # Waste of memory issue The code below, it will put the same value in the queue six times. {code:java} public class App { public static void main(String[] args) throws IOException { Path path = Paths.get("generated.json"); OutputStream out = Files.newOutputStream(path); JsonGenerator jsonGen = Json.createGenerator(out); jsonGen.writeStartObject(); jsonGen.write("false", JsonValue.FALSE); jsonGen.write("true", JsonValue.TRUE); jsonGen.writeEnd(); jsonGen.close(); jsonGen.close(); jsonGen.close(); jsonGen.close(); jsonGen.close(); jsonGen.close(); } } {code} Doing a malicious code such as below, it will use a huge number of memory. {code:java} public class App1 { public static void main(String[] args) throws IOException { Path path = Paths.get("generated.json"); OutputStream out = Files.newOutputStream(path); JsonGenerator jsonGen = Json.createGenerator(out); jsonGen.writeStartObject(); jsonGen.write("false", JsonValue.FALSE); jsonGen.write("true", JsonValue.TRUE); jsonGen.writeEnd(); while (true) { jsonGen.close(); } } } {code} # The security issue It uses the value in the queue as a buffer; thereby, it is a security failure once a request can read information from another application, thus, an isolation issue. {code:java} public class App2 { public static void main(String[] args) throws Exception { Path path = Paths.get("generated2.json"); OutputStream out = Files.newOutputStream(path); JsonGenerator jsonGen = Json.createGenerator(out); jsonGen.writeStartObject(); jsonGen.write("keyA", JsonValue.FALSE); jsonGen.write("keyB", JsonValue.TRUE); jsonGen.writeEnd(); jsonGen.close(); Path path3 = Paths.get("generated3.json"); OutputStream out2 = Files.newOutputStream(path3); JsonGenerator jsonGen2 = Json.createGenerator(out2); jsonGen2.writeStartObject(); Field fieldBuffer = jsonGen2.getClass().getDeclaredField("buffer"); fieldBuffer.setAccessible(true); char[] buffer = (char[]) fieldBuffer.get(jsonGen); String json = String.valueOf(buffer); System.out.println(json); jsonGen2.flush(); } } {code} # Race condition issue: As the code below shows, given a mistake of twice close, To class can write using the same buffer, thereby, a write JSON mistake. {code:java} public class App3 { public static void main(String[] args) throws IOException { Path path = Paths.get("generated.json"); OutputStream out = Files.newOutputStream(path); JsonGenerator jsonGen = Json.createGenerator(out); jsonGen.writeStartObject(); jsonGen.write("false", JsonValue.FALSE); jsonGen.write("true", JsonValue.TRUE); jsonGen.writeEnd(); jsonGen.close(); jsonGen.close(); Path path2 = Paths.get("generated2.json"); OutputStream out2 = Files.newOutputStream(path2); JsonGenerator jsonGen2 = Json.createGenerator(out2); Path path3 = Paths.get("generated3.json"); OutputStream out3 = Files.newOutputStream(path3); JsonGenerator jsonGen3 = Json.createGenerator(out3); jsonGen2.writeStartObject(); jsonGen2.write("false1", JsonValue.FALSE); jsonGen2.write("true2", JsonValue.TRUE); jsonGen2.writeEnd(); jsonGen3.writeStartObject(); jsonGen3.write("false3", JsonValue.FALSE); jsonGen3.write("true4", JsonValue.TRUE); jsonGen3.writeEnd(); jsonGen2.close(); jsonGen3.close(); } } {code} Output {code:json} Generated.json: {"false":false,"true":true} Generated2.json: {"false3":false,"true4":true} Generated3.json: {"false3":false,"true4":true} {code} -- This message was sent by Atlassian JIRA (v7.6.3#76005)