Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provides setup for maxInboundPayloadSize and maxFrameSize #876

Merged
merged 2 commits into from
Jul 5, 2020

Conversation

OlegDokuka
Copy link
Member

closes #864

Signed-off-by: Oleh Dokuka shadowgun@i.ua

@OlegDokuka OlegDokuka added this to the 1.0.2 milestone Jun 24, 2020
@OlegDokuka OlegDokuka changed the base branch from master to 1.0.x June 24, 2020 11:05
@OlegDokuka OlegDokuka marked this pull request as draft June 24, 2020 11:06
@OlegDokuka
Copy link
Member Author

OlegDokuka commented Jun 24, 2020

@rstoyanchev right now this implementation terminates the connection if the reassembly limit is overflowed. Should we consider logical stream termination instead?

The second option is a little challenging since this is a connection and not an RSocket one

Copy link
Contributor

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks like a good start. Some initial thoughts below.

@rstoyanchev right now this implementation terminates the connection if the reassembly limit is overflowed. Should we consider logical stream termination instead? The second option is a little challenging since this is a connection and not an RSocket one

Could it perhaps release the accumulated fragments, send an error through the Sink, and then continue to discard further fragments received for that stream?

this.maxReassemblySize = ReassemblyDuplexConnection.assertMaxReassemblySize(maxReassemblySize);
return this;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should apply to any input payload size regardless of whether it is fragmented or not. In fact by default fragmentation is off and in any case once there is a limit in place for fragmented input, it would be expected to have the same for non-fragmented input. I do understand that the rest is at the transport level. Nevertheless from an application perspective, conceptually, it's one limit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is another concern. Spec specifies that Max-Frame size if 16MB, thus it should be clear that RSocket should support that size. Now the question is - if one applies a 1byte memory limit, how a client, which expects that allowed frame size is 16MB, should behave in that case.

From the fragmentation perspective, minimal frame size is 64bytes, so reassembly limit should be more than that at least, but if we wanna send something bigger than that, all tries will fail, so what is the benefit of such reassembly then?

From my point of view, the minimal storage per stream should be at least the default max frame size. Or at least minimal fragment size specified by spec

throw new IllegalStateException("Reassembled payload went out of allowed size");
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the limit is reached on the very last fragment I think it should be allowed through. It is in memory at this point anyway and the purpose of the limit should be more to prevent further growth after the limit is exceeded or otherwise there would be cases where it fail for even 1 byte over. It should be lenient about that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well. Disagree. This will open another spot of the attack. Since now anyone can flash anything in the pipe, it can configure fragmentation to send the very last frame == MAX FRAME SIZE (16MB) so if the limit of in-memory storage is 16KB, then the last frame will do 16MB + 16KB. Which means - one can use it as a vulnerability

@OlegDokuka
Copy link
Member Author

Could it perhaps release the accumulated fragments, send an error through the Sink, and then continue to discard further fragments received for that stream?

I don't sink discarding is a good idea since we will not be able to respond back with any signal.

Also, Sink for ReassemblyDuplexConnection means connection sink so if we send error it automatically terminates transport connection and disposes of RSocket.

If we don't wanna terminate the connection, then we must do it according to the spec - Send error to the responder (depends on the stream type - if it is request-response - ignore payload and send nothing to the responder, but then send an error back to the requester saying something in the error message). If reassembly of an ordinary payload - cancel upstream and error downstream

@OlegDokuka OlegDokuka marked this pull request as ready for review June 30, 2020 11:55
*
* @return return maximum configured frame size limit
*/
default int maxFrameLength() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved maxFrameLength property to the transport, since it describes transport behavior and from my point of view checking that when a connection has already wired is too late

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this one is a default property, so it should not be a breaking change for anybody

@OlegDokuka OlegDokuka force-pushed the enhancement/reassembly-max-size branch from cc845a2 to 6a3dd35 Compare June 30, 2020 13:22
@OlegDokuka OlegDokuka changed the title provides reassembly payload size control provides configurations for maxPayloadSize and maxFrameSize Jun 30, 2020
Copy link
Contributor

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks solid now. Some minor comments related to naming.

@OlegDokuka OlegDokuka force-pushed the enhancement/reassembly-max-size branch from 6a3dd35 to ca2c92e Compare July 5, 2020 06:28
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
@OlegDokuka OlegDokuka force-pushed the enhancement/reassembly-max-size branch from ca2c92e to c0fbd40 Compare July 5, 2020 15:29
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
@OlegDokuka OlegDokuka force-pushed the enhancement/reassembly-max-size branch from c0fbd40 to 39681cb Compare July 5, 2020 15:37
@OlegDokuka OlegDokuka changed the title provides configurations for maxPayloadSize and maxFrameSize provides setup for maxInboundPayloadSize and maxFrameSize Jul 5, 2020
@OlegDokuka OlegDokuka merged commit 1237fc5 into 1.0.x Jul 5, 2020
@OlegDokuka OlegDokuka deleted the enhancement/reassembly-max-size branch July 5, 2020 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Client and server are trivially subject to memory overflow on frame reassembly
2 participants