Created attachment 418446 [details] emerge --info output Hi all, Seems I've hit an issue with the Gentoo package for python-2.7.10-r1 and its 'ctypes' module. When a structure is passed to a library function, the pointer is truncated to 32-bits, causing a crash in the driver module. This is in particular been observed with the `python-mbus` library: https://github.com/rscada/python-mbus which is a ctypes wrapper around https://github.com/rscada/libmbus. libmbus itself works fine, have it happily polling a Siemens UH50 thermal/pulse meter. No hardware is needed to reproduce this bug in ctypes however. RC=0 stuartl@rikishi ~/vrt/projects/metermaster/deps/python-mbus $ gdb --args /usr/bin/python /usr/bin/py.test GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done. (gdb) r Starting program: /usr/bin/python /usr/bin/py.test warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? process 5971 is executing new program: /usr/bin/python2.7 warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". ======================================================================== test session starts ======================================================================== platform linux2 -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 rootdir: /home/stuartl/vrt/projects/metermaster/deps/python-mbus, inifile: pytest.ini plugins: cov collected 16 items tests/test_MBus_connect.py Program received signal SIGSEGV, Segmentation fault. 0x00007ffff19f5be1 in mbus_connect (handle=0x573e00a0) at mbus-protocol-aux.c:1589 1589 mbus-protocol-aux.c: No such file or directory. I've verified that under Debian Wheezy 64-bit (running under LXC on the Gentoo host).
Some further information, tried rebuilding libffi, cffi, python: 1449558950: Started emerge on: Dec 08, 2015 17:15:49 1449558950: *** emerge --oneshot --verbose dev-libs/libffi dev-lang/python:2.7 dev-python/cffi 1449559136: >>> emerge (1 of 3) dev-libs/libffi-3.0.13-r1 to / 1449559136: === (1 of 3) Cleaning (dev-libs/libffi-3.0.13-r1::/usr/portage/dev-libs/libffi/libffi-3.0.13-r1.ebuild) 1449559137: === (1 of 3) Compiling/Packaging (dev-libs/libffi-3.0.13-r1::/usr/portage/dev-libs/libffi/libffi-3.0.13-r1.ebuild) 1449559169: === (1 of 3) Merging (dev-libs/libffi-3.0.13-r1::/usr/portage/dev-libs/libffi/libffi-3.0.13-r1.ebuild) 1449559212: >>> AUTOCLEAN: dev-libs/libffi:0 1449559212: === Unmerging... (dev-libs/libffi-3.0.13-r1) 1449559220: >>> unmerge success: dev-libs/libffi-3.0.13-r1 1449559222: === (1 of 3) Post-Build Cleaning (dev-libs/libffi-3.0.13-r1::/usr/portage/dev-libs/libffi/libffi-3.0.13-r1.ebuild) 1449559222: ::: completed emerge (1 of 3) dev-libs/libffi-3.0.13-r1 to / 1449559222: >>> emerge (2 of 3) dev-lang/python-2.7.10-r1 to / 1449559222: === (2 of 3) Cleaning (dev-lang/python-2.7.10-r1::/usr/portage/dev-lang/python/python-2.7.10-r1.ebuild) 1449559223: === (2 of 3) Compiling/Packaging (dev-lang/python-2.7.10-r1::/usr/portage/dev-lang/python/python-2.7.10-r1.ebuild) 1449559384: === (2 of 3) Merging (dev-lang/python-2.7.10-r1::/usr/portage/dev-lang/python/python-2.7.10-r1.ebuild) 1449559402: >>> AUTOCLEAN: dev-lang/python:2.7 1449559402: === Unmerging... (dev-lang/python-2.7.10-r1) 1449559405: >>> unmerge success: dev-lang/python-2.7.10-r1 1449559410: === (2 of 3) Post-Build Cleaning (dev-lang/python-2.7.10-r1::/usr/portage/dev-lang/python/python-2.7.10-r1.ebuild) 1449559410: ::: completed emerge (2 of 3) dev-lang/python-2.7.10-r1 to / 1449559410: >>> emerge (3 of 3) dev-python/cffi-1.2.1 to / 1449559410: === (3 of 3) Cleaning (dev-python/cffi-1.2.1::/usr/portage/dev-python/cffi/cffi-1.2.1.ebuild) 1449559410: === (3 of 3) Compiling/Packaging (dev-python/cffi-1.2.1::/usr/portage/dev-python/cffi/cffi-1.2.1.ebuild) 1449559439: === (3 of 3) Merging (dev-python/cffi-1.2.1::/usr/portage/dev-python/cffi/cffi-1.2.1.ebuild) 1449559442: >>> AUTOCLEAN: dev-python/cffi:0 1449559442: === Unmerging... (dev-python/cffi-0.8.6) 1449559444: >>> unmerge success: dev-python/cffi-0.8.6 1449559448: === (3 of 3) Post-Build Cleaning (dev-python/cffi-1.2.1::/usr/portage/dev-python/cffi/cffi-1.2.1.ebuild) 1449559448: ::: completed emerge (3 of 3) dev-python/cffi-1.2.1 to / 1449559448: *** Finished. Cleaning up... 1449559452: *** exiting successfully. The python interpreter still segfaults: RC=0 stuartl@rikishi ~/vrt/projects/metermaster/deps/python-mbus $ gdb --args /usr/bin/python /usr/bin/py.test GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done. (gdb) r Starting program: /usr/bin/python /usr/bin/py.test warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? process 2427 is executing new program: /usr/bin/python2.7 warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". ================================================================== test session starts ================================================================== platform linux2 -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 rootdir: /home/stuartl/vrt/projects/metermaster/deps/python-mbus, inifile: pytest.ini plugins: cov collected 16 items tests/test_MBus_connect.py Program received signal SIGSEGV, Segmentation fault. 0x00007ffff19f5be1 in mbus_connect (handle=0x573e31c0) at mbus-protocol-aux.c:1589 1589 mbus-protocol-aux.c: No such file or directory. (gdb) bt #0 0x00007ffff19f5be1 in mbus_connect (handle=0x573e31c0) at mbus-protocol-aux.c:1589 #1 0x00007ffff1c4d8d4 in ffi_call_unix64 () from /usr/lib64/libffi.so.6 #2 0x00007ffff1c4d1ba in ffi_call () from /usr/lib64/libffi.so.6 #3 0x00007ffff1e62fcc in _ctypes_callproc () from /usr/lib64/python2.7/lib-dynload/_ctypes.so #4 0x00007ffff1e5bb68 in ?? () from /usr/lib64/python2.7/lib-dynload/_ctypes.so #5 0x00007ffff7a3c366 in PyObject_Call () from /usr/lib64/libpython2.7.so.1.0 #6 0x00007ffff7aedac8 in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0 #7 0x00007ffff7aef731 in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
Does this occur with 2.7.11? 3.5.0? Is there anything that indicates this is specific to Gentoo's python? I suspect you should probably seek help upstream.
Haven't tried with Python3 (not sure if it's compatible), but I might give 2.7.11 a try later. As I mentioned, I tried running the same code inside an LXC instance of Debian Wheezy 64-bit, and did not suffer the segmentation fault.
(In reply to Stuart Longland from comment #3) > As I mentioned, I tried running the same code inside an LXC instance of > Debian Wheezy 64-bit, and did not suffer the segmentation fault. You said "I've verified that under Debian Wheezy 64-bit", but did not state what the results of said verification were. Thank you for clarifying.
Fair enough, apologies for not being clear. I did a test with Python 2.7.11: RC=0 stuartl@rikishi ~/vrt/projects/metermaster/deps/python-mbus $ gdb --args /usr/bin/python /usr/bin/py.test GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done. (gdb) run Starting program: /usr/bin/python /usr/bin/py.test warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? process 27872 is executing new program: /usr/bin/python2.7 warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". ======================================================================== test session starts ======================================================================== platform linux2 -- Python 2.7.11 -- py-1.4.30 -- pytest-2.7.2 rootdir: /home/stuartl/vrt/projects/metermaster/deps/python-mbus, inifile: pytest.ini plugins: cov collected 16 items tests/test_MBus_connect.py Program received signal SIGSEGV, Segmentation fault. 0x00007ffff19efbe1 in mbus_connect (handle=0x559cb390) at mbus-protocol-aux.c:1589 1589 return handle->open(handle); (gdb) bt #0 0x00007ffff19efbe1 in mbus_connect (handle=0x559cb390) at mbus-protocol-aux.c:1589 #1 0x00007ffff1c478d4 in ffi_call_unix64 () from /usr/lib64/libffi.so.6 #2 0x00007ffff1c471ba in ffi_call () from /usr/lib64/libffi.so.6 #3 0x00007ffff1e5cfcc in _ctypes_callproc () from /usr/lib64/python2.7/lib-dynload/_ctypes.so #4 0x00007ffff1e55b68 in ?? () from /usr/lib64/python2.7/lib-dynload/_ctypes.so #5 0x00007ffff7a37d86 in PyObject_Call () from /usr/lib64/libpython2.7.so.1.0 #6 0x00007ffff7aea1d2 in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0 #7 0x00007ffff7aec28b in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0 #8 0x00007ffff7aefcc8 in PyEval_EvalCodeEx () from /usr/lib64/libpython2.7.so.1.0
For reference, this is what happens when I run the same code under Debian Wheezy: RC=0 stuartl@sjl-lxc-wheezy ~/vrt/projects/metermaster/deps/python-mbus $ py.test ======================================================================== test session starts ======================================================================== platform linux2 -- Python 2.7.3 -- pytest-2.2.4 collected 14 items / 2 errors tests/test_MBus_init.py ...FF......... ============================================================================== ERRORS =============================================================================== ____________________________________________________________ ERROR collecting tests/test_MBus_connect.py ____________________________________________________________ tests/test_MBus_connect.py:7: in <module> > @pytest.fixture E AttributeError: 'module' object has no attribute 'fixture' __________________________________________________________ ERROR collecting tests/test_MBus_disconnect.py ___________________________________________________________ tests/test_MBus_disconnect.py:7: in <module> > @pytest.fixture E AttributeError: 'module' object has no attribute 'fixture' ============================================================================= FAILURES ============================================================================== ______________________________________________________________________ test_device_nonexistent ______________________________________________________________________ @pytest.mark.serial def test_device_nonexistent(): > with pytest.raises(FileNotFoundError): E NameError: global name 'FileNotFoundError' is not defined tests/test_MBus_init.py:36: NameError ________________________________________________________________________ test_device_serial _________________________________________________________________________ pytestconfig = <_pytest.config.Config object at 0x2b77410> @pytest.mark.serial def test_device_serial(pytestconfig): if '/dev/adjustme' == pytestconfig.getini('serialdevice'): pytest.skip("serial device not configured") with pytest.raises(TypeError): > foo = MBus.MBus(device=pytestconfig.getini('serialdevice')) tests/test_MBus_init.py:45: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <mbus.MBus.MBus instance at 0x2f1ae60> def __init__(self, *args, **kwargs): """ Constructor for MBus class. possible arguments are * device * host * libpath: path to libmbus (shared object or dll) * port: default 8888 """ import os from ctypes import cdll # check all given arguments for validity validargs = ('device','host','libpath','port') for arg in kwargs.keys(): if arg not in validargs: raise TypeError("invalid argument") # set default values device = None host = None port = 8888 libpath = None if 'device' in kwargs.keys(): device = kwargs['device'] if 'libpath' in kwargs.keys(): libpath = kwargs['libpath'] if 'host' in kwargs.keys(): host = kwargs['host'] if 'port' in kwargs.keys(): if isinstance(kwargs['port'],int): if 65535 <= kwargs['port']: raise ValueError("port number too high") if 0 > kwargs['port']: raise ValueError("port number too low") port = kwargs['port'] else: raise TypeError("port number not given as integer") if None == libpath: libpath = "/usr/local/lib/libmbus.so" self._libmbus = cdll.LoadLibrary(libpath) try: self._libmbus.mbus_get_current_version() except AttributeError: raise OSError("libmbus not found") if (None != device) and (None != host): raise BaseException("conflicting arguments 'device' and 'host' given") if (None == device) and (None == host): raise BaseException("Must provide either device or host keyword arguments") if device: > fd = os.open(device, os.O_RDONLY) E OSError: [Errno 2] No such file or directory: '/dev/ttyS0' mbus/MBus.py:80: OSError =========================================================== 2 failed, 12 passed, 2 error in 0.18 seconds ============================================================ OSError, because /dev/ttyS0 is on the host, I haven't figured out a way to expose my host's /dev/ttyS0 to the LXC guest. However, the library doesn't segfault.
I'll see if I can reproduce this.
Created attachment 418814 [details] Test log I'm unable to reproduce the segfault here. A test log is attached. I see you are running hardened. Do you experience this on a more vanilla Gentoo system? In my experience, PaX likes to make things segfault at random.
Ahh okay, the plot thickens. No I haven't tried with non-hardened. All my AMD64/x86 systems run the hardened branch of Gentoo. It certainly isn't a "random" segfault, it's segfaulting for a good reason: the pointer address is wrong. I'm just trying to nut out why. I might have a look at grabbing a couple of "fresh" stage3's. One hardened (just in case there's something queer going on here), one not.
(In reply to Stuart Longland from comment #9) > It certainly isn't a "random" segfault, it's segfaulting for a good reason: > the pointer address is wrong. I'm just trying to nut out why. I'm not sure how you have determined that the pointer is being truncated to 32-bits. That sounds rather far-fetched to me.
(In reply to Stuart Longland from comment #9) > I might have a look at grabbing a couple of "fresh" stage3's. One hardened > (just in case there's something queer going on here), one not. The stage tarball is not very important; PaX is mainly a kernel feature, and I suspect it may be causing some issue here.
(In reply to Mike Gilbert from comment #10) > (In reply to Stuart Longland from comment #9) > > It certainly isn't a "random" segfault, it's segfaulting for a good reason: > > the pointer address is wrong. I'm just trying to nut out why. > > I'm not sure how you have determined that the pointer is being truncated to > 32-bits. That sounds rather far-fetched to me. Well, so far I've only ever seen addresses passed to the C code that would fit in a 32-bit address space. Either the pointers are being truncated, or they're completely fictitious. I'll admit truncation is an assumption on my part, it is possible that any old garbage is being passed back to the C code. It is possible that Raditex Control (makers of libmbus, python-mbus) have cocked up their Python code and that it magically works on Debian. I'm just trying to figure out why Gentoo and Debian have such different reactions to the same code. (In reply to Mike Gilbert from comment #11) > (In reply to Stuart Longland from comment #9) > > I might have a look at grabbing a couple of "fresh" stage3's. One hardened > > (just in case there's something queer going on here), one not. > > The stage tarball is not very important; PaX is mainly a kernel feature, and > I suspect it may be causing some issue here. As it's the same kernel running both (LXC container, so chroot on steroids), the kernel should have an identical effect on both instances of Python, correct? I run the hardened stages mainly for the toolchain. The kernels I run are vanilla mainline Linux kernels.
Okay, some further digging. Whatever is happening to that pointer, it's getting mangled badly. I edited the example 'mbus-test-1.py' to print out the "handle" that gets passed when connecting: diff --git a/examples/mbus-test-1.py b/examples/mbus-test-1.py index dae8991..452306d 100755 --- a/examples/mbus-test-1.py +++ b/examples/mbus-test-1.py @@ -17,6 +17,7 @@ mbus = MBus(host="mbus-gw1", port=8888) if debug: print("mbus = " + str(mbus)) + print 'handle = %r' % mbus.handle mbus.connect() On Debian, I get this: RC=0 stuartl@sjl-lxc-wheezy ~/vrt/projects/metermaster/deps/python-mbus/examples $ gdb --args /usr/bin/python mbus-test-1.py GNU gdb (GDB) 7.4.1-debian Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /usr/bin/python...Reading symbols from /usr/lib/debug/usr/bin/python2.7...done. done. (gdb) break mbus_connect Function "mbus_connect" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (mbus_connect) pending. (gdb) r Starting program: /usr/bin/python mbus-test-1.py warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". mbus = <mbus.MBus.MBus instance at 0x7ffff7e77c20> handle = 10224256 Breakpoint 1, mbus_connect (handle=0x9c0280) at mbus-protocol-aux.c:1583 1583 if (handle == NULL) On Gentoo: RC=0 stuartl@rikishi ~/vrt/projects/metermaster/deps/python-mbus/examples $ gdb --args /usr/bin/python mbus-test-1.py GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done. (gdb) break mbus_connect Function "mbus_connect" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (mbus_connect) pending. (gdb) r Starting program: /usr/bin/python mbus-test-1.py warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? process 23397 is executing new program: /usr/bin/python2.7 warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". mbus = <mbus.MBus.MBus instance at 0x7ffff7e4f3f8> handle = 1434631936 Breakpoint 1, mbus_connect (handle=0x5582bf00) at mbus-protocol-aux.c:1582 1582 { (gdb) Now the variable, from a Python perspective is just a plain integer, which is probably wrong: I've never dealt with ctypes before, if I've needed C code in Python I usually use the C extension API. (I'm tempted to do that actually.) The value is the return value from mbus_context_serial or mbus_context_tcp, which are both C functions that return a pointer. It seems this pointer is getting mangled. Running that code again on Gentoo, and this time setting a few more breakpoints: RC=0 stuartl@rikishi ~/vrt/projects/metermaster/deps/python-mbus/examples $ gdb --args /usr/bin/python mbus-test-1.py GNU gdb (Gentoo 7.7.1 p1) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://bugs.gentoo.org/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done. (gdb) break mbus_context_tcp Function "mbus_context_tcp" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (mbus_context_tcp) pending. (gdb) break mbus_connect Function "mbus_connect" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 2 (mbus_connect) pending. (gdb) r Starting program: /usr/bin/python mbus-test-1.py warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? process 4275 is executing new program: /usr/bin/python2.7 warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Breakpoint 1, mbus_context_tcp (host=0x7ffff7ea8f84 "mbus-gw1", port=43225) at mbus-protocol-aux.c:1523 1523 { (gdb) s 1528 if ((handle = (mbus_handle *) malloc(sizeof(mbus_handle))) == NULL) (gdb) s 1534 if ((tcp_data = (mbus_tcp_data *)malloc(sizeof(mbus_tcp_data))) == NULL) (gdb) s … (gdb) s 1567 return handle; (gdb) print handle $1 = (mbus_handle *) 0x55555582bf00 (gdb) c Continuing. mbus = <mbus.MBus.MBus instance at 0x7ffff7e4f3f8> handle = 1434631936 Breakpoint 2, mbus_connect (handle=0x5582bf00) at mbus-protocol-aux.c:1582 1582 { (gdb) Sure looks like truncation to me.
If I modify MBus.py: diff --git a/mbus/MBus.py b/mbus/MBus.py index 7f26165..466781f 100644 --- a/mbus/MBus.py +++ b/mbus/MBus.py @@ -2,7 +2,7 @@ Python bindings for rSCADA libmbus. """ -from ctypes import c_int,c_char_p,addressof,pointer +from ctypes import c_int,c_char_p,c_void_p,addressof,pointer from mbus.MBusFrame import MBusFrame from mbus.MBusFrameData import MBusFrameData @@ -81,9 +81,13 @@ class MBus: if not os.isatty(fd): raise TypeError(device+" is not a TTY") os.close(fd) - self.handle = self._libmbus.mbus_context_serial(device) + mbus_context_serial = self._libmbus.mbus_context_serial + mbus_context_serial.restype = c_void_p + self.handle = mbus_context_serial(device) elif host != None and port: - self.handle = self._libmbus.mbus_context_tcp(host) + mbus_context_tcp = self._libmbus.mbus_context_tcp + mbus_context_tcp.restype = c_void_p + self.handle = mbus_context_tcp(host) I still get truncation: mbus = <mbus.MBus.MBus instance at 0x7ffff7e4f3f8> handle = 93824995231520 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff6101be1 in mbus_connect (handle=0x55830720) at mbus-protocol-aux.c:1589 1589 return handle->open(handle); (gdb) print handle $1 = (mbus_handle *) 0x55830720
Okay, I think I see what's going on here now. The bug is technically in python-mbus: it isn't declaring argument/return data types, and so Python assumes they are integers. 32-bit integers. I started to get things moving when I made the following changes: diff --git a/mbus/MBus.py b/mbus/MBus.py index 7f26165..e12546a 100644 --- a/mbus/MBus.py +++ b/mbus/MBus.py @@ -2,7 +2,7 @@ Python bindings for rSCADA libmbus. """ -from ctypes import c_int,c_char_p,addressof,pointer +from ctypes import c_int,c_char_p,c_void_p,addressof,pointer from mbus.MBusFrame import MBusFrame from mbus.MBusFrameData import MBusFrameData @@ -81,16 +81,22 @@ class MBus: if not os.isatty(fd): raise TypeError(device+" is not a TTY") os.close(fd) - self.handle = self._libmbus.mbus_context_serial(device) + mbus_context_serial = self._libmbus.mbus_context_serial + mbus_context_serial.restype = c_void_p + self.handle = mbus_context_serial(device) elif host != None and port: - self.handle = self._libmbus.mbus_context_tcp(host) + mbus_context_tcp = self._libmbus.mbus_context_tcp + mbus_context_tcp.restype = c_void_p + self.handle = mbus_context_tcp(host) def connect(self): """ Connect to MBus. """ if self.handle: - if self._libmbus.mbus_connect(self.handle) == -1: + mbus_connect = self._libmbus.mbus_connect + mbus_connect.argtypes = [c_void_p] + if mbus_connect(self.handle) == -1: raise Exception("libmbus.mbus_connect failed") else: raise Exception("Handle object not configure") It worked on Debian because Debian used addresses in the lower 32-bits. It only showed itself on Gentoo because on Gentoo, the addresses were allocated above that first 4GB of address space. If everything gets allocated in that low area of memory, all is good, but if it moves higher, all hell breaks loose. Perhaps this is a quirk of the hardened libc? Since I know where the fault is now, I can mark this bug as invalid. It might be a handy reference for others that might be looking at similar bugs.