lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
440 stars 70 forks source link

Misaligned memory accesses in marshal_2c_int and marshal_2lua_int #289

Open fstirlitz opened 2 years ago

fstirlitz commented 2 years ago

The UBSan suppression file that I added in the CI migration PR contains two entries:

https://github.com/lgi-devs/lgi/blob/7ea9a487ce11b9226c86bb63e85ae86d5c312f73/.github/ubsan.supp#L1-L3

These instances of UB should be fixed, and the file removed. (I attempted to do so in the first place, when doing the migration, but it was taking too long.)

psychon commented 2 years ago

What exactly do you mean?

I tried the following:

diff --git a/lgi/Makefile b/lgi/Makefile
index 08419bd..d48396f 100644
--- a/lgi/Makefile
+++ b/lgi/Makefile
@@ -12,14 +12,14 @@ LUA_LIBDIR = $(PREFIX)/lib/lua/$(LUA_VERSION)
 LUA_SHAREDIR = $(PREFIX)/share/lua/$(LUA_VERSION)

 PKG_CONFIG = pkg-config
-GINAME = gobject-introspection-1.0
+GINAME = gobject-introspection-1.0 lua5.3
 PKGS = $(GINAME) gmodule-2.0 libffi
 VERSION_FILE = version.lua

 ifneq ($(filter cygwin% msys% mingw%, $(HOST_OS)),)
 CORE = corelgilua51.dll
 LIBFLAG = -shared
-LIBS += -llua
+LIBS += -llua5.3 -fsanitize=undefined
 else
 ifeq ($(HOST_OS),darwin)
 CORE = corelgilua51.so
@@ -37,7 +37,7 @@ OBJS = buffer.o callable.o core.o gi.o marshal.o object.o record.o

 ifndef CFLAGS
 ifndef COPTFLAGS
-CFLAGS = -Wall -Wextra -O2 -g
+CFLAGS = -Wall -Wextra -O2 -g -fsanitize=undefined
 endif
 endif
 ifeq ($(HOST_OS),darwin)
@@ -45,7 +45,7 @@ CFLAGS += -DGOBJECT_INTROSPECTION_LIBDIR=\"$(GOBJECT_INTROSPECTION_LIBDIR)\"
 endif
 ALL_CFLAGS = $(CCSHARED) $(COPTFLAGS) $(LUA_CFLAGS) $(shell $(PKG_CONFIG) --cflags $(PKGS)) $(CFLAGS)
 LIBS += $(shell $(PKG_CONFIG) --libs $(PKGS))
-ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS)
+ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS) -fsanitize=undefined
 DEPCHECK = .depcheck

 # Precondition check
diff --git a/tests/Makefile b/tests/Makefile
index f11c20e..280ced0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -25,18 +25,18 @@ CCSHARED = -fPIC
 endif
 endif

-PKGS = gio-2.0 cairo cairo-gobject gobject-introspection-1.0 gmodule-2.0 libffi
-LUA = lua
+PKGS = gio-2.0 cairo cairo-gobject gobject-introspection-1.0 gmodule-2.0 libffi lua5.3
+LUA = lua5.3
 PKG_CONFIG = pkg-config

 ifndef CFLAGS
 ifndef COPTFLAGS
-CFLAGS = -Wall -g
+CFLAGS = -Wall -g -fsanitize=undefined
 endif
 endif
 ALL_CFLAGS = $(CCSHARED) $(COPTFLAGS) $(LUA_CFLAGS) $(shell $(PKG_CONFIG) --cflags $(PKGS)) $(CFLAGS) -I .
 LIBS += $(shell $(PKG_CONFIG) --libs $(PKGS))
-ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS)
+ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS) -fsanitize=undefined
 DEPCHECK = .depcheck

 # Precondition check

Result of make check:

cd .. && LD_LIBRARY_PATH=tests:$LD_LIBRARY_PATH \
    GI_TYPELIB_PATH=tests:$GI_TYPELIB_PATH \
    LUA_PATH="./?.lua;;" \
    LUA_CPATH="./?.so;;" \
    /usr/bin/dbus-run-session lua5.3 tests/test.lua
marshal.c:75:7: runtime error: member access within misaligned address 0x5603c74b8cb4 for type 'union GIArgument', which requires 8 byte alignment
0x5603c74b8cb4: note: pointer points here
  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  66 61 63 65 00 00 00 00  81 00 00 00 00 00 00 00
              ^ 
marshal.c:124:7: runtime error: member access within misaligned address 0x5603c74bb924 for type 'union GIArgument', which requires 8 byte alignment
0x5603c74bb924: note: pointer points here
  00 00 00 00 01 00 00 00  02 00 00 00 03 00 00 00  04 00 00 00 00 00 00 00  f1 00 00 00 00 00 00 00
              ^ 
marshal.c:71:7: runtime error: member access within misaligned address 0x5603c74b8cb1 for type 'union GIArgument', which requires 8 byte alignment
0x5603c74b8cb1: note: pointer points here
 00 00 00  01 00 00 a7 06 56 00 00  00 00 00 00 00 00 00 00  66 61 63 65 00 00 00 00  81 00 00 00 00
              ^ 
marshal.c:73:7: runtime error: member access within misaligned address 0x5603c74b8cb2 for type 'union GIArgument', which requires 8 byte alignment
0x5603c74b8cb2: note: pointer points here
 00 00  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  66 61 63 65 00 00 00 00  81 00 00 00 00 00
              ^ 
marshal.c:120:7: runtime error: member access within misaligned address 0x5603c74b8b9c for type 'union GIArgument', which requires 8 byte alignment
0x5603c74b8b9c: note: pointer points here
  2a 00 00 00 0c 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  60 00 00 00 00 00 00 00
              ^ 

(process:7628): Lgi-WARNING **: 18:30:21.233: Error raised while calling 'lgi.cbk (number): Regress': attempt to call a number value

(process:7628): Lgi-WARNING **: 18:30:21.233: Error raised while calling 'lgi.cbk (string): Regress': attempt to call a string value

(process:7628): Lgi-WARNING **: 18:30:21.233: Error raised while calling 'lgi.cbk (table: 0x5603c74dd670): Regress': attempt to call a table value

(process:7628): Lgi-WARNING **: 18:30:21.233: Error raised while calling 'lgi.cbk (table: 0x5603c73aee80): Regress': attempt to call a table value
gireg   : all 114 tests passed.
marshal : all 1 tests passed.
corocbk : all 3 tests passed.
record  : all 1 tests passed.

(lua5.3:7628): dbind-WARNING **: 18:30:21.786: AT-SPI: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files
marshal.c:125:7: runtime error: member access within misaligned address 0x5603c771e1ec for type 'union GIArgument', which requires 8 byte alignment
0x5603c771e1ec: note: pointer points here
  88 00 00 00 18 00 00 00  00 00 00 00 00 00 00 00  01 02 00 00 00 00 00 00  20 e2 71 c7 03 56 00 00
              ^ 

(lua5.3:7628): GLib-GObject-CRITICAL **: 18:30:21.819: Object class LgiTestFakeMonitor1 doesn't implement property 'network-metered' from interface 'GNetworkMonitor'
gobject : all 18 tests passed.
glib    : all 6 tests passed.
variant : all 17 tests passed.
dbus    : all 3 tests passed.
gtk     : all 21 tests passed.
cairo   : all 12 tests passed.
pango   : all 1 tests passed.
gio     : all 2 tests passed.
psychon commented 2 years ago

I managed to get a gdb breakpoint via rbreak ^__ubsan_handle_ (needs to be done when the process is already running) and got the following backtrace for the first hit:

(gdb) 
#0  0x00007ffff7bd7c80 in __ubsan_handle_type_mismatch_v1@plt () at ./lgi/corelgilua51.so
#1  0x00007ffff7be8f8f in marshal_2c_int (L=L@entry=0x5555555922a8, tag=<optimized out>, val=val@entry=0x555555748614, narg=narg@entry=6, parent=parent@entry=0, optional=<optimized out>)
    at marshal.c:75
#2  0x00007ffff7be91c6 in lgi_marshal_2c (L=L@entry=0x5555555922a8, ti=ti@entry=0x55555568b000, ai=ai@entry=0x0, transfer=transfer@entry=GI_TRANSFER_NOTHING, target=0x555555748614, narg=6, 
    narg@entry=-1, parent=0, ci=0x0, args=0x0) at marshal.c:1133
#3  0x00007ffff7bea50d in marshal_2c_array
    (L=L@entry=0x5555555922a8, ti=ti@entry=0x55555568a370, atype=atype@entry=GI_ARRAY_TYPE_C, out_array=out_array@entry=0x7fffffffde88, out_size=out_size@entry=0x7fffffffdd68, narg=narg@entry=2, optional=0, transfer=GI_TRANSFER_NOTHING) at marshal.c:394
#4  0x00007ffff7be942f in lgi_marshal_2c
    (L=L@entry=0x5555555922a8, ti=0x55555568a370, ai=ai@entry=0x5555557780e8, transfer=GI_TRANSFER_NOTHING, target=target@entry=0x7fffffffde88, narg=narg@entry=2, parent=0, ci=0x55555568a280, args=0x7fffffffde40) at marshal.c:1075
#5  0x00007ffff7bdad8e in callable_param_2c
    (L=L@entry=0x5555555922a8, param=param@entry=0x5555557780e0, narg=2, parent=parent@entry=0, arg=0x7fffffffde88, callable_index=callable_index@entry=1, callable=0x555555777fc8, args=0x7fffffffde40) at callable.c:734
#6  0x00007ffff7bdfff4 in callable_call (L=0x5555555922a8) at callable.c:889
#7  0x000055555556160f in luaD_precall (L=0x5555555922a8, func=0x555555667f20, nresults=1) at ./ldo.c:434
#8  0x000055555556d511 in luaV_execute (L=<optimized out>) at ./lvm.c:1134
#9  0x00005555555619c8 in luaD_call (nResults=<optimized out>, func=<optimized out>, L=0x5555555922a8) at ./ldo.c:499
#10 luaD_callnoyield (L=0x5555555922a8, func=<optimized out>, nResults=<optimized out>) at ./ldo.c:509
#11 0x0000555555560d4f in luaD_rawrunprotected (L=L@entry=0x5555555922a8, f=0x55555555c900 <f_call>, ud=0x7fffffffe1b0) at ./ldo.c:142
#12 0x0000555555561d3b in luaD_pcall (L=0x5555555922a8, func=<optimized out>, u=<optimized out>, old_top=496, ef=<optimized out>) at ./ldo.c:729
#13 0x000055555555eeea in lua_pcallk
    (L=L@entry=0x5555555922a8, nargs=nargs@entry=0, nresults=nresults@entry=-1, errfunc=errfunc@entry=2, ctx=ctx@entry=2, k=k@entry=0x555555575cf0 <finishpcall>) at ./lapi.c:969
#14 0x00005555555763d0 in luaB_xpcall (L=0x5555555922a8) at ./lbaselib.c:441
#15 0x000055555556160f in luaD_precall (L=0x5555555922a8, func=0x555555667eb0, nresults=2) at ./ldo.c:434
#16 0x000055555556d511 in luaV_execute (L=<optimized out>) at ./lvm.c:1134
#17 0x00005555555619c8 in luaD_call (nResults=<optimized out>, func=<optimized out>, L=0x5555555922a8) at ./ldo.c:499
#18 luaD_callnoyield (L=0x5555555922a8, func=<optimized out>, nResults=<optimized out>) at ./ldo.c:509
#19 0x0000555555560d4f in luaD_rawrunprotected (L=L@entry=0x5555555922a8, f=0x55555555c900 <f_call>, ud=0x7fffffffe480) at ./ldo.c:142
#20 0x0000555555561d3b in luaD_pcall (L=0x5555555922a8, func=<optimized out>, u=<optimized out>, old_top=80, ef=<optimized out>) at ./ldo.c:729
#21 0x000055555555eeea in lua_pcallk (L=L@entry=0x5555555922a8, nargs=nargs@entry=0, nresults=nresults@entry=-1, errfunc=errfunc@entry=3, ctx=ctx@entry=0, k=k@entry=0x0) at ./lapi.c:969
#22 0x000055555555b8bf in docall (L=L@entry=0x5555555922a8, narg=narg@entry=0, nres=nres@entry=-1) at ./lua.c:205
#23 0x000055555555c567 in handle_script (argv=<optimized out>, L=0x5555555922a8) at ./lua.c:445
#24 pmain (L=0x5555555922a8) at ./lua.c:580
#25 0x000055555556160f in luaD_precall (L=L@entry=0x5555555922a8, func=0x5555555928d0, nresults=1) at ./ldo.c:434
#26 0x000055555556198b in luaD_call (nResults=<optimized out>, func=<optimized out>, L=0x5555555922a8) at ./ldo.c:498
#27 luaD_callnoyield (L=0x5555555922a8, func=<optimized out>, nResults=<optimized out>) at ./ldo.c:509
#28 0x0000555555560d4f in luaD_rawrunprotected (L=L@entry=0x5555555922a8, f=0x55555555c900 <f_call>, ud=0x7fffffffe700) at ./ldo.c:142
#29 0x0000555555561d3b in luaD_pcall (L=0x5555555922a8, func=<optimized out>, u=<optimized out>, old_top=16, ef=<optimized out>) at ./ldo.c:729
#30 0x000055555555eeea in lua_pcallk (L=L@entry=0x5555555922a8, nargs=nargs@entry=2, nresults=nresults@entry=1, errfunc=errfunc@entry=0, ctx=ctx@entry=0, k=k@entry=0x0) at ./lapi.c:969
#31 0x000055555555b67b in main (argc=2, argv=0x7fffffffe848) at ./lua.c:606

The misaligned pointer comes from here: https://github.com/lgi-devs/lgi/blob/4a12286ffd5ec162a50efeff3c4896d6cd14c43c/lgi/marshal.c#L412-L416

gdb cannot print esize, but:

(gdb) print (GITypeTag) g_type_info_get_tag(eti)
$9 = GI_TYPE_TAG_INT32
(gdb) print objlen
$10 = 3

So, the code is creating something like guint32[3] and tries to fill it, and to fill it it uses the "general mechanism" that requires casting to GIArgument which is an union that also has pointer elements and thus "by the rules of ubsan" requires 64 bit alignment. Which this code, of course, cannot provide...