diff -u mysql-dfsg-5.0-5.0.24a/debian/changelog mysql-dfsg-5.0-5.0.24a/debian/changelog --- mysql-dfsg-5.0-5.0.24a/debian/changelog +++ mysql-dfsg-5.0-5.0.24a/debian/changelog @@ -1,3 +1,38 @@ +mysql-dfsg-5.0 (5.0.24a-9ubuntu2.3) edgy-security; urgency=low + + * SECURITY UPDATE: buffer overflow via ProcessOldClientHello() in + handshake.cpp and input_buffer& operator>> in yassl_imp.cpp + * SECURITY UPDATE: buffer overread in HASHwithTransform::Update in hash.cpp + * debian/patches/99_SECURITY_CVE-2008-0226_0227.dpatch: properly verify + length of input (LP: #186978). + * SECURITY UPDATE: privilege escalation via crafted CREATE SQL SECURITY + DEFINER VIEW and ALTER VIEW statements + * debian/patches/100_SECURITY_CVE-2007-6303.dpatch: make sure lex->definer + is non-NULL in sql_view.cc (LP: #185039). This patch also fixes upstream + bug #21080, which was needed to keep VIEW definitions in sync. + * SECURITY UPDATE: denial of service via crafted EXPLAIN SELECT FROM on the + INFORMATION_SCHEMA table + * debian/patches/101_SECURITY_CVE-2006-7232.dpatch: make sure + thd->lex-describe is non-NULL in sql_select.cc (LP: #161127) + * debian/patches/102_view_fix-now.dpatch: update view.test and view.result to + use a static year instead of now(). These tests are not part of the build + but helps with qa-regression-testing + * SECURITY UPDATE: privilege escalation via SQL SECURITY INVOKER stored + routines + * debian/patches/103_SECURITY_CVE-2007-2692.dpatch: restore THD::db_access + when returning from stored routine by performing privilege checks in the + execution stage rather than the parsing stage. + * References + CVE-2008-0226 + CVE-2008-0227 + CVE-2007-6303 + CVE-2006-7232 + CVE-2007-2692 + http://bugs.mysql.com/bug.php?id=27337 + http://bugs.mysql.com/bug.php?id=21080 + + -- Jamie Strandboge Thu, 06 Mar 2008 09:09:00 -0500 + mysql-dfsg-5.0 (5.0.24a-9ubuntu2.2) edgy-security; urgency=low * SECURITY UPDATE: denial of service via crafted CONTAINS operation when diff -u mysql-dfsg-5.0-5.0.24a/debian/patches/00list mysql-dfsg-5.0-5.0.24a/debian/patches/00list --- mysql-dfsg-5.0-5.0.24a/debian/patches/00list +++ mysql-dfsg-5.0-5.0.24a/debian/patches/00list @@ -35,0 +36,5 @@ +99_SECURITY_CVE-2008-0226_0227.dpatch +100_SECURITY_CVE-2007-6303.dpatch +101_SECURITY_CVE-2006-7232.dpatch +102_view_fix-now.dpatch +103_SECURITY_CVE-2007-2692.dpatch only in patch2: unchanged: --- mysql-dfsg-5.0-5.0.24a.orig/debian/patches/100_SECURITY_CVE-2007-6303.dpatch +++ mysql-dfsg-5.0-5.0.24a/debian/patches/100_SECURITY_CVE-2007-6303.dpatch @@ -0,0 +1,280 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 100_SECURITY_CVE-2007-6303.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view.result mysql-dfsg-5.0-5.0.24a/mysql-test/r/view.result +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view.result 2006-08-25 17:44:09.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/r/view.result 2008-02-28 11:08:26.000000000 -0500 +@@ -2747,3 +2747,14 @@ + VIEW v2 AS SELECT b FROM t1; + ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) + DROP TABLE t1; ++CREATE TABLE t1 (x INT, y INT); ++CREATE ALGORITHM=TEMPTABLE SQL SECURITY INVOKER VIEW v1 AS SELECT x FROM t1; ++SHOW CREATE VIEW v1; ++View Create View ++v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select `t1`.`x` AS `x` from `t1` ++ALTER VIEW v1 AS SELECT x, y FROM t1; ++SHOW CREATE VIEW v1; ++View Create View ++v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select `t1`.`x` AS `x`,`t1`.`y` AS `y` from `t1` ++DROP VIEW v1; ++DROP TABLE t1; +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view_grant.result mysql-dfsg-5.0-5.0.24a/mysql-test/r/view_grant.result +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view_grant.result 2006-08-25 17:44:09.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/r/view_grant.result 2008-02-28 11:07:20.000000000 -0500 +@@ -659,3 +659,46 @@ + DROP TABLE test2.t1, test1.t0; + DROP DATABASE test2; + DROP DATABASE test1; ++# ++# Bug#29908: A user can gain additional access through the ALTER VIEW. ++# ++CREATE DATABASE mysqltest_29908; ++USE mysqltest_29908; ++CREATE TABLE t1(f1 INT, f2 INT); ++CREATE USER u29908_1@localhost; ++CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; ++CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS ++SELECT f1 FROM t1; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; ++GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; ++CREATE USER u29908_2@localhost; ++GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; ++GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; ++ALTER VIEW v1 AS SELECT f2 FROM t1; ++ERROR 42000: Access denied; you need the SUPER privilege for this operation ++ALTER VIEW v2 AS SELECT f2 FROM t1; ++ERROR 42000: Access denied; you need the SUPER privilege for this operation ++SHOW CREATE VIEW v2; ++View Create View ++v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` ++ALTER VIEW v1 AS SELECT f2 FROM t1; ++SHOW CREATE VIEW v1; ++View Create View ++v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f2` AS `f2` from `t1` ++ALTER VIEW v2 AS SELECT f2 FROM t1; ++SHOW CREATE VIEW v2; ++View Create View ++v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f2` AS `f2` from `t1` ++ALTER VIEW v1 AS SELECT f1 FROM t1; ++SHOW CREATE VIEW v1; ++View Create View ++v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` ++ALTER VIEW v2 AS SELECT f1 FROM t1; ++SHOW CREATE VIEW v2; ++View Create View ++v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` ++DROP USER u29908_1@localhost; ++DROP USER u29908_2@localhost; ++DROP DATABASE mysqltest_29908; +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view.test mysql-dfsg-5.0-5.0.24a/mysql-test/t/view.test +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view.test 2006-08-25 17:44:06.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/t/view.test 2008-02-28 11:09:19.000000000 -0500 +@@ -2623,3 +2623,16 @@ + # Cleanup. + + DROP TABLE t1; ++ ++# ++#Bug #21080: ALTER VIEW makes user restate SQL SECURITY mode, and ALGORITHM ++# ++CREATE TABLE t1 (x INT, y INT); ++CREATE ALGORITHM=TEMPTABLE SQL SECURITY INVOKER VIEW v1 AS SELECT x FROM t1; ++SHOW CREATE VIEW v1; ++ ++ALTER VIEW v1 AS SELECT x, y FROM t1; ++SHOW CREATE VIEW v1; ++ ++DROP VIEW v1; ++DROP TABLE t1; +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view_grant.test mysql-dfsg-5.0-5.0.24a/mysql-test/t/view_grant.test +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view_grant.test 2006-08-25 17:44:06.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/t/view_grant.test 2008-02-28 11:03:59.000000000 -0500 +@@ -866,3 +866,49 @@ + DROP TABLE test2.t1, test1.t0; + DROP DATABASE test2; + DROP DATABASE test1; ++ ++--echo # ++--echo # Bug#29908: A user can gain additional access through the ALTER VIEW. ++--echo # ++disconnect default; ++connect (root,localhost,root,,test); ++connection root; ++CREATE DATABASE mysqltest_29908; ++USE mysqltest_29908; ++CREATE TABLE t1(f1 INT, f2 INT); ++CREATE USER u29908_1@localhost; ++CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; ++CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS ++ SELECT f1 FROM t1; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; ++GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; ++CREATE USER u29908_2@localhost; ++GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; ++GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; ++GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; ++ ++connect (u2,localhost,u29908_2,,mysqltest_29908); ++--error ER_SPECIFIC_ACCESS_DENIED_ERROR ++ALTER VIEW v1 AS SELECT f2 FROM t1; ++--error ER_SPECIFIC_ACCESS_DENIED_ERROR ++ALTER VIEW v2 AS SELECT f2 FROM t1; ++SHOW CREATE VIEW v2; ++ ++connect (u1,localhost,u29908_1,,mysqltest_29908); ++ALTER VIEW v1 AS SELECT f2 FROM t1; ++SHOW CREATE VIEW v1; ++ALTER VIEW v2 AS SELECT f2 FROM t1; ++SHOW CREATE VIEW v2; ++ ++connection root; ++ALTER VIEW v1 AS SELECT f1 FROM t1; ++SHOW CREATE VIEW v1; ++ALTER VIEW v2 AS SELECT f1 FROM t1; ++SHOW CREATE VIEW v2; ++ ++DROP USER u29908_1@localhost; ++DROP USER u29908_2@localhost; ++DROP DATABASE mysqltest_29908; ++disconnect u1; ++disconnect u2; +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_lex.h mysql-dfsg-5.0-5.0.24a/sql/sql_lex.h +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_lex.h 2006-08-25 17:11:45.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_lex.h 2008-02-28 10:59:18.000000000 -0500 +@@ -978,7 +978,7 @@ + /* + view created to be run from definer (standard behaviour) + */ +- bool create_view_suid; ++ uint8 create_view_suid; + /* Characterstics of trigger being created */ + st_trg_chistics trg_chistics; + /* +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_view.cc mysql-dfsg-5.0-5.0.24a/sql/sql_view.cc +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_view.cc 2006-08-25 17:11:50.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_view.cc 2008-02-28 10:59:18.000000000 -0500 +@@ -155,6 +155,54 @@ + DBUG_RETURN(TRUE); + } + ++/* ++ Fill defined view parts ++ ++ SYNOPSIS ++ fill_defined_view_parts() ++ thd current thread. ++ view view to operate on ++ ++ DESCRIPTION ++ This function will initialize the parts of the view ++ definition that are not specified in ALTER VIEW ++ to their values from CREATE VIEW. ++ The view must be opened to get it's definition. ++ We use a copy of the view when opening because we want ++ to preserve the original view instance. ++ ++ RETURN VALUE ++ TRUE can't open table ++ FALSE success ++*/ ++static bool ++fill_defined_view_parts (THD *thd, TABLE_LIST *view) ++{ ++ LEX *lex= thd->lex; ++ bool not_used; ++ TABLE_LIST decoy; ++ ++ memcpy (&decoy, view, sizeof (TABLE_LIST)); ++ if (!open_table(thd, &decoy, thd->mem_root, ¬_used, 0) && ++ !decoy.view) ++ { ++ return TRUE; ++ } ++ if (!lex->definer) ++ { ++ view->definer.host= decoy.definer.host; ++ view->definer.user= decoy.definer.user; ++ lex->definer= &view->definer; ++ } ++ if (lex->create_view_algorithm == VIEW_ALGORITHM_UNDEFINED) ++ lex->create_view_algorithm= decoy.algorithm; ++ if (lex->create_view_suid == VIEW_SUID_DEFAULT) ++ lex->create_view_suid= decoy.view_suid ? ++ VIEW_SUID_DEFINER : VIEW_SUID_INVOKER; ++ ++ return FALSE; ++} ++ + + /* + Creating/altering VIEW procedure +@@ -207,7 +255,15 @@ + } + + if (mode != VIEW_CREATE_NEW) ++ { ++ if (mode == VIEW_ALTER && ++ fill_defined_view_parts(thd, view)) ++ { ++ res= TRUE; ++ goto err; ++ } + sp_cache_invalidate(); ++ } + + if (!lex->definer) + { +@@ -235,11 +291,11 @@ + - same as current user + - current user has SUPER_ACL + */ +- if (strcmp(lex->definer->user.str, ++ if (lex->definer && (strcmp(lex->definer->user.str, + thd->security_ctx->priv_user) != 0 || + my_strcasecmp(system_charset_info, + lex->definer->host.str, +- thd->security_ctx->priv_host) != 0) ++ thd->security_ctx->priv_host) != 0)) + { + if (!(thd->security_ctx->master_access & SUPER_ACL)) + { +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_yacc.yy mysql-dfsg-5.0-5.0.24a/sql/sql_yacc.yy +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_yacc.yy 2008-02-28 10:58:11.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_yacc.yy 2008-02-28 10:59:18.000000000 -0500 +@@ -9024,11 +9024,11 @@ + + view_suid: + /* empty */ +- { Lex->create_view_suid= TRUE; } ++ { Lex->create_view_suid= VIEW_SUID_DEFAULT; } + | SQL_SYM SECURITY_SYM DEFINER_SYM +- { Lex->create_view_suid= TRUE; } ++ { Lex->create_view_suid= VIEW_SUID_DEFINER; } + | SQL_SYM SECURITY_SYM INVOKER_SYM +- { Lex->create_view_suid= FALSE; } ++ { Lex->create_view_suid= VIEW_SUID_INVOKER; } + ; + + view_tail: +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/table.h mysql-dfsg-5.0-5.0.24a/sql/table.h +--- mysql-dfsg-5.0-5.0.24a~/sql/table.h 2006-08-25 17:11:58.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/table.h 2008-02-28 10:59:18.000000000 -0500 +@@ -360,6 +360,10 @@ + #define VIEW_ALGORITHM_TMPTABLE 1 + #define VIEW_ALGORITHM_MERGE 2 + ++#define VIEW_SUID_INVOKER 0 ++#define VIEW_SUID_DEFINER 1 ++#define VIEW_SUID_DEFAULT 2 ++ + /* view WITH CHECK OPTION parameter options */ + #define VIEW_CHECK_NONE 0 + #define VIEW_CHECK_LOCAL 1 only in patch2: unchanged: --- mysql-dfsg-5.0-5.0.24a.orig/debian/patches/103_SECURITY_CVE-2007-2692.dpatch +++ mysql-dfsg-5.0-5.0.24a/debian/patches/103_SECURITY_CVE-2007-2692.dpatch @@ -0,0 +1,523 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 103_SECURITY_CVE-2007-2692.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/r/grant.result mysql-dfsg-5.0-5.0.24a/mysql-test/r/grant.result +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/r/grant.result 2008-03-05 14:47:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/r/grant.result 2008-03-05 14:48:08.000000000 -0500 +@@ -920,3 +920,78 @@ + DROP DATABASE db27878; + use test; + DROP TABLE t1; ++DROP DATABASE IF EXISTS mysqltest1; ++DROP DATABASE IF EXISTS mysqltest2; ++CREATE DATABASE mysqltest1; ++CREATE DATABASE mysqltest2; ++GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost; ++GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost; ++CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER ++SELECT 1; ++ ++---> connection: bug27337_con1 ++CREATE TABLE t1(c INT); ++ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' ++CALL mysqltest1.p1(); ++1 ++1 ++CREATE TABLE t1(c INT); ++ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' ++ ++---> connection: bug27337_con2 ++CREATE TABLE t1(c INT); ++ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' ++SHOW TABLES; ++Tables_in_mysqltest2 ++ ++---> connection: default ++DROP DATABASE mysqltest1; ++DROP DATABASE mysqltest2; ++DROP USER mysqltest_1@localhost; ++DROP DATABASE IF EXISTS mysqltest1; ++DROP DATABASE IF EXISTS mysqltest2; ++CREATE DATABASE mysqltest1; ++CREATE DATABASE mysqltest2; ++CREATE TABLE mysqltest1.t1(c INT); ++CREATE TABLE mysqltest2.t2(c INT); ++GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; ++GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost; ++ ++---> connection: bug27337_con1 ++SHOW TABLES FROM mysqltest1; ++Tables_in_mysqltest1 ++t1 ++PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1'; ++EXECUTE stmt1; ++Tables_in_mysqltest1 ++t1 ++ ++---> connection: bug27337_con2 ++SHOW COLUMNS FROM mysqltest2.t2; ++Field Type Null Key Default Extra ++c int(11) YES NULL ++PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2'; ++EXECUTE stmt2; ++Field Type Null Key Default Extra ++c int(11) YES NULL ++ ++---> connection: default ++REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost; ++REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost; ++ ++---> connection: bug27337_con1 ++SHOW TABLES FROM mysqltest1; ++ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1' ++EXECUTE stmt1; ++ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1' ++ ++---> connection: bug27337_con2 ++SHOW COLUMNS FROM mysqltest2.t2; ++ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' ++EXECUTE stmt2; ++ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' ++ ++---> connection: default ++DROP DATABASE mysqltest1; ++DROP DATABASE mysqltest2; ++DROP USER mysqltest_1@localhost; +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/t/grant.test mysql-dfsg-5.0-5.0.24a/mysql-test/t/grant.test +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/t/grant.test 2008-03-05 14:47:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/t/grant.test 2008-03-05 14:47:44.000000000 -0500 +@@ -778,3 +778,146 @@ + use test; + DROP TABLE t1; + ++# ++# BUG#27337: Privileges are not restored properly. ++# ++# Actually, the patch for this bugs fixes two problems. So, here are two test ++# cases. ++ ++# Test case 1: privileges are not restored properly after calling a stored ++# routine defined with SQL SECURITY INVOKER clause. ++ ++# Prepare. ++ ++--disable_warnings ++DROP DATABASE IF EXISTS mysqltest1; ++DROP DATABASE IF EXISTS mysqltest2; ++--enable_warnings ++ ++CREATE DATABASE mysqltest1; ++CREATE DATABASE mysqltest2; ++ ++GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost; ++GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost; ++ ++CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER ++ SELECT 1; ++ ++# Test. ++ ++--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest2) ++--echo ++--echo ---> connection: bug27337_con1 ++ ++--error ER_TABLEACCESS_DENIED_ERROR ++CREATE TABLE t1(c INT); ++ ++CALL mysqltest1.p1(); ++ ++--error ER_TABLEACCESS_DENIED_ERROR ++CREATE TABLE t1(c INT); ++ ++--disconnect bug27337_con1 ++ ++--connect (bug27337_con2,localhost,mysqltest_1,,mysqltest2) ++--echo ++--echo ---> connection: bug27337_con2 ++ ++--error ER_TABLEACCESS_DENIED_ERROR ++CREATE TABLE t1(c INT); ++ ++SHOW TABLES; ++ ++# Cleanup. ++ ++--connection default ++--echo ++--echo ---> connection: default ++ ++--disconnect bug27337_con2 ++ ++DROP DATABASE mysqltest1; ++DROP DATABASE mysqltest2; ++ ++DROP USER mysqltest_1@localhost; ++ ++# Test case 2: priveleges are not checked properly for prepared statements. ++ ++# Prepare. ++ ++--disable_warnings ++DROP DATABASE IF EXISTS mysqltest1; ++DROP DATABASE IF EXISTS mysqltest2; ++--enable_warnings ++ ++CREATE DATABASE mysqltest1; ++CREATE DATABASE mysqltest2; ++ ++CREATE TABLE mysqltest1.t1(c INT); ++CREATE TABLE mysqltest2.t2(c INT); ++ ++GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; ++GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost; ++ ++# Test. ++ ++--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest1) ++--echo ++--echo ---> connection: bug27337_con1 ++ ++SHOW TABLES FROM mysqltest1; ++ ++PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1'; ++ ++EXECUTE stmt1; ++ ++--connect (bug27337_con2,localhost,mysqltest_2,,mysqltest2) ++--echo ++--echo ---> connection: bug27337_con2 ++ ++SHOW COLUMNS FROM mysqltest2.t2; ++ ++PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2'; ++ ++EXECUTE stmt2; ++ ++--connection default ++--echo ++--echo ---> connection: default ++ ++REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost; ++REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost; ++ ++--connection bug27337_con1 ++--echo ++--echo ---> connection: bug27337_con1 ++ ++--error ER_DBACCESS_DENIED_ERROR ++SHOW TABLES FROM mysqltest1; ++ ++--error ER_DBACCESS_DENIED_ERROR ++EXECUTE stmt1; ++ ++--connection bug27337_con2 ++--echo ++--echo ---> connection: bug27337_con2 ++ ++--error ER_TABLEACCESS_DENIED_ERROR ++SHOW COLUMNS FROM mysqltest2.t2; ++ ++--error ER_TABLEACCESS_DENIED_ERROR ++EXECUTE stmt2; ++ ++# Cleanup. ++ ++--connection default ++--echo ++--echo ---> connection: default ++ ++--disconnect bug27337_con2 ++ ++DROP DATABASE mysqltest1; ++DROP DATABASE mysqltest2; ++ ++DROP USER mysqltest_1@localhost; ++ +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/mysql_priv.h mysql-dfsg-5.0-5.0.24a/sql/mysql_priv.h +--- mysql-dfsg-5.0-5.0.24a~/sql/mysql_priv.h 2006-08-25 17:12:28.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/mysql_priv.h 2008-03-05 14:47:44.000000000 -0500 +@@ -876,6 +876,8 @@ + int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); + int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); + bool get_schema_tables_result(JOIN *join); ++enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table); ++ + #define is_schema_db(X) \ + !my_strcasecmp(system_charset_info, information_schema_name.str, (X)) + +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_db.cc mysql-dfsg-5.0-5.0.24a/sql/sql_db.cc +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_db.cc 2006-08-25 17:12:10.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_db.cc 2008-03-05 14:47:53.000000000 -0500 +@@ -1175,13 +1175,13 @@ + } + + #ifndef NO_EMBEDDED_ACCESS_CHECKS ++ if (test_all_bits(sctx->master_access, DB_ACLS)) ++ db_access=DB_ACLS; ++ else ++ db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) | ++ sctx->master_access); + if (!no_access_check) + { +- if (test_all_bits(sctx->master_access, DB_ACLS)) +- db_access=DB_ACLS; +- else +- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) | +- sctx->master_access); + if (!(db_access & DB_ACLS) && (!grant_option || + check_grant_db(thd,db_name))) + { +@@ -1211,8 +1211,7 @@ + DBUG_ASSERT(db_name == NULL || db_name[0] != '\0'); + thd->reset_db(db_name, db_length); // THD::~THD will free this + #ifndef NO_EMBEDDED_ACCESS_CHECKS +- if (!no_access_check) +- sctx->db_access= db_access; ++ sctx->db_access= db_access; + #endif + if (system_db) + { +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.24a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_parse.cc 2008-03-05 14:47:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_parse.cc 2008-03-05 14:47:44.000000000 -0500 +@@ -2189,7 +2189,8 @@ + enum enum_schema_tables schema_table_idx) + { + DBUG_ENTER("prepare_schema_table"); +- SELECT_LEX *sel= 0; ++ SELECT_LEX *schema_select_lex= NULL; ++ + switch (schema_table_idx) { + case SCH_SCHEMATA: + #if defined(DONT_ALLOW_SHOW_COMMANDS) +@@ -2197,11 +2198,9 @@ + ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ + DBUG_RETURN(1); + #else +- if ((specialflag & SPECIAL_SKIP_SHOW_DB) && +- check_global_access(thd, SHOW_DB_ACL)) +- DBUG_RETURN(1); + break; + #endif ++ + case SCH_TABLE_NAMES: + case SCH_TABLES: + case SCH_VIEWS: +@@ -2211,32 +2210,25 @@ + ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ + DBUG_RETURN(1); + #else ++ if (lex->select_lex.db == NULL && ++ thd->copy_db_to(&lex->select_lex.db, NULL)) + { +- char *db; +- if (lex->select_lex.db == NULL && +- thd->copy_db_to(&lex->select_lex.db, 0)) +- { +- DBUG_RETURN(1); +- } +- db= lex->select_lex.db; +- remove_escape(db); // Fix escaped '_' +- if (check_db_name(db)) +- { +- my_error(ER_WRONG_DB_NAME, MYF(0), db); +- DBUG_RETURN(1); +- } +- if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0, +- is_schema_db(db))) +- DBUG_RETURN(1); /* purecov: inspected */ +- if (!thd->col_access && check_grant_db(thd,db)) +- { +- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), +- thd->security_ctx->priv_user, thd->security_ctx->priv_host, +- db); +- DBUG_RETURN(1); +- } +- break; ++ DBUG_RETURN(1); ++ } ++ ++ schema_select_lex= new SELECT_LEX(); ++ schema_select_lex->db= lex->select_lex.db; ++ schema_select_lex->table_list.first= NULL; ++ remove_escape(schema_select_lex->db); // Fix escaped '_' ++ ++ if (check_db_name(schema_select_lex->db)) ++ { ++ my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db); ++ DBUG_RETURN(1); + } ++ ++ ++ break; + #endif + case SCH_COLUMNS: + case SCH_STATISTICS: +@@ -2245,28 +2237,23 @@ + ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ + DBUG_RETURN(1); + #else +- if (table_ident) + { ++ DBUG_ASSERT(table_ident); ++ + TABLE_LIST **query_tables_last= lex->query_tables_last; +- sel= new SELECT_LEX(); ++ schema_select_lex= new SELECT_LEX(); + /* 'parent_lex' is used in init_query() so it must be before it. */ +- sel->parent_lex= lex; +- sel->init_query(); +- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, +- (List *) 0, (List *) 0)) ++ schema_select_lex->parent_lex= lex; ++ schema_select_lex->init_query(); ++ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ, ++ (List *) 0, (List *) 0)) + DBUG_RETURN(1); + lex->query_tables_last= query_tables_last; +- TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first; +- char *db= table_list->db; +- remove_escape(db); // Fix escaped '_' +- remove_escape(table_list->table_name); +- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, +- &table_list->grant.privilege, 0, 0, +- test(table_list->schema_table))) +- DBUG_RETURN(1); /* purecov: inspected */ +- if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2, +- UINT_MAX, 0)) +- DBUG_RETURN(1); ++ ++ TABLE_LIST *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first; ++ remove_escape(dst_table->db); // Fix escaped '_' ++ remove_escape(dst_table->table_name); ++ + break; + } + #endif +@@ -2293,7 +2280,7 @@ + DBUG_RETURN(1); + } + TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; +- table_list->schema_select_lex= sel; ++ table_list->schema_select_lex= schema_select_lex; + table_list->schema_table_reformed= 1; + statistic_increment(thd->status_var.com_stat[lex->orig_sql_command], + &LOCK_status); +@@ -5240,6 +5227,83 @@ + } + + ++static bool check_show_access(THD *thd, TABLE_LIST *table) ++{ ++ switch (get_schema_table_idx(table->schema_table)) ++ { ++ case SCH_SCHEMATA: ++ return (specialflag & SPECIAL_SKIP_SHOW_DB) && ++ check_global_access(thd, SHOW_DB_ACL); ++ ++ case SCH_TABLE_NAMES: ++ case SCH_TABLES: ++ case SCH_VIEWS: ++ case SCH_TRIGGERS: ++ { ++ const char *dst_db_name= table->schema_select_lex->db; ++ ++ DBUG_ASSERT(dst_db_name); ++ ++ if (check_access(thd, SELECT_ACL, dst_db_name, ++ &thd->col_access, FALSE, FALSE, ++ is_schema_db(dst_db_name))) ++ { ++ return TRUE; ++ } ++ ++ if (!thd->col_access && check_grant_db(thd, dst_db_name)) ++ { ++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), ++ thd->security_ctx->priv_user, ++ thd->security_ctx->priv_host, ++ dst_db_name); ++ return TRUE; ++ } ++ ++ return FALSE; ++ } ++ ++ case SCH_COLUMNS: ++ case SCH_STATISTICS: ++ { ++ TABLE_LIST *dst_table= ++ (TABLE_LIST *) table->schema_select_lex->table_list.first; ++ ++ DBUG_ASSERT(dst_table); ++ ++ if (check_access(thd, SELECT_ACL | EXTRA_ACL, ++ dst_table->db, ++ &dst_table->grant.privilege, ++ FALSE, FALSE, ++ test(dst_table->schema_table))) ++ { ++ return FALSE; ++ } ++ ++ return grant_option && ++ check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE); ++ } ++ ++ case SCH_OPEN_TABLES: ++ case SCH_VARIABLES: ++ case SCH_STATUS: ++ case SCH_PROCEDURES: ++ case SCH_CHARSETS: ++ case SCH_COLLATIONS: ++ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY: ++ case SCH_USER_PRIVILEGES: ++ case SCH_SCHEMA_PRIVILEGES: ++ case SCH_TABLE_PRIVILEGES: ++ case SCH_COLUMN_PRIVILEGES: ++ case SCH_TABLE_CONSTRAINTS: ++ case SCH_KEY_COLUMN_USAGE: ++ break; ++ } ++ ++ return FALSE; ++} ++ ++ + /* + Check the privilege for all used tables. + +@@ -5298,7 +5362,16 @@ + Remove SHOW_VIEW_ACL, because it will be checked during making view + */ + tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); +- if (tables->derived || tables->schema_table || ++ ++ if (tables->schema_table_reformed) ++ { ++ if (check_show_access(thd, tables)) ++ goto deny; ++ ++ continue; ++ } ++ ++ if (tables->derived || + (tables->table && (int)tables->table->s->tmp_table) || + my_tz_check_n_skip_implicit_tables(&tables, + thd->lex->time_zone_tables_used)) +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_show.cc mysql-dfsg-5.0-5.0.24a/sql/sql_show.cc +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_show.cc 2006-08-25 17:12:00.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_show.cc 2008-03-05 14:47:44.000000000 -0500 +@@ -2124,7 +2124,7 @@ + */ + thd->reset_n_backup_open_tables_state(&open_tables_state_backup); + +- if (lsel) ++ if (lsel && lsel->table_list.first) + { + TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first; + bool res; only in patch2: unchanged: --- mysql-dfsg-5.0-5.0.24a.orig/debian/patches/101_SECURITY_CVE-2006-7232.dpatch +++ mysql-dfsg-5.0-5.0.24a/debian/patches/101_SECURITY_CVE-2006-7232.dpatch @@ -0,0 +1,68 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 101_SECURITY_CVE-2006-7232.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/r/information_schema.result mysql-dfsg-5.0-5.0.24a/mysql-test/r/information_schema.result +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/r/information_schema.result 2006-08-25 17:44:07.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/r/information_schema.result 2008-03-03 15:44:13.000000000 -0500 +@@ -1134,3 +1134,18 @@ + .t1 . t1 + .t2 . t2 + drop table t1,t2; ++create view v1 as ++select table_schema as object_schema, ++table_name as object_name, ++table_type as object_type ++from information_schema.tables ++order by object_schema; ++explain select * from v1; ++id select_type table type possible_keys key key_len ref rows Extra ++1 PRIMARY system NULL NULL NULL NULL 0 const row not found ++2 DERIVED tables ALL NULL NULL NULL NULL 2 Using filesort ++explain select * from (select table_name from information_schema.tables) as a; ++id select_type table type possible_keys key key_len ref rows Extra ++1 PRIMARY system NULL NULL NULL NULL 0 const row not found ++2 DERIVED tables ALL NULL NULL NULL NULL 2 ++drop view v1; +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/t/information_schema.test mysql-dfsg-5.0-5.0.24a/mysql-test/t/information_schema.test +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/t/information_schema.test 2006-08-25 17:44:06.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/t/information_schema.test 2008-03-03 15:38:29.000000000 -0500 +@@ -852,3 +852,16 @@ + select concat(@a, table_name), @a, table_name + from information_schema.tables where table_schema = 'test'; + drop table t1,t2; ++ ++# ++# Bug#22413: EXPLAIN SELECT FROM view with ORDER BY yield server crash ++# ++create view v1 as ++select table_schema as object_schema, ++ table_name as object_name, ++ table_type as object_type ++from information_schema.tables ++order by object_schema; ++explain select * from v1; ++explain select * from (select table_name from information_schema.tables) as a; ++drop view v1; +diff -urNad mysql-dfsg-5.0-5.0.24a~/sql/sql_select.cc mysql-dfsg-5.0-5.0.24a/sql/sql_select.cc +--- mysql-dfsg-5.0-5.0.24a~/sql/sql_select.cc 2006-08-25 17:11:45.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/sql/sql_select.cc 2008-03-03 15:38:29.000000000 -0500 +@@ -1334,6 +1334,7 @@ + TABLE *curr_tmp_table= 0; + + if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) && ++ !thd->lex->describe && + get_schema_tables_result(curr_join)) + { + DBUG_VOID_RETURN; +@@ -11545,6 +11546,7 @@ + + /* Fill schema tables with data before filesort if it's necessary */ + if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && ++ !thd->lex->describe && + get_schema_tables_result(join)) + goto err; + only in patch2: unchanged: --- mysql-dfsg-5.0-5.0.24a.orig/debian/patches/102_view_fix-now.dpatch +++ mysql-dfsg-5.0-5.0.24a/debian/patches/102_view_fix-now.dpatch @@ -0,0 +1,43 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 102_view_fix-now.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view.result mysql-dfsg-5.0-5.0.24a/mysql-test/r/view.result +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/r/view.result 2008-03-03 15:45:45.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/r/view.result 2008-03-03 15:46:08.000000000 -0500 +@@ -2679,12 +2679,12 @@ + ('Tom', 'Adams', '1908-02-14'), + ('Homer', 'Simpson', '1968-03-05'); + CREATE VIEW v1 AS +-SELECT (year(now())-year(DOB)) AS Age ++SELECT (year('2006-01-01')-year(DOB)) AS Age + FROM t1 HAVING Age < 75; + SHOW CREATE VIEW v1; + View Create View +-v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (year(now()) - year(`t1`.`DOB`)) AS `Age` from `t1` having (`Age` < 75) +-SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75; ++v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (year(_latin1'2006-01-01') - year(`t1`.`DOB`)) AS `Age` from `t1` having (`Age` < 75) ++SELECT (year('2006-01-01')-year(DOB)) AS Age FROM t1 HAVING Age < 75; + Age + 42 + 38 +diff -urNad mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view.test mysql-dfsg-5.0-5.0.24a/mysql-test/t/view.test +--- mysql-dfsg-5.0-5.0.24a~/mysql-test/t/view.test 2008-03-03 15:45:45.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.24a/mysql-test/t/view.test 2008-03-03 15:46:08.000000000 -0500 +@@ -2556,11 +2556,11 @@ + ('Homer', 'Simpson', '1968-03-05'); + + CREATE VIEW v1 AS +- SELECT (year(now())-year(DOB)) AS Age ++ SELECT (year('2006-01-01')-year(DOB)) AS Age + FROM t1 HAVING Age < 75; + SHOW CREATE VIEW v1; + +-SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75; ++SELECT (year('2006-01-01')-year(DOB)) AS Age FROM t1 HAVING Age < 75; + SELECT * FROM v1; + + DROP VIEW v1; only in patch2: unchanged: --- mysql-dfsg-5.0-5.0.24a.orig/debian/patches/99_SECURITY_CVE-2008-0226_0227.dpatch +++ mysql-dfsg-5.0-5.0.24a/debian/patches/99_SECURITY_CVE-2008-0226_0227.dpatch @@ -0,0 +1,71 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 99_SECURITY_CVE-2008-0226_0227.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.24a~/extra/yassl/src/handshake.cpp mysql-dfsg-5.0-5.0.24a/extra/yassl/src/handshake.cpp +--- mysql-dfsg-5.0-5.0.24a~/extra/yassl/src/handshake.cpp 2006-08-25 17:11:51.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/extra/yassl/src/handshake.cpp 2008-02-28 17:41:58.000000000 -0500 +@@ -487,6 +487,11 @@ + input.read(len, sizeof(len)); + uint16 randomLen; + ato16(len, randomLen); ++ if (ch.suite_len_ > MAX_SUITE_SZ || sessionLen > ID_LEN || ++ randomLen > RAN_LEN) { ++ ssl.SetError(bad_input); ++ return; ++ } + + int j = 0; + for (uint16 i = 0; i < ch.suite_len_; i += 3) { +diff -urNad mysql-dfsg-5.0-5.0.24a~/extra/yassl/src/yassl_imp.cpp mysql-dfsg-5.0-5.0.24a/extra/yassl/src/yassl_imp.cpp +--- mysql-dfsg-5.0-5.0.24a~/extra/yassl/src/yassl_imp.cpp 2006-08-25 17:12:30.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.24a/extra/yassl/src/yassl_imp.cpp 2008-02-28 17:48:41.000000000 -0500 +@@ -605,7 +605,13 @@ + ssl.SetError(factory_error); + return; + } +- hashHandShake(ssl, input, c24to32(length_)); ++ ++ uint len = c24to32(length_); ++ if (len > input.get_remaining()) { ++ ssl.SetError(bad_input); ++ return; ++ } ++ hashHandShake(ssl, input, len); + + input >> *hs; + hs->Process(input, ssl); +@@ -1306,6 +1312,13 @@ + } + + ++// workaround for g++ bug ++inline const uint16 min_uint16(const uint16 a, const uint16 b) ++{ ++ return b < a ? b : a; ++} ++ ++ + // input operator for Client Hello + input_buffer& operator>>(input_buffer& input, ClientHello& hello) + { +@@ -1322,10 +1335,15 @@ + + // Suites + byte tmp[2]; ++ uint16 len; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; +- ato16(tmp, hello.suite_len_); ++ ato16(tmp, len); ++ ++ hello.suite_len_ = min_uint16(len, static_cast(MAX_SUITE_SZ)); + input.read(hello.cipher_suites_, hello.suite_len_); ++ if (len > hello.suite_len_) // ignore extra suites ++ input.set_current(input.get_current() + len - hello.suite_len_); + + // Compression + hello.comp_len_ = input[AUTO];