Skip to content

Commit 6e9e486

Browse files
committed
MDEV-34322: ASAN heap-buffer-overflow in Field::is_null / Item_param::assign_default or bogus ER_BAD_NULL_ERROR
Execution of UPDATE statement on a table that has an associated trigger and the UPDATE statement tries to modify a column having the DEFAULT clause, could result in either assert firing or incorrect issuing of the ER_BAD_NULL_ERROR error. The reason of such behaviour is that on opening of a table that has an associated trigger, the method Table_triggers_list::prepare_record_accessors called to prepare Field objects referencing TABLE::record[1] instead of record[0]. This method allocates a new array of Field objects as copies of original table fields but updated null_ptr data members pointing to an array of extra_null_bitmap allocated before that on table's mem_root. Later switch_to_nullable_trigger_fields() is called where table' fields is switched to the new array allocated at Table_triggers_list::prepare_record_accessors(). After that, when fill_record() is invoked to fill table fields with values, so the make_default_field is invoked to handle the clause DEFAULT and the function make_default_field() called to create a field object. The function make_default_field() creates a copy of Field object and updates its data member prt/null_tr to position their to right place of table's record buffer, but since the method Table_triggers_list::prepare_record_accessors has been invoked before, the expression def_field->table->s->default_values - def_field->table->record[0] used for pointers adjustment leads to pointing to arbitrary memory not associated with the table. To fix the issue, use the TABLE_SHARE fields for referencing to columns default values.
1 parent dad29f2 commit 6e9e486

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

mysql-test/main/ps.result

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5991,3 +5991,27 @@ DROP VIEW t1;
59915991
#
59925992
# End of 10.4 tests
59935993
#
5994+
#
5995+
# MDEV-34322: ASAN heap-buffer-overflow in Field::is_null / Item_param::assign_default or bogus ER_BAD_NULL_ERROR
5996+
#
5997+
CREATE TABLE t1 (a INT NOT NULL DEFAULT '0', b INT);
5998+
INSERT INTO t1 VALUES (1,11);
5999+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
6000+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
6001+
DROP TABLE t1;
6002+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (30 + 100), b INT);
6003+
INSERT INTO t1 VALUES (1,11);
6004+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
6005+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
6006+
DROP TABLE t1;
6007+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (b + 100), b INT);
6008+
INSERT INTO t1 VALUES (1,11);
6009+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
6010+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
6011+
DROP TABLE t1;
6012+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (FLOOR(RAND()*100)), b INT);
6013+
INSERT INTO t1 VALUES (1,11);
6014+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
6015+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
6016+
DROP TABLE t1;
6017+
# End of 11.4 tests

mysql-test/main/ps.test

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5447,3 +5447,36 @@ DROP VIEW t1;
54475447
--echo #
54485448
--echo # End of 10.4 tests
54495449
--echo #
5450+
5451+
--echo #
5452+
--echo # MDEV-34322: ASAN heap-buffer-overflow in Field::is_null / Item_param::assign_default or bogus ER_BAD_NULL_ERROR
5453+
--echo #
5454+
CREATE TABLE t1 (a INT NOT NULL DEFAULT '0', b INT);
5455+
INSERT INTO t1 VALUES (1,11);
5456+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
5457+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
5458+
# Cleanup
5459+
DROP TABLE t1;
5460+
5461+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (30 + 100), b INT);
5462+
INSERT INTO t1 VALUES (1,11);
5463+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
5464+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
5465+
# Cleanup
5466+
DROP TABLE t1;
5467+
5468+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (b + 100), b INT);
5469+
INSERT INTO t1 VALUES (1,11);
5470+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
5471+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
5472+
# Cleanup
5473+
DROP TABLE t1;
5474+
5475+
CREATE TABLE t1 (a INT NOT NULL DEFAULT (FLOOR(RAND()*100)), b INT);
5476+
INSERT INTO t1 VALUES (1,11);
5477+
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @x = NULL;
5478+
EXECUTE IMMEDIATE "UPDATE t1 SET a = ?" USING DEFAULT;
5479+
# Cleanup
5480+
DROP TABLE t1;
5481+
5482+
--echo # End of 11.4 tests

sql/item.cc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5241,9 +5241,36 @@ static Field *make_default_field(THD *thd, Field *field_arg)
52415241
def_field->move_field(newptr + 1, def_field->maybe_null() ? newptr : 0, 1);
52425242
}
52435243
else
5244-
def_field->move_field_offset((my_ptrdiff_t)
5245-
(def_field->table->s->default_values -
5246-
def_field->table->record[0]));
5244+
{
5245+
if (field_arg->table->s->field != nullptr)
5246+
{
5247+
/*
5248+
Use fields array from TABLE_SHARE for referencing to null byte and
5249+
field's value on construction of a Field object for default value of
5250+
table column
5251+
*/
5252+
Field *target= field_arg->table->s->field[field_arg->field_index];
5253+
5254+
/*
5255+
Set up table field's pointers ptr, null_ptr to point to corresponding
5256+
s->default_values parts.
5257+
*/
5258+
def_field->move_field(target->ptr, target->null_ptr, target->null_bit);
5259+
}
5260+
else
5261+
{
5262+
/*
5263+
We get to here in case the field references a temporary table.
5264+
Triggers in not associated with a temporary table. Check these
5265+
invariants by DBUG_ASSERTs.
5266+
*/
5267+
DBUG_ASSERT(field_arg->table->s->tmp_table != NO_TMP_TABLE);
5268+
DBUG_ASSERT(field_arg->table->triggers == nullptr);
5269+
def_field->move_field_offset((my_ptrdiff_t)
5270+
(def_field->table->s->default_values -
5271+
def_field->table->record[0]));
5272+
}
5273+
}
52475274
return def_field;
52485275
}
52495276

0 commit comments

Comments
 (0)