← Back to team overview

maria-developers team mailing list archive

Re: 489a7fba324: MDEV-29322 ASAN heap-use-after-free in Query_log_event::do_apply_event

 

Hi, Andrei,

I still don't understand this.

1. Why rgi->options_to_bin_log is only set for GTID_EVENT?
   Is there a guarantee that there always be a GTID_EVENT before a
   QUERY_EVENT? What if gtids aren't enabled?

2. how do you guarantee that all query events for a previous value of
   options_written_to_bin_log have been applied before updating it
   in the rgi?

3. and if you do guarantee it, why is it atomic? No query events =
   nobody reads options_written_to_bin_log concurrently.

And why not to do a simple patch, like the one I've attached?
(note, it's an intentionally minimal patch to show the fix, practically
I'd accompany it with a small cleanup patch)

Regards,
Sergei
VP of MariaDB Server Engineering
and security@xxxxxxxxxxx

On Sep 02, Andrei Elkin wrote:
> 
> > Query_log_event cannot just randomly use some
> > options_written_to_bin_log, it must use options_written_to_bin_log
> > from the Format_description_log_event that came from the binlog file
> > where the Query_log_event was read from.
> 
> [ Not to engage you into a separate discussion,
>   still why 'randomly'? In the quoted description p.1 says
>   the Query_log_event uses `options_written_to_bin_log` from the
>   immediately preceding-in-binlog FD. ]
> 
> > If rli->relay_log.description_event_for_exec is not that
> > Format_description_log_event, and assuming that the correct
> > Format_description_log_event is not stored anywhere, the Query_log_event
> > has to remember options_written_to_bin_log itself,
> 
> It's an option, but the chosen one avoids such remembering per each
> Query event. Instead ...
> 
> > there's not much we can do about it.
> >
> > Or it can apply the mask in the constructor and store not flags2 but
> > the new value of thd->variables.option_bits.
> >
> > Or it can extend flags2 to cover all OPTIONS_WRITTEN_TO_BINLOG.
> 
> ... of taking care of individual events the patch basically goes along
> the base to use a placeholder that
> A. lasts (unlike FD instance) the whole slave session time, and
> B. the stored `options_written_to_binlog` is guaranteed to be a copy
>    of the most recent FD before the Query
> 
> To help you to understand the method, here is a sequence diagram,
> where on the top line
> the slave SQL thread, its Relay-log-info object, a similar to that Worker's instance,
> and a Worker thread.
> 
> 
> SQL thread       RLI/RGI    Worker RGI         Worker     
>     |              .            .                .
> --->+   read  FD   .            .                i
>     |              .            .                .
>     +-------------->            
>       stores options            
>     .                            
> --->+  read Query                   
>     |                           .
>     +-------------------------->+
>        finds Worker RGI
>        to store in theree a copy FD.options
>     |                                             .
>     +-------------------------------------------->+
>        schedules Query Worker                     |
>                                 .                 | 
>                                 .<----------------+
>                                    reads options  |             
>                                                   |  applies
>                                                  ... Query
> 
> It must be clear the A holds.
> To prove B let after Query a second FD^2 is read by the SQL thread and
> that FD^2 is from a different version server.
> Then the SQL thread always have a wait-for-workers-to-become-idle
> condition, so execution would go like this:
> 
> --->+  read Query               .                ... 
>     |                           .                 |
>     +-------------------------->+                 |
>        finds Worker RGI                           |
>        to store in theree a copy FD.options       |
>     |                                             |
> --->+  read FD^2                                  |  applying of
>     |                                             |  Query
>    ...                                            |
>    ... wait for Worker to complete Query          |
>    ...                                            |
>     +<============================================|
>     |
>     +-------------->.
>     | stores FD^2
>     |   options    
>    ...
> 
> So FD^2 can't affect queries from earlier binlogs.
> 
> I am all ears to hear about your feedback.
> 
> Cheers,
> 
> Andrei
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0aeec20b2ea..7cf27438700 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1509,7 +1509,7 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
     switch (*pos++) {
     case Q_FLAGS2_CODE:
       CHECK_SPACE(pos, end, 4);
-      flags2_inited= 1;
+      flags2_inited= description_event->options_written_to_bin_log;
       flags2= uint4korr(pos);
       DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2));
       pos+= 4;
diff --git a/sql/log_event.h b/sql/log_event.h
index 82cfe0abfa6..b031fec665d 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2099,7 +2099,7 @@ class Query_log_event: public Log_event
     flags2==0 (5.0 master, we know this has a meaning of flags all down which
     must influence the query).
   */
-  bool flags2_inited;
+  uint32 flags2_inited;
   bool sql_mode_inited;
   bool charset_inited;
 
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index 2cae9f60e4e..02fb8d9dd80 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -1728,7 +1728,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
           OPTIONS_WRITTEN_TO_BIN_LOG must take their value from
           flags2.
         */
-        ulonglong mask= rli->relay_log.description_event_for_exec->options_written_to_bin_log;
+        ulonglong mask= flags2_inited;
         thd->variables.option_bits= (flags2 & mask) |
                                     (thd->variables.option_bits & ~mask);
       }

Follow ups

References