aboutgitcodelistschat:MatrixIRC
path: root/cooker/emit.c
blob: 3fcddba15a8427abfae2f622901f335a7c5053af (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                    
                                                                             


                                              
                                          




                   
                 
 
                                 
                        

                                       
                                       








                                        


                                                
 





                                                               
 



                                                              


                                               
                                              
 

                                                                       




                                             






                                                                                


                                                              



                                                              





                                             

                                                           




                                             









                                                                     

                                                                          
 

                                                              
 
                          
 












                                                                               
 

                                             

 








                                                              

                                                               
                                                                   
                                       
 
                              



                                                                          




































                                                               
                                                                    
                                                                  



                                           




                                                                  


                                                                       


                                            









                                                                       

                                                          
                                                                  








                                                                          
         
 
                   
 





































                                                                               
// SPDX-License-Identifier: GPL-3.0-or-later

/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
 *
 * cooker/emit.c - Generate gluten (bytecode) instructions and read-only data
 *
 * Copyright 2023 Red Hat GmbH
 * Author: Stefano Brivio <sbrivio@redhat.com>
 *         Alice Frosi <afrosi@redhat.com>
 */

#include "cooker.h"
#include "gluten.h"
#include "util.h"
#include "emit.h"

static const char *type_str[] = {
	"UNDEF", "NONE",
	"INT",  "INTMASK",  "INTFLAGS",
	"U32",  "U32MASK",  "U32FLAGS",
	"U64",  "U64MASK",  "U64FLAGS",
	"LONG", "LONGMASK", "LONGFLAGS",
	"STRING",
	"STRUCT", "SELECT",
	"PID",
	"PORT", "IPV4", "IPV6",
	"FDPATH",
	NULL
};

static const char *cmp_type_str[] = {
	"EQ", "NE", "GT", "GE", "LT", "LE", NULL
};

/**
 * emit_nr() - Emit OP_NR instruction: jump on syscall mismatch
 * @g:		gluten context
 * @number:	Pointer to system call number
 */
void emit_nr(struct gluten_ctx *g, struct gluten_offset number)
{
	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
	struct op_nr *nr = &op->op.nr;

	op->type = OP_NR;

	nr->nr = number;
	nr->no_match.type = OFFSET_INSTRUCTION;
	nr->no_match.offset = JUMP_NEXT_BLOCK;

	debug("   %i: OP_NR: if syscall number is not %li, jump to %s",
	      g->ip.offset, number, jump_name[nr->no_match.offset]);

	if (++g->ip.offset > INST_MAX)
		die("Too many instructions");
}

/**
 * emit_load() - Emit OP_LOAD instruction: dereference and copy syscall argument
 * @g:		gluten context
 * @dst:	gluten destination to copy dereferenced data
 * @index:	Index of system call argument
 * @len:	Length of data item pointed by reference
 */
void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
	       int index, size_t len)
{
	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
	struct op_load *load = &op->op.load;

	op->type = OP_LOAD;

	load->src.type = OFFSET_SECCOMP_DATA;
	load->src.offset = index;

	load->dst = dst;

	debug("   %i: OP_LOAD: #%i < args[%i] (size: %lu)",
	      g->ip.offset, dst.offset, index, len);

	if (++g->ip.offset > INST_MAX)
		die("Too many instructions");
}

/**
 * emit_cmp(): Emit OP_CMP instruction: compare data from two offsets
 * @g:		gluten context
 * @cmp_type:	Type of comparison
 * @x:		gluten pointer to first operand of comparison
 * @y:		gluten pointer to second operand of comparison
 * @size:	Size of comparison
 * @jmp:	Jump direction if comparison is true
 */
void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp_type,
	      struct gluten_offset x, struct gluten_offset y, size_t size,
	      enum jump_type jmp)
{
	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
	struct op_cmp *cmp = &op->op.cmp;

	op->type = OP_CMP;

	cmp->x = x;
	cmp->y = y;
	cmp->size = size;
	cmp->cmp = cmp_type;
	cmp->jmp.type = OFFSET_INSTRUCTION;
	cmp->jmp.offset = jmp;

	debug("   %i: OP_CMP: if %s: #%lu %s (size: %lu) %s: #%lu, jump to %s",
	      g->ip.offset,
	      gluten_offset_name[x.type], x.offset,
	      cmp_type_str[cmp_type], size,
	      gluten_offset_name[y.type], y.offset,
	      jump_name[jmp]);

	if (++g->ip.offset > INST_MAX)
		die("Too many instructions");
}

/**
 * emit_cmp_field() - Emit OP_CMP for a given field type
 * @g:		gluten context
 * @cmp:	Type of comparison
 * @field:	Description of field from system call model
 * @x:		gluten pointer to first operand of comparison
 * @y:		gluten pointer to second operand of comparison
 * @jmp:	Jump direction if comparison is true
 */
void emit_cmp_field(struct gluten_ctx *g, enum op_cmp_type cmp,
		    struct field *field,
		    struct gluten_offset x, struct gluten_offset y,
		    enum jump_type jmp)
{
	emit_cmp(g, cmp, x, y,
		 field->strlen ? field->strlen : gluten_size[field->type],
		 jmp);
}

/**
 * emit_return() - Emit OP_RETURN instruction: return value
 * @g:		gluten context
 * @v:		Pointer to return value
 */
void emit_return(struct gluten_ctx *g, struct gluten_offset v)
{
	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
	struct op_return *ret = &op->op.ret;

	op->type = OP_RETURN;
	ret->val = v;

	debug("   %i: OP_RETURN:",  g->ip.offset);

	if (++g->ip.offset > INST_MAX)
		die("Too many instructions");
}
/**
 * emit_block() - Emit OP_BLOCK instruction: return error value
 * @g:		gluten context
 * @error:	Error value
 */
void emit_block(struct gluten_ctx *g, int32_t error)
{
	struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
	struct op_block *block = &op->op.block;

	op->type = OP_BLOCK;
	block->error = error;

	debug("   %i: OP_BLOCK: %d", g->ip.offset, error);

	if (++g->ip.offset > INST_MAX)
		die("Too many instructions");
}

struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
			       size_t str_len, union value *value)
{
	void *p = gluten_ptr(&g->g, g->cp);
	struct gluten_offset ret = g->cp;

	switch (type) {
	case INT:
		if (g->cp.offset + sizeof(int) > RO_DATA_SIZE)
			die("   Read-only data section exceeded");

		*(int *)p = value->v_int;
		debug("   C#%i: (%s) %i", g->cp.offset, type_str[type],
		      value->v_int);

		g->cp.offset += sizeof(int);
		break;
	case U64:
		if (g->cp.offset + sizeof(uint64_t) > RO_DATA_SIZE)
			die("   Read-only data section exceeded");

		*(uint64_t *)p = value->v_u64;
		debug("   C#%i: (%s) %i", g->cp.offset, type_str[type],
		      value->v_u64);

		g->cp.offset += sizeof(uint64_t);
		break;
	case STRING:
		if (g->cp.offset + str_len > RO_DATA_SIZE)
			die("   Read-only data section exceeded");

		strncpy(p, value->v_str, str_len);
		debug("   C#%i: (%s:%i) %s", g->cp.offset, type_str[type],
		      str_len, value->v_str);

		g->cp.offset += str_len;
		break;
	default:
		;
	}

	return ret;
}

static void gluten_link(struct gluten_ctx *g, enum jump_type type,
			struct op *start)
{
	struct gluten_offset *jmp;
	struct op *op;

	for (op = (struct op *)start; op->type; op++) {
		switch (op->type) {
		case OP_NR:
			jmp = &op->op.nr.no_match;
			break;
		case OP_CMP:
			jmp = &op->op.cmp.jmp;
			break;
		default:
			continue;
		}

		if (jmp->offset == type) {
			jmp->offset = g->ip.offset;
			debug("    linked jump of instruction #%i to #%i",
			      op - (struct op *)g->g.inst, g->ip.offset);
		}
	}
}

void link_block(struct gluten_ctx *g)
{
	debug("   Linking block...");
	gluten_link(g, JUMP_NEXT_BLOCK, (struct op *)gluten_ptr(&g->g, g->lr));
}

void link_match(struct gluten_ctx *g)
{
	debug("   Linking match...");
	gluten_link(g, JUMP_NEXT_MATCH, (struct op *)gluten_ptr(&g->g, g->mr));
}