On Fri, 1 Dec 2023 01:19:32 GMT, jmehrens <[email protected]> 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