linux/security/apparmor/policy_unpack.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * AppArmor security module
 *
 * This file contains AppArmor functions for unpacking policy loaded from
 * userspace.
 *
 * Copyright (C) 1998-2008 Novell/SUSE
 * Copyright 2009-2010 Canonical Ltd.
 *
 * AppArmor uses a serialized binary format for loading policy. To find
 * policy format documentation see Documentation/admin-guide/LSM/apparmor.rst
 * All policy is validated before it is used.
 */

#include <linux/unaligned.h>
#include <kunit/visibility.h>
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/zstd.h>

#include "include/apparmor.h"
#include "include/audit.h"
#include "include/cred.h"
#include "include/crypto.h"
#include "include/file.h"
#include "include/match.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/policy_unpack.h"
#include "include/policy_compat.h"

/* audit callback for unpack fields */
static void audit_cb(struct audit_buffer *ab, void *va)
{}

/**
 * audit_iface - do audit message for policy unpacking/load/replace/remove
 * @new: profile if it has been allocated (MAYBE NULL)
 * @ns_name: name of the ns the profile is to be loaded to (MAY BE NULL)
 * @name: name of the profile being manipulated (MAYBE NULL)
 * @info: any extra info about the failure (MAYBE NULL)
 * @e: buffer position info
 * @error: error code
 *
 * Returns: %0 or error
 */
static int audit_iface(struct aa_profile *new, const char *ns_name,
		       const char *name, const char *info, struct aa_ext *e,
		       int error)
{}

void __aa_loaddata_update(struct aa_loaddata *data, long revision)
{}

bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
{}

/*
 * need to take the ns mutex lock which is NOT safe most places that
 * put_loaddata is called, so we have to delay freeing it
 */
static void do_loaddata_free(struct work_struct *work)
{}

void aa_loaddata_kref(struct kref *kref)
{}

struct aa_loaddata *aa_loaddata_alloc(size_t size)
{}

/* test if read will be in packed data bounds */
VISIBLE_IF_KUNIT bool aa_inbounds(struct aa_ext *e, size_t size)
{}
EXPORT_SYMBOL_IF_KUNIT();

/**
 * aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
 * @e: serialized data read head (NOT NULL)
 * @chunk: start address for chunk of data (NOT NULL)
 *
 * Returns: the size of chunk found with the read head at the end of the chunk.
 */
VISIBLE_IF_KUNIT size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk)
{}
EXPORT_SYMBOL_IF_KUNIT();

/* unpack control byte */
VISIBLE_IF_KUNIT bool aa_unpack_X(struct aa_ext *e, enum aa_code code)
{}
EXPORT_SYMBOL_IF_KUNIT();

/**
 * aa_unpack_nameX - check is the next element is of type X with a name of @name
 * @e: serialized data extent information  (NOT NULL)
 * @code: type code
 * @name: name to match to the serialized element.  (MAYBE NULL)
 *
 * check that the next serialized data element is of type X and has a tag
 * name @name.  If @name is specified then there must be a matching
 * name element in the stream.  If @name is NULL any name element will be
 * skipped and only the typecode will be tested.
 *
 * Returns true on success (both type code and name tests match) and the read
 * head is advanced past the headers
 *
 * Returns: false if either match fails, the read head does not move
 */
VISIBLE_IF_KUNIT bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();

static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
{}

VISIBLE_IF_KUNIT bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();

VISIBLE_IF_KUNIT bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();

static bool aa_unpack_cap_low(struct aa_ext *e, kernel_cap_t *data, const char *name)
{}

static bool aa_unpack_cap_high(struct aa_ext *e, kernel_cap_t *data, const char *name)
{}

VISIBLE_IF_KUNIT bool aa_unpack_array(struct aa_ext *e, const char *name, u16 *size)
{}
EXPORT_SYMBOL_IF_KUNIT();

VISIBLE_IF_KUNIT size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();

VISIBLE_IF_KUNIT int aa_unpack_str(struct aa_ext *e, const char **string, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();

VISIBLE_IF_KUNIT int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name)
{}
EXPORT_SYMBOL_IF_KUNIT();


/**
 * unpack_dfa - unpack a file rule dfa
 * @e: serialized data extent information (NOT NULL)
 * @flags: dfa flags to check
 *
 * returns dfa or ERR_PTR or NULL if no dfa
 */
static struct aa_dfa *unpack_dfa(struct aa_ext *e, int flags)
{}

/**
 * unpack_trans_table - unpack a profile transition table
 * @e: serialized data extent information  (NOT NULL)
 * @strs: str table to unpack to (NOT NULL)
 *
 * Returns: true if table successfully unpacked or not present
 */
static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
{}

static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
{}

static bool unpack_secmark(struct aa_ext *e, struct aa_ruleset *rules)
{}

static bool unpack_rlimits(struct aa_ext *e, struct aa_ruleset *rules)
{}

static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm)
{}

static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
{}

static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
		      bool required_dfa, bool required_trans,
		      const char **info)
{}

static u32 strhash(const void *data, u32 len, u32 seed)
{}

static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
{}

/**
 * unpack_profile - unpack a serialized profile
 * @e: serialized data extent information (NOT NULL)
 * @ns_name: pointer of newly allocated copy of %NULL in case of error
 *
 * NOTE: unpack profile sets audit struct if there is a failure
 */
static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
{}

/**
 * verify_header - unpack serialized stream header
 * @e: serialized data read head (NOT NULL)
 * @required: whether the header is required or optional
 * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
 *
 * Returns: error or 0 if header is good
 */
static int verify_header(struct aa_ext *e, int required, const char **ns)
{}

/**
 * verify_dfa_accept_index - verify accept indexes are in range of perms table
 * @dfa: the dfa to check accept indexes are in range
 * @table_size: the permission table size the indexes should be within
 */
static bool verify_dfa_accept_index(struct aa_dfa *dfa, int table_size)
{}

static bool verify_perm(struct aa_perms *perm)
{}

static bool verify_perms(struct aa_policydb *pdb)
{}

/**
 * verify_profile - Do post unpack analysis to verify profile consistency
 * @profile: profile to verify (NOT NULL)
 *
 * Returns: 0 if passes verification else error
 *
 * This verification is post any unpack mapping or changes
 */
static int verify_profile(struct aa_profile *profile)
{}

void aa_load_ent_free(struct aa_load_ent *ent)
{}

struct aa_load_ent *aa_load_ent_alloc(void)
{}

static int compress_zstd(const char *src, size_t slen, char **dst, size_t *dlen)
{}

static int compress_loaddata(struct aa_loaddata *data)
{}

/**
 * aa_unpack - unpack packed binary profile(s) data loaded from user space
 * @udata: user data copied to kmem  (NOT NULL)
 * @lh: list to place unpacked profiles in a aa_repl_ws
 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
 *
 * Unpack user data and return refcounted allocated profile(s) stored in
 * @lh in order of discovery, with the list chain stored in base.list
 * or error
 *
 * Returns: profile(s) on @lh else error pointer if fails to unpack
 */
int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
	      const char **ns)
{}