/ meson.build
meson.build
1 # SPDX-FileCopyrightText: Copyright (C) 2024-2025 Marek Küthe <m.k@mk16.de> 2 # 3 # SPDX-License-Identifier: GPL-3.0-or-later 4 5 project( 6 'crazytrace', 7 'cpp', 8 version: '1.0.7', 9 license: ['GPL-3.0-or-later'], 10 default_options: [ 11 'buildtype=release', 12 'optimization=2', 13 'warning_level=3', 14 'werror=true', 15 'cpp_std=gnu++26', 16 'b_asneeded=true', 17 'b_lto=true', 18 'b_ndebug=if-release', 19 'b_pie=true' 20 ], 21 meson_version: '>=1.5.0' 22 ) 23 24 cpp_compiler = meson.get_compiler('cpp') 25 26 main_file = files('src/main.cpp') 27 sources = files( 28 'src/capability_managment.cpp', 29 'src/configuration.cpp', 30 'src/crazytrace.cpp', 31 'src/landlock.cpp', 32 'src/loglevel.cpp', 33 'src/posix_wrapper.cpp', 34 'src/postup_commands.cpp', 35 'src/nodecontainer.cpp', 36 'src/nodeinfo.cpp', 37 'src/nodereply.cpp', 38 'src/noderequest.cpp', 39 'src/randomgenerator.cpp', 40 'src/seccomp.cpp' 41 ) 42 headers = files( 43 'src/capability_managment.hpp', 44 'src/capsicum.hpp', 45 'src/configuration.hpp', 46 'src/crazytrace.hpp', 47 'src/deviceclient.hpp', 48 'src/ip_ranges.hpp', 49 'src/landlock.hpp', 50 'src/loglevel.hpp', 51 'src/posix_wrapper.hpp', 52 'src/postup_commands.hpp', 53 'src/nodecontainer.hpp', 54 'src/nodeinfo.hpp', 55 'src/nodereply.hpp', 56 'src/noderequest.hpp', 57 'src/randomgenerator.hpp', 58 'src/seccomp.hpp' 59 ) 60 tests_sources = files( 61 'tests/loglevel_test.cpp', 62 'tests/nodecontainer_test.cpp', 63 'tests/nodeinfo_test.cpp', 64 'tests/nodeinfo_children_test.cpp', 65 'tests/nodereply_test.cpp', 66 'tests/noderequest_test.cpp', 67 'tests/randomgenerator_test.cpp' 68 ) 69 markdown_files = files( 70 'BUILDING.md', 71 'CHANGELOG.md', 72 'CONTRIBUTING.md', 73 'README.md', 74 'SECURITY.md' 75 ) 76 all_sources = main_file + sources + headers + tests_sources 77 78 if get_option('native') 79 native_flags = ['-march=native', '-mtune=native'] 80 81 add_project_arguments(cpp_compiler.get_supported_arguments(native_flags), language: 'cpp') 82 endif 83 84 # see https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html 85 hardening_compiler_flags = [ 86 '-Wformat=2', # Strict printf/scanf format checks 87 '-Wconversion', # Warnings for potentially lossy implicit conversions 88 '-Wsign-conversion', 89 '-Wtrampolines', # Warn about stack trampolines (conflicts with non‑executable stack) 90 '-Wbidi-chars=any', # Enable warnings for possibly misleading Unicode bidirectional control characters 91 '-fstrict-flex-arrays=3', # Flexible arrays can only be declared with []. 92 '-fcf-protection=full', # Prevent certain attacks by enabling additional protection against unexpected control flow jumps. Minimal performance loss, as often implemented on the hardware side. 93 '-mbranch-protection=standard' 94 ] 95 add_project_arguments(cpp_compiler.get_supported_arguments(hardening_compiler_flags), language: 'cpp') 96 97 hardening_linker_flags = [ 98 '-Wl,-z,noexecstack', # Mark the stack in memory as non-executable 99 '-Wl,-z,nodlopen', # Prevent loading this code via dlopen() 100 '-Wl,-z,relro', # Make relocation data read‑only after startup 101 '-Wl,-z,now' # Force the resolution of symbols from dynamic libraries at program startup 102 ] 103 add_project_link_arguments(cpp_compiler.get_supported_link_arguments(hardening_linker_flags), language: 'cpp') 104 105 if get_option('debug') 106 # see https://sourceware.org/bugzilla/show_bug.cgi?id=27375 107 add_project_arguments(cpp_compiler.get_supported_arguments(['-gdwarf-4']), language: 'cpp') 108 endif 109 110 if host_machine.system() == 'freebsd' 111 # see https://github.com/exult/exult/commit/202264bcf37d4edc8eafdaf53e1a910c8cf181a7 112 add_project_arguments('-isystem/usr/local/include', language: 'cpp') 113 endif 114 115 cpp_compiler.has_header('unistd.h', required: true) 116 cpp_compiler.has_function('dup', prefix: '#include <unistd.h>', required: true) 117 118 if get_option('enable_setugid') 119 cpp_compiler.has_function('setuid', prefix: '#include <unistd.h>', required: true) 120 cpp_compiler.has_function('setgid', prefix: '#include <unistd.h>', required: true) 121 cpp_compiler.has_type('struct passwd', prefix: '#include <pwd.h>', required: true) 122 cpp_compiler.has_type('struct group', prefix: '#include <grp.h>', required: true) 123 add_project_arguments('-DHAVE_SETUGID', language: 'cpp') 124 endif 125 126 libtuntappp_dep = dependency('libtuntap++', required: false, include_type: 'system') 127 if not libtuntappp_dep.found() 128 libtuntappp_dep = cpp_compiler.find_library('libtuntap++', has_headers: ['tuntap++.hh'], required: false) 129 if not libtuntappp_dep.found() 130 libtuntappp_dep = cpp_compiler.find_library('tuntap++', has_headers: ['tuntap++.hh'], required: true) 131 endif 132 endif 133 134 libtuntap_dep = dependency('libtuntap', required: false, include_type: 'system') 135 if not libtuntap_dep.found() 136 libtuntap_dep = cpp_compiler.find_library('libtuntap', has_headers: ['tuntap.h'], required: false) 137 if not libtuntap_dep.found() 138 libtuntap_dep = cpp_compiler.find_library('tuntap', has_headers: ['tuntap.h'], required: true) 139 endif 140 endif 141 142 # Workaround for https://github.com/boostorg/process/issues/494#issuecomment-3392312248 143 boost_dep = dependency('boost', modules: ['log', 'process', 'filesystem'], required: false, include_type: 'system') 144 if not boost_dep.found() 145 boost_dep = dependency('boost', modules: ['log'], include_type: 'system') 146 add_project_arguments('-DBOOST_PROCESS_V1', language: 'cpp') 147 endif 148 149 libcapng_dep = dependency('libcap-ng', required: false) 150 if libcapng_dep.found() 151 add_project_arguments('-DHAVE_LIBCAPNG', language: 'cpp') 152 endif 153 154 seccomp_dep = dependency('libseccomp', required: false) 155 if seccomp_dep.found() and cpp_compiler.has_header('sys/syscall.h') 156 add_project_arguments('-DHAVE_SECCOMP', language: 'cpp') 157 endif 158 159 if cpp_compiler.has_header('linux/landlock.h') 160 add_project_arguments('-DHAVE_LANDLOCK', language: 'cpp') 161 162 landlock_functions = [ 163 'landlock_create_ruleset', 164 'landlock_add_rule', 165 'landlock_restrict_self', 166 ] 167 168 foreach function : landlock_functions 169 if not cpp_compiler.has_function(function, prefix: '#include <linux/landlock.h>') 170 cpp_compiler.has_header('unistd.h', required: true) 171 cpp_compiler.has_function('syscall', prefix: '#include <unistd.h>', required: true) 172 cpp_compiler.has_header('sys/syscall.h', required: true) 173 syscall_number_macro = 'SYS_' + function 174 cpp_compiler.compiles('#include <sys/syscall.h>\nint number = ' + syscall_number_macro + ';', name: syscall_number_macro + ' number is available', required: true) 175 176 macro = 'NO_' + function.to_upper() 177 add_project_arguments('-D' + macro, language: 'cpp') 178 endif 179 endforeach 180 181 # see also https://lore.kernel.org/landlock/20251119212707.71275873@ciel/T/ 182 cpp_compiler.compiles( 183 ''' 184 #include <linux/landlock.h> 185 struct landlock_ruleset_attr attr = { 186 .handled_access_fs = 0, 187 .handled_access_net = 0, 188 .scoped = 0 189 }; 190 ''', 191 name: 'Landlock supports scoped access control', 192 required: true 193 ) 194 195 cpp_compiler.compiles( 196 ''' 197 #include <linux/landlock.h> 198 struct landlock_path_beneath_attr attr = { 199 .allowed_access = 0, 200 .parent_fd = 0 201 }; 202 ''', 203 name: 'Landlock has landlock_path_beneath_attr', 204 required: true 205 ) 206 207 cpp_compiler.compiles( 208 ''' 209 #include <linux/landlock.h> 210 struct landlock_net_port_attr attr = { 211 .allowed_access = 0, 212 .port = 0 213 }; 214 ''', 215 name: 'Landlock has landlock_net_port_attr', 216 required: true 217 ) 218 219 landlock_macros = [ 220 'LANDLOCK_RULE_PATH_BENEATH', 221 'LANDLOCK_RULE_NET_PORT', 222 223 'LANDLOCK_CREATE_RULESET_VERSION', 224 225 'LANDLOCK_ACCESS_FS_EXECUTE', 226 'LANDLOCK_ACCESS_FS_WRITE_FILE', 227 'LANDLOCK_ACCESS_FS_READ_FILE', 228 'LANDLOCK_ACCESS_FS_TRUNCATE', 229 'LANDLOCK_ACCESS_FS_READ_DIR', 230 'LANDLOCK_ACCESS_FS_REMOVE_DIR', 231 'LANDLOCK_ACCESS_FS_REMOVE_FILE', 232 'LANDLOCK_ACCESS_FS_MAKE_CHAR', 233 'LANDLOCK_ACCESS_FS_MAKE_DIR', 234 'LANDLOCK_ACCESS_FS_MAKE_REG', 235 'LANDLOCK_ACCESS_FS_MAKE_SOCK', 236 'LANDLOCK_ACCESS_FS_MAKE_FIFO', 237 'LANDLOCK_ACCESS_FS_MAKE_BLOCK', 238 'LANDLOCK_ACCESS_FS_MAKE_SYM', 239 'LANDLOCK_ACCESS_FS_REFER', 240 'LANDLOCK_ACCESS_FS_IOCTL_DEV', 241 242 'LANDLOCK_ACCESS_NET_BIND_TCP', 243 'LANDLOCK_ACCESS_NET_CONNECT_TCP', 244 245 'LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET', 246 'LANDLOCK_SCOPE_SIGNAL' 247 ] 248 249 foreach macro : landlock_macros 250 cpp_compiler.compiles('#include <linux/landlock.h>\nint number = ' + macro + ';', name: macro + ' number is available', required: true) 251 endforeach 252 253 if cpp_compiler.compiles('#include <linux/landlock.h>\nint number = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;', name: 'LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON number is available') 254 add_project_arguments('-DHAVE_LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON', language: 'cpp') 255 endif 256 endif 257 258 if cpp_compiler.has_header('capsicum_helpers.h') and cpp_compiler.has_header('sys/capsicum.h') 259 add_project_arguments('-DHAVE_CAPSICUM', language: 'cpp') 260 endif 261 262 threads_dep = declare_dependency() 263 if host_machine.system() == 'freebsd' 264 # see https://github.com/exult/exult/issues/436 265 # https://github.com/exult/exult/blob/38e8b8d140102ea9ec3632f618af7e73a43955df/configure.ac 266 threads_dep = dependency('threads') 267 endif 268 269 libtins_dep = dependency('libtins', include_type: 'system') 270 yamlcpp_dep = dependency('yaml-cpp', include_type: 'system') 271 gtest_dep = dependency('gtest', main: true, required: false, include_type: 'system') 272 273 cppcheck = find_program('cppcheck', required: false) 274 if cppcheck.found() 275 run_target('cppcheck', command: [ 276 cppcheck, 277 # Do not check external libraries 278 '--suppress=*:*/tins/*', 279 '--suppress=*:*/boost/*', 280 '--suppress=*:*/gtest/*', 281 282 # Problems with detecting system libraries 283 '--suppress=missingIncludeSystem', 284 '--suppress=unmatchedSuppression', 285 '--suppress=functionStatic', 286 287 '--enable=warning,style,information,missingInclude', 288 '--error-exitcode=1', 289 '--check-level=exhaustive', 290 '--inline-suppr', 291 '--project=' + join_paths(meson.current_build_dir(), 'compile_commands.json') 292 ]) 293 endif 294 295 infer = find_program('infer', required: false) 296 if infer.found() 297 run_target('infer', command: [ 298 infer, 299 '--compilation-database', 300 join_paths(meson.current_build_dir(), 'compile_commands.json'), 301 '--fail-on-issue' 302 ]) 303 endif 304 305 flawfinder = find_program('flawfinder', required: false) 306 if flawfinder.found() 307 run_target('flawfinder', command: [ 308 flawfinder, 309 '--error-level=0', 310 all_sources 311 ]) 312 endif 313 314 lizard = find_program('lizard', required: false) 315 if lizard.found() 316 run_target('lizard', command: [ 317 lizard, 318 '--CCN', '25', 319 '--length', '400', 320 '--arguments', '10', 321 all_sources 322 ]) 323 endif 324 325 mdl = find_program('mdl', required: false) 326 if mdl.found() 327 run_target('mdl', command: [ 328 mdl, 329 markdown_files 330 ]) 331 endif 332 333 reuse = find_program('reuse', required: false) 334 if reuse.found() 335 run_target('reuse-annotate', command: [ 336 reuse, 337 'annotate', 338 '--copyright', 'Marek Küthe <m.k@mk16.de>', 339 '--license', 'GPL-3.0-or-later', 340 '--year', '2025', 341 '--copyright-prefix', 'spdx-string-c', 342 '--merge-copyrights', 343 '--recursive', 344 '--skip-unrecognised', 345 meson.current_source_dir() 346 ]) 347 run_target('reuse-download', command: [ 348 reuse, 349 'download', 350 '--all' 351 ]) 352 run_target('reuse-lint', command: [ 353 reuse, 354 'lint' 355 ]) 356 endif 357 358 if get_option('install_systemd_unit') 359 install_data( 360 'systemd/crazytrace@.service', 361 install_dir: 'lib/systemd/system' 362 ) 363 endif 364 365 if get_option('install_rc_script') 366 install_data( 367 'rc/crazytrace', 368 install_dir: 'etc/rc.d' 369 ) 370 endif 371 372 if get_option('install_apparmor_profile') 373 install_data( 374 'apparmor/usr.bin.crazytrace', 375 install_dir: '/etc/apparmor.d' 376 ) 377 endif 378 379 if get_option('install_documentation') 380 documentation_files = [ 381 'BUILDING.md', 382 'CHANGELOG.md', 383 'CONTRIBUTING.md', 384 'README.md', 385 'SECURITY.md', 386 'LICENSE.txt' 387 ] 388 389 foreach file : documentation_files 390 install_data( 391 file, 392 install_dir: 'share/doc/crazytrace' 393 ) 394 endforeach 395 endif 396 397 deps = [libtuntappp_dep, libtuntap_dep, boost_dep, libtins_dep, yamlcpp_dep, libcapng_dep, seccomp_dep, threads_dep] 398 399 if gtest_dep.found() 400 gtest = executable('gtest', sources + tests_sources, dependencies: [gtest_dep] + deps, include_directories: ['src/']) 401 test('gtest', gtest) 402 endif 403 404 executable( 405 'crazytrace', 406 sources + main_file, 407 dependencies: deps, 408 install : true 409 )