1b4540a72SMickaël Salaün // SPDX-License-Identifier: GPL-2.0-only 2b4540a72SMickaël Salaün /* 3b4540a72SMickaël Salaün * Landlock - Tracepoint helpers 4b4540a72SMickaël Salaün * 5b4540a72SMickaël Salaün * Copyright © 2025 Microsoft Corporation 6b4540a72SMickaël Salaün * Copyright © 2026 Cloudflare, Inc. 7b4540a72SMickaël Salaün */ 8b4540a72SMickaël Salaün 9*d41d0021SMickaël Salaün #include <kunit/test.h> 1001ce260fSMickaël Salaün #include <linux/cleanup.h> 1101ce260fSMickaël Salaün #include <linux/dcache.h> 1201ce260fSMickaël Salaün #include <linux/err.h> 1301ce260fSMickaël Salaün #include <linux/fs.h> 1401ce260fSMickaël Salaün #include <linux/lsm_audit.h> 1501ce260fSMickaël Salaün #include <net/sock.h> 1601ce260fSMickaël Salaün 1701ce260fSMickaël Salaün #include "access.h" 1867567f03SMickaël Salaün #include "domain.h" 1901ce260fSMickaël Salaün #include "fs.h" 2001ce260fSMickaël Salaün #include "log.h" 21b4540a72SMickaël Salaün #include "ruleset.h" 2201ce260fSMickaël Salaün #include "trace.h" 23b4540a72SMickaël Salaün 24b4540a72SMickaël Salaün /* 25b4540a72SMickaël Salaün * Generates the tracepoint definitions in this translation unit. The trace 26b4540a72SMickaël Salaün * event header dereferences the traced objects in TP_fast_assign, so the full 2767567f03SMickaël Salaün * struct definitions (e.g. ruleset.h, domain.h) must be included before it. 28b4540a72SMickaël Salaün */ 29b4540a72SMickaël Salaün #define CREATE_TRACE_POINTS 30b4540a72SMickaël Salaün #include <trace/events/landlock.h> 3167567f03SMickaël Salaün 3267567f03SMickaël Salaün /** 3367567f03SMickaël Salaün * landlock_trace_free_domain - Emit a tracepoint on domain deallocation 3467567f03SMickaël Salaün * 3567567f03SMickaël Salaün * @hierarchy: The domain's hierarchy being deallocated. 3667567f03SMickaël Salaün * 3767567f03SMickaël Salaün * Fires only for a hierarchy whose creation event was emitted, i.e. one that 3867567f03SMickaël Salaün * left LANDLOCK_LOG_UNCOMMITTED in landlock_restrict_self(). This keeps the 3967567f03SMickaël Salaün * create/free pair balanced: a hierarchy that never became observable is freed 4067567f03SMickaël Salaün * silently, while a domain that landlock_restrict_self() created and a 4167567f03SMickaël Salaün * thread-sync failure then aborted still fires free_domain, because its 4267567f03SMickaël Salaün * creation event already fired. 4367567f03SMickaël Salaün * 4467567f03SMickaël Salaün * Called from landlock_log_free_domain(). 4567567f03SMickaël Salaün */ 4667567f03SMickaël Salaün void landlock_trace_free_domain(const struct landlock_hierarchy *const hierarchy) 4767567f03SMickaël Salaün { 4867567f03SMickaël Salaün /* 4967567f03SMickaël Salaün * The log_status read is a correctness guard (keep the create/free pair 5067567f03SMickaël Salaün * balanced), not a cost guard, so this cold path needs no 5167567f03SMickaël Salaün * trace_..._enabled() check: the tracepoint is a static-branch no-op 5267567f03SMickaël Salaün * when disabled. The denial path guards trace_..._enabled() instead 5367567f03SMickaël Salaün * because it does expensive __getname()/path work before emitting. 5467567f03SMickaël Salaün */ 5567567f03SMickaël Salaün if (READ_ONCE(hierarchy->log_status) != LANDLOCK_LOG_UNCOMMITTED) 5667567f03SMickaël Salaün trace_landlock_free_domain(hierarchy); 5767567f03SMickaël Salaün } 5801ce260fSMickaël Salaün 5901ce260fSMickaël Salaün /** 6001ce260fSMickaël Salaün * landlock_trace_denial - Emit a tracepoint for a denied access request 6101ce260fSMickaël Salaün * 6201ce260fSMickaël Salaün * @request: Detail of the user space request. 6301ce260fSMickaël Salaün * @youngest_denied: The youngest hierarchy node that denied the access. 6401ce260fSMickaël Salaün * @missing: The set of denied access rights. 6501ce260fSMickaël Salaün * @same_exec: Whether the current task is the same executable that called 6601ce260fSMickaël Salaün * landlock_restrict_self() for the denying domain, as computed 6701ce260fSMickaël Salaün * by landlock_log_denial(). 6801ce260fSMickaël Salaün * @logged: Whether the domain's policy selects this denial for logging, as 6901ce260fSMickaël Salaün * computed by landlock_log_denial(). 7001ce260fSMickaël Salaün * 7101ce260fSMickaël Salaün * Emits the tracepoint matching @request->type when its event is enabled. 7201ce260fSMickaël Salaün * Unlike audit, fires regardless of @logged; the value is recorded in the event 7301ce260fSMickaël Salaün * so consumers can filter on it. 7401ce260fSMickaël Salaün * 7501ce260fSMickaël Salaün * Called from landlock_log_denial(). 7601ce260fSMickaël Salaün */ 7701ce260fSMickaël Salaün void landlock_trace_denial( 7801ce260fSMickaël Salaün const struct landlock_request *const request, 7901ce260fSMickaël Salaün const struct landlock_hierarchy *const youngest_denied, 8001ce260fSMickaël Salaün const access_mask_t missing, const bool same_exec, const bool logged) 8101ce260fSMickaël Salaün { 8201ce260fSMickaël Salaün switch (request->type) { 8301ce260fSMickaël Salaün case LANDLOCK_REQUEST_FS_ACCESS: 8401ce260fSMickaël Salaün case LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY: 8501ce260fSMickaël Salaün if (trace_landlock_deny_access_fs_enabled()) { 8601ce260fSMickaël Salaün char *buf __free(__putname) = __getname(); 8701ce260fSMickaël Salaün struct path dentry_path; 8801ce260fSMickaël Salaün const char *pathname; 8901ce260fSMickaël Salaün const struct path *path = NULL; 9001ce260fSMickaël Salaün 9101ce260fSMickaël Salaün /* 9201ce260fSMickaël Salaün * Selects the path from the audit data type, as 9301ce260fSMickaël Salaün * dump_common_audit_data() does. A FS_ACCESS denial 9401ce260fSMickaël Salaün * carries a file (hook_file_truncate) or an ioctl op 9501ce260fSMickaël Salaün * (hook_file_ioctl) rather than a path; 9601ce260fSMickaël Salaün * FS_CHANGE_TOPOLOGY carries a path or a bare dentry. 9701ce260fSMickaël Salaün * Reading the wrong union member would dereference 9801ce260fSMickaël Salaün * garbage, so every reachable type is handled here. 9901ce260fSMickaël Salaün */ 10001ce260fSMickaël Salaün switch (request->audit.type) { 10101ce260fSMickaël Salaün case LSM_AUDIT_DATA_FILE: 10201ce260fSMickaël Salaün path = &request->audit.u.file->f_path; 10301ce260fSMickaël Salaün break; 10401ce260fSMickaël Salaün case LSM_AUDIT_DATA_IOCTL_OP: 10501ce260fSMickaël Salaün path = &request->audit.u.op->path; 10601ce260fSMickaël Salaün break; 10701ce260fSMickaël Salaün case LSM_AUDIT_DATA_DENTRY: 10801ce260fSMickaël Salaün /* 10901ce260fSMickaël Salaün * Build a path on the stack with the real 11001ce260fSMickaël Salaün * dentry so TP_fast_assign can extract dev and 11101ce260fSMickaël Salaün * ino; the mnt field is unused there. 11201ce260fSMickaël Salaün */ 11301ce260fSMickaël Salaün dentry_path = (struct path){ 11401ce260fSMickaël Salaün .dentry = request->audit.u.dentry, 11501ce260fSMickaël Salaün }; 11601ce260fSMickaël Salaün path = &dentry_path; 11701ce260fSMickaël Salaün break; 11801ce260fSMickaël Salaün case LSM_AUDIT_DATA_PATH: 11901ce260fSMickaël Salaün path = &request->audit.u.path; 12001ce260fSMickaël Salaün break; 12101ce260fSMickaël Salaün default: 12201ce260fSMickaël Salaün WARN_ONCE(1, 12301ce260fSMickaël Salaün "Unhandled Landlock FS audit type %d", 12401ce260fSMickaël Salaün request->audit.type); 12501ce260fSMickaël Salaün break; 12601ce260fSMickaël Salaün } 12701ce260fSMickaël Salaün 12801ce260fSMickaël Salaün if (!path) 12901ce260fSMickaël Salaün break; 13001ce260fSMickaël Salaün 13101ce260fSMickaël Salaün if (!buf) { 13201ce260fSMickaël Salaün pathname = "<no_mem>"; 13301ce260fSMickaël Salaün } else if (request->audit.type == 13401ce260fSMickaël Salaün LSM_AUDIT_DATA_DENTRY) { 13501ce260fSMickaël Salaün /* No vfsmount: render the dentry path alone. */ 13601ce260fSMickaël Salaün pathname = dentry_path_raw( 13701ce260fSMickaël Salaün request->audit.u.dentry, buf, PATH_MAX); 13801ce260fSMickaël Salaün if (IS_ERR(pathname)) 13901ce260fSMickaël Salaün pathname = 14001ce260fSMickaël Salaün PTR_ERR(pathname) == 14101ce260fSMickaël Salaün -ENAMETOOLONG ? 14201ce260fSMickaël Salaün "<too_long>" : 14301ce260fSMickaël Salaün "<unreachable>"; 14401ce260fSMickaël Salaün } else { 14501ce260fSMickaël Salaün pathname = resolve_path_for_trace(path, buf); 14601ce260fSMickaël Salaün } 14701ce260fSMickaël Salaün 14801ce260fSMickaël Salaün trace_landlock_deny_access_fs(youngest_denied, 14901ce260fSMickaël Salaün same_exec, logged, 15001ce260fSMickaël Salaün missing, path, pathname); 15101ce260fSMickaël Salaün } 15201ce260fSMickaël Salaün break; 15301ce260fSMickaël Salaün case LANDLOCK_REQUEST_NET_ACCESS: 15401ce260fSMickaël Salaün if (trace_landlock_deny_access_net_enabled()) 15501ce260fSMickaël Salaün trace_landlock_deny_access_net( 15601ce260fSMickaël Salaün youngest_denied, same_exec, logged, missing, 15701ce260fSMickaël Salaün request->audit.u.net->sk, 15801ce260fSMickaël Salaün ntohs(request->audit.u.net->sport), 15901ce260fSMickaël Salaün ntohs(request->audit.u.net->dport)); 16001ce260fSMickaël Salaün break; 161bb91730fSMickaël Salaün case LANDLOCK_REQUEST_PTRACE: 162bb91730fSMickaël Salaün if (trace_landlock_deny_ptrace_enabled()) 163bb91730fSMickaël Salaün trace_landlock_deny_ptrace(youngest_denied, same_exec, 164bb91730fSMickaël Salaün logged, 165bb91730fSMickaël Salaün request->other_domain_id, 166bb91730fSMickaël Salaün request->audit.u.tsk); 167bb91730fSMickaël Salaün break; 168bb91730fSMickaël Salaün case LANDLOCK_REQUEST_SCOPE_SIGNAL: 169bb91730fSMickaël Salaün if (trace_landlock_deny_scope_signal_enabled()) 170bb91730fSMickaël Salaün trace_landlock_deny_scope_signal( 171bb91730fSMickaël Salaün youngest_denied, same_exec, logged, 172bb91730fSMickaël Salaün request->other_domain_id, request->audit.u.tsk); 173bb91730fSMickaël Salaün break; 174bb91730fSMickaël Salaün case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET: 175bb91730fSMickaël Salaün if (trace_landlock_deny_scope_abstract_unix_socket_enabled()) 176bb91730fSMickaël Salaün trace_landlock_deny_scope_abstract_unix_socket( 177bb91730fSMickaël Salaün youngest_denied, same_exec, logged, 178bb91730fSMickaël Salaün request->other_domain_id, 179bb91730fSMickaël Salaün request->audit.u.net->sk); 180bb91730fSMickaël Salaün break; 18101ce260fSMickaël Salaün default: 182bb91730fSMickaël Salaün WARN_ONCE(1, "Unhandled Landlock request type %d", 183bb91730fSMickaël Salaün request->type); 18401ce260fSMickaël Salaün break; 18501ce260fSMickaël Salaün } 18601ce260fSMickaël Salaün } 187*d41d0021SMickaël Salaün 188*d41d0021SMickaël Salaün #ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST 189*d41d0021SMickaël Salaün 190*d41d0021SMickaël Salaün static void test_trace_seq_init(struct trace_seq *const seq, const size_t size) 191*d41d0021SMickaël Salaün { 192*d41d0021SMickaël Salaün memset(seq, 0, sizeof(*seq)); 193*d41d0021SMickaël Salaün seq_buf_init(&seq->seq, seq->buffer, size); 194*d41d0021SMickaël Salaün } 195*d41d0021SMickaël Salaün 196*d41d0021SMickaël Salaün static void test_untrusted_str_data(struct kunit *const test) 197*d41d0021SMickaël Salaün { 198*d41d0021SMickaël Salaün const char binary[] = { 'a', '\0', '<' }; 199*d41d0021SMickaël Salaün static const char ellipsis[] = "\xe2\x80\xa6"; 200*d41d0021SMickaël Salaün struct trace_seq *const seq = 201*d41d0021SMickaël Salaün kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 202*d41d0021SMickaël Salaün const char *output; 203*d41d0021SMickaël Salaün 204*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, seq); 205*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 206*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, "<too_long>", 10); 207*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 208*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, "<too_long>"); 209*d41d0021SMickaël Salaün 210*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 211*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, binary, sizeof(binary)); 212*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 213*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, "a\\000<"); 214*d41d0021SMickaël Salaün 215*d41d0021SMickaël Salaün /* Input ellipsis bytes are escaped and cannot mimic the raw marker. */ 216*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 217*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, ellipsis, 218*d41d0021SMickaël Salaün sizeof(ellipsis) - 1); 219*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 220*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, "\\342\\200\\246"); 221*d41d0021SMickaël Salaün } 222*d41d0021SMickaël Salaün 223*d41d0021SMickaël Salaün static void test_untrusted_str_boundaries(struct kunit *const test) 224*d41d0021SMickaël Salaün { 225*d41d0021SMickaël Salaün static const char escaped_space[] = "\\040"; 226*d41d0021SMickaël Salaün const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE; 227*d41d0021SMickaël Salaün const size_t marker_len = sizeof(TRACE_TRUNCATION_MARKER) - 1; 228*d41d0021SMickaël Salaün const size_t escape_len = sizeof(escaped_space) - 1; 229*d41d0021SMickaël Salaün const size_t exact_prefix_len = 230*d41d0021SMickaël Salaün output_size - marker_len - 1 - escape_len; 231*d41d0021SMickaël Salaün const size_t short_prefix_len = exact_prefix_len + 1; 232*d41d0021SMickaël Salaün struct trace_seq *const seq = 233*d41d0021SMickaël Salaün kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 234*d41d0021SMickaël Salaün char *const input = kunit_kmalloc(test, output_size + 1, GFP_KERNEL); 235*d41d0021SMickaël Salaün char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL); 236*d41d0021SMickaël Salaün const char *output; 237*d41d0021SMickaël Salaün 238*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, seq); 239*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, input); 240*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, expected); 241*d41d0021SMickaël Salaün 242*d41d0021SMickaël Salaün /* The escaped string and its trailing NUL exactly fit the limit. */ 243*d41d0021SMickaël Salaün memset(input, 'a', output_size - 1); 244*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 245*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, input, output_size - 1); 246*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 247*d41d0021SMickaël Salaün KUNIT_EXPECT_EQ(test, seq->seq.len, output_size); 248*d41d0021SMickaël Salaün KUNIT_EXPECT_EQ(test, memcmp(output, input, output_size - 1), 0); 249*d41d0021SMickaël Salaün 250*d41d0021SMickaël Salaün /* Stop before a four-byte escape when only three bytes remain. */ 251*d41d0021SMickaël Salaün memset(input, 'a', short_prefix_len); 252*d41d0021SMickaël Salaün input[short_prefix_len] = ' '; 253*d41d0021SMickaël Salaün memset(input + short_prefix_len + 1, 'b', 5); 254*d41d0021SMickaël Salaün memset(expected, 'a', short_prefix_len); 255*d41d0021SMickaël Salaün memcpy(expected + short_prefix_len, TRACE_TRUNCATION_MARKER, 256*d41d0021SMickaël Salaün marker_len + 1); 257*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 258*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, input, short_prefix_len + 6); 259*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 260*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, expected); 261*d41d0021SMickaël Salaün 262*d41d0021SMickaël Salaün /* Include a four-byte escape that exactly fills the prefix capacity. */ 263*d41d0021SMickaël Salaün memset(input, 'a', exact_prefix_len); 264*d41d0021SMickaël Salaün input[exact_prefix_len] = ' '; 265*d41d0021SMickaël Salaün memset(input + exact_prefix_len + 1, 'b', marker_len + 1); 266*d41d0021SMickaël Salaün memset(expected, 'a', exact_prefix_len); 267*d41d0021SMickaël Salaün memcpy(expected + exact_prefix_len, escaped_space, escape_len); 268*d41d0021SMickaël Salaün memcpy(expected + exact_prefix_len + escape_len, 269*d41d0021SMickaël Salaün TRACE_TRUNCATION_MARKER, marker_len + 1); 270*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 271*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, input, 272*d41d0021SMickaël Salaün exact_prefix_len + marker_len + 2); 273*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 274*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, expected); 275*d41d0021SMickaël Salaün 276*d41d0021SMickaël Salaün /* Literal backslashes remain escaped in complete output. */ 277*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 278*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, "/\\000", 5); 279*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 280*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, "/\\\\000"); 281*d41d0021SMickaël Salaün } 282*d41d0021SMickaël Salaün 283*d41d0021SMickaël Salaün static void test_untrusted_str_cursor(struct kunit *const test) 284*d41d0021SMickaël Salaün { 285*d41d0021SMickaël Salaün const size_t padding_len = 286*d41d0021SMickaël Salaün TRACE_SEQ_BUFFER_SIZE - TRACE_UNTRUSTED_STR_OUTPUT_SIZE + 1; 287*d41d0021SMickaël Salaün struct trace_seq *const seq = 288*d41d0021SMickaël Salaün kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 289*d41d0021SMickaël Salaün char *const padding = kunit_kzalloc(test, padding_len, GFP_KERNEL); 290*d41d0021SMickaël Salaün const char *output; 291*d41d0021SMickaël Salaün 292*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, seq); 293*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, padding); 294*d41d0021SMickaël Salaün 295*d41d0021SMickaël Salaün /* Accept available space exactly equal to the fixed reservation. */ 296*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 297*d41d0021SMickaël Salaün trace_seq_putmem(seq, padding, padding_len - 1); 298*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, "/a", 2); 299*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, output); 300*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, output, "/a"); 301*d41d0021SMickaël Salaün KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len - 1 + sizeof("/a")); 302*d41d0021SMickaël Salaün 303*d41d0021SMickaël Salaün /* Reject one byte less without changing the scratch cursor. */ 304*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 305*d41d0021SMickaël Salaün trace_seq_putmem(seq, padding, padding_len); 306*d41d0021SMickaël Salaün output = __trace_print_untrusted_str(seq, "/a", 2); 307*d41d0021SMickaël Salaün KUNIT_EXPECT_NULL(test, output); 308*d41d0021SMickaël Salaün KUNIT_EXPECT_EQ(test, seq->seq.len, padding_len); 309*d41d0021SMickaël Salaün } 310*d41d0021SMickaël Salaün 311*d41d0021SMickaël Salaün static void test_untrusted_str_composition(struct kunit *const test) 312*d41d0021SMickaël Salaün { 313*d41d0021SMickaël Salaün static const struct trace_print_flags flags[] = { 314*d41d0021SMickaël Salaün { .mask = 1, .name = "read" }, 315*d41d0021SMickaël Salaün }; 316*d41d0021SMickaël Salaün const size_t output_size = TRACE_UNTRUSTED_STR_OUTPUT_SIZE; 317*d41d0021SMickaël Salaün const size_t prefix_len = output_size - sizeof(TRACE_TRUNCATION_MARKER); 318*d41d0021SMickaël Salaün struct trace_seq *const seq = 319*d41d0021SMickaël Salaün kunit_kzalloc(test, sizeof(*seq), GFP_KERNEL); 320*d41d0021SMickaël Salaün char *const expected = kunit_kmalloc(test, output_size, GFP_KERNEL); 321*d41d0021SMickaël Salaün char *const path = kunit_kmalloc(test, output_size, GFP_KERNEL); 322*d41d0021SMickaël Salaün const char *flags_output, *path_output; 323*d41d0021SMickaël Salaün 324*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, seq); 325*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, expected); 326*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, path); 327*d41d0021SMickaël Salaün memset(path, 'a', output_size); 328*d41d0021SMickaël Salaün memset(expected, 'a', prefix_len); 329*d41d0021SMickaël Salaün memcpy(expected + prefix_len, TRACE_TRUNCATION_MARKER, 330*d41d0021SMickaël Salaün sizeof(TRACE_TRUNCATION_MARKER)); 331*d41d0021SMickaël Salaün 332*d41d0021SMickaël Salaün /* Exercise both legal TP_printk() sibling evaluation orders. */ 333*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 334*d41d0021SMickaël Salaün path_output = __trace_print_untrusted_str(seq, path, output_size); 335*d41d0021SMickaël Salaün flags_output = 336*d41d0021SMickaël Salaün trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags)); 337*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, path_output); 338*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, path_output, expected); 339*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, flags_output, "read"); 340*d41d0021SMickaël Salaün 341*d41d0021SMickaël Salaün test_trace_seq_init(seq, TRACE_SEQ_BUFFER_SIZE); 342*d41d0021SMickaël Salaün flags_output = 343*d41d0021SMickaël Salaün trace_print_flags_seq(seq, "|", 1, flags, ARRAY_SIZE(flags)); 344*d41d0021SMickaël Salaün path_output = __trace_print_untrusted_str(seq, path, output_size); 345*d41d0021SMickaël Salaün KUNIT_ASSERT_NOT_NULL(test, path_output); 346*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, path_output, expected); 347*d41d0021SMickaël Salaün KUNIT_EXPECT_STREQ(test, flags_output, "read"); 348*d41d0021SMickaël Salaün } 349*d41d0021SMickaël Salaün 350*d41d0021SMickaël Salaün static struct kunit_case test_cases[] = { 351*d41d0021SMickaël Salaün /* clang-format off */ 352*d41d0021SMickaël Salaün KUNIT_CASE(test_untrusted_str_data), 353*d41d0021SMickaël Salaün KUNIT_CASE(test_untrusted_str_boundaries), 354*d41d0021SMickaël Salaün KUNIT_CASE(test_untrusted_str_cursor), 355*d41d0021SMickaël Salaün KUNIT_CASE(test_untrusted_str_composition), 356*d41d0021SMickaël Salaün {} 357*d41d0021SMickaël Salaün /* clang-format on */ 358*d41d0021SMickaël Salaün }; 359*d41d0021SMickaël Salaün 360*d41d0021SMickaël Salaün static struct kunit_suite test_suite = { 361*d41d0021SMickaël Salaün .name = "landlock_trace", 362*d41d0021SMickaël Salaün .test_cases = test_cases, 363*d41d0021SMickaël Salaün }; 364*d41d0021SMickaël Salaün 365*d41d0021SMickaël Salaün kunit_test_suite(test_suite); 366*d41d0021SMickaël Salaün 367*d41d0021SMickaël Salaün #endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */ 368