I'm trying to use the FreeIPA Python API on macOS. With builtin Python (3.9 as of macOS 14), it seems to work normal. But with Python installed from MacPorts (even if it's the same major version), the interpreter terminates with SIGSEGV once the code execution reaches ipapython.session_storage.get_data and calls krb5_build_principal.
ipapython.session_storage.get_data
krb5_build_principal
port install python39
/opt/local/bin/python3.9 -c 'from ipapython import session_storage; session_storage.store_data("user@REALM", "key", "value")'
What's interesting is that it doesn't matter if the libkrb5.dylib library is a system Heimdal kerberos library or a MIT one from MacPorts package kerberos5, the crash happens in either case.
libkrb5.dylib
kerberos5
The traceback with PYTHONFAULTHANDLER=1 is identical:
PYTHONFAULTHANDLER=1
Fatal Python error: Segmentation fault Current thread 0x00000001ff964c00 (most recent call first): File "/Users/gasinvein/Library/Python/3.9/lib/python/site-packages/ipapython/session_storage.py", line 297 in get_data File "/Users/gasinvein/Library/Python/3.9/lib/python/site-packages/ipapython/session_storage.py", line 237 in store_data File "<string>", line 1 in <module> fish: Job 1, 'PYTHONFAULTHANDLER=1 python3.9 …' terminated by signal SIGSEGV (Address boundary error)
In the crash report with builtin Heimdal libkrb5.dylib:
0 libsystem_kernel.dylib 0x197af2a60 __pthread_kill + 8 1 libsystem_pthread.dylib 0x197b2ac20 pthread_kill + 288 2 libsystem_c.dylib 0x197a011e0 raise + 32 3 Python 0x101c5c7f4 faulthandler_fatal_error + 412 4 libsystem_platform.dylib 0x197b5b584 _sigtramp + 56 5 Heimdal 0x1a62b4f54 va_princ + 120 6 Heimdal 0x1a62b4eb8 build_principal + 232 7 Heimdal 0x1a62b4dc4 krb5_build_principal_va + 80 8 Kerberos 0x1a87f1cc8 krb5_build_principal + 116 9 libffi.8.dylib 0x100c34050 ffi_call_SYSV + 80 10 libffi.8.dylib 0x100c31548 ffi_call_int + 1432 11 _ctypes.cpython-312-darwin.so 0x100c0f9e8 _ctypes_callproc + 808 12 _ctypes.cpython-312-darwin.so 0x100c08a14 PyCFuncPtr_call + 216 13 Python 0x101aec428 _PyObject_MakeTpCall + 128 14 Python 0x101be0048 _PyEval_EvalFrameDefault + 44060 15 Python 0x101bd51bc PyEval_EvalCode + 184 16 Python 0x101c36590 run_eval_code_obj + 88 17 Python 0x101c34628 run_mod + 132 18 Python 0x101c33d0c PyRun_StringFlags + 124 19 Python 0x101c33c38 PyRun_SimpleStringFlags + 64 20 Python 0x101c56d94 Py_RunMain + 572 21 Python 0x101c57330 pymain_main + 304 22 Python 0x101c573d0 Py_BytesMain + 40 23 dyld 0x1977a20e0 start + 2360
In the crash report with MIT libkrb5.dylib from MacPorts (running python with DYLD_LIBRARY_PATH=/opt/local/lib:
DYLD_LIBRARY_PATH=/opt/local/lib
0 libsystem_kernel.dylib 0x197af2a60 __pthread_kill + 8 1 libsystem_pthread.dylib 0x197b2ac20 pthread_kill + 288 2 libsystem_c.dylib 0x197a011e0 raise + 32 3 libsystem_platform.dylib 0x197b5b584 _sigtramp + 56 4 libkrb5.3.3.dylib 0x103201970 build_principal_va + 204 5 libkrb5.3.3.dylib 0x103201a9c krb5_build_principal_alloc_va + 68 6 libkrb5.3.3.dylib 0x103201af0 krb5_build_principal + 28 7 libffi.8.dylib 0x102c94050 ffi_call_SYSV + 80 8 libffi.8.dylib 0x102c91548 ffi_call_int + 1432 9 _ctypes.cpython-39-darwin.so 0x102cc468c _ctypes_callproc + 860 10 _ctypes.cpython-39-darwin.so 0x102cbf450 PyCFuncPtr_call + 220 11 Python 0x10330ed34 _PyObject_MakeTpCall + 132 12 Python 0x1033e7cb4 call_function + 268 13 Python 0x1033e1b94 _PyEval_EvalFrameDefault + 15808 14 Python 0x10330f92c _PyFunction_Vectorcall + 184 15 Python 0x1033e7c28 call_function + 128 16 Python 0x1033e1b94 _PyEval_EvalFrameDefault + 15808 17 Python 0x10330f92c _PyFunction_Vectorcall + 184 18 Python 0x1033e7c28 call_function + 128 19 Python 0x1033e2e20 _PyEval_EvalFrameDefault + 20556 20 Python 0x1033dcf90 _PyEval_EvalCode + 416 21 Python 0x103428944 run_eval_code_obj + 136 22 Python 0x103428874 run_mod + 112 23 Python 0x103429384 PyRun_StringFlags + 148 24 Python 0x1034292a8 PyRun_SimpleStringFlags + 64 25 Python 0x10343fe88 Py_RunMain + 336 26 Python 0x103441188 Py_BytesMain + 40 27 dyld 0x1977a20e0 start + 2360
The command shouldn't cause the interpreter to crash.
FreeIPA python modules from 4.12.1
IPA code is not supposed to be used with Heimdal at all.
It seems in both cases it is failing in the krb5_build_principal().
krb5_build_principal(context, ctypes.byref(srv_princ), len(CONF_REALM), ctypes.c_char_p(CONF_REALM), ctypes.c_char_p(CONF_NAME), ctypes.c_char_p(key), pname, ctypes.c_char_p(None))
Are you able to run that under gdb and have bt full after a crash so that we can see actual context?
bt full
How is its client supposed to be used on macOS, then? Judging from the session_storage.py code, which has a special case for macOS, I've assumed it was at least considered at some point. MIT Kerberos isn't widely available on macOS.
session_storage.py
It's what I've figured, yes.
AFAIK GDB isn't available on Apple Silicon macs, and LLDB backtrace if essentially the same as what I've copy-pasted from crash reports. Anyway, here it is:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) * frame #0: 0x0000000197b58904 libsystem_platform.dylib`_platform_strlen + 4 frame #1: 0x0000000100705970 libkrb5.3.3.dylib`build_principal_va + 204 frame #2: 0x0000000100705a9c libkrb5.3.3.dylib`krb5_build_principal_alloc_va + 68 frame #3: 0x0000000100705af0 libkrb5.3.3.dylib`krb5_build_principal + 28 frame #4: 0x0000000100198050 libffi.8.dylib`ffi_call_SYSV + 80 frame #5: 0x0000000100195548 libffi.8.dylib`ffi_call_int + 1432 frame #6: 0x00000001001c868c _ctypes.cpython-39-darwin.so`_ctypes_callproc + 860 frame #7: 0x00000001001c3450 _ctypes.cpython-39-darwin.so`PyCFuncPtr_call + 220 frame #8: 0x0000000100812d34 Python`_PyObject_MakeTpCall + 132 frame #9: 0x00000001008ebcb4 Python`call_function + 268 frame #10: 0x00000001008e5b94 Python`_PyEval_EvalFrameDefault + 15808 frame #11: 0x000000010081392c Python`_PyFunction_Vectorcall + 184 frame #12: 0x00000001008ebc28 Python`call_function + 128 frame #13: 0x00000001008e5b94 Python`_PyEval_EvalFrameDefault + 15808 frame #14: 0x000000010081392c Python`_PyFunction_Vectorcall + 184 frame #15: 0x00000001008ebc28 Python`call_function + 128 frame #16: 0x00000001008e6e20 Python`_PyEval_EvalFrameDefault + 20556 frame #17: 0x00000001008e0f90 Python`_PyEval_EvalCode + 416 frame #18: 0x000000010092c944 Python`run_eval_code_obj + 136 frame #19: 0x000000010092c874 Python`run_mod + 112 frame #20: 0x000000010092d384 Python`PyRun_StringFlags + 148 frame #21: 0x000000010092d2a8 Python`PyRun_SimpleStringFlags + 64 frame #22: 0x0000000100943e88 Python`Py_RunMain + 336 frame #23: 0x0000000100945188 Python`Py_BytesMain + 40 frame #24: 0x00000001977a20e0 dyld`start + 2360
I guess Python must be built with debug symbols to make this useful? In this case, I'll need to figure out how to do this with MacPorts.
IPA client code was not and is currently not planned to work on macOS. session_storage.py was developed as a generic wrapper using ctypes/CFFI, but never targeted to use macOS. May be one of developers had macOS access at that time and added it for convenience, at that time.
Debug symbols are needed, yes, to get context... It may be one of arguments is NULL and that causes crashes -- judging by strlen() in the build_principal_va it is probably
build_principal_va
data[count].length = strlen(component);
where component is one of elements obtained through va_arg() macro. There are no checks for NULL arguments in there so we definitely passed something NULL in the original list.
component
va_arg()
Here is the LLDB backtrace from python and kerberos both build with debug symbols:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10) * frame #0: 0x0000000197b58904 libsystem_platform.dylib`_platform_strlen + 4 frame #1: 0x00000001002b2a3c libkrb5.3.3.dylib`build_principal_va(context=0x00000001126049f0, princ=0x0000600000740450, rlen=12, realm="X-CACHECONF:", ap="\U00000010\xaa\xdfo\U00000001") at bld_princ.c:76:34 frame #2: 0x00000001002b2c00 libkrb5.3.3.dylib`krb5_build_principal_alloc_va(context=0x00000001126049f0, princ=0x0000000100126f08, rlen=12, realm="X-CACHECONF:", ap="\xc0Kp\"\U00000001") at bld_princ.c:128:14 frame #3: 0x00000001002b2c94 libkrb5.3.3.dylib`krb5_build_principal(context=0x00000001126049f0, princ=0x0000000100126f08, rlen=12, realm="X-CACHECONF:") at bld_princ.c:148:14 frame #4: 0x00000001001cc050 libffi.8.dylib`ffi_call_SYSV + 80 frame #5: 0x00000001001ca78c libffi.8.dylib`ffi_call_int(cif=0x000000016fdfacb8, fn=(libkrb5.3.3.dylib`krb5_build_principal at bld_princ.c:143), orig_rvalue=0x000000016fdfadc0, avalue=0x000000016fdfad80, closure=0x0000000000000000) at ffi.c:829:3 frame #6: 0x00000001001ca134 libffi.8.dylib`ffi_call(cif=0x000000016fdfacb8, fn=(libkrb5.3.3.dylib`krb5_build_principal at bld_princ.c:143), rvalue=0x000000016fdfadc0, avalue=0x000000016fdfad80) at ffi.c:838:3 frame #7: 0x00000001002043d8 _ctypes.cpython-39-darwin.so`_call_function_pointer(flags=4353, pProc=(libkrb5.3.3.dylib`krb5_build_principal at bld_princ.c:143), avalues=0x000000016fdfad80, atypes=0x000000016fdfad40, restype=0x000000010018b2f8, resmem=0x000000016fdfadc0, argcount=8, argtypecount=8) at callproc.c:920:17 frame #8: 0x0000000100203c18 _ctypes.cpython-39-darwin.so`_ctypes_callproc(pProc=(libkrb5.3.3.dylib`krb5_build_principal at bld_princ.c:143), argtuple=0x0000000100151e40, flags=4353, argtypes=0x0000000100151a50, restype=0x000000012260da20, checker=0x0000000000000000) at callproc.c:1263:15 frame #9: 0x00000001001f8668 _ctypes.cpython-39-darwin.so`PyCFuncPtr_call(self=0x0000000100170c40, inargs=0x0000000100151e40, kwds=0x0000000000000000) at _ctypes.c:4201:14 frame #10: 0x0000000100e487e4 Python`_PyObject_MakeTpCall + 392 frame #11: 0x0000000100fa4a54 Python`_PyObject_VectorcallTstate + 100 frame #12: 0x0000000100fa1a5c Python`PyObject_Vectorcall + 60 frame #13: 0x0000000100fa1b70 Python`call_function + 264 frame #14: 0x0000000100f9df10 Python`_PyEval_EvalFrameDefault + 42356 frame #15: 0x0000000100e4a738 Python`_PyEval_EvalFrame + 52 frame #16: 0x0000000100e49450 Python`function_code_fastcall + 204 frame #17: 0x0000000100e491a4 Python`_PyFunction_Vectorcall + 288 frame #18: 0x0000000100fa4a74 Python`_PyObject_VectorcallTstate + 132 frame #19: 0x0000000100fa1a5c Python`PyObject_Vectorcall + 60 frame #20: 0x0000000100fa1b70 Python`call_function + 264 frame #21: 0x0000000100f9df10 Python`_PyEval_EvalFrameDefault + 42356 frame #22: 0x0000000100e4a738 Python`_PyEval_EvalFrame + 52 frame #23: 0x0000000100e49450 Python`function_code_fastcall + 204 frame #24: 0x0000000100e491a4 Python`_PyFunction_Vectorcall + 288 frame #25: 0x0000000100fa4a74 Python`_PyObject_VectorcallTstate + 132 frame #26: 0x0000000100fa1a5c Python`PyObject_Vectorcall + 60 frame #27: 0x0000000100fa1b70 Python`call_function + 264 frame #28: 0x0000000100f9ddb0 Python`_PyEval_EvalFrameDefault + 42004 frame #29: 0x0000000100f93958 Python`_PyEval_EvalFrame + 52 frame #30: 0x0000000100fa2da0 Python`_PyEval_EvalCode + 3164 frame #31: 0x0000000100fa36d0 Python`_PyEval_EvalCodeWithName + 216 frame #32: 0x0000000100f938e4 Python`PyEval_EvalCodeEx + 252 frame #33: 0x0000000100f937dc Python`PyEval_EvalCode + 76 frame #34: 0x00000001010003c0 Python`run_eval_code_obj + 164 frame #35: 0x0000000100ffe7e0 Python`run_mod + 188 frame #36: 0x0000000100ffd9a0 Python`PyRun_StringFlags + 260 frame #37: 0x0000000100ffd854 Python`PyRun_SimpleStringFlags + 104 frame #38: 0x000000010102d0f0 Python`pymain_run_command + 180 frame #39: 0x000000010102c974 Python`pymain_run_python + 388 frame #40: 0x000000010102c794 Python`Py_RunMain + 24 frame #41: 0x000000010102cb98 Python`pymain_main + 112 frame #42: 0x000000010102cbe8 Python`Py_BytesMain + 56 frame #43: 0x0000000100003f90 Python`___lldb_unnamed_symbol3 + 36 frame #44: 0x00000001977a20e0 dyld`start + 2360