RFR: 8321053: Use ByteArrayInputStream.buf directly when parameter of transferTo() is trusted [v2]
Brian Burkhalter
bpb at openjdk.org
Fri Dec 1 02:51:04 UTC 2023
On Fri, 1 Dec 2023 01:19:32 GMT, jmehrens <duke at openjdk.org> wrote:
>> Changed in 176d5165f7d8f3fa4814c9838abb5d18d9f3c338 not to trust `FilterOutputStream`s.
>
> The only other alternative would be to walk `((FilterOutputStream)out).out` and if everything in the out chain is in the "java." package then the out can be trusted.
>
> byte[] tmp = null;
> for (OutputStream os = out; os != null;) {
> if (os.getClass().getPackageName().startsWith("java.")) {
> if (os instanceof FilterOutputStream fos) {
> //loops in this chain is going to cause this code to never end.
> // self reference A -> A or transitive reference A -> B -> C ->A
> os = fos.out;
> continue;
> }
> break;
> }
>
> tmp = new byte[Integer.min(len, MAX_TRANSFER_SIZE)];
> break;
> }
>
> I don't like the approach of deny list, walking the chain as (subjectively) it seems too fragile.
>
> Also I think I can break this version of the code with ChannelOutputStream. I didn't run this through a compiler nor test it but the idea is that ChannelOutputStream calls ByteBuffer.wrap(bs) and doesn't call ByteBuffer.asReadOnlyBuffer. So a malicious WritableByteChannel should be able to gain access to the original array:
>
> WritableByteChannel wolf = new WritableByteChannel() {
> public int write(ByteBuffer src) throws IOException {
> src.array()[0] = '0'; //oh no!
> return 0;
> }
> };
>
> ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
> OutputStream wolfInSheepSuitAndTie = Channels.newOutputStream(wolf);
> bais.transferTo(wolfInSheepSuitAndTie);
>
> However, the ChannelOutputStream is in sun.nio.ch so on second thought it shouldn't break. The pattern is repeated in Channels.newOutputStream(AsynchronousByteChannel ch) so that should fail as it is in the "java." namespace.
>
> I think an allow list would be safer but that brings all the drawbacks that Alan was talking about before.
I might have done this incorrectly, but with this version of the above `wolf` I do not see any corruption:
java.nio.channels.WritableByteChannel wolf =
new java.nio.channels.WritableByteChannel() {
private boolean closed = false;
public int write(java.nio.ByteBuffer src) throws IOException {
int rem = src.remaining();
Arrays.fill(src.array(), src.arrayOffset() + src.position(),
src.arrayOffset() + src.limit(),
(byte)'0');
src.position(src.limit());
return rem;
}
public boolean isOpen() {
return !closed;
}
public void close() throws IOException {
closed = true;
}
};
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/16893#discussion_r1411539285
More information about the core-libs-dev
mailing list