!15 fix CVE-2019-7164
From: @tong_1001 Reviewed-by: @small_leek Signed-off-by: @small_leek
This commit is contained in:
commit
d770f4f5b8
332
backport-CVE-2019-7164.patch
Normal file
332
backport-CVE-2019-7164.patch
Normal file
@ -0,0 +1,332 @@
|
||||
From 82b4dcdeb0505f2dfcece5f76045b28b0edda03d Mon Sep 17 00:00:00 2001
|
||||
From: Mike Bayer <mike_mp@zzzcomputing.com>
|
||||
Date: Mon, 08 Apr 2019 22:07:35 -0400
|
||||
Subject: [PATCH] Illustrate fix for #4481 in terms of a 1.2 patch
|
||||
|
||||
Release 1.2 has decided (so far) not to backport 1.3's fix for #4481 as it is
|
||||
backwards-incompatible with code that relied upon the feature of automatic text
|
||||
coercion in SQL statements. However, for the specific case of order_by() and
|
||||
group_by(), we present a patch that backports the specific change in compiler
|
||||
to have 1.3's behavior for order_by/group_by specifically. This is much more
|
||||
targeted than the 0.9 version of the patch as it takes advantage 1.0's
|
||||
architecture which runs all order_by() / group_by() through a label lookup that
|
||||
only warns if the label can't be matched.
|
||||
|
||||
For an example of an application that was actually impacted by 1.3's change
|
||||
and how they had to change it, see:
|
||||
|
||||
https://github.com/ctxis/CAPE/commit/be0482294f5eb30026fe97a967ee5a768d032278
|
||||
|
||||
Basically, in the uncommon case an application is actually using the text
|
||||
coercion feature which was generally little-known, within the order_by()
|
||||
and group_by() an error is now raised instead of a warning; the application
|
||||
must instead ensure the SQL fragment is passed within a text() construct.
|
||||
The above application has also been seeing a warning about this since 1.0
|
||||
which apparently remained unattended.
|
||||
|
||||
The patch includes adjustments to the tests that were testing for the
|
||||
warning to now test that an exception is raised. Any distro that wants
|
||||
to patch the specific CVE issue resolved in #4481 to SQLAlchemy 1.0, 1.1
|
||||
or 1.2 can use this patch.
|
||||
|
||||
Change-Id: I3363b21428f1ad8797394b63197375a2e56a0bd7
|
||||
References: #4481
|
||||
---
|
||||
|
||||
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
|
||||
index 5a11ed1..4780bab 100644
|
||||
--- a/lib/sqlalchemy/sql/compiler.py
|
||||
+++ b/lib/sqlalchemy/sql/compiler.py
|
||||
@@ -757,12 +757,11 @@
|
||||
else:
|
||||
col = with_cols[element.element]
|
||||
except KeyError:
|
||||
- # treat it like text()
|
||||
- util.warn_limited(
|
||||
- "Can't resolve label reference %r; converting to text()",
|
||||
- util.ellipses_string(element.element),
|
||||
+ elements._no_text_coercion(
|
||||
+ element.element,
|
||||
+ exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY.",
|
||||
)
|
||||
- return self.process(element._text_clause)
|
||||
else:
|
||||
kwargs["render_label_as_label"] = col
|
||||
return self.process(
|
||||
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
|
||||
index 299fcad..ff86deb 100644
|
||||
--- a/lib/sqlalchemy/sql/elements.py
|
||||
+++ b/lib/sqlalchemy/sql/elements.py
|
||||
@@ -4432,6 +4432,17 @@
|
||||
)
|
||||
|
||||
|
||||
+def _no_text_coercion(element, exc_cls=exc.ArgumentError, extra=None):
|
||||
+ raise exc_cls(
|
||||
+ "%(extra)sTextual SQL expression %(expr)r should be "
|
||||
+ "explicitly declared as text(%(expr)r)"
|
||||
+ % {
|
||||
+ "expr": util.ellipses_string(element),
|
||||
+ "extra": "%s " % extra if extra else "",
|
||||
+ }
|
||||
+ )
|
||||
+
|
||||
+
|
||||
def _no_literals(element):
|
||||
if hasattr(element, "__clause_element__"):
|
||||
return element.__clause_element__()
|
||||
diff --git a/test/orm/test_eager_relations.py b/test/orm/test_eager_relations.py
|
||||
index abcb597..fc9531d 100644
|
||||
--- a/test/orm/test_eager_relations.py
|
||||
+++ b/test/orm/test_eager_relations.py
|
||||
@@ -32,7 +32,6 @@
|
||||
from sqlalchemy.testing import assert_raises
|
||||
from sqlalchemy.testing import assert_raises_message
|
||||
from sqlalchemy.testing import eq_
|
||||
-from sqlalchemy.testing import expect_warnings
|
||||
from sqlalchemy.testing import fixtures
|
||||
from sqlalchemy.testing import in_
|
||||
from sqlalchemy.testing import is_
|
||||
@@ -343,16 +342,11 @@
|
||||
.order_by("email_address")
|
||||
)
|
||||
|
||||
- with expect_warnings("Can't resolve label reference 'email_address'"):
|
||||
- self.assert_compile(
|
||||
- q,
|
||||
- "SELECT users.id AS users_id, users.name AS users_name, "
|
||||
- "addresses_1.id AS addresses_1_id, addresses_1.user_id AS "
|
||||
- "addresses_1_user_id, addresses_1.email_address AS "
|
||||
- "addresses_1_email_address FROM users LEFT OUTER JOIN "
|
||||
- "addresses AS addresses_1 ON users.id = addresses_1.user_id "
|
||||
- "ORDER BY email_address",
|
||||
- )
|
||||
+ assert_raises_message(
|
||||
+ sa.exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY.",
|
||||
+ q.all,
|
||||
+ )
|
||||
|
||||
def test_deferred_fk_col(self):
|
||||
users, Dingaling, User, dingalings, Address, addresses = (
|
||||
diff --git a/test/orm/test_query.py b/test/orm/test_query.py
|
||||
index 04ce8b5..0710507 100644
|
||||
--- a/test/orm/test_query.py
|
||||
+++ b/test/orm/test_query.py
|
||||
@@ -51,7 +51,6 @@
|
||||
from sqlalchemy.orm.util import with_parent
|
||||
from sqlalchemy.sql import expression
|
||||
from sqlalchemy.sql import operators
|
||||
-from sqlalchemy.testing import assert_warnings
|
||||
from sqlalchemy.testing import AssertsCompiledSQL
|
||||
from sqlalchemy.testing import fixtures
|
||||
from sqlalchemy.testing import is_
|
||||
@@ -2139,18 +2138,10 @@
|
||||
ua = aliased(User)
|
||||
q = s.query(ua).order_by("email_ad")
|
||||
|
||||
- def go():
|
||||
- self.assert_compile(
|
||||
- q,
|
||||
- "SELECT (SELECT max(addresses.email_address) AS max_1 "
|
||||
- "FROM addresses WHERE addresses.user_id = users_1.id) "
|
||||
- "AS anon_1, users_1.id AS users_1_id, "
|
||||
- "users_1.name AS users_1_name FROM users AS users_1 "
|
||||
- "ORDER BY email_ad",
|
||||
- )
|
||||
-
|
||||
- assert_warnings(
|
||||
- go, ["Can't resolve label reference 'email_ad'"], regex=True
|
||||
+ assert_raises_message(
|
||||
+ sa.exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY",
|
||||
+ q.with_labels().statement.compile,
|
||||
)
|
||||
|
||||
def test_order_by_column_labeled_prop_attr_aliased_one(self):
|
||||
@@ -4143,47 +4134,33 @@
|
||||
# the queries here are again "invalid" from a SQL perspective, as the
|
||||
# "name" field isn't matched up to anything.
|
||||
#
|
||||
- with expect_warnings("Can't resolve label reference 'name';"):
|
||||
- self.assert_compile(
|
||||
- s.query(User)
|
||||
- .options(joinedload("addresses"))
|
||||
- .order_by(desc("name"))
|
||||
- .limit(1),
|
||||
- "SELECT anon_1.users_id AS anon_1_users_id, "
|
||||
- "anon_1.users_name AS anon_1_users_name, "
|
||||
- "addresses_1.id AS addresses_1_id, "
|
||||
- "addresses_1.user_id AS addresses_1_user_id, "
|
||||
- "addresses_1.email_address AS addresses_1_email_address "
|
||||
- "FROM (SELECT users.id AS users_id, users.name AS users_name "
|
||||
- "FROM users ORDER BY users.name "
|
||||
- "DESC LIMIT :param_1) AS anon_1 "
|
||||
- "LEFT OUTER JOIN addresses AS addresses_1 "
|
||||
- "ON anon_1.users_id = addresses_1.user_id "
|
||||
- "ORDER BY name DESC, addresses_1.id",
|
||||
- )
|
||||
+ q = (
|
||||
+ s.query(User)
|
||||
+ .options(joinedload("addresses"))
|
||||
+ .order_by(desc("name"))
|
||||
+ .limit(1)
|
||||
+ )
|
||||
+ assert_raises_message(
|
||||
+ sa_exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY.",
|
||||
+ q.with_labels().statement.compile,
|
||||
+ )
|
||||
|
||||
def test_order_by_w_eager_two(self):
|
||||
User = self.classes.User
|
||||
s = create_session()
|
||||
|
||||
- with expect_warnings("Can't resolve label reference 'name';"):
|
||||
- self.assert_compile(
|
||||
- s.query(User)
|
||||
- .options(joinedload("addresses"))
|
||||
- .order_by("name")
|
||||
- .limit(1),
|
||||
- "SELECT anon_1.users_id AS anon_1_users_id, "
|
||||
- "anon_1.users_name AS anon_1_users_name, "
|
||||
- "addresses_1.id AS addresses_1_id, "
|
||||
- "addresses_1.user_id AS addresses_1_user_id, "
|
||||
- "addresses_1.email_address AS addresses_1_email_address "
|
||||
- "FROM (SELECT users.id AS users_id, users.name AS users_name "
|
||||
- "FROM users ORDER BY users.name "
|
||||
- "LIMIT :param_1) AS anon_1 "
|
||||
- "LEFT OUTER JOIN addresses AS addresses_1 "
|
||||
- "ON anon_1.users_id = addresses_1.user_id "
|
||||
- "ORDER BY name, addresses_1.id",
|
||||
- )
|
||||
+ q = (
|
||||
+ s.query(User)
|
||||
+ .options(joinedload("addresses"))
|
||||
+ .order_by("name")
|
||||
+ .limit(1)
|
||||
+ )
|
||||
+ assert_raises_message(
|
||||
+ sa_exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY.",
|
||||
+ q.with_labels().statement.compile,
|
||||
+ )
|
||||
|
||||
def test_order_by_w_eager_three(self):
|
||||
User = self.classes.User
|
||||
@@ -4268,22 +4245,11 @@
|
||||
.limit(1)
|
||||
.offset(0)
|
||||
)
|
||||
- with expect_warnings(
|
||||
- "Can't resolve label reference 'email_address desc'"
|
||||
- ):
|
||||
- eq_(
|
||||
- [
|
||||
- (
|
||||
- User(
|
||||
- id=7,
|
||||
- orders=[Order(id=1), Order(id=3), Order(id=5)],
|
||||
- addresses=[Address(id=1)],
|
||||
- ),
|
||||
- "jack@bean.com",
|
||||
- )
|
||||
- ],
|
||||
- result.all(),
|
||||
- )
|
||||
+ assert_raises_message(
|
||||
+ sa_exc.CompileError,
|
||||
+ "Can't resolve label reference for ORDER BY / GROUP BY",
|
||||
+ result.all,
|
||||
+ )
|
||||
|
||||
|
||||
class TextWarningTest(QueryTest, AssertsCompiledSQL):
|
||||
diff --git a/test/sql/test_text.py b/test/sql/test_text.py
|
||||
index 317fc61..75f1d6f 100644
|
||||
--- a/test/sql/test_text.py
|
||||
+++ b/test/sql/test_text.py
|
||||
@@ -22,7 +22,6 @@
|
||||
from sqlalchemy.sql import table
|
||||
from sqlalchemy.sql import util as sql_util
|
||||
from sqlalchemy.testing import assert_raises_message
|
||||
-from sqlalchemy.testing import assert_warnings
|
||||
from sqlalchemy.testing import AssertsCompiledSQL
|
||||
from sqlalchemy.testing import eq_
|
||||
from sqlalchemy.testing import expect_warnings
|
||||
@@ -633,15 +632,13 @@
|
||||
class OrderByLabelResolutionTest(fixtures.TestBase, AssertsCompiledSQL):
|
||||
__dialect__ = "default"
|
||||
|
||||
- def _test_warning(self, stmt, offending_clause, expected):
|
||||
- with expect_warnings(
|
||||
- "Can't resolve label reference %r;" % offending_clause
|
||||
- ):
|
||||
- self.assert_compile(stmt, expected)
|
||||
+ def _test_exception(self, stmt, offending_clause):
|
||||
assert_raises_message(
|
||||
- exc.SAWarning,
|
||||
- "Can't resolve label reference %r; converting to text"
|
||||
- % offending_clause,
|
||||
+ exc.CompileError,
|
||||
+ r"Can't resolve label reference for ORDER BY / GROUP BY. "
|
||||
+ "Textual SQL "
|
||||
+ "expression %r should be explicitly "
|
||||
+ r"declared as text\(%r\)" % (offending_clause, offending_clause),
|
||||
stmt.compile,
|
||||
)
|
||||
|
||||
@@ -691,9 +688,7 @@
|
||||
|
||||
def test_unresolvable_warning_order_by(self):
|
||||
stmt = select([table1.c.myid]).order_by("foobar")
|
||||
- self._test_warning(
|
||||
- stmt, "foobar", "SELECT mytable.myid FROM mytable ORDER BY foobar"
|
||||
- )
|
||||
+ self._test_exception(stmt, "foobar")
|
||||
|
||||
def test_group_by_label(self):
|
||||
stmt = select([table1.c.myid.label("foo")]).group_by("foo")
|
||||
@@ -709,9 +704,7 @@
|
||||
|
||||
def test_unresolvable_warning_group_by(self):
|
||||
stmt = select([table1.c.myid]).group_by("foobar")
|
||||
- self._test_warning(
|
||||
- stmt, "foobar", "SELECT mytable.myid FROM mytable GROUP BY foobar"
|
||||
- )
|
||||
+ self._test_exception(stmt, "foobar")
|
||||
|
||||
def test_asc(self):
|
||||
stmt = select([table1.c.myid]).order_by(asc("name"), "description")
|
||||
@@ -810,23 +803,13 @@
|
||||
.order_by("myid", "t1name", "x")
|
||||
)
|
||||
|
||||
- def go():
|
||||
- # the labels here are anonymized, so label naming
|
||||
- # can't catch these.
|
||||
- self.assert_compile(
|
||||
- s1,
|
||||
- "SELECT mytable_1.myid AS mytable_1_myid, "
|
||||
- "mytable_1.name AS name_1, foo(:foo_2) AS foo_1 "
|
||||
- "FROM mytable AS mytable_1 ORDER BY mytable_1.myid, t1name, x",
|
||||
- )
|
||||
-
|
||||
- assert_warnings(
|
||||
- go,
|
||||
- [
|
||||
- "Can't resolve label reference 't1name'",
|
||||
- "Can't resolve label reference 'x'",
|
||||
- ],
|
||||
- regex=True,
|
||||
+ assert_raises_message(
|
||||
+ exc.CompileError,
|
||||
+ r"Can't resolve label reference for ORDER BY / GROUP BY. "
|
||||
+ "Textual SQL "
|
||||
+ "expression 't1name' should be explicitly "
|
||||
+ r"declared as text\('t1name'\)",
|
||||
+ s1.compile,
|
||||
)
|
||||
|
||||
def test_columnadapter_non_anonymized(self):
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
Name: python-sqlalchemy
|
||||
Version: 1.2.19
|
||||
Release: 2
|
||||
Release: 3
|
||||
Summary: SQL toolkit and object relational mapper for Python
|
||||
License: MIT
|
||||
URL: http://www.sqlalchemy.org/
|
||||
Source0: https://files.pythonhosted.org/packages/source/S/SQLAlchemy/SQLAlchemy-%{version}.tar.gz
|
||||
|
||||
Patch1: Expect_ordering_NULLs_to_work.patch
|
||||
Patch2: backport-CVE-2019-7164.patch
|
||||
|
||||
BuildRequires: python2-devel >= 2.6 python2-setuptools python2-mock python2-pytest
|
||||
BuildRequires: python3-devel python3-setuptools python3-pytest
|
||||
@ -89,6 +90,9 @@ PYTHONPATH=. %{__python3} -m pytest test
|
||||
%doc doc examples
|
||||
|
||||
%changelog
|
||||
* Mon Feb 08 2021 shixuantong <shixuantong@huawei.com> - 1.2.19-3
|
||||
- fix CVE-2019-7164
|
||||
|
||||
* Thu Dec 03 2020 shixuantong <shixuantong@huawei> - 1.2.19-2
|
||||
- fix test_order_by_nulls error
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user