Skip to content

postgres: validate message syntax before parsing#16575

Merged
lizan merged 15 commits intoenvoyproxy:mainfrom
cpakulski:issue/12340
Jun 18, 2021
Merged

postgres: validate message syntax before parsing#16575
lizan merged 15 commits intoenvoyproxy:mainfrom
cpakulski:issue/12340

Conversation

@cpakulski
Copy link
Copy Markdown
Contributor

Commit Message:
Validate postgres messages before parsing.

Additional Description:
Introduced InSync and OutOfSync states in decoder. When decoder detects a wrongly formatted message, it stops parsing and moves to OutOfSync state. Continuing parsing after encountering message with wrong syntax may lead to interpreting random bytes as length of the message and possibly causing OOM.

Risk Level: Low
Testing: Added unit tests and run full regression tests.
Docs Changes: No.
Release Notes: No.
Platform Specific Features:
Fixes #12340

and postgres message body..

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
…alidator.

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
@cpakulski cpakulski requested review from dio and lizan May 19, 2021 19:14
@cpakulski cpakulski marked this pull request as ready for review May 19, 2021 19:15
std::string message_;
uint32_t message_len_{};

static const std::string FRONTEND;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

static const string (non-POD) is source of flaky test, use singleton (CONSTRUCT_ON_FIRST_USE) or constexpr string_view.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Converted to constexpr string_view. Thanks!

…inmutable strings

used for logging.

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
@cpakulski
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #16575 (comment) was created by @cpakulski.

see: more, trace.

@zuercher
Copy link
Copy Markdown
Member

zuercher commented Jun 7, 2021

cc @fabriziomello could have a look as an extension owner?

message_len_ = data.peekBEInt<uint32_t>(0);
// MAX_STARTUP_PACKET_LENGTH is defined in Postgres source code
// as maximum size of initial packet.
#define MAX_STARTUP_PACKET_LENGTH 10000
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Perhaps move it to postgres_decoder.h and add the following link to comments: https://github.com/postgres/postgres/search?q=MAX_STARTUP_PACKET_LENGTH&type=code


// The minimum size of the message sufficient for parsing is 5 bytes.
if (data.length() < 5) {
if (data.length() < 4) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about create something like #define MIN_MESSAGE_LENGTH 4 ? And seems the comment above is not in sync what code does...

encrypted_ = true;
// Handler for SSLRequest (Int32(80877103) = 0x04d2162f)
// See details in https://www.postgresql.org/docs/current/protocol-message-formats.html.
if (code == 0x04d2162f) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Both lines 249 and 253 use SSLRequest codes... for code legibility what about add some macros?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

IMHO macro will make it more difficult to read and will not add any value. The meaning of this value is documented pretty clearly here.

data.drain(data.length());
return encrypted_ ? Decoder::ReadyForNext : Decoder::Stopped;
Decoder::Result result = Decoder::Result::ReadyForNext;
uint32_t code = data.peekBEInt<uint32_t>(4);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rename code to startup_packet just to use the Postgres vocabulary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, but this is not really a packet itself, but just 4-bytes code which can be either a version or encryption type.

@fabriziomello
Copy link
Copy Markdown
Contributor

cc @fabriziomello could have a look as an extension owner?

Thanks for remember me ... did some minor comments. Me and @cpakulski already discussed a bit about this in PVT before he send the PR. Mostly about MAX_STARTUP_PACKET_LENGTH because we decided implement it the same way Postgres does.

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
@fabriziomello
Copy link
Copy Markdown
Contributor

@cpakulski the Postgres Regression using your last commit 60b5585 worked but seems our current pipeline doesn't like it so much.

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
@cpakulski
Copy link
Copy Markdown
Contributor Author

@fabriziomello Would you mind running Postgres Regression test on the latest commit? Thanks.

@fabriziomello
Copy link
Copy Markdown
Contributor

@fabriziomello Would you mind running Postgres Regression test on the latest commit? Thanks.

I did it when I saw your new commit and it ran without any issue: https://github.com/fabriziomello/envoy-postgres-regression/actions/runs/940000625

@fabriziomello
Copy link
Copy Markdown
Contributor

/LGTM

@cpakulski
Copy link
Copy Markdown
Contributor Author

@lizan How can we move this PR forward? All regression tests have passed.
If there are no style comments, it is ready for merge. Thanks!

@lizan lizan merged commit 4533ea1 into envoyproxy:main Jun 18, 2021
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
Commit Message:
Validate postgres messages before parsing.

Additional Description:
Introduced InSync and OutOfSync states in decoder. When decoder detects a wrongly formatted message, it stops parsing and moves to OutOfSync state. Continuing parsing after encountering message with wrong syntax may lead to interpreting random bytes as length of the message and possibly causing OOM.

Risk Level: Low
Testing: Added unit tests and run full regression tests.
Docs Changes: No.
Release Notes: No.
Platform Specific Features:
Fixes envoyproxy#12340 

Signed-off-by: Christoph Pakulski <christoph@tetrate.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[postgres_proxy] assert failure with untrusted buffer when onData()

5 participants