2019-06-01 10:08:55 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2010-07-29 14:48:02 -07:00
/*
* 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 .
*
2011-05-19 15:59:38 -07:00
* AppArmor uses a serialized binary format for loading policy . To find
2017-05-13 04:51:45 -07:00
* policy format documentation see Documentation / admin - guide / LSM / apparmor . rst
2010-07-29 14:48:02 -07:00
* All policy is validated before it is used .
*/
# include <asm/unaligned.h>
2022-12-07 01:40:24 +00:00
# include <kunit/visibility.h>
2010-07-29 14:48:02 -07:00
# include <linux/ctype.h>
# include <linux/errno.h>
2022-07-11 11:36:08 -05:00
# include <linux/zstd.h>
2010-07-29 14:48:02 -07:00
# include "include/apparmor.h"
# include "include/audit.h"
2017-10-11 01:04:48 -07:00
# include "include/cred.h"
2013-08-14 11:27:36 -07:00
# include "include/crypto.h"
2020-03-30 16:43:29 -04:00
# include "include/file.h"
2010-07-29 14:48:02 -07:00
# include "include/match.h"
2017-06-09 08:14:28 -07:00
# include "include/path.h"
2010-07-29 14:48:02 -07:00
# include "include/policy.h"
# include "include/policy_unpack.h"
2022-08-21 22:48:32 -07:00
# include "include/policy_compat.h"
2017-01-16 00:42:38 -08:00
2010-07-29 14:48:02 -07:00
/* audit callback for unpack fields */
static void audit_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
2017-01-16 00:43:02 -08:00
if ( aad ( sa ) - > iface . ns ) {
audit_log_format ( ab , " ns= " ) ;
audit_log_untrustedstring ( ab , aad ( sa ) - > iface . ns ) ;
}
2017-07-18 23:37:18 -07:00
if ( aad ( sa ) - > name ) {
2010-07-29 14:48:02 -07:00
audit_log_format ( ab , " name= " ) ;
2017-07-18 23:37:18 -07:00
audit_log_untrustedstring ( ab , aad ( sa ) - > name ) ;
2010-07-29 14:48:02 -07:00
}
2017-01-16 00:43:02 -08:00
if ( aad ( sa ) - > iface . pos )
audit_log_format ( ab , " offset=%ld " , aad ( sa ) - > iface . pos ) ;
2010-07-29 14:48:02 -07:00
}
/**
* audit_iface - do audit message for policy unpacking / load / replace / remove
* @ new : profile if it has been allocated ( MAYBE NULL )
2017-01-16 00:42:56 -08:00
* @ ns_name : name of the ns the profile is to be loaded to ( MAY BE NULL )
2010-07-29 14:48:02 -07:00
* @ name : name of the profile being manipulated ( MAYBE NULL )
* @ info : any extra info about the failure ( MAYBE NULL )
2012-03-10 11:25:30 -08:00
* @ e : buffer position info
2010-07-29 14:48:02 -07:00
* @ error : error code
*
* Returns : % 0 or error
*/
2017-01-16 00:42:56 -08:00
static int audit_iface ( struct aa_profile * new , const char * ns_name ,
const char * name , const char * info , struct aa_ext * e ,
int error )
2010-07-29 14:48:02 -07:00
{
2017-06-09 08:14:28 -07:00
struct aa_profile * profile = labels_profile ( aa_current_raw_label ( ) ) ;
2022-04-19 16:25:55 -07:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , AA_CLASS_NONE , NULL ) ;
2012-03-10 11:25:30 -08:00
if ( e )
2017-01-16 00:43:02 -08:00
aad ( & sa ) - > iface . pos = e - > pos - e - > start ;
aad ( & sa ) - > iface . ns = ns_name ;
if ( new )
2017-07-18 23:37:18 -07:00
aad ( & sa ) - > name = new - > base . hname ;
2017-01-16 00:43:02 -08:00
else
2017-07-18 23:37:18 -07:00
aad ( & sa ) - > name = name ;
2017-01-16 00:43:02 -08:00
aad ( & sa ) - > info = info ;
aad ( & sa ) - > error = error ;
2010-07-29 14:48:02 -07:00
2017-01-16 00:43:02 -08:00
return aa_audit ( AUDIT_APPARMOR_STATUS , profile , & sa , audit_cb ) ;
2010-07-29 14:48:02 -07:00
}
2017-05-09 00:08:41 -07:00
void __aa_loaddata_update ( struct aa_loaddata * data , long revision )
{
AA_BUG ( ! data ) ;
AA_BUG ( ! data - > ns ) ;
AA_BUG ( ! mutex_is_locked ( & data - > ns - > lock ) ) ;
AA_BUG ( data - > revision > revision ) ;
data - > revision = revision ;
2021-02-01 03:43:18 -08:00
if ( ( data - > dents [ AAFS_LOADDATA_REVISION ] ) ) {
d_inode ( data - > dents [ AAFS_LOADDATA_DIR ] ) - > i_mtime =
current_time ( d_inode ( data - > dents [ AAFS_LOADDATA_DIR ] ) ) ;
d_inode ( data - > dents [ AAFS_LOADDATA_REVISION ] ) - > i_mtime =
current_time ( d_inode ( data - > dents [ AAFS_LOADDATA_REVISION ] ) ) ;
}
2017-05-09 00:08:41 -07:00
}
bool aa_rawdata_eq ( struct aa_loaddata * l , struct aa_loaddata * r )
{
if ( l - > size ! = r - > size )
return false ;
2019-01-23 19:17:09 +00:00
if ( l - > compressed_size ! = r - > compressed_size )
return false ;
2017-05-09 00:08:41 -07:00
if ( aa_g_hash_policy & & memcmp ( l - > hash , r - > hash , aa_hash_size ( ) ) ! = 0 )
return false ;
2019-01-23 19:17:09 +00:00
return memcmp ( l - > data , r - > data , r - > compressed_size ? : r - > size ) = = 0 ;
2017-05-09 00:08:41 -07:00
}
/*
* 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 )
{
struct aa_loaddata * d = container_of ( work , struct aa_loaddata , work ) ;
struct aa_ns * ns = aa_get_ns ( d - > ns ) ;
if ( ns ) {
2017-11-20 23:24:09 -08:00
mutex_lock_nested ( & ns - > lock , ns - > level ) ;
2017-05-09 00:08:41 -07:00
__aa_fs_remove_rawdata ( d ) ;
mutex_unlock ( & ns - > lock ) ;
aa_put_ns ( ns ) ;
}
2020-08-06 23:18:13 -07:00
kfree_sensitive ( d - > hash ) ;
kfree_sensitive ( d - > name ) ;
2018-02-03 20:08:28 +01:00
kvfree ( d - > data ) ;
2020-08-06 23:18:13 -07:00
kfree_sensitive ( d ) ;
2017-05-09 00:08:41 -07:00
}
2017-01-16 00:42:55 -08:00
void aa_loaddata_kref ( struct kref * kref )
{
struct aa_loaddata * d = container_of ( kref , struct aa_loaddata , count ) ;
if ( d ) {
2017-05-09 00:08:41 -07:00
INIT_WORK ( & d - > work , do_loaddata_free ) ;
schedule_work ( & d - > work ) ;
2017-01-16 00:42:55 -08:00
}
}
2017-05-09 00:08:41 -07:00
struct aa_loaddata * aa_loaddata_alloc ( size_t size )
{
2018-02-03 20:08:28 +01:00
struct aa_loaddata * d ;
2017-05-09 00:08:41 -07:00
2018-02-03 20:08:28 +01:00
d = kzalloc ( sizeof ( * d ) , GFP_KERNEL ) ;
2017-05-09 00:08:41 -07:00
if ( d = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2018-02-03 20:08:28 +01:00
d - > data = kvzalloc ( size , GFP_KERNEL ) ;
if ( ! d - > data ) {
kfree ( d ) ;
return ERR_PTR ( - ENOMEM ) ;
}
2017-05-09 00:08:41 -07:00
kref_init ( & d - > count ) ;
INIT_LIST_HEAD ( & d - > list ) ;
return d ;
}
2010-07-29 14:48:02 -07:00
/* test if read will be in packed data bounds */
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT bool aa_inbounds ( struct aa_ext * e , size_t size )
2010-07-29 14:48:02 -07:00
{
return ( size < = e - > end - e - > pos ) ;
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_inbounds ) ;
2010-07-29 14:48:02 -07:00
/**
2022-12-07 01:40:24 +00:00
* aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
2010-07-29 14:48:02 -07:00
* @ 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 .
*/
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT size_t aa_unpack_u16_chunk ( struct aa_ext * e , char * * chunk )
2010-07-29 14:48:02 -07:00
{
size_t size = 0 ;
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2010-07-29 14:48:02 -07:00
2022-12-07 01:40:24 +00:00
if ( ! aa_inbounds ( e , sizeof ( u16 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2017-01-16 00:43:14 -08:00
size = le16_to_cpu ( get_unaligned ( ( __le16 * ) e - > pos ) ) ;
e - > pos + = sizeof ( __le16 ) ;
2022-12-07 01:40:24 +00:00
if ( ! aa_inbounds ( e , size ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2010-07-29 14:48:02 -07:00
* chunk = e - > pos ;
e - > pos + = size ;
return size ;
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
return 0 ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_u16_chunk ) ;
2010-07-29 14:48:02 -07:00
/* unpack control byte */
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT bool aa_unpack_X ( struct aa_ext * e , enum aa_code code )
2010-07-29 14:48:02 -07:00
{
2022-12-07 01:40:24 +00:00
if ( ! aa_inbounds ( e , 1 ) )
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
if ( * ( u8 * ) e - > pos ! = code )
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
e - > pos + + ;
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_X ) ;
2010-07-29 14:48:02 -07:00
/**
2022-12-07 01:40:24 +00:00
* aa_unpack_nameX - check is the next element is of type X with a name of @ name
2010-07-29 14:48:02 -07:00
* @ 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 .
*
2020-04-28 19:52:21 +08:00
* Returns true on success ( both type code and name tests match ) and the read
2010-07-29 14:48:02 -07:00
* head is advanced past the headers
*
2020-04-28 19:52:21 +08:00
* Returns : false if either match fails , the read head does not move
2010-07-29 14:48:02 -07:00
*/
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT bool aa_unpack_nameX ( struct aa_ext * e , enum aa_code code , const char * name )
2010-07-29 14:48:02 -07:00
{
/*
* May need to reset pos if name or type doesn ' t match
*/
void * pos = e - > pos ;
/*
* Check for presence of a tagname , and if present name size
* AA_NAME tag value is a u16 .
*/
2022-12-07 01:40:24 +00:00
if ( aa_unpack_X ( e , AA_NAME ) ) {
2010-07-29 14:48:02 -07:00
char * tag = NULL ;
2022-12-07 01:40:24 +00:00
size_t size = aa_unpack_u16_chunk ( e , & tag ) ;
2010-07-29 14:48:02 -07:00
/* if a name is specified it must match. otherwise skip tag */
2019-05-28 17:32:26 +02:00
if ( name & & ( ! size | | tag [ size - 1 ] ! = ' \0 ' | | strcmp ( name , tag ) ) )
2010-07-29 14:48:02 -07:00
goto fail ;
} else if ( name ) {
/* if a name is specified and there is no name tag fail */
goto fail ;
}
/* now check if type code matches */
2022-12-07 01:40:24 +00:00
if ( aa_unpack_X ( e , code ) )
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_nameX ) ;
2010-07-29 14:48:02 -07:00
2018-05-24 13:27:46 -07:00
static bool unpack_u8 ( struct aa_ext * e , u8 * data , const char * name )
{
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_U8 , name ) ) {
if ( ! aa_inbounds ( e , sizeof ( u8 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2018-05-24 13:27:46 -07:00
if ( data )
2021-05-08 00:07:54 +02:00
* data = * ( ( u8 * ) e - > pos ) ;
2018-05-24 13:27:46 -07:00
e - > pos + = sizeof ( u8 ) ;
2020-04-28 19:52:21 +08:00
return true ;
2018-05-24 13:27:46 -07:00
}
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2018-05-24 13:27:46 -07:00
}
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT bool aa_unpack_u32 ( struct aa_ext * e , u32 * data , const char * name )
2010-07-29 14:48:02 -07:00
{
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_U32 , name ) ) {
if ( ! aa_inbounds ( e , sizeof ( u32 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2010-07-29 14:48:02 -07:00
if ( data )
2017-01-16 00:43:14 -08:00
* data = le32_to_cpu ( get_unaligned ( ( __le32 * ) e - > pos ) ) ;
2010-07-29 14:48:02 -07:00
e - > pos + = sizeof ( u32 ) ;
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
}
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_u32 ) ;
2010-07-29 14:48:02 -07:00
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT bool aa_unpack_u64 ( struct aa_ext * e , u64 * data , const char * name )
2010-07-29 14:48:02 -07:00
{
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_U64 , name ) ) {
if ( ! aa_inbounds ( e , sizeof ( u64 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2010-07-29 14:48:02 -07:00
if ( data )
2017-01-16 00:43:14 -08:00
* data = le64_to_cpu ( get_unaligned ( ( __le64 * ) e - > pos ) ) ;
2010-07-29 14:48:02 -07:00
e - > pos + = sizeof ( u64 ) ;
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
}
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_u64 ) ;
2010-07-29 14:48:02 -07:00
2023-02-28 11:39:09 -08:00
static bool aa_unpack_cap_low ( struct aa_ext * e , kernel_cap_t * data , const char * name )
{
u32 val ;
if ( ! aa_unpack_u32 ( e , & val , name ) )
return false ;
data - > val = val ;
return true ;
}
static bool aa_unpack_cap_high ( struct aa_ext * e , kernel_cap_t * data , const char * name )
{
u32 val ;
if ( ! aa_unpack_u32 ( e , & val , name ) )
return false ;
data - > val = ( u32 ) data - > val | ( ( u64 ) val < < 32 ) ;
return true ;
}
2022-12-14 13:42:09 -08:00
VISIBLE_IF_KUNIT bool aa_unpack_array ( struct aa_ext * e , const char * name , u16 * size )
2010-07-29 14:48:02 -07:00
{
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_ARRAY , name ) ) {
if ( ! aa_inbounds ( e , sizeof ( u16 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2022-08-26 09:26:57 -07:00
* size = le16_to_cpu ( get_unaligned ( ( __le16 * ) e - > pos ) ) ;
2010-07-29 14:48:02 -07:00
e - > pos + = sizeof ( u16 ) ;
2022-12-14 13:42:09 -08:00
return true ;
2010-07-29 14:48:02 -07:00
}
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
2022-12-14 13:42:09 -08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_array ) ;
2010-07-29 14:48:02 -07:00
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT size_t aa_unpack_blob ( struct aa_ext * e , char * * blob , const char * name )
2010-07-29 14:48:02 -07:00
{
2019-06-12 14:55:14 -07:00
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_BLOB , name ) ) {
2010-07-29 14:48:02 -07:00
u32 size ;
2022-12-07 01:40:24 +00:00
if ( ! aa_inbounds ( e , sizeof ( u32 ) ) )
2019-06-12 14:55:14 -07:00
goto fail ;
2017-01-16 00:43:14 -08:00
size = le32_to_cpu ( get_unaligned ( ( __le32 * ) e - > pos ) ) ;
2010-07-29 14:48:02 -07:00
e - > pos + = sizeof ( u32 ) ;
2022-12-07 01:40:24 +00:00
if ( aa_inbounds ( e , ( size_t ) size ) ) {
2010-07-29 14:48:02 -07:00
* blob = e - > pos ;
e - > pos + = size ;
return size ;
}
}
2019-06-12 14:55:14 -07:00
fail :
e - > pos = pos ;
2010-07-29 14:48:02 -07:00
return 0 ;
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_blob ) ;
2010-07-29 14:48:02 -07:00
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT int aa_unpack_str ( struct aa_ext * e , const char * * string , const char * name )
2010-07-29 14:48:02 -07:00
{
char * src_str ;
size_t size = 0 ;
void * pos = e - > pos ;
* string = NULL ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRING , name ) ) {
size = aa_unpack_u16_chunk ( e , & src_str ) ;
2010-07-29 14:48:02 -07:00
if ( size ) {
/* strings are null terminated, length is size - 1 */
if ( src_str [ size - 1 ] ! = 0 )
goto fail ;
* string = src_str ;
2019-06-12 14:55:14 -07:00
return size ;
2010-07-29 14:48:02 -07:00
}
}
fail :
e - > pos = pos ;
return 0 ;
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_str ) ;
2010-07-29 14:48:02 -07:00
2022-12-07 01:40:24 +00:00
VISIBLE_IF_KUNIT int aa_unpack_strdup ( struct aa_ext * e , char * * string , const char * name )
2010-07-29 14:48:02 -07:00
{
const char * tmp ;
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
int res = aa_unpack_str ( e , & tmp , name ) ;
2010-07-29 14:48:02 -07:00
* string = NULL ;
if ( ! res )
return 0 ;
* string = kmemdup ( tmp , res , GFP_KERNEL ) ;
if ( ! * string ) {
e - > pos = pos ;
return 0 ;
}
return res ;
}
2022-12-07 01:40:24 +00:00
EXPORT_SYMBOL_IF_KUNIT ( aa_unpack_strdup ) ;
2010-07-29 14:48:02 -07:00
/**
* unpack_dfa - unpack a file rule dfa
* @ e : serialized data extent information ( NOT NULL )
2022-08-26 08:53:42 -07:00
* @ flags : dfa flags to check
2010-07-29 14:48:02 -07:00
*
* returns dfa or ERR_PTR or NULL if no dfa
*/
2022-08-26 08:53:42 -07:00
static struct aa_dfa * unpack_dfa ( struct aa_ext * e , int flags )
2010-07-29 14:48:02 -07:00
{
char * blob = NULL ;
size_t size ;
struct aa_dfa * dfa = NULL ;
2022-12-07 01:40:24 +00:00
size = aa_unpack_blob ( e , & blob , " aadfa " ) ;
2010-07-29 14:48:02 -07:00
if ( size ) {
/*
* The dfa is aligned with in the blob to 8 bytes
* from the beginning of the stream .
2013-07-10 21:05:43 -07:00
* alignment adjust needed by dfa unpack
2010-07-29 14:48:02 -07:00
*/
2013-07-10 21:05:43 -07:00
size_t sz = blob - ( char * ) e - > start -
( ( e - > pos - e - > start ) & 7 ) ;
2010-07-29 14:48:02 -07:00
size_t pad = ALIGN ( sz , 8 ) - sz ;
2021-02-03 01:35:12 -08:00
if ( aa_g_paranoid_load )
flags | = DFA_FLAG_VERIFY_STATES ;
2010-07-29 14:48:02 -07:00
dfa = aa_dfa_unpack ( blob + pad , size - pad , flags ) ;
if ( IS_ERR ( dfa ) )
return dfa ;
}
return dfa ;
}
/**
* unpack_trans_table - unpack a profile transition table
* @ e : serialized data extent information ( NOT NULL )
2022-08-23 01:06:15 -07:00
* @ table : str table to unpack to ( NOT NULL )
2010-07-29 14:48:02 -07:00
*
2022-08-23 01:06:15 -07:00
* Returns : true if table successfully unpacked or not present
2010-07-29 14:48:02 -07:00
*/
2022-08-23 01:06:15 -07:00
static bool unpack_trans_table ( struct aa_ext * e , struct aa_str_table * strs )
2010-07-29 14:48:02 -07:00
{
2017-07-06 10:56:21 +02:00
void * saved_pos = e - > pos ;
2022-10-10 11:18:50 -07:00
char * * table = NULL ;
2010-07-29 14:48:02 -07:00
/* exec table is optional */
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " xtable " ) ) {
2022-08-26 09:26:57 -07:00
u16 size ;
int i ;
2010-07-29 14:48:02 -07:00
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_array ( e , NULL , & size ) )
2022-09-24 22:34:07 -07:00
/*
* Note : index into trans table array is a max
* of 2 ^ 24 , but unpack array can only unpack
* an array of 2 ^ 16 in size atm so no need
* for size check here
*/
2010-07-29 14:48:02 -07:00
goto fail ;
2022-08-23 01:06:15 -07:00
table = kcalloc ( size , sizeof ( char * ) , GFP_KERNEL ) ;
if ( ! table )
2010-07-29 14:48:02 -07:00
goto fail ;
for ( i = 0 ; i < size ; i + + ) {
char * str ;
2022-12-07 01:40:24 +00:00
int c , j , pos , size2 = aa_unpack_strdup ( e , & str , NULL ) ;
/* aa_unpack_strdup verifies that the last character is
2010-07-29 14:48:02 -07:00
* null termination byte .
*/
2011-08-29 11:43:02 +10:00
if ( ! size2 )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-08-23 01:06:15 -07:00
table [ i ] = str ;
2010-07-29 14:48:02 -07:00
/* verify that name doesn't start with space */
if ( isspace ( * str ) )
goto fail ;
/* count internal # of internal \0 */
2017-06-09 17:29:12 -07:00
for ( c = j = 0 ; j < size2 - 1 ; j + + ) {
if ( ! str [ j ] ) {
pos = j ;
2010-07-29 14:48:02 -07:00
c + + ;
2017-06-09 17:29:12 -07:00
}
2010-07-29 14:48:02 -07:00
}
if ( * str = = ' : ' ) {
2017-06-09 17:29:12 -07:00
/* first character after : must be valid */
if ( ! str [ 1 ] )
goto fail ;
2010-07-29 14:48:02 -07:00
/* beginning with : requires an embedded \0,
* verify that exactly 1 internal \ 0 exists
2022-12-07 01:40:24 +00:00
* trailing \ 0 already verified by aa_unpack_strdup
2017-06-09 17:29:12 -07:00
*
* convert \ 0 back to : for label_parse
2010-07-29 14:48:02 -07:00
*/
2017-06-09 17:29:12 -07:00
if ( c = = 1 )
str [ pos ] = ' : ' ;
else if ( c > 1 )
2010-07-29 14:48:02 -07:00
goto fail ;
} else if ( c )
/* fail - all other cases with embedded \0 */
goto fail ;
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_ARRAYEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-08-23 01:06:15 -07:00
strs - > table = table ;
strs - > size = size ;
2010-07-29 14:48:02 -07:00
}
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
fail :
2022-08-23 01:06:15 -07:00
kfree_sensitive ( table ) ;
2017-07-06 10:56:21 +02:00
e - > pos = saved_pos ;
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2018-02-08 12:37:19 -08:00
static bool unpack_xattrs ( struct aa_ext * e , struct aa_profile * profile )
{
void * pos = e - > pos ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " xattrs " ) ) {
2022-08-26 09:26:57 -07:00
u16 size ;
int i ;
2018-02-08 12:37:19 -08:00
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_array ( e , NULL , & size ) )
2022-08-26 09:26:57 -07:00
goto fail ;
2022-07-29 17:17:31 -07:00
profile - > attach . xattr_count = size ;
profile - > attach . xattrs = kcalloc ( size , sizeof ( char * ) , GFP_KERNEL ) ;
if ( ! profile - > attach . xattrs )
2018-02-08 12:37:19 -08:00
goto fail ;
for ( i = 0 ; i < size ; i + + ) {
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_strdup ( e , & profile - > attach . xattrs [ i ] , NULL ) )
2018-02-08 12:37:19 -08:00
goto fail ;
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_ARRAYEND , NULL ) )
2018-02-08 12:37:19 -08:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2018-02-08 12:37:19 -08:00
goto fail ;
}
2020-04-28 19:52:21 +08:00
return true ;
2018-02-08 12:37:19 -08:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2018-02-08 12:37:19 -08:00
}
2022-09-05 20:47:36 -07:00
static bool unpack_secmark ( struct aa_ext * e , struct aa_ruleset * rules )
2018-05-24 13:27:46 -07:00
{
void * pos = e - > pos ;
2022-08-26 09:26:57 -07:00
u16 size ;
int i ;
2018-05-24 13:27:46 -07:00
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " secmark " ) ) {
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_array ( e , NULL , & size ) )
2022-08-26 09:26:57 -07:00
goto fail ;
2018-05-24 13:27:46 -07:00
2022-07-29 17:17:31 -07:00
rules - > secmark = kcalloc ( size , sizeof ( struct aa_secmark ) ,
2018-05-24 13:27:46 -07:00
GFP_KERNEL ) ;
2022-07-29 17:17:31 -07:00
if ( ! rules - > secmark )
2018-05-24 13:27:46 -07:00
goto fail ;
2022-07-29 17:17:31 -07:00
rules - > secmark_count = size ;
2018-05-24 13:27:46 -07:00
for ( i = 0 ; i < size ; i + + ) {
2022-07-29 17:17:31 -07:00
if ( ! unpack_u8 ( e , & rules - > secmark [ i ] . audit , NULL ) )
2018-05-24 13:27:46 -07:00
goto fail ;
2022-07-29 17:17:31 -07:00
if ( ! unpack_u8 ( e , & rules - > secmark [ i ] . deny , NULL ) )
2018-05-24 13:27:46 -07:00
goto fail ;
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_strdup ( e , & rules - > secmark [ i ] . label , NULL ) )
2018-05-24 13:27:46 -07:00
goto fail ;
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_ARRAYEND , NULL ) )
2018-05-24 13:27:46 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2018-05-24 13:27:46 -07:00
goto fail ;
}
2020-04-28 19:52:21 +08:00
return true ;
2018-05-24 13:27:46 -07:00
fail :
2022-07-29 17:17:31 -07:00
if ( rules - > secmark ) {
2018-05-24 13:27:46 -07:00
for ( i = 0 ; i < size ; i + + )
2022-07-29 17:17:31 -07:00
kfree ( rules - > secmark [ i ] . label ) ;
kfree ( rules - > secmark ) ;
rules - > secmark_count = 0 ;
rules - > secmark = NULL ;
2018-05-24 13:27:46 -07:00
}
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2018-05-24 13:27:46 -07:00
}
2022-09-05 20:47:36 -07:00
static bool unpack_rlimits ( struct aa_ext * e , struct aa_ruleset * rules )
2010-07-29 14:48:02 -07:00
{
void * pos = e - > pos ;
/* rlimits are optional */
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " rlimits " ) ) {
2022-08-26 09:26:57 -07:00
u16 size ;
int i ;
2010-07-29 14:48:02 -07:00
u32 tmp = 0 ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & tmp , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-09-05 20:47:36 -07:00
rules - > rlimits . mask = tmp ;
2010-07-29 14:48:02 -07:00
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_array ( e , NULL , & size ) | |
2022-08-26 09:26:57 -07:00
size > RLIM_NLIMITS )
2010-07-29 14:48:02 -07:00
goto fail ;
for ( i = 0 ; i < size ; i + + ) {
2011-08-29 11:43:02 +10:00
u64 tmp2 = 0 ;
2010-07-29 14:48:02 -07:00
int a = aa_map_resource ( i ) ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u64 ( e , & tmp2 , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-09-05 20:47:36 -07:00
rules - > rlimits . limits [ a ] . rlim_max = tmp2 ;
2010-07-29 14:48:02 -07:00
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_ARRAYEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
}
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
fail :
e - > pos = pos ;
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-08-26 08:53:42 -07:00
static bool unpack_perm ( struct aa_ext * e , u32 version , struct aa_perms * perm )
{
if ( version ! = 1 )
return false ;
2022-12-14 13:42:09 -08:00
return aa_unpack_u32 ( e , & perm - > allow , NULL ) & &
aa_unpack_u32 ( e , & perm - > allow , NULL ) & &
aa_unpack_u32 ( e , & perm - > deny , NULL ) & &
aa_unpack_u32 ( e , & perm - > subtree , NULL ) & &
aa_unpack_u32 ( e , & perm - > cond , NULL ) & &
aa_unpack_u32 ( e , & perm - > kill , NULL ) & &
aa_unpack_u32 ( e , & perm - > complain , NULL ) & &
aa_unpack_u32 ( e , & perm - > prompt , NULL ) & &
aa_unpack_u32 ( e , & perm - > audit , NULL ) & &
aa_unpack_u32 ( e , & perm - > quiet , NULL ) & &
aa_unpack_u32 ( e , & perm - > hide , NULL ) & &
aa_unpack_u32 ( e , & perm - > xindex , NULL ) & &
aa_unpack_u32 ( e , & perm - > tag , NULL ) & &
aa_unpack_u32 ( e , & perm - > label , NULL ) ;
2022-08-26 08:53:42 -07:00
}
static ssize_t unpack_perms_table ( struct aa_ext * e , struct aa_perms * * perms )
{
void * pos = e - > pos ;
u16 size = 0 ;
AA_BUG ( ! perms ) ;
/*
* policy perms are optional , in which case perms are embedded
* in the dfa accept table
*/
2022-12-14 13:42:09 -08:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " perms " ) ) {
2022-08-26 08:53:42 -07:00
int i ;
u32 version ;
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_u32 ( e , & version , " version " ) )
2022-08-26 08:53:42 -07:00
goto fail_reset ;
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_array ( e , NULL , & size ) )
2022-08-26 08:53:42 -07:00
goto fail_reset ;
* perms = kcalloc ( size , sizeof ( struct aa_perms ) , GFP_KERNEL ) ;
if ( ! * perms )
goto fail_reset ;
for ( i = 0 ; i < size ; i + + ) {
if ( ! unpack_perm ( e , version , & ( * perms ) [ i ] ) )
goto fail ;
}
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_nameX ( e , AA_ARRAYEND , NULL ) )
2022-08-26 08:53:42 -07:00
goto fail ;
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2022-08-26 08:53:42 -07:00
goto fail ;
} else
* perms = NULL ;
return size ;
fail :
kfree ( * perms ) ;
fail_reset :
e - > pos = pos ;
return - EPROTO ;
}
2022-07-18 16:53:17 -07:00
static int unpack_pdb ( struct aa_ext * e , struct aa_policydb * policy ,
bool required_dfa , bool required_trans ,
const char * * info )
{
2022-08-26 08:53:42 -07:00
void * pos = e - > pos ;
int i , flags , error = - EPROTO ;
2022-10-04 13:45:15 +05:00
ssize_t size ;
2022-07-18 16:53:17 -07:00
2022-10-04 13:45:15 +05:00
size = unpack_perms_table ( e , & policy - > perms ) ;
if ( size < 0 ) {
error = size ;
2022-08-26 08:53:42 -07:00
policy - > perms = NULL ;
* info = " failed to unpack - perms " ;
goto fail ;
2022-10-04 13:45:15 +05:00
}
policy - > size = size ;
if ( policy - > perms ) {
2022-08-26 08:53:42 -07:00
/* perms table present accept is index */
flags = TO_ACCEPT1_FLAG ( YYTD_DATA32 ) ;
} else {
/* packed perms in accept1 and accept2 */
flags = TO_ACCEPT1_FLAG ( YYTD_DATA32 ) |
TO_ACCEPT2_FLAG ( YYTD_DATA32 ) ;
}
2022-07-18 16:53:17 -07:00
2022-08-26 08:53:42 -07:00
policy - > dfa = unpack_dfa ( e , flags ) ;
if ( IS_ERR ( policy - > dfa ) ) {
error = PTR_ERR ( policy - > dfa ) ;
2022-07-18 16:53:17 -07:00
policy - > dfa = NULL ;
* info = " failed to unpack - dfa " ;
2022-08-26 08:53:42 -07:00
goto fail ;
2022-07-18 16:53:17 -07:00
} else if ( ! policy - > dfa ) {
if ( required_dfa ) {
* info = " missing required dfa " ;
2022-08-26 08:53:42 -07:00
goto fail ;
2022-07-18 16:53:17 -07:00
}
goto out ;
}
/*
* only unpack the following if a dfa is present
*
* sadly start was given different names for file and policydb
* but since it is optional we can try both
*/
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_u32 ( e , & policy - > start [ 0 ] , " start " ) )
2022-07-18 16:53:17 -07:00
/* default start state */
policy - > start [ 0 ] = DFA_START ;
2022-12-14 13:42:09 -08:00
if ( ! aa_unpack_u32 ( e , & policy - > start [ AA_CLASS_FILE ] , " dfa_start " ) ) {
2022-07-18 16:53:17 -07:00
/* default start state for xmatch and file dfa */
policy - > start [ AA_CLASS_FILE ] = DFA_START ;
} /* setup class index */
for ( i = AA_CLASS_FILE + 1 ; i < = AA_CLASS_LAST ; i + + ) {
policy - > start [ i ] = aa_dfa_next ( policy - > dfa , policy - > start [ 0 ] ,
i ) ;
}
if ( ! unpack_trans_table ( e , & policy - > trans ) & & required_trans ) {
* info = " failed to unpack profile transition table " ;
2022-08-26 08:53:42 -07:00
goto fail ;
2022-07-18 16:53:17 -07:00
}
2022-08-26 13:32:34 -07:00
/* TODO: move compat mapping here, requires dfa merging first */
/* TODO: move verify here, it has to be done after compat mappings */
2022-07-18 16:53:17 -07:00
out :
return 0 ;
2022-08-26 08:53:42 -07:00
fail :
e - > pos = pos ;
return error ;
2022-07-18 16:53:17 -07:00
}
2017-01-15 16:49:28 -08:00
static u32 strhash ( const void * data , u32 len , u32 seed )
{
const char * const * key = data ;
return jhash ( * key , strlen ( * key ) , seed ) ;
}
static int datacmp ( struct rhashtable_compare_arg * arg , const void * obj )
{
const struct aa_data * data = obj ;
const char * const * key = arg - > key ;
return strcmp ( data - > key , * key ) ;
}
2010-07-29 14:48:02 -07:00
/**
* unpack_profile - unpack a serialized profile
* @ e : serialized data extent information ( NOT NULL )
2022-01-29 10:51:00 +08:00
* @ ns_name : pointer of newly allocated copy of % NULL in case of error
2010-07-29 14:48:02 -07:00
*
* NOTE : unpack profile sets audit struct if there is a failure
*/
2017-01-16 00:42:56 -08:00
static struct aa_profile * unpack_profile ( struct aa_ext * e , char * * ns_name )
2010-07-29 14:48:02 -07:00
{
2022-07-29 17:17:31 -07:00
struct aa_ruleset * rules ;
2010-07-29 14:48:02 -07:00
struct aa_profile * profile = NULL ;
2017-01-16 00:42:56 -08:00
const char * tmpname , * tmpns = NULL , * name = NULL ;
2017-07-18 23:37:18 -07:00
const char * info = " failed to unpack profile " ;
2017-10-26 19:35:35 +02:00
size_t ns_len ;
2017-01-15 16:49:28 -08:00
struct rhashtable_params params = { 0 } ;
char * key = NULL ;
struct aa_data * data ;
2022-07-18 16:53:17 -07:00
int error = - EPROTO ;
2010-07-29 14:48:02 -07:00
kernel_cap_t tmpcap ;
u32 tmp ;
2017-01-16 00:42:56 -08:00
* ns_name = NULL ;
2010-07-29 14:48:02 -07:00
/* check that we have the right struct being passed */
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCT , " profile " ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_str ( e , & name , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2017-01-16 00:42:56 -08:00
if ( * name = = ' \0 ' )
goto fail ;
tmpname = aa_splitn_fqname ( name , strlen ( name ) , & tmpns , & ns_len ) ;
if ( tmpns ) {
* ns_name = kstrndup ( tmpns , ns_len , GFP_KERNEL ) ;
2017-07-18 23:37:18 -07:00
if ( ! * ns_name ) {
info = " out of memory " ;
2022-10-10 12:15:10 -07:00
error = - ENOMEM ;
2017-01-16 00:42:56 -08:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2017-01-16 00:42:56 -08:00
name = tmpname ;
}
2010-07-29 14:48:02 -07:00
2017-06-09 08:14:28 -07:00
profile = aa_alloc_profile ( name , NULL , GFP_KERNEL ) ;
2022-10-21 17:36:02 +08:00
if ( ! profile ) {
info = " out of memory " ;
error = - ENOMEM ;
goto fail ;
}
2022-09-05 20:47:36 -07:00
rules = list_first_entry ( & profile - > rules , typeof ( * rules ) , list ) ;
2010-07-29 14:48:02 -07:00
/* profile renaming is optional */
2022-12-07 01:40:24 +00:00
( void ) aa_unpack_str ( e , & profile - > rename , " rename " ) ;
2010-07-29 14:48:02 -07:00
2013-07-10 21:17:43 -07:00
/* attachment string is optional */
2022-12-14 13:42:09 -08:00
( void ) aa_unpack_str ( e , & profile - > attach . xmatch_str , " attach " ) ;
2013-07-10 21:17:43 -07:00
2010-07-29 14:48:02 -07:00
/* xmatch is optional and may be NULL */
2022-07-29 17:17:31 -07:00
error = unpack_pdb ( e , & profile - > attach . xmatch , false , false , & info ) ;
if ( error ) {
2017-07-18 23:37:18 -07:00
info = " bad xmatch " ;
2010-07-29 14:48:02 -07:00
goto fail ;
}
2022-07-18 16:53:17 -07:00
2020-05-31 10:52:06 -04:00
/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
2022-07-29 17:17:31 -07:00
if ( profile - > attach . xmatch . dfa ) {
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & tmp , NULL ) ) {
2017-07-18 23:37:18 -07:00
info = " missing xmatch len " ;
2010-07-29 14:48:02 -07:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2022-07-29 17:17:31 -07:00
profile - > attach . xmatch_len = tmp ;
profile - > attach . xmatch . start [ AA_CLASS_XMATCH ] = DFA_START ;
2022-10-10 12:15:10 -07:00
error = aa_compat_map_xmatch ( & profile - > attach . xmatch ) ;
if ( error ) {
2020-11-13 16:30:47 -08:00
info = " failed to convert xmatch permission table " ;
goto fail ;
}
2010-07-29 14:48:02 -07:00
}
2017-05-22 03:06:52 -07:00
/* disconnected attachment string is optional */
2022-12-07 01:40:24 +00:00
( void ) aa_unpack_str ( e , & profile - > disconnected , " disconnected " ) ;
2017-05-22 03:06:52 -07:00
2010-07-29 14:48:02 -07:00
/* per profile debug flags (complain, audit) */
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCT , " flags " ) ) {
2017-07-18 23:37:18 -07:00
info = " profile missing flags " ;
2010-07-29 14:48:02 -07:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
info = " failed to unpack profile flags " ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & tmp , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2013-07-10 21:12:43 -07:00
if ( tmp & PACKED_FLAG_HAT )
2017-06-09 08:14:28 -07:00
profile - > label . flags | = FLAG_HAT ;
2022-03-26 01:46:18 -07:00
if ( tmp & PACKED_FLAG_DEBUG1 )
profile - > label . flags | = FLAG_DEBUG1 ;
if ( tmp & PACKED_FLAG_DEBUG2 )
profile - > label . flags | = FLAG_DEBUG2 ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & tmp , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-03-26 01:52:06 -07:00
if ( tmp = = PACKED_MODE_COMPLAIN | | ( e - > version & FORCE_COMPLAIN_FLAG ) ) {
2010-07-29 14:48:02 -07:00
profile - > mode = APPARMOR_COMPLAIN ;
2022-03-26 01:52:06 -07:00
} else if ( tmp = = PACKED_MODE_ENFORCE ) {
2019-12-19 15:55:39 -08:00
profile - > mode = APPARMOR_ENFORCE ;
2022-03-26 01:52:06 -07:00
} else if ( tmp = = PACKED_MODE_KILL ) {
2013-07-10 21:12:43 -07:00
profile - > mode = APPARMOR_KILL ;
2022-03-26 01:52:06 -07:00
} else if ( tmp = = PACKED_MODE_UNCONFINED ) {
2013-07-10 21:12:43 -07:00
profile - > mode = APPARMOR_UNCONFINED ;
2022-03-26 01:52:06 -07:00
profile - > label . flags | = FLAG_UNCONFINED ;
2019-12-17 15:40:41 -08:00
} else if ( tmp = = PACKED_MODE_USER ) {
profile - > mode = APPARMOR_USER ;
2022-03-26 01:52:06 -07:00
} else {
2019-12-19 15:55:39 -08:00
goto fail ;
2022-03-26 01:52:06 -07:00
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & tmp , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
if ( tmp )
profile - > audit = AUDIT_ALL ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
/* path_flags is optional */
2022-12-07 01:40:24 +00:00
if ( aa_unpack_u32 ( e , & profile - > path_flags , " path_flags " ) )
2017-06-09 08:14:28 -07:00
profile - > path_flags | = profile - > label . flags &
PATH_MEDIATE_DELETED ;
2010-07-29 14:48:02 -07:00
else
/* set a default value if path_flags field is not present */
2017-06-09 08:14:28 -07:00
profile - > path_flags = PATH_MEDIATE_DELETED ;
2010-07-29 14:48:02 -07:00
2017-07-18 23:37:18 -07:00
info = " failed to unpack profile capabilities " ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_low ( e , & rules - > caps . allow , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_low ( e , & rules - > caps . audit , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_low ( e , & rules - > caps . quiet , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_low ( e , & tmpcap , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2017-07-18 23:37:18 -07:00
info = " failed to unpack upper profile capabilities " ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " caps64 " ) ) {
2010-07-29 14:48:02 -07:00
/* optional upper half of 64 bit caps */
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_high ( e , & rules - > caps . allow , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_high ( e , & rules - > caps . audit , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_high ( e , & rules - > caps . quiet , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_high ( e , & tmpcap , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
}
2017-07-18 23:37:18 -07:00
info = " failed to unpack extended profile capabilities " ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " capsx " ) ) {
2010-07-29 14:48:02 -07:00
/* optional extended caps mediation mask */
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_low ( e , & rules - > caps . extended , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2023-02-28 11:39:09 -08:00
if ( ! aa_unpack_cap_high ( e , & rules - > caps . extended , NULL ) )
2010-07-29 14:48:02 -07:00
goto fail ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2012-02-16 07:06:41 -08:00
goto fail ;
2010-07-29 14:48:02 -07:00
}
2018-02-08 12:37:19 -08:00
if ( ! unpack_xattrs ( e , profile ) ) {
info = " failed to unpack profile xattrs " ;
goto fail ;
}
2022-09-05 20:47:36 -07:00
if ( ! unpack_rlimits ( e , rules ) ) {
2017-07-18 23:37:18 -07:00
info = " failed to unpack profile rlimits " ;
2010-07-29 14:48:02 -07:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2010-07-29 14:48:02 -07:00
2022-09-05 20:47:36 -07:00
if ( ! unpack_secmark ( e , rules ) ) {
2018-05-24 13:27:46 -07:00
info = " failed to unpack profile secmark rules " ;
goto fail ;
}
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " policydb " ) ) {
2012-02-16 07:07:53 -08:00
/* generic policy dfa - optional and may be NULL */
2017-07-18 23:37:18 -07:00
info = " failed to unpack policydb " ;
2022-07-29 17:17:31 -07:00
error = unpack_pdb ( e , & rules - > policy , true , false ,
& info ) ;
2022-07-18 16:53:17 -07:00
if ( error )
2016-06-15 10:00:55 +03:00
goto fail ;
2022-07-18 16:53:17 -07:00
/* Fixup: drop when we get rid of start array */
2022-07-29 17:17:31 -07:00
if ( aa_dfa_next ( rules - > policy . dfa , rules - > policy . start [ 0 ] ,
2022-07-18 16:53:17 -07:00
AA_CLASS_FILE ) )
2022-07-29 17:17:31 -07:00
rules - > policy . start [ AA_CLASS_FILE ] =
aa_dfa_next ( rules - > policy . dfa ,
rules - > policy . start [ 0 ] ,
2022-07-18 16:53:17 -07:00
AA_CLASS_FILE ) ;
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) )
2012-02-16 07:07:53 -08:00
goto fail ;
2022-10-10 12:15:10 -07:00
error = aa_compat_map_policy ( & rules - > policy , e - > version ) ;
if ( error ) {
2022-07-16 01:53:46 -07:00
info = " failed to remap policydb permission table " ;
goto fail ;
}
2017-01-16 00:42:42 -08:00
} else
2022-07-29 17:17:31 -07:00
rules - > policy . dfa = aa_get_dfa ( nulldfa ) ;
2012-02-16 07:07:53 -08:00
2010-07-29 14:48:02 -07:00
/* get file rules */
2022-07-29 17:17:31 -07:00
error = unpack_pdb ( e , & rules - > file , false , true , & info ) ;
2022-07-18 16:53:17 -07:00
if ( error ) {
2010-07-29 14:48:02 -07:00
goto fail ;
2022-07-29 17:17:31 -07:00
} else if ( rules - > file . dfa ) {
2022-10-10 12:15:10 -07:00
error = aa_compat_map_file ( & rules - > file ) ;
if ( error ) {
2020-11-13 01:46:23 -08:00
info = " failed to remap file permission table " ;
goto fail ;
}
2022-07-29 17:17:31 -07:00
} else if ( rules - > policy . dfa & &
rules - > policy . start [ AA_CLASS_FILE ] ) {
rules - > file . dfa = aa_get_dfa ( rules - > policy . dfa ) ;
rules - > file . start [ AA_CLASS_FILE ] = rules - > policy . start [ AA_CLASS_FILE ] ;
2017-01-16 00:42:42 -08:00
} else
2022-07-29 17:17:31 -07:00
rules - > file . dfa = aa_get_dfa ( nulldfa ) ;
2010-07-29 14:48:02 -07:00
2022-10-10 12:15:10 -07:00
error = - EPROTO ;
2022-12-07 01:40:24 +00:00
if ( aa_unpack_nameX ( e , AA_STRUCT , " data " ) ) {
2017-07-18 23:37:18 -07:00
info = " out of memory " ;
2017-01-15 16:49:28 -08:00
profile - > data = kzalloc ( sizeof ( * profile - > data ) , GFP_KERNEL ) ;
2022-10-10 12:15:10 -07:00
if ( ! profile - > data ) {
error = - ENOMEM ;
2017-01-15 16:49:28 -08:00
goto fail ;
2022-10-10 12:15:10 -07:00
}
2017-01-15 16:49:28 -08:00
params . nelem_hint = 3 ;
params . key_len = sizeof ( void * ) ;
params . key_offset = offsetof ( struct aa_data , key ) ;
params . head_offset = offsetof ( struct aa_data , head ) ;
params . hashfn = strhash ;
params . obj_cmpfn = datacmp ;
2017-07-18 23:37:18 -07:00
if ( rhashtable_init ( profile - > data , & params ) ) {
info = " failed to init key, value hash table " ;
2017-01-15 16:49:28 -08:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2017-01-15 16:49:28 -08:00
2022-12-07 01:40:24 +00:00
while ( aa_unpack_strdup ( e , & key , NULL ) ) {
2017-01-15 16:49:28 -08:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data ) {
2020-08-06 23:18:13 -07:00
kfree_sensitive ( key ) ;
2022-10-10 12:15:10 -07:00
error = - ENOMEM ;
2017-01-15 16:49:28 -08:00
goto fail ;
}
data - > key = key ;
2022-12-07 01:40:24 +00:00
data - > size = aa_unpack_blob ( e , & data - > data , NULL ) ;
2022-12-21 22:42:45 +08:00
data - > data = kvmemdup ( data - > data , data - > size , GFP_KERNEL ) ;
2017-01-15 16:49:28 -08:00
if ( data - > size & & ! data - > data ) {
2020-08-06 23:18:13 -07:00
kfree_sensitive ( data - > key ) ;
kfree_sensitive ( data ) ;
2022-10-10 12:15:10 -07:00
error = - ENOMEM ;
2017-01-15 16:49:28 -08:00
goto fail ;
}
rhashtable_insert_fast ( profile - > data , & data - > head ,
profile - > data - > p ) ;
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) ) {
2017-07-18 23:37:18 -07:00
info = " failed to unpack end of key, value data table " ;
2017-01-15 16:49:28 -08:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2017-01-15 16:49:28 -08:00
}
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_nameX ( e , AA_STRUCTEND , NULL ) ) {
2017-07-18 23:37:18 -07:00
info = " failed to unpack end of profile " ;
2010-07-29 14:48:02 -07:00
goto fail ;
2017-07-18 23:37:18 -07:00
}
2010-07-29 14:48:02 -07:00
return profile ;
fail :
2022-10-10 12:15:10 -07:00
if ( error = = 0 )
/* default error covers most cases */
error = - EPROTO ;
2022-10-21 17:36:02 +08:00
if ( * ns_name ) {
kfree ( * ns_name ) ;
* ns_name = NULL ;
}
2010-07-29 14:48:02 -07:00
if ( profile )
name = NULL ;
else if ( ! name )
name = " unknown " ;
2017-07-18 23:37:18 -07:00
audit_iface ( profile , NULL , name , info , e , error ) ;
2013-07-10 21:11:43 -07:00
aa_free_profile ( profile ) ;
2010-07-29 14:48:02 -07:00
return ERR_PTR ( error ) ;
}
/**
2022-01-29 10:51:00 +08:00
* verify_header - unpack serialized stream header
2010-07-29 14:48:02 -07:00
* @ e : serialized data read head ( NOT NULL )
2013-07-10 21:05:43 -07:00
* @ required : whether the header is required or optional
2010-07-29 14:48:02 -07:00
* @ ns : Returns - namespace if one is specified else NULL ( NOT NULL )
*
* Returns : error or 0 if header is good
*/
2013-07-10 21:05:43 -07:00
static int verify_header ( struct aa_ext * e , int required , const char * * ns )
2010-07-29 14:48:02 -07:00
{
int error = - EPROTONOSUPPORT ;
2013-07-10 21:05:43 -07:00
const char * name = NULL ;
* ns = NULL ;
2010-07-29 14:48:02 -07:00
/* get the interface version */
2022-12-07 01:40:24 +00:00
if ( ! aa_unpack_u32 ( e , & e - > version , " version " ) ) {
2013-07-10 21:05:43 -07:00
if ( required ) {
2017-01-16 00:42:56 -08:00
audit_iface ( NULL , NULL , NULL , " invalid profile format " ,
2013-07-10 21:05:43 -07:00
e , error ) ;
return error ;
}
2010-07-29 14:48:02 -07:00
}
2017-01-16 00:42:39 -08:00
/* Check that the interface version is currently supported.
* if not specified use previous version
* Mask off everything that is not kernel abi version
*/
2022-05-10 02:21:22 -07:00
if ( VERSION_LT ( e - > version , v5 ) | | VERSION_GT ( e - > version , v9 ) ) {
2017-01-16 00:42:56 -08:00
audit_iface ( NULL , NULL , NULL , " unsupported interface version " ,
2017-01-16 00:42:39 -08:00
e , error ) ;
return error ;
}
2013-07-10 21:05:43 -07:00
2010-07-29 14:48:02 -07:00
/* read the namespace if present */
2022-12-07 01:40:24 +00:00
if ( aa_unpack_str ( e , & name , " namespace " ) ) {
2017-01-16 00:42:56 -08:00
if ( * name = = ' \0 ' ) {
audit_iface ( NULL , NULL , NULL , " invalid namespace name " ,
e , error ) ;
return error ;
}
2019-03-09 16:58:10 -08:00
if ( * ns & & strcmp ( * ns , name ) ) {
2017-01-16 00:42:56 -08:00
audit_iface ( NULL , NULL , NULL , " invalid ns change " , e ,
error ) ;
2019-03-09 16:58:10 -08:00
} else if ( ! * ns ) {
* ns = kstrdup ( name , GFP_KERNEL ) ;
if ( ! * ns )
return - ENOMEM ;
}
2013-07-10 21:05:43 -07:00
}
2010-07-29 14:48:02 -07:00
return 0 ;
}
static bool verify_xindex ( int xindex , int table_size )
{
int index , xtype ;
xtype = xindex & AA_X_TYPE_MASK ;
index = xindex & AA_X_INDEX_MASK ;
2016-03-17 12:02:54 -07:00
if ( xtype = = AA_X_TABLE & & index > = table_size )
2020-04-28 19:52:21 +08:00
return false ;
return true ;
2010-07-29 14:48:02 -07:00
}
/* verify dfa xindexes are in range of transition tables */
static bool verify_dfa_xindex ( struct aa_dfa * dfa , int table_size )
{
int i ;
for ( i = 0 ; i < dfa - > tables [ YYTD_ID_ACCEPT ] - > td_lolen ; i + + ) {
2020-11-13 01:46:23 -08:00
if ( ! verify_xindex ( ACCEPT_TABLE ( dfa ) [ i ] , table_size ) )
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
}
2022-09-06 00:38:20 -07:00
static bool verify_perm ( struct aa_perms * perm )
{
/* TODO: allow option to just force the perms into a valid state */
if ( perm - > allow & perm - > deny )
return false ;
if ( perm - > subtree & ~ perm - > allow )
return false ;
if ( perm - > cond & ( perm - > allow | perm - > deny ) )
return false ;
if ( perm - > kill & perm - > allow )
return false ;
if ( perm - > complain & ( perm - > allow | perm - > deny ) )
return false ;
if ( perm - > prompt & ( perm - > allow | perm - > deny ) )
return false ;
if ( perm - > complain & perm - > prompt )
return false ;
if ( perm - > hide & perm - > allow )
return false ;
return true ;
}
static bool verify_perms ( struct aa_policydb * pdb )
2022-08-26 13:32:34 -07:00
{
int i ;
for ( i = 0 ; i < pdb - > size ; i + + ) {
2022-09-06 00:38:20 -07:00
if ( ! verify_perm ( & pdb - > perms [ i ] ) )
return false ;
/* verify indexes into str table */
2022-08-26 13:32:34 -07:00
if ( pdb - > perms [ i ] . xindex > = pdb - > trans . size )
2020-04-28 19:52:21 +08:00
return false ;
2022-08-26 13:32:34 -07:00
if ( pdb - > perms [ i ] . tag > = pdb - > trans . size )
return false ;
if ( pdb - > perms [ i ] . label > = pdb - > trans . size )
2020-04-28 19:52:21 +08:00
return false ;
2010-07-29 14:48:02 -07:00
}
2022-08-26 13:32:34 -07:00
2020-04-28 19:52:21 +08:00
return true ;
2010-07-29 14:48:02 -07:00
}
/**
* verify_profile - Do post unpack analysis to verify profile consistency
* @ profile : profile to verify ( NOT NULL )
*
* Returns : 0 if passes verification else error
2020-11-13 01:46:23 -08:00
*
* This verification is post any unpack mapping or changes
2010-07-29 14:48:02 -07:00
*/
static int verify_profile ( struct aa_profile * profile )
{
2022-09-05 20:47:36 -07:00
struct aa_ruleset * rules = list_first_entry ( & profile - > rules ,
typeof ( * rules ) , list ) ;
if ( ! rules )
return 0 ;
if ( ( rules - > file . dfa & & ! verify_dfa_xindex ( rules - > file . dfa ,
rules - > file . trans . size ) ) | |
( rules - > policy . dfa & &
! verify_dfa_xindex ( rules - > policy . dfa , rules - > policy . trans . size ) ) ) {
2020-11-13 01:46:23 -08:00
audit_iface ( profile , NULL , NULL ,
" Unpack: Invalid named transition " , NULL , - EPROTO ) ;
2017-01-16 00:42:37 -08:00
return - EPROTO ;
2010-07-29 14:48:02 -07:00
}
2022-09-05 20:47:36 -07:00
if ( ! verify_perms ( & rules - > file ) ) {
2022-08-26 13:32:34 -07:00
audit_iface ( profile , NULL , NULL ,
" Unpack: Invalid perm index " , NULL , - EPROTO ) ;
return - EPROTO ;
}
2022-09-05 20:47:36 -07:00
if ( ! verify_perms ( & rules - > policy ) ) {
2022-08-26 13:32:34 -07:00
audit_iface ( profile , NULL , NULL ,
" Unpack: Invalid perm index " , NULL , - EPROTO ) ;
return - EPROTO ;
}
2022-07-29 17:17:31 -07:00
if ( ! verify_perms ( & profile - > attach . xmatch ) ) {
2022-08-26 13:32:34 -07:00
audit_iface ( profile , NULL , NULL ,
" Unpack: Invalid perm index " , NULL , - EPROTO ) ;
2017-01-16 00:42:37 -08:00
return - EPROTO ;
2010-07-29 14:48:02 -07:00
}
return 0 ;
}
2013-07-10 21:05:43 -07:00
void aa_load_ent_free ( struct aa_load_ent * ent )
{
if ( ent ) {
aa_put_profile ( ent - > rename ) ;
aa_put_profile ( ent - > old ) ;
aa_put_profile ( ent - > new ) ;
2017-01-16 00:42:56 -08:00
kfree ( ent - > ns_name ) ;
2020-08-06 23:18:13 -07:00
kfree_sensitive ( ent ) ;
2013-07-10 21:05:43 -07:00
}
}
struct aa_load_ent * aa_load_ent_alloc ( void )
{
struct aa_load_ent * ent = kzalloc ( sizeof ( * ent ) , GFP_KERNEL ) ;
if ( ent )
INIT_LIST_HEAD ( & ent - > list ) ;
return ent ;
}
2022-07-11 11:36:08 -05:00
static int compress_zstd ( const char * src , size_t slen , char * * dst , size_t * dlen )
2019-01-23 19:17:09 +00:00
{
2022-02-22 02:09:20 -08:00
# ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
2022-07-11 11:36:08 -05:00
const zstd_parameters params =
zstd_get_params ( aa_g_rawdata_compression_level , slen ) ;
const size_t wksp_len = zstd_cctx_workspace_bound ( & params . cParams ) ;
void * wksp = NULL ;
zstd_cctx * ctx = NULL ;
size_t out_len = zstd_compress_bound ( slen ) ;
void * out = NULL ;
int ret = 0 ;
out = kvzalloc ( out_len , GFP_KERNEL ) ;
if ( ! out ) {
ret = - ENOMEM ;
goto cleanup ;
2019-01-23 19:17:09 +00:00
}
2022-07-11 11:36:08 -05:00
wksp = kvzalloc ( wksp_len , GFP_KERNEL ) ;
if ( ! wksp ) {
ret = - ENOMEM ;
goto cleanup ;
2019-01-23 19:17:09 +00:00
}
2022-07-11 11:36:08 -05:00
ctx = zstd_init_cctx ( wksp , wksp_len ) ;
if ( ! ctx ) {
ret = - EINVAL ;
goto cleanup ;
}
2019-01-23 19:17:09 +00:00
2022-07-11 11:36:08 -05:00
out_len = zstd_compress_cctx ( ctx , out , out_len , src , slen , & params ) ;
2022-09-29 06:48:10 -07:00
if ( zstd_is_error ( out_len ) | | out_len > = slen ) {
2022-07-11 11:36:08 -05:00
ret = - EINVAL ;
goto cleanup ;
2019-01-23 19:17:09 +00:00
}
2022-07-11 11:36:08 -05:00
if ( is_vmalloc_addr ( out ) ) {
* dst = kvzalloc ( out_len , GFP_KERNEL ) ;
if ( * dst ) {
memcpy ( * dst , out , out_len ) ;
kvfree ( out ) ;
out = NULL ;
2019-01-23 19:17:09 +00:00
}
2022-07-11 11:36:08 -05:00
} else {
2019-01-23 19:17:09 +00:00
/*
* If the staging buffer was kmalloc ' d , then using krealloc is
* probably going to be faster . The destination buffer will
* always be smaller , so it ' s just shrunk , avoiding a memcpy
*/
2022-07-11 11:36:08 -05:00
* dst = krealloc ( out , out_len , GFP_KERNEL ) ;
}
2019-01-23 19:17:09 +00:00
2022-07-11 11:36:08 -05:00
if ( ! * dst ) {
ret = - ENOMEM ;
goto cleanup ;
2019-01-23 19:17:09 +00:00
}
2022-07-11 11:36:08 -05:00
* dlen = out_len ;
2019-01-23 19:17:09 +00:00
2022-07-11 11:36:08 -05:00
cleanup :
if ( ret ) {
kvfree ( out ) ;
* dst = NULL ;
}
2019-01-23 19:17:09 +00:00
2022-07-11 11:36:08 -05:00
kvfree ( wksp ) ;
return ret ;
2022-02-22 02:09:20 -08:00
# else
* dlen = slen ;
return 0 ;
# endif
2019-01-23 19:17:09 +00:00
}
static int compress_loaddata ( struct aa_loaddata * data )
{
AA_BUG ( data - > compressed_size > 0 ) ;
/*
* Shortcut the no compression case , else we increase the amount of
* storage required by a small amount
*/
if ( aa_g_rawdata_compression_level ! = 0 ) {
void * udata = data - > data ;
2022-07-11 11:36:08 -05:00
int error = compress_zstd ( udata , data - > size , & data - > data ,
& data - > compressed_size ) ;
2022-09-29 06:48:10 -07:00
if ( error ) {
data - > compressed_size = data - > size ;
2019-01-23 19:17:09 +00:00
return error ;
2022-09-29 06:48:10 -07:00
}
2022-02-22 02:09:20 -08:00
if ( udata ! = data - > data )
kvfree ( udata ) ;
2019-01-23 19:17:09 +00:00
} else
data - > compressed_size = data - > size ;
return 0 ;
}
2010-07-29 14:48:02 -07:00
/**
2013-07-10 21:05:43 -07:00
* aa_unpack - unpack packed binary profile ( s ) data loaded from user space
2010-07-29 14:48:02 -07:00
* @ udata : user data copied to kmem ( NOT NULL )
2013-07-10 21:05:43 -07:00
* @ lh : list to place unpacked profiles in a aa_repl_ws
2010-07-29 14:48:02 -07:00
* @ ns : Returns namespace profile is in if specified else NULL ( NOT NULL )
*
2013-07-10 21:05:43 -07:00
* 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
2010-07-29 14:48:02 -07:00
*
2013-07-10 21:05:43 -07:00
* Returns : profile ( s ) on @ lh else error pointer if fails to unpack
2010-07-29 14:48:02 -07:00
*/
2017-01-16 00:42:55 -08:00
int aa_unpack ( struct aa_loaddata * udata , struct list_head * lh ,
const char * * ns )
2010-07-29 14:48:02 -07:00
{
2013-07-10 21:05:43 -07:00
struct aa_load_ent * tmp , * ent ;
2010-07-29 14:48:02 -07:00
struct aa_profile * profile = NULL ;
2022-10-21 17:36:02 +08:00
char * ns_name = NULL ;
2010-07-29 14:48:02 -07:00
int error ;
struct aa_ext e = {
2017-01-16 00:42:55 -08:00
. start = udata - > data ,
. end = udata - > data + udata - > size ,
. pos = udata - > data ,
2010-07-29 14:48:02 -07:00
} ;
2013-07-10 21:05:43 -07:00
* ns = NULL ;
while ( e . pos < e . end ) {
2013-08-14 11:27:36 -07:00
void * start ;
2013-07-10 21:05:43 -07:00
error = verify_header ( & e , e . pos = = e . start , ns ) ;
if ( error )
goto fail ;
2010-07-29 14:48:02 -07:00
2013-08-14 11:27:36 -07:00
start = e . pos ;
2017-01-16 00:42:56 -08:00
profile = unpack_profile ( & e , & ns_name ) ;
2013-07-10 21:05:43 -07:00
if ( IS_ERR ( profile ) ) {
error = PTR_ERR ( profile ) ;
goto fail ;
}
error = verify_profile ( profile ) ;
2013-08-14 11:27:36 -07:00
if ( error )
goto fail_profile ;
2017-01-16 00:43:07 -08:00
if ( aa_g_hash_policy )
error = aa_calc_profile_hash ( profile , e . version , start ,
2014-10-24 09:16:14 -07:00
e . pos - start ) ;
2013-08-14 11:27:36 -07:00
if ( error )
goto fail_profile ;
2013-07-10 21:05:43 -07:00
ent = aa_load_ent_alloc ( ) ;
if ( ! ent ) {
error = - ENOMEM ;
2013-08-14 11:27:36 -07:00
goto fail_profile ;
2013-07-10 21:05:43 -07:00
}
2010-07-29 14:48:02 -07:00
2013-07-10 21:05:43 -07:00
ent - > new = profile ;
2017-01-16 00:42:56 -08:00
ent - > ns_name = ns_name ;
2022-10-21 17:36:02 +08:00
ns_name = NULL ;
2013-07-10 21:05:43 -07:00
list_add_tail ( & ent - > list , lh ) ;
2010-07-29 14:48:02 -07:00
}
2017-01-16 00:42:55 -08:00
udata - > abi = e . version & K_ABI_MASK ;
2017-01-16 00:43:07 -08:00
if ( aa_g_hash_policy ) {
udata - > hash = aa_calc_hash ( udata - > data , udata - > size ) ;
if ( IS_ERR ( udata - > hash ) ) {
error = PTR_ERR ( udata - > hash ) ;
udata - > hash = NULL ;
goto fail ;
}
2017-01-16 00:42:55 -08:00
}
2021-02-01 03:43:18 -08:00
if ( aa_g_export_binary ) {
error = compress_loaddata ( udata ) ;
if ( error )
goto fail ;
}
2013-07-10 21:05:43 -07:00
return 0 ;
2013-08-14 11:27:36 -07:00
fail_profile :
2022-10-21 17:36:02 +08:00
kfree ( ns_name ) ;
2013-08-14 11:27:36 -07:00
aa_put_profile ( profile ) ;
2013-07-10 21:05:43 -07:00
fail :
list_for_each_entry_safe ( ent , tmp , lh , list ) {
list_del_init ( & ent - > list ) ;
aa_load_ent_free ( ent ) ;
}
return error ;
2010-07-29 14:48:02 -07:00
}