Bug #44767 invalid memory reads in password() and old_password() functions
Submitted: 10 May 2009 16:53 Modified: 29 Jun 2009 19:39
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: General Severity:S1 (Critical)
Version:5.0.82, 5.1.30, 5.1.34, 5.1.35, 6.0.10 OS:Linux (32-bit fc8)
Assigned to: Alexey Kopytov CPU Architecture:Any
Tags: old_password, password, valgrind

[10 May 2009 16:53] Shane Bester
Description:
the password() and old_password() functions read invalid memory when their arguments are longer than 128k.  When <128k valgrind still outputs warnings about jumps depending on uninitialized memory values. 

 Invalid read of size 1
: Item_func_old_password::val_str(String*) (sql_string.h:102)
: Item::send(Protocol*, String*) (item.cc:5302)
: select_send::send_data(List<Item>&) (sql_class.cc:1587)
: end_send(JOIN*, st_join_table*, bool) (sql_select.cc:11976)
: evaluate_join_record(JOIN*, st_join_table*, int) (sql_select.cc:11236)
: sub_select(JOIN*, st_join_table*, bool) (sql_select.cc:11121)
: do_select(JOIN*, List<Item>*, st_table*, Procedure*) (sql_select.cc:10877)
: JOIN::exec() (sql_select.cc:2199)
: mysql_select (sql_select.cc:2378)
: handle_select(THD*, st_lex*, select_result*, unsigned long) (sql_select.cc:268)
: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5009)
: mysql_execute_command(THD*) (sql_parse.cc:2211)
  Address 0xC215AA0 is 0 bytes after a block of size 131,152 alloc'd
: malloc (vg_replace_malloc.c:149)
: ut_malloc_low (ut0mem.c:82)
: ut_malloc (ut0mem.c:189)
: mem_area_alloc (mem0pool.c:355)
: mem_heap_create_block (mem0mem.c:362)
: mem_heap_add_block (mem0mem.c:465)
: btr_copy_externally_stored_field (mem0mem.ic:155)
: btr_rec_copy_externally_stored_field (btr0cur.c:3847)
: row_sel_store_mysql_rec (row0sel.c:2638)
: row_search_for_mysql (row0sel.c:4234)
: ha_innobase::index_read (ha_innodb.cc:4410)
: ha_innobase::index_first(unsigned char*) (ha_innodb.cc:4674)
 
 
 Invalid read of size 1
: make_scrambled_password_323 (password.c:148)
: Item_func_old_password::val_str(String*) (item_strfunc.cc:1655)
: Item::send(Protocol*, String*) (item.cc:5302)
: select_send::send_data(List<Item>&) (sql_class.cc:1587)
: end_send(JOIN*, st_join_table*, bool) (sql_select.cc:11976)
: evaluate_join_record(JOIN*, st_join_table*, int) (sql_select.cc:11236)
: sub_select(JOIN*, st_join_table*, bool) (sql_select.cc:11121)
: do_select(JOIN*, List<Item>*, st_table*, Procedure*) (sql_select.cc:10877)
: JOIN::exec() (sql_select.cc:2199)
: mysql_select (sql_select.cc:2378)
: handle_select(THD*, st_lex*, select_result*, unsigned long) (sql_select.cc:268)
: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5009)
  
  Address 0xC215AA0 is 0 bytes after a block of size 131,152 alloc'd
: malloc (vg_replace_malloc.c:149)
: ut_malloc_low (ut0mem.c:82)
: ut_malloc (ut0mem.c:189)
: mem_area_alloc (mem0pool.c:355)
: mem_heap_create_block (mem0mem.c:362)
: mem_heap_add_block (mem0mem.c:465)
: btr_copy_externally_stored_field (mem0mem.ic:155)
: btr_rec_copy_externally_stored_field (btr0cur.c:3847)
: row_sel_store_mysql_rec (row0sel.c:2638)
: row_search_for_mysql (row0sel.c:4234)
: ha_innobase::index_read (ha_innodb.cc:4410)
: ha_innobase::index_first(unsigned char*) (ha_innodb.cc:4674)

 Invalid read of size 1
: Item_func_password::val_str(String*) (sql_string.h:102)
: Item::send(Protocol*, String*) (item.cc:5302)
: select_send::send_data(List<Item>&) (sql_class.cc:1587)
: end_send(JOIN*, st_join_table*, bool) (sql_select.cc:11976)
: evaluate_join_record(JOIN*, st_join_table*, int) (sql_select.cc:11236)
: sub_select(JOIN*, st_join_table*, bool) (sql_select.cc:11121)
: do_select(JOIN*, List<Item>*, st_table*, Procedure*) (sql_select.cc:10877)
: JOIN::exec() (sql_select.cc:2199)
: mysql_select (sql_select.cc:2378)
: handle_select(THD*, st_lex*, select_result*, unsigned long) (sql_select.cc:268)
: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5009)
: mysql_execute_command(THD*) (sql_parse.cc:2211)

  Address 0xC215AA0 is 0 bytes after a block of size 131,152 alloc'd
: malloc (vg_replace_malloc.c:149)
: ut_malloc_low (ut0mem.c:82)
: ut_malloc (ut0mem.c:189)
: mem_area_alloc (mem0pool.c:355)
: mem_heap_create_block (mem0mem.c:362)
: mem_heap_add_block (mem0mem.c:465)
: btr_copy_externally_stored_field (mem0mem.ic:155)
: btr_rec_copy_externally_stored_field (btr0cur.c:3847)
: row_sel_store_mysql_rec (row0sel.c:2638)
: row_search_for_mysql (row0sel.c:4234)
: ha_innobase::index_read (ha_innodb.cc:4410)
: ha_innobase::index_first(unsigned char*) (ha_innodb.cc:4674)

 Invalid read of size 1
: make_scrambled_password (password.c:399)
: Item_func_password::val_str(String*) (item_strfunc.cc:1632)
: Item::send(Protocol*, String*) (item.cc:5302)
: select_send::send_data(List<Item>&) (sql_class.cc:1587)
: end_send(JOIN*, st_join_table*, bool) (sql_select.cc:11976)
: evaluate_join_record(JOIN*, st_join_table*, int) (sql_select.cc:11236)
: sub_select(JOIN*, st_join_table*, bool) (sql_select.cc:11121)
: do_select(JOIN*, List<Item>*, st_table*, Procedure*) (sql_select.cc:10877)
: JOIN::exec() (sql_select.cc:2199)
: mysql_select (sql_select.cc:2378)
: handle_select(THD*, st_lex*, select_result*, unsigned long) (sql_select.cc:268)
: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5009)

  Address 0xC215AA0 is 0 bytes after a block of size 131,152 alloc'd
: malloc (vg_replace_malloc.c:149)
: ut_malloc_low (ut0mem.c:82)
: ut_malloc (ut0mem.c:189)
: mem_area_alloc (mem0pool.c:355)
: mem_heap_create_block (mem0mem.c:362)
: mem_heap_add_block (mem0mem.c:465)
: btr_copy_externally_stored_field (mem0mem.ic:155)
: btr_rec_copy_externally_stored_field (btr0cur.c:3847)
: row_sel_store_mysql_rec (row0sel.c:2638)
: row_search_for_mysql (row0sel.c:4234)
: ha_innobase::index_read (ha_innodb.cc:4410)
: ha_innobase::index_first(unsigned char*) (ha_innodb.cc:4674)

How to repeat:
#start mysqld under valgrind and run the following sql:

drop table if exists `t1`;
create table `t1`(`c3` mediumblob)engine=innodb;
insert into t1 values (repeat('a',131072));
select old_password(`c3`),password(`c3`) from `t1`;
[27 May 2009 10:24] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/75039

2748 Alexey Kopytov	2009-05-27
      Bug #44767: invalid memory reads in password() and   
                  old_password() functions   
      The PASSWORD() and OLD_PASSWORD() functions could lead to   
      memory reads outside of an internal buffer when used with BLOB   
      arguments.   
        
      String::c_ptr() assumes there is at least one extra byte  
      in the internally allocated buffer when adding the trailing  
      '\0'.  This, however, may not be the case when a String object  
      was initialized with externally allocated buffer.  
        
      The bug was fixed by adding an additional "length" argument to  
      make_scrambled_password_323() and make_scrambled_password() in  
      order to avoid String::c_ptr() calls for  
      PASSWORD()/OLD_PASSWORD().  
        
      However, since the make_scrambled_password[_323] functions are  
      a part of the client library ABI, the functions with the new  
      interfaces were implemented with the 'my_' prefix in their  
      names, with the old functions changed to be wrappers around  
      the new ones to maintain interface compatibility.  
      modified:
        mysql-test/r/func_crypt.result
        mysql-test/t/func_crypt.test
        sql/item_strfunc.cc
        sql/item_strfunc.h
        sql/mysql_priv.h
        sql/password.c
        sql/sql_yacc.yy
[16 Jun 2009 8:32] Bugs System
Pushed into 5.0.84 (revid:gkodinov@mysql.com-20090616082753-kwe0l8uoictxhojf) (version source revid:alexey.kopytov@sun.com-20090601124224-zgt3yov9wou590e9) (merge vers: 5.0.83) (pib:6)
[16 Jun 2009 11:03] Bugs System
Pushed into 5.1.36 (revid:joro@sun.com-20090616102155-3zhezogudt4uxdyn) (version source revid:alexey.kopytov@sun.com-20090601124316-kezp7g9u9lzcqhl0) (merge vers: 5.1.36) (pib:6)
[17 Jun 2009 19:24] Bugs System
Pushed into 5.4.4-alpha (revid:alik@sun.com-20090616183122-chjzbaa30qopdra9) (version source revid:alexey.kopytov@sun.com-20090601124405-svrero3hrfse6esa) (merge vers: 6.0.12-alpha) (pib:11)
[29 Jun 2009 19:39] Paul DuBois
Noted in 5.0.84, 5.1.36, 5.4.4 changelogs.

The PASSWORD() and OLD_PASSWORD() functions could read memory outside
of an internal buffer when used with BLOB arguments.
[12 Aug 2009 22:29] Paul DuBois
Noted in 5.4.2 changelog because next 5.4 version will be 5.4.2 and not 5.4.4.
[15 Aug 2009 1:47] Paul DuBois
Ignore previous comment about 5.4.2.
[26 Aug 2009 13:46] Bugs System
Pushed into 5.1.37-ndb-7.0.8 (revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (version source revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (merge vers: 5.1.37-ndb-7.0.8) (pib:11)
[26 Aug 2009 13:46] Bugs System
Pushed into 5.1.37-ndb-6.3.27 (revid:jonas@mysql.com-20090826105955-bkj027t47gfbamnc) (version source revid:jonas@mysql.com-20090826105955-bkj027t47gfbamnc) (merge vers: 5.1.37-ndb-6.3.27) (pib:11)
[26 Aug 2009 13:48] Bugs System
Pushed into 5.1.37-ndb-6.2.19 (revid:jonas@mysql.com-20090825194404-37rtosk049t9koc4) (version source revid:jonas@mysql.com-20090825194404-37rtosk049t9koc4) (merge vers: 5.1.37-ndb-6.2.19) (pib:11)
[27 Aug 2009 16:33] Bugs System
Pushed into 5.1.35-ndb-7.1.0 (revid:magnus.blaudd@sun.com-20090827163030-6o3kk6r2oua159hr) (version source revid:jonas@mysql.com-20090826132541-yablppc59e3yb54l) (merge vers: 5.1.37-ndb-7.0.8) (pib:11)
[7 Oct 2009 19:34] Paul DuBois
The 5.4 fix has been pushed to 5.4.2.