

#ifndef __LINUX_LSM_HOOKS_H
#define __LINUX_LSM_HOOKS_H

#include <uapi/linux/lsm.h>
#include <linux/security.h>
#include <linux/init.h>
#include <linux/rculist.h>
#include <linux/xattr.h>
#include <linux/static_call.h>
#include <linux/unroll.h>
#include <linux/jump_label.h>
#include <linux/lsm_count.h>

union security_list_options {
	#define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
	#include "lsm_hook_defs.h"
	#undef LSM_HOOK
	void *lsm_func_addr;
};


struct lsm_static_call {
	struct static_call_key *key;
	void *trampoline;
	struct security_hook_list *hl;
	
	struct static_key_false *active;
} __randomize_layout;


struct lsm_static_calls_table {
	#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
		struct lsm_static_call NAME[MAX_LSM_COUNT];
	#include <linux/lsm_hook_defs.h>
	#undef LSM_HOOK
} __packed __randomize_layout;


struct lsm_id {
	const char *name;
	u64 id;
};


struct security_hook_list {
	struct lsm_static_call *scalls;
	union security_list_options hook;
	const struct lsm_id *lsmid;
} __randomize_layout;


struct lsm_blob_sizes {
	unsigned int lbs_cred;
	unsigned int lbs_file;
	unsigned int lbs_backing_file;
	unsigned int lbs_ib;
	unsigned int lbs_inode;
	unsigned int lbs_sock;
	unsigned int lbs_superblock;
	unsigned int lbs_ipc;
	unsigned int lbs_key;
	unsigned int lbs_msg_msg;
	unsigned int lbs_perf_event;
	unsigned int lbs_task;
	unsigned int lbs_xattr_count; 
	unsigned int lbs_tun_dev;
	unsigned int lbs_bdev;
	unsigned int lbs_bpf_map;
	unsigned int lbs_bpf_prog;
	unsigned int lbs_bpf_token;
};


#define LSM_RET_VOID ((void) 0)


#define LSM_HOOK_INIT(NAME, HOOK)			\
	{						\
		.scalls = static_calls_table.NAME,	\
		.hook = { .NAME = HOOK }		\
	}

extern void security_add_hooks(struct security_hook_list *hooks, int count,
			       const struct lsm_id *lsmid);

#define LSM_FLAG_LEGACY_MAJOR	BIT(0)
#define LSM_FLAG_EXCLUSIVE	BIT(1)

enum lsm_order {
	LSM_ORDER_FIRST = -1,	
	LSM_ORDER_MUTABLE = 0,
	LSM_ORDER_LAST = 1,	
};


struct lsm_info {
	const struct lsm_id *id;
	enum lsm_order order;
	unsigned long flags;
	struct lsm_blob_sizes *blobs;
	int *enabled;
	int (*init)(void);
	int (*initcall_pure)(void);
	int (*initcall_early)(void);
	int (*initcall_core)(void);
	int (*initcall_subsys)(void);
	int (*initcall_fs)(void);
	int (*initcall_device)(void);
	int (*initcall_late)(void);
};

#define DEFINE_LSM(lsm)							\
	static struct lsm_info __lsm_##lsm				\
		__used __section(".lsm_info.init")			\
		__aligned(sizeof(unsigned long))

#define DEFINE_EARLY_LSM(lsm)						\
	static struct lsm_info __early_lsm_##lsm			\
		__used __section(".early_lsm_info.init")		\
		__aligned(sizeof(unsigned long))



extern struct lsm_static_calls_table static_calls_table __ro_after_init;


static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs,
					       int *xattr_count)
{
	if (unlikely(!xattrs))
		return NULL;
	return &xattrs[(*xattr_count)++];
}

#endif 
