@@ -297,4 +297,188 @@ TEST(signal_scoping_threads)
297297 EXPECT_EQ (0 , close (thread_pipe [1 ]));
298298}
299299
300+ const short backlog = 10 ;
301+
302+ static volatile sig_atomic_t signal_received ;
303+
304+ static void handle_sigurg (int sig )
305+ {
306+ if (sig == SIGURG )
307+ signal_received = 1 ;
308+ else
309+ signal_received = -1 ;
310+ }
311+
312+ static int setup_signal_handler (int signal )
313+ {
314+ struct sigaction sa = {
315+ .sa_handler = handle_sigurg ,
316+ };
317+
318+ if (sigemptyset (& sa .sa_mask ))
319+ return -1 ;
320+
321+ sa .sa_flags = SA_SIGINFO | SA_RESTART ;
322+ return sigaction (SIGURG , & sa , NULL );
323+ }
324+
325+ /* clang-format off */
326+ FIXTURE (fown ) {};
327+ /* clang-format on */
328+
329+ enum fown_sandbox {
330+ SANDBOX_NONE ,
331+ SANDBOX_BEFORE_FORK ,
332+ SANDBOX_BEFORE_SETOWN ,
333+ SANDBOX_AFTER_SETOWN ,
334+ };
335+
336+ FIXTURE_VARIANT (fown )
337+ {
338+ const enum fown_sandbox sandbox_setown ;
339+ };
340+
341+ /* clang-format off */
342+ FIXTURE_VARIANT_ADD (fown , no_sandbox ) {
343+ /* clang-format on */
344+ .sandbox_setown = SANDBOX_NONE ,
345+ };
346+
347+ /* clang-format off */
348+ FIXTURE_VARIANT_ADD (fown , sandbox_before_fork ) {
349+ /* clang-format on */
350+ .sandbox_setown = SANDBOX_BEFORE_FORK ,
351+ };
352+
353+ /* clang-format off */
354+ FIXTURE_VARIANT_ADD (fown , sandbox_before_setown ) {
355+ /* clang-format on */
356+ .sandbox_setown = SANDBOX_BEFORE_SETOWN ,
357+ };
358+
359+ /* clang-format off */
360+ FIXTURE_VARIANT_ADD (fown , sandbox_after_setown ) {
361+ /* clang-format on */
362+ .sandbox_setown = SANDBOX_AFTER_SETOWN ,
363+ };
364+
365+ FIXTURE_SETUP (fown )
366+ {
367+ drop_caps (_metadata );
368+ }
369+
370+ FIXTURE_TEARDOWN (fown )
371+ {
372+ }
373+
374+ /*
375+ * Sending an out of bound message will trigger the SIGURG signal
376+ * through file_send_sigiotask.
377+ */
378+ TEST_F (fown , sigurg_socket )
379+ {
380+ int server_socket , recv_socket ;
381+ struct service_fixture server_address ;
382+ char buffer_parent ;
383+ int status ;
384+ int pipe_parent [2 ], pipe_child [2 ];
385+ pid_t child ;
386+
387+ memset (& server_address , 0 , sizeof (server_address ));
388+ set_unix_address (& server_address , 0 );
389+
390+ ASSERT_EQ (0 , pipe2 (pipe_parent , O_CLOEXEC ));
391+ ASSERT_EQ (0 , pipe2 (pipe_child , O_CLOEXEC ));
392+
393+ if (variant -> sandbox_setown == SANDBOX_BEFORE_FORK )
394+ create_scoped_domain (_metadata , LANDLOCK_SCOPE_SIGNAL );
395+
396+ child = fork ();
397+ ASSERT_LE (0 , child );
398+ if (child == 0 ) {
399+ int client_socket ;
400+ char buffer_child ;
401+
402+ EXPECT_EQ (0 , close (pipe_parent [1 ]));
403+ EXPECT_EQ (0 , close (pipe_child [0 ]));
404+
405+ ASSERT_EQ (0 , setup_signal_handler (SIGURG ));
406+ client_socket = socket (AF_UNIX , SOCK_STREAM , 0 );
407+ ASSERT_LE (0 , client_socket );
408+
409+ /* Waits for the parent to listen. */
410+ ASSERT_EQ (1 , read (pipe_parent [0 ], & buffer_child , 1 ));
411+ ASSERT_EQ (0 , connect (client_socket , & server_address .unix_addr ,
412+ server_address .unix_addr_len ));
413+
414+ /*
415+ * Waits for the parent to accept the connection, sandbox
416+ * itself, and call fcntl(2).
417+ */
418+ ASSERT_EQ (1 , read (pipe_parent [0 ], & buffer_child , 1 ));
419+ /* May signal itself. */
420+ ASSERT_EQ (1 , send (client_socket , "." , 1 , MSG_OOB ));
421+ EXPECT_EQ (0 , close (client_socket ));
422+ ASSERT_EQ (1 , write (pipe_child [1 ], "." , 1 ));
423+ EXPECT_EQ (0 , close (pipe_child [1 ]));
424+
425+ /* Waits for the message to be received. */
426+ ASSERT_EQ (1 , read (pipe_parent [0 ], & buffer_child , 1 ));
427+ EXPECT_EQ (0 , close (pipe_parent [0 ]));
428+
429+ if (variant -> sandbox_setown == SANDBOX_BEFORE_SETOWN ) {
430+ ASSERT_EQ (0 , signal_received );
431+ } else {
432+ /*
433+ * A signal is only received if fcntl(F_SETOWN) was
434+ * called before any sandboxing or if the signal
435+ * receiver is in the same domain.
436+ */
437+ ASSERT_EQ (1 , signal_received );
438+ }
439+ _exit (_metadata -> exit_code );
440+ return ;
441+ }
442+ EXPECT_EQ (0 , close (pipe_parent [0 ]));
443+ EXPECT_EQ (0 , close (pipe_child [1 ]));
444+
445+ server_socket = socket (AF_UNIX , SOCK_STREAM , 0 );
446+ ASSERT_LE (0 , server_socket );
447+ ASSERT_EQ (0 , bind (server_socket , & server_address .unix_addr ,
448+ server_address .unix_addr_len ));
449+ ASSERT_EQ (0 , listen (server_socket , backlog ));
450+ ASSERT_EQ (1 , write (pipe_parent [1 ], "." , 1 ));
451+
452+ recv_socket = accept (server_socket , NULL , NULL );
453+ ASSERT_LE (0 , recv_socket );
454+
455+ if (variant -> sandbox_setown == SANDBOX_BEFORE_SETOWN )
456+ create_scoped_domain (_metadata , LANDLOCK_SCOPE_SIGNAL );
457+
458+ /*
459+ * Sets the child to receive SIGURG for MSG_OOB. This uncommon use is
460+ * a valid attack scenario which also simplifies this test.
461+ */
462+ ASSERT_EQ (0 , fcntl (recv_socket , F_SETOWN , child ));
463+
464+ if (variant -> sandbox_setown == SANDBOX_AFTER_SETOWN )
465+ create_scoped_domain (_metadata , LANDLOCK_SCOPE_SIGNAL );
466+
467+ ASSERT_EQ (1 , write (pipe_parent [1 ], "." , 1 ));
468+
469+ /* Waits for the child to send MSG_OOB. */
470+ ASSERT_EQ (1 , read (pipe_child [0 ], & buffer_parent , 1 ));
471+ EXPECT_EQ (0 , close (pipe_child [0 ]));
472+ ASSERT_EQ (1 , recv (recv_socket , & buffer_parent , 1 , MSG_OOB ));
473+ EXPECT_EQ (0 , close (recv_socket ));
474+ EXPECT_EQ (0 , close (server_socket ));
475+ ASSERT_EQ (1 , write (pipe_parent [1 ], "." , 1 ));
476+ EXPECT_EQ (0 , close (pipe_parent [1 ]));
477+
478+ ASSERT_EQ (child , waitpid (child , & status , 0 ));
479+ if (WIFSIGNALED (status ) || !WIFEXITED (status ) ||
480+ WEXITSTATUS (status ) != EXIT_SUCCESS )
481+ _metadata -> exit_code = KSFT_FAIL ;
482+ }
483+
300484TEST_HARNESS_MAIN
0 commit comments