aboutgitcodelistschat:MatrixIRC
path: root/tests/unit/test_operations.c
blob: dfcb72c49c5cf39ee476cbe344e0e0dfb3156f10 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                                            



                                          







                   
                  


                        
                     



                          

                       


                  
                       
                          
                     
 

                         

                       



                                                                           
                                                         
                


               



                                                                           
                                                         
                

 

                 
                     



                                                                           
                                                         


                


                                

               








                                                                           


                                                          
                                                         


                
                            
 

                                                                   



                                     
                         
 



                                                               



                                                                                
                                                


        
                                                                         
 






                                                                   
 
 
                                  
 


                                          
 


                                       


        
                        
 
                               
                                      


                                                                                

                                                       
                                                           



                                        
                            
 
                               
               
                           
                          




                                                                 
          
 

                                                       
                                                           
                                        
                                                      
                                 


        
                                                                  
 
                                                           
                        
                   

                                  
                                    






                                                          


                                      
                            
 
                                          


        
                                
 
                                       


        
                          
 
                                           


        
                              
 
                                        


        
                        
 
                           





                                                                               
                                     
          


                                

                                                      
                                                           

                                         
                                                         

                                                          


        
















                                                             




                                                 
                                                         

                                      

                                                  
          
 



                                                        
 
                                                           
                                         
 
                                 
 

                                     
                    
                           




                                                 
                                                         

                                      

                                                  
                      
          




                                                        
 
                                                           
                                         


        
                                    

                                     
                                     

                           




                                                 
                                                         
                                                  
                                     

                                      
                      
          
 



                                                        
 
                                                           
                                         


        

                                 
                           





                                                  


                                      
                      

          


                                                            
 
                                                           






                                                
                           





                                                  


                                      
          
 


                                                             
 
                                                           
                                          


        




                              
                           








                                                                 


                                                            



















                                                                 
                          

                 
                         

                                                      
                                 
                                
 
                                        
 
                                           

                                                                    
                                               

                                 
                                         

                                                                     
                                             

                                  







                                                                   

                                                                    

                                               

                                 
                                           

                                                              

                                                   

                                   
                                               

                                                                

                                                       
                                     
 




                                                                        
 


                                                                   

                                                      

                                


                                                                      
                                                                                      

                                   



                                                                    
                                                           

                                       









                                                                  








                          
                            






                                                              
/* SPDX-License-Identifier: GPL-2.0-or-later
 * Copyright 2023 Red Hat GmbH
 * Author: Alice Frosi <afrosi@redhat.com>
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <signal.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <sys/mman.h>
#include <sys/un.h>
#include <sys/socket.h>

#include <check.h>

#include "operations.h"
#include "common/common.h"
#include "testutil.h"

#define MAX_TEST_PATH 250

void setup_without_fd()
{
	at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
		  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	at->check_fd = false;
	at->nr = __NR_getpid;
	at->install_filter = install_notification_filter;
	setup();
}
void setup_fd()
{
	at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
		  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	at->check_fd = true;
	at->nr = __NR_getpid;
	at->install_filter = install_notification_filter;
	setup();
}

void setup_path()
{
	unlink(path);
	at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
		  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	at->open_path = true;
	at->nr = __NR_getpid;
	at->install_filter = install_notification_filter;
	setup();
}

void setup_target_connect()
{
	struct sockaddr_un addr;
	int fd;

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	ck_assert_int_ge(fd, 0);
	memset(&addr, 0, sizeof(addr));
	strcpy(addr.sun_path, "/tmp/test.sock");
	addr.sun_family = AF_UNIX;
	at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
		  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	at->check_fd = false;
	at->nr = __NR_connect;
	at->targs[0] = (void *)(long)fd;
	at->targs[1] = (void *)&addr;
	at->targs[2] = (void *)(long)(sizeof(char) * 108);
	at->install_filter = install_notification_filter;
	setup();
}

START_TEST(test_op_continue)
{
	ck_assert_msg(op_continue(&req, notifyfd, NULL, NULL) == 0,
		      strerror(errno));
	ck_assert_int_eq(at->err, 0);
}
END_TEST

START_TEST(test_op_block)
{
	struct op_block op = { -1 };

	ck_assert_msg(op_block(&req, notifyfd, NULL, &op) == 0,
		      strerror(errno));
	/*
	 * The tests use getpid that returns the error with ret and it is always
	 * successful
	 */
	check_target_result(op.error, 1, false);
}
END_TEST

static void test_op_return(enum gluten_offset_type type, uint16_t offset)
{
	struct op_return op = { { type, offset } };
	int64_t v = 2;

	ck_write_gluten(gluten, op.val, v);
	ck_assert_msg(op_return(&req, notifyfd, &gluten, &op) == 0,
		      strerror(errno));
	check_target_result(v, 0, false);
}

START_TEST(test_op_return_ro_data)
{
	test_op_return(OFFSET_RO_DATA, 4);
}
END_TEST

START_TEST(test_op_return_data)
{
	test_op_return(OFFSET_DATA, 4);
}
END_TEST

START_TEST(test_op_call)
{
	long nr = __NR_getppid;
	struct op ops[] = { { OP_CALL,
				     { .call = { .nr = { OFFSET_DATA, 0 } } } },
				   { OP_CONT, OP_EMPTY },
				   { OP_END, OP_EMPTY } };
	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.call.nr, nr);
	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result(1, 0, true);
}
END_TEST

START_TEST(test_op_call_ret)
{
	long nr = __NR_getppid;
	long r;
	struct op ops[] = {
		{ OP_CALL,
		  { .call = { .nr = { OFFSET_DATA, 0 },
			      .ret = { OFFSET_DATA, sizeof(nr) },
			      .has_ret = true } } },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.call.nr, nr);
	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result(1, 0, true);
	ck_read_gluten(gluten, ops[0].op.call.ret, r);
	ck_assert(r == getpid());
}
END_TEST

static void test_inject(enum gluten_offset_type type, bool atomic)
{
	struct op_inject op = { { type, 0 }, { type, 4 } };
	int test_fd = 3;
	int fd_inj;

	fd_inj = create_test_fd();
	ck_assert_int_ge(fd_inj, 0);
	ck_write_gluten(gluten, op.old_fd, test_fd);
	ck_write_gluten(gluten, op.new_fd, fd_inj);

	if (atomic)
		op_inject(&req, notifyfd, &gluten, &op);
	else
		op_inject_a(&req, notifyfd, &gluten, &op);
	check_target_fd(pid, test_fd);
}

START_TEST(test_op_inject_a)
{
	test_inject(OFFSET_RO_DATA, true);
}
END_TEST

START_TEST(test_op_inject_a_ref)
{
	test_inject(OFFSET_DATA, true);
}
END_TEST

START_TEST(test_op_inject)
{
	test_inject(OFFSET_RO_DATA, false);
}
END_TEST

START_TEST(test_op_inject_ref)
{
	test_inject(OFFSET_DATA, false);
}
END_TEST

START_TEST(test_op_load)
{
	struct op ops[] = {
		{ OP_LOAD,
		  { .load = { { OFFSET_SECCOMP_DATA, 1 },
			      { OFFSET_DATA, 0 },
			      sizeof(struct sockaddr_un) } } },
		{ OP_RETURN,
		  { .ret = { { OFFSET_DATA, sizeof(struct sockaddr_un) } } } },
		{ OP_END, OP_EMPTY },
	};
	struct sockaddr_un addr;
	int v = 2;

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[1].op.ret.val, v);
	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result(v, 0, false);

	ck_read_gluten(gluten, ops[0].op.load.dst, addr);
	ck_assert_str_eq(addr.sun_path, "/tmp/test.sock");
	ck_assert(addr.sun_family == AF_UNIX);
}
END_TEST

struct top_cmp_int_data_t {
	int a;
	int b;
	enum op_cmp_type cmp;
};
struct top_cmp_int_data_t top_cmp_int_data[] = {
	{ 1, 1, CMP_EQ }, { 1, 2, CMP_NE }, { 2, 1, CMP_GT },
	{ 1, 1, CMP_GE }, { 1, 2, CMP_LT }, { 1, 1, CMP_LE },
};

START_TEST(test_op_cmp_int)
{
	enum op_cmp_type cmp = top_cmp_int_data[_i].cmp;
	int a = top_cmp_int_data[_i].a;
	int b = top_cmp_int_data[_i].b;
	int jmp = 2;
	struct op ops[] = {
		{ OP_CMP,
		  { .cmp = { { OFFSET_DATA, 0 },
			     { OFFSET_DATA, 10 },
			     sizeof(int),
			     cmp,
			     { OFFSET_RO_DATA, 0 } } } },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.cmp.x, a);
	ck_write_gluten(gluten, ops[0].op.cmp.y, b);
	ck_write_gluten(gluten, ops[0].op.cmp.jmp, jmp);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result_nonegative();
}
START_TEST(test_op_cmp_string_eq)
{
	char s1[30] = "Hello Test!!";
	char s2[30] = "Hello Test!!";
	int jmp = 3;
	struct op ops[] = {
		{ OP_CMP,
		  { .cmp = { { OFFSET_DATA, 0 },
			     { OFFSET_DATA, 30 },
			     sizeof(s1),
			     CMP_EQ,
			     { OFFSET_RO_DATA, 0 } } } },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
		{ 0 },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.cmp.x, s1);
	ck_write_gluten(gluten, ops[0].op.cmp.y, s2);
	ck_write_gluten(gluten, ops[0].op.cmp.jmp, jmp);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result_nonegative();
}
END_TEST

START_TEST(test_op_cmp_string_false)
{
	char s1[30] = "Hello Test!!";
	char s2[30] = "Hello Tost!!";
	int jmp = 3;
	struct op ops[] = {
		{ OP_CMP,
		  { .cmp = { { OFFSET_DATA, 0 },
			     { OFFSET_DATA, 30 },
			     sizeof(s1),
			     CMP_EQ,
			     { OFFSET_RO_DATA, 0 } } } },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
		{ 0 },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.cmp.x, s1);
	ck_write_gluten(gluten, ops[0].op.cmp.y, s2);
	ck_write_gluten(gluten, ops[0].op.cmp.jmp, jmp);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result_nonegative();
}
END_TEST

START_TEST(test_op_resolvedfd_eq)
{
	struct op ops[] = {
		{ OP_RESOLVEDFD,
		  { .resfd = { { OFFSET_DATA, 0 },
			       { OFFSET_DATA, 4 },
			       sizeof(path),
			       3 } } },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
		{ 0 },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.resfd.fd, at->fd);
	ck_write_gluten(gluten, ops[0].op.resfd.path, path);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result(-1, 1, false);
}
END_TEST

START_TEST(test_op_resolvedfd_neq)
{
	char path2[] = "/tmp/seitan-test-wrong";
	struct op ops[] = {
		{ OP_RESOLVEDFD,
		  { .resfd = { { OFFSET_DATA, 0 },
			       { OFFSET_DATA, 4 },
			       sizeof(path),
			       3 } } },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.resfd.fd, at->fd);
	ck_write_gluten(gluten, ops[0].op.resfd.path, path2);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result(-1, 1, false);
}
END_TEST


START_TEST(test_op_nr)
{
	long nr = __NR_getpid;
	int jmp = 3;
	struct op ops[] = {
		{ OP_NR,
		  { .nr = { { OFFSET_RO_DATA, 0 },
			    { OFFSET_RO_DATA, sizeof(nr) } } } },
		{ OP_BLOCK, { .block = { -1 } } },
		{ OP_END, OP_EMPTY },
		{ OP_CONT, OP_EMPTY },
		{ OP_END, OP_EMPTY },
	};

	write_instr(gluten, ops);
	ck_write_gluten(gluten, ops[0].op.nr.nr, nr);
	ck_write_gluten(gluten, ops[0].op.nr.no_match, jmp);
	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	check_target_result_nonegative();
}

START_TEST(test_op_copy)
{
	int a[] = { 1, 2, 3, 4, 5, 6 };
	int b[ARRAY_SIZE(a)];
	struct op_copy op = { { OFFSET_DATA, 30 },
			      { OFFSET_DATA, 0 },
			      sizeof(a) };

	ck_write_gluten(gluten, op.src, a);
	ck_assert_msg(op_copy(&req, notifyfd, &gluten, &op) == 0,
		      strerror(errno));
	ck_read_gluten(gluten, op.dst, b);
	ck_assert_mem_eq(a, b, sizeof(a));
}
END_TEST

Suite *op_call_suite(void)
{
	Suite *s;
	int timeout = 30;
	TCase *cont, *block, *ret, *call, *resolvedfd;
	TCase *cmp, *cmpint;
	TCase *inject, *inject_a;
	TCase *load, *nr, *copy;

	s = suite_create("Perform ops");

	cont = tcase_create("op_continue");
	tcase_add_checked_fixture(cont, setup_without_fd, teardown);
	tcase_set_timeout(cont, timeout);
	tcase_add_test(cont, test_op_continue);
	suite_add_tcase(s, cont);

	block = tcase_create("op_block");
	tcase_add_checked_fixture(block, setup_without_fd, teardown);
	tcase_set_timeout(block, timeout);
	tcase_add_test(block, test_op_block);
	suite_add_tcase(s, block);

	ret = tcase_create("op_return");
	tcase_add_checked_fixture(ret, setup_without_fd, teardown);
	tcase_set_timeout(ret, timeout);
	tcase_add_test(ret, test_op_return_ro_data);
	tcase_add_test(ret, test_op_return_data);
	suite_add_tcase(s, ret);

	call = tcase_create("op_call");
	tcase_add_checked_fixture(call, setup_without_fd, teardown);
	tcase_set_timeout(call, timeout);
	tcase_add_test(call, test_op_call);
	tcase_add_test(call, test_op_call_ret);
	suite_add_tcase(s, call);

	inject = tcase_create("op_inject");
	tcase_add_checked_fixture(inject, setup_fd, teardown);
	tcase_set_timeout(inject, timeout);
	tcase_add_test(inject, test_op_inject);
	tcase_add_test(inject, test_op_inject_ref);
	suite_add_tcase(s, inject);

	inject_a = tcase_create("op_inject_a");
	tcase_add_checked_fixture(inject_a, setup_fd, teardown);
	tcase_set_timeout(inject_a, timeout);
	tcase_add_test(inject_a, test_op_inject_a);
	tcase_add_test(inject_a, test_op_inject_a_ref);
	suite_add_tcase(s, inject_a);

	load = tcase_create("op_load");
	tcase_add_checked_fixture(load, setup_target_connect, teardown);
	tcase_set_timeout(load, 120);
	tcase_add_test(load, test_op_load);
	suite_add_tcase(s, load);

	cmp = tcase_create("op_cmp");
	tcase_add_checked_fixture(cmp, setup_without_fd, teardown);
	tcase_set_timeout(cmp, timeout);
	tcase_add_test(cmp, test_op_cmp_string_eq);
	tcase_add_test(cmp, test_op_cmp_string_false);
	suite_add_tcase(s, cmp);

	cmpint = tcase_create("op_cmp_int");
	tcase_add_checked_fixture(cmpint, setup_without_fd, teardown);
	tcase_set_timeout(cmpint, timeout);
	tcase_add_loop_test(cmpint, test_op_cmp_int, 0, ARRAY_SIZE(top_cmp_int_data));
	suite_add_tcase(s, cmpint);

	resolvedfd = tcase_create("op_resolvedfd");
	tcase_add_checked_fixture(resolvedfd, setup_path, teardown);
	tcase_set_timeout(resolvedfd, timeout);
	tcase_add_test(resolvedfd, test_op_resolvedfd_eq);
	tcase_add_test(resolvedfd, test_op_resolvedfd_neq);
	suite_add_tcase(s, resolvedfd);

	nr = tcase_create("op_nr");
	tcase_add_checked_fixture(nr, setup_without_fd, teardown);
	tcase_set_timeout(nr, timeout);
	tcase_add_test(nr, test_op_nr);
	suite_add_tcase(s, nr);

	copy = tcase_create("op_copy");
	tcase_add_test(copy, test_op_copy);
	suite_add_tcase(s, copy);

	return s;
}

int main(void)
{
	int no_failed = 0;
	Suite *s;
	SRunner *runner;

	s = op_call_suite();
	runner = srunner_create(s);

	srunner_run_all(runner, CK_VERBOSE);
	no_failed = srunner_ntests_failed(runner);
	srunner_free(runner);
	return (no_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}