On Thu, 30 Nov 2023 23:27:13 GMT, Brian Burkhalter <b...@openjdk.org> wrote:

>> Good catch: that in fact defeats the protection.
>
> 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);


Which leads us back to an allow list that Alan was talking about and the draw 
backs that it brings.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/16893#discussion_r1411491609

Reply via email to