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

server, sessionctx: add multi statement workaround #22351

Merged
merged 8 commits into from
Jan 21, 2021

Conversation

morgo
Copy link
Contributor

@morgo morgo commented Jan 11, 2021

What problem does this PR solve?

Problem Summary:

v4.0.9 shipped with a fix for a server protocol vulnerability: #19459

It can be worked around by changing client library settings, but that's not always easy given each client library is different. This provides a server workaround as well, which adjusts from an error to a warning by default.

What is changed and how it works?

A new sysvar is added, called tidb_multi_statement_mode (scope: SESSION or GLOBAL). The type is an ENUM:

  • OFF: the MySQL compatible/safest behavior. Multi-statement is not permitted unless the client sets the multi-statement attribute. An error is returned.
  • ON: Multi-statement is permitted without errors or warnings.
  • WARN (default): Multi-statement is permitted, but returns a warning.

Thus, the "4.0.8 and earlier" behavior can be restored with "ON". The 4.0.9 and 4.0.10 behavior is effectively "OFF".

Both the warning and error message is as follows:

client has multi-statement capability disabled. Run SET GLOBAL tidb_multi_statement_mode='ON' after you understand the security risk

The intention is to change the default from WARN back to OFF in a 4.0-series release in the short future, so users are safe-by-default. In order to do this, SQL client error tracking will have to be added (see #14433 ). This PR ensures that this error uses the unique code of 8030 so that deployment tools can check if a user depends on the unsafe behavior before attempting to upgrade them.

Related changes

  • Need to cherry-pick to the release branch

Check List

Tests

  • Unit test

Side effects

  • Introduces security risk again (but not by default, and not materially different from enabling client multi-statement)

Release note

  • TiDB 4.0.9 fixed a security issue, where TiDB incorrectly permitted multiple statements to be executed in one COM_QUERY packet, leading to increased risk of SQL injection. To provide backwards compatibility for applications that depend on this behavior, a new option tidb_multi_statement_mode has been added. Assuming you understand the security risks, you can revert to the 4.0.8 by executing SET GLOBAL tidb_multi_statement_mode='ON'. The default behavior of tidb_multi_statement_mode also relaxes the error introduced in 4.0.9 to a warning. It is intended to be changed to an error again in a future release.

@haohaoxuex2005
Copy link
Contributor

SQL injection is a high risk, do we have a better way to ensure that user upgrade it?

@morgo
Copy link
Contributor Author

morgo commented Jan 12, 2021

SQL injection is a high risk, do we have a better way to ensure that user upgrade it?

To clarify: SQL injection is still possible either way. But the SQL injection cases are much riskier with multi-statement, since you can terminate the existing partial statement and then execute an entirely new statement.

The protection is still enabled by default. Clients need to send the multi-statement flag, or (from this PR) SET tidb_allow_multi_statement=1. This provides an easier upgrade path for those that can not modify their client drivers. Edit: it is now a warning by default.

@haohaoxuex2005
Copy link
Contributor

SQL injection is a high risk, do we have a better way to ensure that user upgrade it?

To clarify: SQL injection is still possible either way. But the SQL injection cases are much riskier with multi-statement, since you can terminate the existing partial statement and then execute an entirely new statement.

The protection is still enabled by default. Clients need to send the multi-statement flag, or (from this PR) SET tidb_allow_multi_statement=1. This provides an easier upgrade path for those that can not modify their client drivers.

Yeah, I understand, thank you!

@morgo
Copy link
Contributor Author

morgo commented Jan 13, 2021

/run-all-tests

@morgo morgo requested a review from xhebox January 21, 2021 03:31
Copy link
Contributor

@xhebox xhebox left a comment

Choose a reason for hiding this comment

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

Rest LGTM

// Warn means return warnings
Warn = "WARN"
// OffInt is used by TiDBMultiStatementMode
OffInt = 0
Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest you mark a type to OffInt and the field TiDBMultiStatementMode itself, like type TiDBMultiStatementModeEnum int or something else. Then move it closer to the variable field or the handle function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I'll move it.

@@ -1433,7 +1433,19 @@ func (cc *clientConn) handleQuery(ctx context.Context, sql string) (err error) {

capabilities := cc.ctx.GetSessionVars().ClientCapability
if capabilities&mysql.ClientMultiStatements < 1 {
Copy link
Contributor

@xhebox xhebox Jan 21, 2021

Choose a reason for hiding this comment

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

Is it intended that, if user set multi-statements on, even MultiStatementMode is Warn, the server will not report any error? Or if user set multi-statements on, even MultiStatementMode is Off, the server will continue without errors?

That is, is it intended to put your MultiStatementMode code in the branch of multi-statements disabled
by users/clients?

If it is, is there any way to test cases where multi-statements are enabled by clients?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it intended that, if user set multi-statements on, even MultiStatementMode is Warn, the server will not report any error? Or if user set multi-statements on, even MultiStatementMode is Off, the server will continue without errors?

Correct: If multiStatements are ON or WARN, there is no error. The error is caused by OFF, because multiStatement support is "turned off". This is assuming that the client has not set the multi-statement flag correctly, in which case it is permitted and none of this applies.

That is, is it intended to put your MultiStatementMode code in the branch of multi-statements disabled
by users/clients?

Correct. If they enable multi-statements in their client, I have no issue with it. This flag is only for preserving the upgrade story because TiDB previously ignored the client multi-statement flag.

If it is, is there any way to test cases where multi-statements are enabled by clients?

Yes, there are preexisting tests. See runTestMultiStatements in server/server_test.go which started setting this flag correctly from the PR https://github.com/pingcap/tidb/pull/19459/files

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for you detailed explanation :)

Copy link
Contributor

Choose a reason for hiding this comment

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

it that a conclusion above?
client multi-statements = on will pass through the check, otherwise, TiDB will take internal MultiStatementMode into consideration?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct. Ideally clients would always set this, and we don't have the internal MultiStatementMode check. But per the description, this is a workaround because TiDB only started enforcing the multi-statement check in 4.0.9 and it's been causing users problems.

Copy link
Contributor

@xhebox xhebox left a comment

Choose a reason for hiding this comment

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

LGTM

@ti-srebot ti-srebot added the status/LGT1 Indicates that a PR has LGTM 1. label Jan 21, 2021
@xhebox
Copy link
Contributor

xhebox commented Jan 21, 2021

You may want to request another team member to review.

@tiancaiamao tiancaiamao self-requested a review January 21, 2021 06:23
@tiancaiamao
Copy link
Contributor

LGTM

@ti-srebot ti-srebot removed the status/LGT1 Indicates that a PR has LGTM 1. label Jan 21, 2021
@ti-srebot ti-srebot added the status/LGT2 Indicates that a PR has LGTM 2. label Jan 21, 2021
@tiancaiamao
Copy link
Contributor

/merge

@ti-srebot ti-srebot added the status/can-merge Indicates a PR has been approved by a committer. label Jan 21, 2021
@ti-srebot
Copy link
Contributor

/run-all-tests

@ti-srebot ti-srebot merged commit 57eef13 into pingcap:master Jan 21, 2021
@morgo morgo deleted the add-multi-stmt-workaround branch January 21, 2021 07:15
ti-srebot pushed a commit to ti-srebot/tidb that referenced this pull request Jan 21, 2021
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
@ti-srebot
Copy link
Contributor

cherry pick to release-4.0 in PR #22468

ti-srebot pushed a commit to ti-srebot/tidb that referenced this pull request Jan 21, 2021
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
@ti-srebot
Copy link
Contributor

cherry pick to release-5.0-rc in PR #22469

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sig/sql-infra SIG: SQL Infra status/can-merge Indicates a PR has been approved by a committer. status/LGT2 Indicates that a PR has LGTM 2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants