aboutgitcodelistschat:MatrixIRC
path: root/common/gluten.h
blob: e80916a700eea69549d32cf43ea6a74ae55f526d (plain) (tree)
1
2
3
4
5
6
7
8
9
                                            

                                          
                                              
  


                       
 
                   

                    
                      
                         
                   

                          

                  
                 
 

                                                  



                                     
 
                                   



                                                          

                                    
 
                                                 
 
                         




                                    

                                                  

  

                                                                   

                                                           

                      
                                                                       
     
                                                                       
      
                                                                  

  
                                                                           
 
              

                   
                
                
              
                  
                
                 
                   
               
                      

  
   
                                                                              
   

                                            
 
                                                                          
                                            
 

                                                
 



                                                                    


   
                                                                           
   










                                          


                                      

  

                                                                     
   
                                                                          
                                                                               

                                               

                                        
                                                         
                                              
   
                     
               

                                                                             
     

                                                                             


                          

                          
                                    
                                          


                 

                                                                         
 


                       

                                  


                                                       
                     




                                   

                                                                    

  







                                   
                






                                      

  
                 


                      
                    
                                 
                                   




                                  

  

                                                            

  



                                 

  





                                   






                  
                         
  
                                             
 


                             

                               
                                 

  



                                                             








                                                     
                    
                               
                                 

                               

  

                                                                 

  







                                  

  





                                 

                          
               
                                
                                    
                                     
                                
                                    
                                      
                                          
                                  
                                          
                                    


             
                                           











                                                

                                                 




                                                      


                                                                

                             












                                               






                                                                              
                                
                            



















                                                                  

                                                   
                            
         
 

                                                         
                            
         
 












                                                               



                                                                           
 
                                                                  



                                           





                                                                          
 











                                                                             
 

                                                         
 




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

#ifndef COMMON_GLUTEN_H
#define COMMON_GLUTEN_H

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <linux/limits.h>
#include <limits.h>
#include <linux/seccomp.h>

#include <stdio.h>

#include "util.h"

extern struct seccomp_data anonymous_seccomp_data;

#define HEADER_SIZE		65536
#define INST_SIZE		65536
#define RO_DATA_SIZE		65536
#define DATA_SIZE		65536

#define INST_MAX		256
#define OFFSET_MAX                                       \
	MAX(MAX(MAX(DATA_SIZE, RO_DATA_SIZE), INST_MAX), \
	    ARRAY_SIZE(anonymous_seccomp_data.args))

#define OP_EMPTY { .block = { -1 } }
#define NO_FIELD block

#define GET_BIT(x, i) (((x) & (1UL << (i))) != 0)

enum gluten_offset_type {
	OFFSET_NULL		= 0,
	OFFSET_RO_DATA		= 1,
	OFFSET_DATA		= 2,
	OFFSET_SECCOMP_DATA	= 3,
	OFFSET_INSTRUCTION	= 4,
	OFFSET_METADATA		= 5,
	OFFSET_TYPE_MAX		= OFFSET_METADATA,
};

#define NULL_OFFSET ((struct gluten_offset){ .type = OFFSET_NULL })

extern const char *gluten_offset_name[OFFSET_TYPE_MAX + 1];

struct gluten_offset {
#ifdef __GNUC__
	enum gluten_offset_type type	:BITS_PER_NUM(OFFSET_TYPE_MAX);
#else
	uint32_t type			:BITS_PER_NUM(OFFSET_TYPE_MAX);
#endif
	uint32_t offset			:BITS_PER_NUM(OFFSET_MAX);
};

BUILD_BUG_ON(BITS_PER_NUM(OFFSET_TYPE_MAX) + BITS_PER_NUM(OFFSET_MAX) > 32)

enum op_type {
	OP_END = 0,
	OP_NR,
	OP_CALL,
	OP_COPY,
	OP_FD,
	OP_RETURN,
	OP_LOAD,
	OP_STORE,
	OP_BITWISE,
	OP_CMP,
	OP_RESOLVEDFD,
};

/**
 * enum context_spec_type - Type of reference to namespace, directory, UID/GID
 */
enum context_spec_type {
	CONTEXT_SPEC_NONE		= 0,

	/* PID from seccomp_data, UID/GID resolved via procfs in seitan */
	CONTEXT_SPEC_CALLER		= 1,

	/* UID/GID, or PID resolved in seitan */
	CONTEXT_SPEC_NUM		= 2,

	/* User/group names or namespace path, resolved in seitan */
	CONTEXT_SPEC_NAME		= 3,

	CONTEXT_SPEC_TYPE_MAX		= CONTEXT_SPEC_NAME,
};

/**
 * enum context_type - Directory, namespaces (see <linux/sched.h>), UID/GID
 */
enum context_type {
	NS_MOUNT		= 0,
	NS_CGROUP		= 1,
	NS_UTS			= 2,
	NS_IPC			= 3,
	NS_USER			= 4,
	NS_PID			= 5,
	NS_NET			= 6,
	NS_TIME			= 7,
	NS_TYPE_MAX		= NS_TIME,
	CWD			= 8,
	UID			= 9,
	GID			= 10,
	CONTEXT_TYPE_MAX	= GID,
};

extern const char *context_type_name[CONTEXT_TYPE_MAX + 1];
extern const char *context_spec_type_name[CONTEXT_SPEC_TYPE_MAX + 1];
/**
 * struct context_desc - Identification of one type of context information
 * @context:		Type of context (namespace, working directory, UID/GID)
 * @spec:		Reference type
 * @target.pid:		PID in procfs reference
 * @target.uid:		UID to switch to
 * @target.gid:		GID to switch to
 * @target.path:	Filesystem-bound (nsfs) reference
 * @target.name:	Username or group name
 */
struct context_desc {
#ifdef __GNUC__
	enum context_type type		:BITS_PER_NUM(CONTEXT_TYPE_MAX);
	enum context_spec_type spec	:BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX);
#else
	uint8_t type			:BITS_PER_NUM(CONTEXT_TYPE_MAX);
	uint8_t spec			:BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX);
#endif
	union {
		pid_t pid;
		uid_t uid;
		gid_t gid;
		char path[PATH_MAX];
		char name[LOGIN_NAME_MAX];
	} target;
};

BUILD_BUG_ON(BITS_PER_NUM(CONTEXT_TYPE_MAX) +				\
	     BITS_PER_NUM(CONTEXT_SPEC_TYPE_MAX) > 8)

enum metadata_type {
	UID_TARGET = 0,
	GID_TARGET = 1,
	PID_TARGET = 2,
	METADATA_MAX = PID_TARGET,
};
extern const char *metadata_type_str[METADATA_MAX + 1];

struct syscall_desc {
	uint32_t nr		:9;
	uint32_t arg_count	:3;
	uint32_t has_ret	:1;
	uint32_t arg_deref	:6;

	struct gluten_offset context;	/* struct context_desc [] */
	struct gluten_offset args[];
};

struct fd_desc {
	struct gluten_offset srcfd;
	struct gluten_offset newfd;
	uint8_t setfd		:1;
	uint8_t cloexec		:1;
	uint8_t do_return	:1;
};

struct op_call {
        struct gluten_offset desc;
};


struct op_nr {
	struct gluten_offset nr;
	struct gluten_offset no_match;
};

struct op_block {
	int32_t error;
};

struct return_desc {
	struct gluten_offset val;
	struct gluten_offset error;
	bool cont;
};

struct op_return {
	struct gluten_offset desc;
};

struct op_fd {
	struct gluten_offset desc;	/* struct fd_desc */
};

struct op_load {
	struct gluten_offset src;
	struct gluten_offset dst;
	size_t size;
};

struct op_store {
	struct gluten_offset src;
	struct gluten_offset dst;
	struct gluten_offset count;
};

enum op_cmp_type {
	CMP_EQ,
	CMP_NE,
	CMP_GT,
	CMP_GE,
	CMP_LT,
	CMP_LE,
	CMP_MAX = CMP_LE,
};
extern const char *cmp_type_str[CMP_MAX + 1];

struct cmp_desc {
	enum op_cmp_type cmp;
	size_t size;
	struct gluten_offset x;
	struct gluten_offset y;
	struct gluten_offset jmp;
};

struct op_cmp {
	struct gluten_offset desc;	/* struct cmp_desc */
};

enum bitwise_type {
	BITWISE_AND,
	BITWISE_OR,
	BITWISE_MAX = BITWISE_OR,
};

extern const char *bitwise_type_str[BITWISE_MAX + 1];

struct bitwise_desc {
	size_t size;
	enum bitwise_type type;
	struct gluten_offset dst;
	struct gluten_offset x;
	struct gluten_offset y;
};

struct op_bitwise {
	struct gluten_offset desc;	/* struct bitwise_desc */
};

struct resolvefd_desc {
        struct gluten_offset fd;
        struct gluten_offset path;
        size_t path_max;
};

struct op_resolvefd {
	struct gluten_offset desc;
};

struct op_copy {
	struct gluten_offset src;
	struct gluten_offset dst;
	size_t size;
};

struct op {
	enum op_type type;
	union {
		struct op_nr nr;
		struct op_call call;
		struct op_return ret;
		struct op_fd fd;
		struct op_load load;
		struct op_store store;
		struct op_bitwise bitwise;
		struct op_cmp cmp;
		struct op_resolvefd resfd;
		struct op_copy copy;
	} op;
};

#if defined(COOKER) || defined(SEITAN_TEST)
# define GLUTEN_CONST
#else
# define GLUTEN_CONST const
#endif

struct gluten {
	GLUTEN_CONST char header[HEADER_SIZE];

	GLUTEN_CONST char inst[INST_SIZE];

	GLUTEN_CONST char ro_data[RO_DATA_SIZE];

	GLUTEN_CONST enum metadata_type metadata;

	char data[DATA_SIZE];
} __attribute__((packed));

BUILD_BUG_ON(INST_SIZE < INST_MAX * sizeof(struct op))

static inline bool is_offset_valid(const struct gluten_offset x)
{
	switch (x.type) {
	case OFFSET_NULL:
		return false;
	case OFFSET_DATA:
		return x.offset < DATA_SIZE;
	case OFFSET_RO_DATA:
		return x.offset < RO_DATA_SIZE;
	case OFFSET_INSTRUCTION:
		return x.offset < INST_SIZE;
	case OFFSET_SECCOMP_DATA:
		return x.offset < 6;
	default:
		return false;
	}
}

#ifdef COOKER
static inline void *gluten_ptr(struct gluten *g, const struct gluten_offset x)
#else
static inline void *gluten_write_ptr(struct gluten *g,
				     const struct gluten_offset x)
#endif
{
	if (!is_offset_valid(x))
		return NULL;

	switch (x.type) {
	case OFFSET_DATA:
		return (char *)g->data + x.offset;
#ifdef COOKER
	case OFFSET_RO_DATA:
		return (char *)g->ro_data + x.offset;
	case OFFSET_INSTRUCTION:
		return (struct op *)(g->inst) + x.offset;
#endif
	default:
		return NULL;
	}
}

#ifndef COOKER
static inline const void *gluten_ptr(const struct seccomp_data *s,
				     struct gluten *g,
				     const struct gluten_offset x)
{
	if (!is_offset_valid(x)) {
		err("  offset limits are invalid");
		return NULL;
	}

	if (x.type == OFFSET_SECCOMP_DATA && s == NULL) {
		err("  seccomp data is empty");
		return NULL;
	}

	switch (x.type) {
	case OFFSET_DATA:
		return g->data + x.offset;
	case OFFSET_RO_DATA:
		return g->ro_data + x.offset;
	case OFFSET_SECCOMP_DATA:
		return (const uint64_t *)s->args + x.offset;
	case OFFSET_INSTRUCTION:
		return (const struct op *)(g->inst) + x.offset;
	default:
		return NULL;
	}
}

static inline bool check_gluten_limits(struct gluten_offset v, size_t size)
{
	struct gluten_offset off = { v.type, v.offset + size };

	if (v.type == OFFSET_SECCOMP_DATA || is_offset_valid(off))
		return true;

	err("  offset limits are invalid");
	return false;
}

static inline int gluten_write(struct gluten *g, struct gluten_offset dst,
			       const void *src, size_t size)
{
	void *p = gluten_write_ptr(g, dst);

	if (p == NULL || !check_gluten_limits(dst, size))
		return -1;
	memcpy(p, src, size);

	return 0;
}

static inline int gluten_read(const struct seccomp_data *s, struct gluten *g,
			      void *dst, const struct gluten_offset src,
			      size_t size)
{
	const void *p = gluten_ptr(s, g, src);

	if (p == NULL || !check_gluten_limits(src, size))
		return -1;

	memcpy(dst, p, size);

	return 0;
}

#endif
#endif /* COMMON_GLUTEN_H */