[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#929321: marked as done (unblock: sqlalchemy/1.2.18+ds1-2 (CVE-2019-7164 CVE-2019-7548))



Your message dated Sun, 2 Jun 2019 21:10:43 +0200
with message-id <b4b3dd2f-6f0a-ba9c-035b-2f7204d20948@debian.org>
and subject line Re: Bug#929321: Update for SQLAlchemy to address CVE-2019-7164 CVE-2019-7548
has caused the Debian Bug report #929321,
regarding unblock: sqlalchemy/1.2.18+ds1-2 (CVE-2019-7164 CVE-2019-7548)
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
929321: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=929321
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package sqlalchemy,

My last (team-)upload for version 1.2.18+ds1-2 adds a patch from upstream
for CVE-2019-7164 CVE-2019-7548, which is an SQL vulnerability problem.

Note that it may (or not) break some reverse dependencies, though according
to upstream, OpenStack (the biggest SQLAlchemy consumer in Debian) behaves
correctly with it. If this happens, then these reverse dependencies will
have to be fixed.

Debdiff attached.

unblock sqlalchemy/1.2.18+ds1-2

Cheers,

Thomas Goirand (zigo)
diff -Nru sqlalchemy-1.2.18+ds1/debian/changelog sqlalchemy-1.2.18+ds1/debian/changelog
--- sqlalchemy-1.2.18+ds1/debian/changelog	2019-02-25 00:01:50.000000000 +0100
+++ sqlalchemy-1.2.18+ds1/debian/changelog	2019-05-21 16:23:35.000000000 +0200
@@ -1,3 +1,11 @@
+sqlalchemy (1.2.18+ds1-2) unstable; urgency=high
+
+  * Team upload.
+  * CVE-2019-7164 CVE-2019-7548: SQL injection. Apply upstream backported patch
+    for this. Note: This potentially impacts applications (Closes: #922669).
+
+ -- Thomas Goirand <zigo@debian.org>  Tue, 21 May 2019 16:23:35 +0200
+
 sqlalchemy (1.2.18+ds1-1) unstable; urgency=medium
 
   * New upstream release
diff -Nru sqlalchemy-1.2.18+ds1/debian/patches/CVE-2019-7164_and_7548_Illustrate_fix_for_4481_in_terms_of_a_1.2_patch.patch sqlalchemy-1.2.18+ds1/debian/patches/CVE-2019-7164_and_7548_Illustrate_fix_for_4481_in_terms_of_a_1.2_patch.patch
--- sqlalchemy-1.2.18+ds1/debian/patches/CVE-2019-7164_and_7548_Illustrate_fix_for_4481_in_terms_of_a_1.2_patch.patch	1970-01-01 01:00:00.000000000 +0100
+++ sqlalchemy-1.2.18+ds1/debian/patches/CVE-2019-7164_and_7548_Illustrate_fix_for_4481_in_terms_of_a_1.2_patch.patch	2019-05-21 16:23:35.000000000 +0200
@@ -0,0 +1,331 @@
+Description: CVE-2019-7164 / CVE-2019-7548: 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.
+Author: Mike Bayer <mike_mp@zzzcomputing.com>
+Date: Mon, 08 Apr 2019 22:07:35 -0400
+Change-Id: I3363b21428f1ad8797394b63197375a2e56a0bd7
+References: #4481
+Bug-Debian: https://bugs.debian.org/922669
+Origin: upstream, https://gerrit.sqlalchemy.org/#/c/sqlalchemy/sqlalchemy/+/1184/
+Last-Update: 2019-05-21
+
+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):
diff -Nru sqlalchemy-1.2.18+ds1/debian/patches/series sqlalchemy-1.2.18+ds1/debian/patches/series
--- sqlalchemy-1.2.18+ds1/debian/patches/series	2018-12-30 12:30:19.000000000 +0100
+++ sqlalchemy-1.2.18+ds1/debian/patches/series	2019-05-21 16:21:55.000000000 +0200
@@ -1 +1,2 @@
 0001-drop_notfound_page_from_docs.patch
+CVE-2019-7164_and_7548_Illustrate_fix_for_4481_in_terms_of_a_1.2_patch.patch

--- End Message ---
--- Begin Message ---
Hi Thomas,

On 31-05-2019 20:32, Paul Gevers wrote:
> Thanks for sending this. I'll give this a day or two and then I intend
> unblock SQLAlchemy.

Unblocked, thanks.

Paul

Attachment: signature.asc
Description: OpenPGP digital signature


--- End Message ---

Reply to: