aboutgitcodelistschat:MatrixIRC
path: root/tests/unit/test_op_call.c
blob: ea6f4420d6e75fc6e210ec6814c9aa8635a1e859 (plain) (tree)
1
2
3
4
5




                                            










                        
                     


                  
                          
                       
                     






                        






                                                          

                                                         

               
                                                             
                                 
                           







                                                               


                                           
 




                                                                   

                                           


                 
                                                
 

                                                   

 
                                                  
 






                                                                           
 




                                           









                                                          
                           

                        
 
                                                        
                            
                                                 
                                                  











                                                                            





                                 




                                            
                                  
                     
 
                                                 
                                                  







                                                                                


        






























































                                                                                                      
                          
 
                 

                                         
 
                                             
 








                                                   
 



                                                           
 
                 







                          
                            






                                                              
/* SPDX-License-Identifier: GPL-3.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 <stdbool.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sched.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/mman.h>

#include <check.h>

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

struct args_write_file {
	char *file;
	char *t;
	ssize_t size;
};

static long nr;

static void write_arg(struct op_call *call, int i, long v)
{
	ck_write_gluten(gluten, call->args[i], v);
}

static void write_file(char *file, char *t, ssize_t size)
{
	int fd;

	fd = open(file, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
	ck_assert_int_ge(fd, -1);
	write(fd, t, size);
	close(fd);
}

static int write_file_get_fd(char *file, char *t, ssize_t size)
{
	int fd;

	write_file(file, t, size);
	fd = open(file, O_RDONLY, S_IWUSR);
	unlink(file);
	return fd;
}

static int write_file_clone(void *a)
{
	struct args_write_file *args = (struct args_write_file *)a;
	write_file(args->file, args->t, args->size);
	install_single_syscall(SYS_getpid);
	getpid();
	return 0;
}

static void set_ns_to_none(struct op_call *call)
{
	for (unsigned int i = 0; i < NS_NUM; i++)
		call->context.ns[i].type = NS_NONE;
}

static void setup_ns(struct args_write_file *args)
{
        at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	at->nr = __NR_getpid;
	at->target = write_file_clone;
	at->tclone = (void *)args;
	at->ns[NS_MOUNT] = true;
	setup();
}

START_TEST(test_with_read)
{
	char test_file[] = "/tmp/test.txt";
	char t[PATH_MAX] = "Hello Test";
	struct op_call call = {
		{ OFFSET_RO_DATA, 0 },
		{
			{ OFFSET_DATA, 0 },
			{ OFFSET_DATA, sizeof(long) },
			{ OFFSET_DATA, sizeof(long) * 2 },
		},
		.has_ret = true,
		.ret = { OFFSET_DATA, sizeof(long) * 3 },
	};
	char buf[PATH_MAX];
	long count, ret;
	int fd;

	fd = write_file_get_fd(test_file, t, sizeof(t));
	count = sizeof(buf);
	for (unsigned int i = 0; i < NS_NUM; i++)
		call.context.ns[i].type = NS_NONE;

	nr = SYS_read;
	ck_write_gluten(gluten, call.nr, nr);
	write_arg(&call, 0, (long)fd);
	write_arg(&call, 1, (long)&buf);
	write_arg(&call, 2, (long)count);
	nr = SYS_read;

	ck_assert_int_eq(op_call(&req, notifyfd, &gluten, &call), 0);

	ck_read_gluten(gluten, call.ret, ret);
	ck_assert_msg(ret == count, "expect ret %ld to be %ld", ret, count);
	ck_assert_str_eq(t, buf);
}
END_TEST

START_TEST(test_with_getppid)
{
	struct op_call call = {
		.nr = { OFFSET_RO_DATA, 0 },
		.has_ret = true,
		.ret = { OFFSET_DATA, 0 },
	};
	long pid = (long)getpid();
	int ret = -1;

	for (unsigned int i = 0; i < NS_NUM; i++)
		call.context.ns[i].type = NS_NONE;

	nr = SYS_getppid;
	ck_write_gluten(gluten, call.nr, nr);

	ck_assert_int_eq(op_call(&req, notifyfd, &gluten, &call), 0);

	ck_read_gluten(gluten, call.ret, ret);
	ck_assert_msg(ret == pid, "expect ret %d to be equal to %ld", ret, pid);
}
END_TEST

START_TEST(test_with_open_read_ns)
{
	char test_file[] = "/tmp/test.txt";
	char t[PATH_MAX] = "Hello Test";
	struct args_write_file args = { test_file, t, sizeof(t) };
	struct op_call *call;
	struct op ops[] = {
		{ OP_CALL,
		  { .call = { { OFFSET_RO_DATA, 0 }, /* open */
			      {
				      { OFFSET_DATA, 0 },
				      { OFFSET_DATA, sizeof(long) },
				      { OFFSET_DATA, sizeof(long) * 2 },
			      },
			      .has_ret = true,
			      .ret = { OFFSET_DATA, sizeof(long) * 3 } } } },
		{ OP_CALL,
		  { .call = { { OFFSET_RO_DATA, sizeof(long) }, /* read */
			      {
				      { OFFSET_DATA, sizeof(long) * 3 }, /* ret of the previous call*/
				      { OFFSET_DATA, sizeof(long) * 5 },
				      { OFFSET_DATA, sizeof(long) * 6 },
			      },
			      .has_ret = true,
			      .ret = { OFFSET_DATA, sizeof(long) * 7 } } } },
		{ OP_END, OP_EMPTY },

	};
	int flags = O_RDWR;
	char buf[PATH_MAX];
	long count, rcount;

	setup_ns(&args);

	/* Copy and configure op_calls */
	set_ns_to_none(&ops[0].op.call);
	set_ns_to_none(&ops[1].op.call);

	nr = SYS_open;
	call = &ops[0].op.call;
	ck_write_gluten(gluten, call->nr, nr);
	write_arg(call, 0, (long)&test_file);
	write_arg(call, 1, (long)flags);
	call->context.ns[NS_MOUNT].type = NS_SPEC_TARGET;

	nr = SYS_read;
	call = &ops[1].op.call;
	count = sizeof(buf);
	ck_write_gluten(gluten, call->nr, nr);
	write_arg(call, 1, (long)&buf);
	write_arg(call, 2, (long)count);
	call->context.ns[NS_MOUNT].type = NS_SPEC_TARGET;

	write_instr(gluten, ops);

	ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0);
	ck_read_gluten(gluten, ops[1].op.call.ret, rcount);
	ck_assert_msg(rcount == count, "expect ret %ld to be %ld", rcount, count);
	ck_assert_str_eq(t, buf);
}
END_TEST


Suite *op_call_suite(void)
{
	Suite *s;
	TCase *tsimple, *tread, *treadns;
	int timeout = 30;

	s = suite_create("Perform ops call");

	tsimple = tcase_create("getppid");
	tcase_add_test(tsimple, test_with_getppid);
	suite_add_tcase(s, tsimple);

	tread = tcase_create("read");
	tcase_add_test(tread, test_with_read);
	suite_add_tcase(s, tread);

	treadns = tcase_create("read ns");

	tcase_add_checked_fixture(treadns, NULL, teardown);
	tcase_set_timeout(treadns, timeout);
	tcase_add_test(treadns, test_with_open_read_ns);
	suite_add_tcase(s, treadns);

	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;
}