Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix leak of dpkg cache when dpkginfo_init is called multiple times #1939

Merged
merged 1 commit into from
Sep 6, 2023

Conversation

0intro
Copy link
Contributor

@0intro 0intro commented Feb 22, 2023

In the dpkginfo probe, the dpkg cache was allocated in dpkginfo_init. However, dpkginfo_init can be called multiple times, leading the cgCache pointer to be overridden and leaking the dpkg cache.

@evgenyz
Copy link
Contributor

evgenyz commented Apr 17, 2023

So the function is called from dpkginfo_probe_init, which should be called just once by the look of the code that deal with probe initialization. If that's not the case, and you have a proof of that we actually have a bigger problem with that function:

pthread_mutex_init (&(g_dpkg.mutex), NULL);

So, are you sure it is being called more than once?

@jan-cerny
Copy link
Member

@0intro What is your opinion on @evgenyz's comment?

@0intro
Copy link
Contributor Author

0intro commented May 22, 2023

I've noticed dpkginfo_probe_init can be instantiated multiple times when evaluating some rules.

For example, you can look at this GDB trace:

$ gdb --args oscap xccdf eval --rule xccdf_org.ssgproject.content_rule_package_gdm_removed ssg-ubuntu2204-ds.xml 
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 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".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
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 oscap...
(gdb) b dpkginfo_init
Function "dpkginfo_init" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (dpkginfo_init) pending.
(gdb) r
Starting program: /home/djc/sysroot/openscap/usr/local/bin/oscap xccdf eval --rule xccdf_org.ssgproject.content_rule_package_gdm_removed ssg-ubuntu2204-ds.xml
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff3ace640 (LWP 202030)]
[New Thread 0x7ffff32cd640 (LWP 202031)]
[New Thread 0x7ffff2acc640 (LWP 202032)]
[New Thread 0x7ffff22cb640 (LWP 202033)]
[Thread 0x7ffff22cb640 (LWP 202033) exited]
--- Starting Evaluation ---

Title   Remove the GDM Package Group
Rule    xccdf_org.ssgproject.content_rule_package_gdm_removed
[New Thread 0x7ffff22cb640 (LWP 202034)]
[New Thread 0x7ffff1aca640 (LWP 202035)]
[New Thread 0x7ffff12c9640 (LWP 202036)]
[New Thread 0x7ffff0ac8640 (LWP 202037)]
[Thread 0x7ffff0ac8640 (LWP 202037) exited]
[New Thread 0x7ffff0ac8640 (LWP 202038)]
[New Thread 0x7fffd3fff640 (LWP 202039)]
[New Thread 0x7fffd37fe640 (LWP 202040)]
[New Thread 0x7fffd2ffd640 (LWP 202041)]
[New Thread 0x7fffd2ffd640 (LWP 202042)]
[Thread 0x7fffd2ffd640 (LWP 202041) exited]
[New Thread 0x7fffd27fc640 (LWP 202043)]
[New Thread 0x7fffd1ffb640 (LWP 202044)]
[New Thread 0x7fffd17fa640 (LWP 202045)]
[Thread 0x7fffd17fa640 (LWP 202045) exited]
[New Thread 0x7fffd17fa640 (LWP 202046)]
[New Thread 0x7fffd0ff9640 (LWP 202047)]
[New Thread 0x7fffbbfff640 (LWP 202048)]
[New Thread 0x7fffbb7fe640 (LWP 202049)]
[Thread 0x7fffbb7fe640 (LWP 202049) exited]
[New Thread 0x7fffbb7fe640 (LWP 202050)]
[Thread 0x7fffbb7fe640 (LWP 202050) exited]
[New Thread 0x7fffbb7fe640 (LWP 202051)]
[New Thread 0x7fffbaffd640 (LWP 202052)]
[Switching to Thread 0x7fffbb7fe640 (LWP 202051)]

Thread 23 "common_main" hit Breakpoint 1, dpkginfo_init () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx:130
130             cgCache = new pkgCacheFile;
(gdb) bt
#0  dpkginfo_init() () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx:130
#1  0x00007ffff7f38776 in dpkginfo_probe_init () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo_probe.c:83
#2  0x00007ffff7f0b564 in probe_common_main (arg=0x555555978f30)
    at /home/djc/src/other/openscap/src/OVAL/probes/probe/probe_main.c:249
#3  0x00007ffff7a94b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#4  0x00007ffff7b26a00 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) t 1
[Switching to thread 1 (Thread 0x7ffff3ad1b40 (LWP 202026))]
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x555555825460)
    at ./nptl/futex-internal.c:57
57      ./nptl/futex-internal.c: No such file or directory.
(gdb) bt
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x555555825460)
    at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (cancel=true, private=0, abstime=0x0, clockid=0, expected=0, futex_word=0x555555825460)
    at ./nptl/futex-internal.c:87
#2  __GI___futex_abstimed_wait_cancelable64
    (futex_word=futex_word@entry=0x555555825460, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007ffff7a93ac1 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x555555825468, cond=0x555555825438)
    at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x555555825438, mutex=0x555555825468) at ./nptl/pthread_cond_wait.c:627
#5  0x00007ffff7f12b89 in sch_queue_recvsexp (desc=0x5555557dc2b0)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/sch_queue.c:92
#6  0x00007ffff7f16e87 in SEAP_packet_recv (ctx=0x555555a2f880, sd=4, packet=0x7fffffffa420)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/seap-packet.c:663
#7  0x00007ffff7f18ab6 in SEAP_recvmsg (ctx=0x555555a2f880, sd=4, seap_msg=0x7fffffffa4c8)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/seap.c:360
#8  0x00007ffff7ec340c in oval_probe_comm
    (ctx=0x555555a2f880, pd=0x555555978c90, s_iobj=0x5555559788b0, flags=0, out_sexp=0x7fffffffa5d8)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:550
#9  0x00007ffff7ec4dc0 in oval_probe_ext_eval
    (ctx=0x555555a2f880, pd=0x555555978c90, pext=0x555555823c70, syschar=0x555555978c10, flags=0)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:980
#10 0x00007ffff7ec49f9 in oval_probe_ext_handler (type=OVAL_LINUX_DPKG_INFO, ptr=0x555555823c70, act=3)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:858
#11 0x00007ffff7eb5a68 in oval_probe_query_object (psess=0x555555a2f8b0, object=0x5555555f4540, flags=0, out_syschar=0x0)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe.c:156
#12 0x00007ffff7eb5e97 in oval_probe_query_test (sess=0x555555a2f8b0, test=0x555555ab5e80)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe.c:257
#13 0x00007ffff7ed0e17 in _oval_result_test_result (rtest=0x555555978b90, args=0x7fffffffb8f0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultTest.c:1031
#14 0x00007ffff7ed1349 in oval_result_test_eval (rtest=0x555555978b90)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultTest.c:1152
#15 0x00007ffff7ec9e52 in _oval_result_criteria_node_result (node=0x5555559787a0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:367
#16 0x00007ffff7ec9f51 in oval_result_criteria_node_eval (node=0x5555559787a0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:390
#17 0x00007ffff7ec9ded in _oval_result_criteria_node_result (node=0x555555977dc0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:358
#18 0x00007ffff7ec9f51 in oval_result_criteria_node_eval (node=0x555555977dc0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:390
#19 0x00007ffff7ecb44b in oval_result_definition_eval (definition=0x555555978b50)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultDefinition.c:165
#20 0x00007ffff7ecd07d in oval_result_system_eval_definition (sys=0x5555555d8290, id=0x55555ce18b00 "oval:ssg-package_gdm:def:1")
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultSystem.c:373
#21 0x00007ffff7e911e8 in oval_agent_eval_definition (ag_sess=0x555555a2efa0, id=0x55555ce18b00 "oval:ssg-package_gdm:def:1")
    at /home/djc/src/other/openscap/src/OVAL/oval_agent.c:181
#22 0x00007ffff7efdb19 in _xccdf_policy_cpe_check_cb
    (sys=0x55555ce18ac0 "http://oval.mitre.org/XMLSchema/oval-definitions-5", href=0x55555ce189d0 "ssg-ubuntu2204-cpe-oval.xml", name=0x55555ce18b00 "oval:ssg-package_gdm:def:1", usr=0x5555555d7eb0)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:805
#23 0x00007ffff7e6fc65 in cpe_testexpr_evaluate
    (expr=0x55555ce18a90, check_cb=0x7ffff7efda70 <_xccdf_policy_cpe_check_cb>, dict_cb=0x7ffff7efdb56 <_xccdf_policy_cpe_dict_cb>, usr=0x5555555d7eb0) at /home/djc/src/other/openscap/src/CPE/cpelang.c:114
#24 0x00007ffff7e6fb6d in cpe_testexpr_evaluate
    (expr=0x55555ce18a20, check_cb=0x7ffff7efda70 <_xccdf_policy_cpe_check_cb>, dict_cb=0x7ffff7efdb56 <_xccdf_policy_cpe_dict_cb>, usr=0x5555555d7eb0) at /home/djc/src/other/openscap/src/CPE/cpelang.c:95
#25 0x00007ffff7e6fd3a in cpe_platform_applicable_lang_model
    (platform=0x55555cf59061 "package_gdm", lang_model=0x55555ce135e0, check_cb=0x7ffff7efda70 <_xccdf_policy_cpe_check_cb>, dict_fn=0x7ffff7efdb56 <_xccdf_policy_cpe_dict_cb>, usr=0x5555555d7eb0) at /home/djc/src/other/openscap/src/CPE/cpelang.c:131
#26 0x00007ffff7efde2d in xccdf_policy_model_platforms_are_applicable_lang_model
    (model=0x55555ec97a90, lang_model=0x55555ce135e0, platforms=0x555555899170)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:905
#27 0x00007ffff7efdf1f in xccdf_policy_model_platforms_are_applicable (model=0x55555ec97a90, platforms=0x555555899170)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:938
#28 0x00007ffff7efe091 in xccdf_policy_model_item_is_applicable (model=0x55555ec97a90, item=0x55555cf57c20)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:973
#29 0x00007ffff7efe06a in xccdf_policy_model_item_is_applicable (model=0x55555ec97a90, item=0x55555cf591d0)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:970
#30 0x00007ffff7efe682 in _xccdf_policy_rule_evaluate
    (policy=0x5555555ba2e0, rule=0x55555cf591d0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1090
#31 0x00007ffff7efeca5 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555cf591d0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1217
#32 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555cf57c20, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#33 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555ce946e0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#34 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555ce93240, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#35 0x00007ffff7f00f1c in xccdf_policy_evaluate (policy=0x5555555ba2e0)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:2133
#36 0x00007ffff7ef995b in xccdf_session_evaluate (session=0x5555555b78c0)
    at /home/djc/src/other/openscap/src/XCCDF/xccdf_session.c:1353
#37 0x000055555556864f in app_evaluate_xccdf (action=0x7fffffffc1b0) at /home/djc/src/other/openscap/utils/oscap-xccdf.c:667
#38 0x000055555556736e in oscap_module_call (action=0x7fffffffc1b0) at /home/djc/src/other/openscap/utils/oscap-tool.c:295
#39 0x00005555555678c1 in oscap_module_process (module=0x555555576e20 <XCCDF_EVAL>, argc=6, argv=0x7fffffffc498)
    at /home/djc/src/other/openscap/utils/oscap-tool.c:389
#40 0x000055555556ad5b in main (argc=6, argv=0x7fffffffc498) at /home/djc/src/other/openscap/utils/oscap.c:88
(gdb) c
Continuing.
[Detaching after fork from child process 202358]
[Detaching after fork from child process 202359]
[New Thread 0x7fffba2e4640 (LWP 202360)]
[New Thread 0x7fffb9ae3640 (LWP 202361)]
[Thread 0x7fffb9ae3640 (LWP 202361) exited]
[New Thread 0x7fffb9ae3640 (LWP 202362)]
[New Thread 0x7fffb92e2640 (LWP 202363)]
[Switching to Thread 0x7fffb9ae3640 (LWP 202362)]

Thread 27 "common_main" hit Breakpoint 1, dpkginfo_init () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx:130
130             cgCache = new pkgCacheFile;
(gdb) bt
#0  dpkginfo_init() () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo-helper.cxx:130
#1  0x00007ffff7f38776 in dpkginfo_probe_init () at /home/djc/src/other/openscap/src/OVAL/probes/unix/linux/dpkginfo_probe.c:83
#2  0x00007ffff7f0b564 in probe_common_main (arg=0x55555596dc30)
    at /home/djc/src/other/openscap/src/OVAL/probes/probe/probe_main.c:249
#3  0x00007ffff7a94b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#4  0x00007ffff7b26a00 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) t 1
[Switching to thread 1 (Thread 0x7ffff3ad1b40 (LWP 202026))]
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5555555f24a0)
    at ./nptl/futex-internal.c:57
57      ./nptl/futex-internal.c: No such file or directory.
(gdb) bt
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5555555f24a0)
    at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (cancel=true, private=0, abstime=0x0, clockid=0, expected=0, futex_word=0x5555555f24a0)
    at ./nptl/futex-internal.c:87
#2  __GI___futex_abstimed_wait_cancelable64
    (futex_word=futex_word@entry=0x5555555f24a0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007ffff7a93ac1 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5555555f24a8, cond=0x5555555f2478)
    at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5555555f2478, mutex=0x5555555f24a8) at ./nptl/pthread_cond_wait.c:627
#5  0x00007ffff7f12b89 in sch_queue_recvsexp (desc=0x5555555c4140)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/sch_queue.c:92
#6  0x00007ffff7f16e87 in SEAP_packet_recv (ctx=0x55555f12fbe0, sd=1, packet=0x7fffffffa5a0)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/seap-packet.c:663
#7  0x00007ffff7f18ab6 in SEAP_recvmsg (ctx=0x55555f12fbe0, sd=1, seap_msg=0x7fffffffa648)
    at /home/djc/src/other/openscap/src/OVAL/probes/SEAP/seap.c:360
#8  0x00007ffff7ec340c in oval_probe_comm
    (ctx=0x55555f12fbe0, pd=0x55555596d840, s_iobj=0x55555596d970, flags=0, out_sexp=0x7fffffffa758)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:550
#9  0x00007ffff7ec4dc0 in oval_probe_ext_eval
    (ctx=0x55555f12fbe0, pd=0x55555596d840, pext=0x55555f125f80, syschar=0x55555596d720, flags=0)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:980
#10 0x00007ffff7ec49f9 in oval_probe_ext_handler (type=OVAL_LINUX_DPKG_INFO, ptr=0x55555f125f80, act=3)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe_ext.c:858
#11 0x00007ffff7eb5a68 in oval_probe_query_object (psess=0x55555f12fb60, object=0x55555eebe730, flags=0, out_syschar=0x0)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe.c:156
#12 0x00007ffff7eb5e97 in oval_probe_query_test (sess=0x55555f12fb60, test=0x55555eda9260)
    at /home/djc/src/other/openscap/src/OVAL/oval_probe.c:257
#13 0x00007ffff7ed0e17 in _oval_result_test_result (rtest=0x55555596d620, args=0x7fffffffba70)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultTest.c:1031
#14 0x00007ffff7ed1349 in oval_result_test_eval (rtest=0x55555596d620)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultTest.c:1152
#15 0x00007ffff7ec9e52 in _oval_result_criteria_node_result (node=0x5555559787d0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:367
#16 0x00007ffff7ec9f51 in oval_result_criteria_node_eval (node=0x5555559787d0)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:390
#17 0x00007ffff7ec9ded in _oval_result_criteria_node_result (node=0x555555978410)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:358
#18 0x00007ffff7ec9f51 in oval_result_criteria_node_eval (node=0x555555978410)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultCriteriaNode.c:390
#19 0x00007ffff7ecb44b in oval_result_definition_eval (definition=0x55555596d580)
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultDefinition.c:165
#20 0x00007ffff7ecd07d in oval_result_system_eval_definition
    (sys=0x55555f1060f0, id=0x5555555bafa0 "oval:ssg-package_gdm_removed:def:1")
    at /home/djc/src/other/openscap/src/OVAL/results/oval_resultSystem.c:373
#21 0x00007ffff7e911e8 in oval_agent_eval_definition
    (ag_sess=0x55555f12ec70, id=0x5555555bafa0 "oval:ssg-package_gdm_removed:def:1")
    at /home/djc/src/other/openscap/src/OVAL/oval_agent.c:181
#22 0x00007ffff7e91f8d in oval_agent_eval_rule
    (policy=0x5555555ba2e0, rule_id=0x0, id=0x5555555bafa0 "oval:ssg-package_gdm_removed:def:1", href=0x5555555bb5a0 "ssg-ubuntu2204-oval.xml", it=0x5555555bb1c0, check_import_it=0x555555978550, usr=0x55555f12ec70)
    at /home/djc/src/other/openscap/src/OVAL/oval_agent.c:621
#23 0x00007ffff7f01765 in xccdf_policy_engine_eval
    (engine=0x55555f105ff0, policy=0x5555555ba2e0, definition_id=0x5555555bafa0 "oval:ssg-package_gdm_removed:def:1", href_id=0x5555555bb5a0 "ssg-ubuntu2204-oval.xml", value_bindings=0x55555596d520, check_import_it=0x555555978550)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy_engine.c:65
#24 0x00007ffff7efcb4f in xccdf_policy_evaluate_cb
    (policy=0x5555555ba2e0, sysname=0x55555596d440 "http://oval.mitre.org/XMLSchema/oval-definitions-5", content=0x5555555bafa0 "oval:ssg-package_gdm_removed:def:1", href=0x5555555bb5a0 "ssg-ubuntu2204-oval.xml", bindings=0x55555596d520, check_import_it=0x555555978550) at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:378
#25 0x00007ffff7efeb64 in _xccdf_policy_rule_evaluate
    (policy=0x5555555ba2e0, rule=0x55555cf591d0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1177
#26 0x00007ffff7efeca5 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555cf591d0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1217
#27 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555cf57c20, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#28 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555ce946e0, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#29 0x00007ffff7efed75 in xccdf_policy_item_evaluate
    (policy=0x5555555ba2e0, item=0x55555ce93240, result=0x55555f12c9b0, parent_selected=true)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:1232
#30 0x00007ffff7f00f1c in xccdf_policy_evaluate (policy=0x5555555ba2e0)
    at /home/djc/src/other/openscap/src/XCCDF_POLICY/xccdf_policy.c:2133
#31 0x00007ffff7ef995b in xccdf_session_evaluate (session=0x5555555b78c0)
    at /home/djc/src/other/openscap/src/XCCDF/xccdf_session.c:1353
#32 0x000055555556864f in app_evaluate_xccdf (action=0x7fffffffc1b0) at /home/djc/src/other/openscap/utils/oscap-xccdf.c:667
#33 0x000055555556736e in oscap_module_call (action=0x7fffffffc1b0) at /home/djc/src/other/openscap/utils/oscap-tool.c:295
#34 0x00005555555678c1 in oscap_module_process (module=0x555555576e20 <XCCDF_EVAL>, argc=6, argv=0x7fffffffc498)
    at /home/djc/src/other/openscap/utils/oscap-tool.c:389
#35 0x000055555556ad5b in main (argc=6, argv=0x7fffffffc498) at /home/djc/src/other/openscap/utils/oscap.c:88
(gdb) c
Continuing.
[Detaching after fork from child process 202544]
[New Thread 0x7fffa4fff640 (LWP 202563)]
[New Thread 0x7fff94fff640 (LWP 202564)]
[Thread 0x7fff94fff640 (LWP 202564) exited]
Result  pass

[Thread 0x7ffff2acc640 (LWP 202032) exited]
[Thread 0x7ffff32cd640 (LWP 202031) exited]
[Thread 0x7ffff3ace640 (LWP 202030) exited]
[Thread 0x7fffa4fff640 (LWP 202563) exited]
[Thread 0x7fffb92e2640 (LWP 202363) exited]
[Thread 0x7fffb9ae3640 (LWP 202362) exited]
[Thread 0x7fffd37fe640 (LWP 202040) exited]
[Thread 0x7fffd3fff640 (LWP 202039) exited]
[Thread 0x7ffff0ac8640 (LWP 202038) exited]
[Thread 0x7fffbbfff640 (LWP 202048) exited]
[Thread 0x7fffd0ff9640 (LWP 202047) exited]
[Thread 0x7fffd17fa640 (LWP 202046) exited]
[Thread 0x7ffff12c9640 (LWP 202036) exited]
[Thread 0x7ffff1aca640 (LWP 202035) exited]
[Thread 0x7ffff22cb640 (LWP 202034) exited]
[Thread 0x7fffba2e4640 (LWP 202360) exited]
[Thread 0x7fffbaffd640 (LWP 202052) exited]
[Thread 0x7fffbb7fe640 (LWP 202051) exited]
[Thread 0x7fffd1ffb640 (LWP 202044) exited]
[Thread 0x7fffd27fc640 (LWP 202043) exited]
[Thread 0x7fffd2ffd640 (LWP 202042) exited]
[Inferior 1 (process 202026) exited normally]
(gdb) q

The dpkg probe was instantiated two times during the execution of the _xccdf_policy_rule_evaluate function.

@evgenyz
Copy link
Contributor

evgenyz commented May 24, 2023

Okay, I can see that the init function is not meant to be executed once. On the contrary, the probe is expected to create its unique context (including mutexes and stuff) every time the init function is called.

The static global context of the dpkg probe is simply wrong:

struct dpkginfo_global {
        int init_done;
        pthread_mutex_t mutex;
};

static struct dpkginfo_global g_dpkg = {
        .init_done = -1,
};

Now, if the cgCache should be shared across all the instances is the question I can't answer right away. But this should probably be dealt with in the opencache function.

@0intro Do you want to try and make a proper fix for the dpkg probe? Because what we have right now is an UB.

@0intro
Copy link
Contributor Author

0intro commented May 24, 2023

Yes. I'll work on a proper fix for the dpkg probe.

@0intro
Copy link
Contributor Author

0intro commented Jun 19, 2023

It might be tempting to move the global cgCache into the dpkginfo_global structure (per dpkginfo probe), however, I think it would be much more efficient if the cgCache was shared across all the dpkginfo probes.

I think the issue is that _init_done is never set. I suppose the original intent was to use _init_done to condition the allocation of the dpkg cache and the call to the opencache function.

I've changed the commit to set _init_done properly after opencache has been called and moved the cgCache allocation after if (_init_done == 0).

What do you think?

@evgenyz
Copy link
Contributor

evgenyz commented Jun 19, 2023

We still have a problem with mutex.

@0intro
Copy link
Contributor Author

0intro commented Jun 19, 2023

Should we add a global mutex on cgCache?

@0intro 0intro force-pushed the dpkginfo_cache_leak branch 2 times, most recently from bfaa758 to 3e9500b Compare June 19, 2023 16:25
@0intro 0intro force-pushed the dpkginfo_cache_leak branch 2 times, most recently from 5469d0c to fc66249 Compare September 4, 2023 13:00
@0intro
Copy link
Contributor Author

0intro commented Sep 4, 2023

Thanks for your review. I've recently worked on a better version of this change.

The cgCache variable is now protected by a statically initialized mutex in dpkginfo_probe.c.

I've made other changes, which are described in the commit message.

I think there are still some cleanup which could be done in the dpkginfo probe,
but this commit should fix the main issues.

In the dpkginfo probe, the dpkg cache was allocated in dpkginfo_init.
However, dpkginfo_init can be called multiple times, leading the
cgCache pointer to be overridden and leaking the dpkg cache.
There are usually two dpkginfo probes running at the same time:
CPE and OVAL.

The opencache function is conditioned by the _init_done flag,
however, this flag was never set, so opencache was always called.

This change sets _init_done to 1 after opencache has been called,
and allocate the dpkg cache only when _init_done is 0.

Concurrent access to the cgCache static variable is now protected
by a statically initialized mutex in dpkginfo_probe.c.

We chose to keep cgCache as a static variable, because allocating
cgCache for every thread has big performance impact.
Also, calling new/delete revealed memory leaks in libapt.
Consequently, cgCache is initialized once and never freed.

The call to the cgCache->ReadOnlyOpen method is now done in the
dpkginfo_get_by_name function, so the dpkg cache is always up to date.
The cgCache->Close method is still called in dpkginfo_ini.

This change also removes the unused dpkg_mmap static variable
in dpkginfo-helper.cxx.
@evgenyz evgenyz added this to the 1.3.9 milestone Sep 4, 2023
@evgenyz evgenyz self-assigned this Sep 4, 2023
dpkginfo_fini();
pthread_mutex_destroy (&(d->mutex));
pthread_mutex_unlock (&(d->mutex));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we reset the .init_done here? The global struct is now uninitialized, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dpkginfo_global structure is initialized statically. .init_done is set to 1 once dpkginfo_init has been called for the first time. dpkginfo_fini only calls cgCache->Close, so cgCache->ReadOnlyOpen could update the dpkg cache the next time dpkginfo_get_by_name will be called. cgCache is allocated once, when dpkginfo_init has been called for the first time. Then, cgCache is never freed.

Copy link
Contributor

@evgenyz evgenyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have my doubts about this global context. What would happen if 2 instances initialize the context and then one of them would finish? How the second remaining instance will operate?

It probably never happens ATM because the instance pool lifetimes are the same, but it could change.

@0intro
Copy link
Contributor Author

0intro commented Sep 5, 2023

I still have my doubts about this global context. What would happen if 2 instances initialize the context and then one of them would finish? How the second remaining instance will operate?

The first call to dpkginfo_init will allocate the cgCache structure. Then, it's never freed.
Multiple dpkginfo threads could run at the same time. Simultaneous access to the cgCache is protected by the mutex.

It probably never happens ATM because the instance pool lifetimes are the same, but it could change.

Actually, this case happens in our use case (which is different from what the oscap tool does).

In our use case, we create a session once (xccdf_session_new), then we execute the checks periodically after cleaning the results.

Consequently dpkginfo_probe_init it called once for the first CPE check, but dpkginfo_probe_fini is not called until the XCCDF session is freed, at the end of the program.

During the lifetime of the XCCDF session, dpkginfo_probe_init is called during OVAL checks and dpkginfo_probe_fini is called each time the OVAL results are reset (using oval_probe_session_reinit).

So, at any point of the lifetime of the XCCDF session, we can have up to two dpkginfo threads: the CPE one (until the end of the XCCDF session) and one that could be ran (briefly) during the OVAL checks.

Copy link
Contributor

@evgenyz evgenyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, you've convinced me. Thanks for the fix and explanation.

@evgenyz evgenyz merged commit a7c2195 into OpenSCAP:maint-1.3 Sep 6, 2023
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants