Path: blob/master/security/apparmor/policy_unpack.c
10814 views
/*1* AppArmor security module2*3* This file contains AppArmor functions for unpacking policy loaded from4* userspace.5*6* Copyright (C) 1998-2008 Novell/SUSE7* Copyright 2009-2010 Canonical Ltd.8*9* This program is free software; you can redistribute it and/or10* modify it under the terms of the GNU General Public License as11* published by the Free Software Foundation, version 2 of the12* License.13*14* AppArmor uses a serialized binary format for loading policy. To find15* policy format documentation look in Documentation/security/apparmor.txt16* All policy is validated before it is used.17*/1819#include <asm/unaligned.h>20#include <linux/ctype.h>21#include <linux/errno.h>2223#include "include/apparmor.h"24#include "include/audit.h"25#include "include/context.h"26#include "include/match.h"27#include "include/policy.h"28#include "include/policy_unpack.h"29#include "include/sid.h"3031/*32* The AppArmor interface treats data as a type byte followed by the33* actual data. The interface has the notion of a a named entry34* which has a name (AA_NAME typecode followed by name string) followed by35* the entries typecode and data. Named types allow for optional36* elements and extensions to be added and tested for without breaking37* backwards compatibility.38*/3940enum aa_code {41AA_U8,42AA_U16,43AA_U32,44AA_U64,45AA_NAME, /* same as string except it is items name */46AA_STRING,47AA_BLOB,48AA_STRUCT,49AA_STRUCTEND,50AA_LIST,51AA_LISTEND,52AA_ARRAY,53AA_ARRAYEND,54};5556/*57* aa_ext is the read of the buffer containing the serialized profile. The58* data is copied into a kernel buffer in apparmorfs and then handed off to59* the unpack routines.60*/61struct aa_ext {62void *start;63void *end;64void *pos; /* pointer to current position in the buffer */65u32 version;66};6768/* audit callback for unpack fields */69static void audit_cb(struct audit_buffer *ab, void *va)70{71struct common_audit_data *sa = va;72if (sa->aad.iface.target) {73struct aa_profile *name = sa->aad.iface.target;74audit_log_format(ab, " name=");75audit_log_untrustedstring(ab, name->base.hname);76}77if (sa->aad.iface.pos)78audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);79}8081/**82* audit_iface - do audit message for policy unpacking/load/replace/remove83* @new: profile if it has been allocated (MAYBE NULL)84* @name: name of the profile being manipulated (MAYBE NULL)85* @info: any extra info about the failure (MAYBE NULL)86* @e: buffer position info (NOT NULL)87* @error: error code88*89* Returns: %0 or error90*/91static int audit_iface(struct aa_profile *new, const char *name,92const char *info, struct aa_ext *e, int error)93{94struct aa_profile *profile = __aa_current_profile();95struct common_audit_data sa;96COMMON_AUDIT_DATA_INIT(&sa, NONE);97sa.aad.iface.pos = e->pos - e->start;98sa.aad.iface.target = new;99sa.aad.name = name;100sa.aad.info = info;101sa.aad.error = error;102103return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,104audit_cb);105}106107/* test if read will be in packed data bounds */108static bool inbounds(struct aa_ext *e, size_t size)109{110return (size <= e->end - e->pos);111}112113/**114* aa_u16_chunck - test and do bounds checking for a u16 size based chunk115* @e: serialized data read head (NOT NULL)116* @chunk: start address for chunk of data (NOT NULL)117*118* Returns: the size of chunk found with the read head at the end of the chunk.119*/120static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)121{122size_t size = 0;123124if (!inbounds(e, sizeof(u16)))125return 0;126size = le16_to_cpu(get_unaligned((u16 *) e->pos));127e->pos += sizeof(u16);128if (!inbounds(e, size))129return 0;130*chunk = e->pos;131e->pos += size;132return size;133}134135/* unpack control byte */136static bool unpack_X(struct aa_ext *e, enum aa_code code)137{138if (!inbounds(e, 1))139return 0;140if (*(u8 *) e->pos != code)141return 0;142e->pos++;143return 1;144}145146/**147* unpack_nameX - check is the next element is of type X with a name of @name148* @e: serialized data extent information (NOT NULL)149* @code: type code150* @name: name to match to the serialized element. (MAYBE NULL)151*152* check that the next serialized data element is of type X and has a tag153* name @name. If @name is specified then there must be a matching154* name element in the stream. If @name is NULL any name element will be155* skipped and only the typecode will be tested.156*157* Returns 1 on success (both type code and name tests match) and the read158* head is advanced past the headers159*160* Returns: 0 if either match fails, the read head does not move161*/162static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)163{164/*165* May need to reset pos if name or type doesn't match166*/167void *pos = e->pos;168/*169* Check for presence of a tagname, and if present name size170* AA_NAME tag value is a u16.171*/172if (unpack_X(e, AA_NAME)) {173char *tag = NULL;174size_t size = unpack_u16_chunk(e, &tag);175/* if a name is specified it must match. otherwise skip tag */176if (name && (!size || strcmp(name, tag)))177goto fail;178} else if (name) {179/* if a name is specified and there is no name tag fail */180goto fail;181}182183/* now check if type code matches */184if (unpack_X(e, code))185return 1;186187fail:188e->pos = pos;189return 0;190}191192static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)193{194if (unpack_nameX(e, AA_U32, name)) {195if (!inbounds(e, sizeof(u32)))196return 0;197if (data)198*data = le32_to_cpu(get_unaligned((u32 *) e->pos));199e->pos += sizeof(u32);200return 1;201}202return 0;203}204205static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)206{207if (unpack_nameX(e, AA_U64, name)) {208if (!inbounds(e, sizeof(u64)))209return 0;210if (data)211*data = le64_to_cpu(get_unaligned((u64 *) e->pos));212e->pos += sizeof(u64);213return 1;214}215return 0;216}217218static size_t unpack_array(struct aa_ext *e, const char *name)219{220if (unpack_nameX(e, AA_ARRAY, name)) {221int size;222if (!inbounds(e, sizeof(u16)))223return 0;224size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));225e->pos += sizeof(u16);226return size;227}228return 0;229}230231static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)232{233if (unpack_nameX(e, AA_BLOB, name)) {234u32 size;235if (!inbounds(e, sizeof(u32)))236return 0;237size = le32_to_cpu(get_unaligned((u32 *) e->pos));238e->pos += sizeof(u32);239if (inbounds(e, (size_t) size)) {240*blob = e->pos;241e->pos += size;242return size;243}244}245return 0;246}247248static int unpack_str(struct aa_ext *e, const char **string, const char *name)249{250char *src_str;251size_t size = 0;252void *pos = e->pos;253*string = NULL;254if (unpack_nameX(e, AA_STRING, name)) {255size = unpack_u16_chunk(e, &src_str);256if (size) {257/* strings are null terminated, length is size - 1 */258if (src_str[size - 1] != 0)259goto fail;260*string = src_str;261}262}263return size;264265fail:266e->pos = pos;267return 0;268}269270static int unpack_strdup(struct aa_ext *e, char **string, const char *name)271{272const char *tmp;273void *pos = e->pos;274int res = unpack_str(e, &tmp, name);275*string = NULL;276277if (!res)278return 0;279280*string = kmemdup(tmp, res, GFP_KERNEL);281if (!*string) {282e->pos = pos;283return 0;284}285286return res;287}288289/**290* verify_accept - verify the accept tables of a dfa291* @dfa: dfa to verify accept tables of (NOT NULL)292* @flags: flags governing dfa293*294* Returns: 1 if valid accept tables else 0 if error295*/296static bool verify_accept(struct aa_dfa *dfa, int flags)297{298int i;299300/* verify accept permissions */301for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {302int mode = ACCEPT_TABLE(dfa)[i];303304if (mode & ~DFA_VALID_PERM_MASK)305return 0;306307if (ACCEPT_TABLE2(dfa)[i] & ~DFA_VALID_PERM2_MASK)308return 0;309}310return 1;311}312313/**314* unpack_dfa - unpack a file rule dfa315* @e: serialized data extent information (NOT NULL)316*317* returns dfa or ERR_PTR or NULL if no dfa318*/319static struct aa_dfa *unpack_dfa(struct aa_ext *e)320{321char *blob = NULL;322size_t size;323struct aa_dfa *dfa = NULL;324325size = unpack_blob(e, &blob, "aadfa");326if (size) {327/*328* The dfa is aligned with in the blob to 8 bytes329* from the beginning of the stream.330*/331size_t sz = blob - (char *)e->start;332size_t pad = ALIGN(sz, 8) - sz;333int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |334TO_ACCEPT2_FLAG(YYTD_DATA32);335336337if (aa_g_paranoid_load)338flags |= DFA_FLAG_VERIFY_STATES;339340dfa = aa_dfa_unpack(blob + pad, size - pad, flags);341342if (IS_ERR(dfa))343return dfa;344345if (!verify_accept(dfa, flags))346goto fail;347}348349return dfa;350351fail:352aa_put_dfa(dfa);353return ERR_PTR(-EPROTO);354}355356/**357* unpack_trans_table - unpack a profile transition table358* @e: serialized data extent information (NOT NULL)359* @profile: profile to add the accept table to (NOT NULL)360*361* Returns: 1 if table successfully unpacked362*/363static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)364{365void *pos = e->pos;366367/* exec table is optional */368if (unpack_nameX(e, AA_STRUCT, "xtable")) {369int i, size;370371size = unpack_array(e, NULL);372/* currently 4 exec bits and entries 0-3 are reserved iupcx */373if (size > 16 - 4)374goto fail;375profile->file.trans.table = kzalloc(sizeof(char *) * size,376GFP_KERNEL);377if (!profile->file.trans.table)378goto fail;379380profile->file.trans.size = size;381for (i = 0; i < size; i++) {382char *str;383int c, j, size = unpack_strdup(e, &str, NULL);384/* unpack_strdup verifies that the last character is385* null termination byte.386*/387if (!size)388goto fail;389profile->file.trans.table[i] = str;390/* verify that name doesn't start with space */391if (isspace(*str))392goto fail;393394/* count internal # of internal \0 */395for (c = j = 0; j < size - 2; j++) {396if (!str[j])397c++;398}399if (*str == ':') {400/* beginning with : requires an embedded \0,401* verify that exactly 1 internal \0 exists402* trailing \0 already verified by unpack_strdup403*/404if (c != 1)405goto fail;406/* first character after : must be valid */407if (!str[1])408goto fail;409} else if (c)410/* fail - all other cases with embedded \0 */411goto fail;412}413if (!unpack_nameX(e, AA_ARRAYEND, NULL))414goto fail;415if (!unpack_nameX(e, AA_STRUCTEND, NULL))416goto fail;417}418return 1;419420fail:421aa_free_domain_entries(&profile->file.trans);422e->pos = pos;423return 0;424}425426static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)427{428void *pos = e->pos;429430/* rlimits are optional */431if (unpack_nameX(e, AA_STRUCT, "rlimits")) {432int i, size;433u32 tmp = 0;434if (!unpack_u32(e, &tmp, NULL))435goto fail;436profile->rlimits.mask = tmp;437438size = unpack_array(e, NULL);439if (size > RLIM_NLIMITS)440goto fail;441for (i = 0; i < size; i++) {442u64 tmp = 0;443int a = aa_map_resource(i);444if (!unpack_u64(e, &tmp, NULL))445goto fail;446profile->rlimits.limits[a].rlim_max = tmp;447}448if (!unpack_nameX(e, AA_ARRAYEND, NULL))449goto fail;450if (!unpack_nameX(e, AA_STRUCTEND, NULL))451goto fail;452}453return 1;454455fail:456e->pos = pos;457return 0;458}459460/**461* unpack_profile - unpack a serialized profile462* @e: serialized data extent information (NOT NULL)463*464* NOTE: unpack profile sets audit struct if there is a failure465*/466static struct aa_profile *unpack_profile(struct aa_ext *e)467{468struct aa_profile *profile = NULL;469const char *name = NULL;470int error = -EPROTO;471kernel_cap_t tmpcap;472u32 tmp;473474/* check that we have the right struct being passed */475if (!unpack_nameX(e, AA_STRUCT, "profile"))476goto fail;477if (!unpack_str(e, &name, NULL))478goto fail;479480profile = aa_alloc_profile(name);481if (!profile)482return ERR_PTR(-ENOMEM);483484/* profile renaming is optional */485(void) unpack_str(e, &profile->rename, "rename");486487/* xmatch is optional and may be NULL */488profile->xmatch = unpack_dfa(e);489if (IS_ERR(profile->xmatch)) {490error = PTR_ERR(profile->xmatch);491profile->xmatch = NULL;492goto fail;493}494/* xmatch_len is not optional if xmatch is set */495if (profile->xmatch) {496if (!unpack_u32(e, &tmp, NULL))497goto fail;498profile->xmatch_len = tmp;499}500501/* per profile debug flags (complain, audit) */502if (!unpack_nameX(e, AA_STRUCT, "flags"))503goto fail;504if (!unpack_u32(e, &tmp, NULL))505goto fail;506if (tmp)507profile->flags |= PFLAG_HAT;508if (!unpack_u32(e, &tmp, NULL))509goto fail;510if (tmp)511profile->mode = APPARMOR_COMPLAIN;512if (!unpack_u32(e, &tmp, NULL))513goto fail;514if (tmp)515profile->audit = AUDIT_ALL;516517if (!unpack_nameX(e, AA_STRUCTEND, NULL))518goto fail;519520/* path_flags is optional */521if (unpack_u32(e, &profile->path_flags, "path_flags"))522profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED;523else524/* set a default value if path_flags field is not present */525profile->path_flags = PFLAG_MEDIATE_DELETED;526527if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))528goto fail;529if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))530goto fail;531if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))532goto fail;533if (!unpack_u32(e, &tmpcap.cap[0], NULL))534goto fail;535536if (unpack_nameX(e, AA_STRUCT, "caps64")) {537/* optional upper half of 64 bit caps */538if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))539goto fail;540if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))541goto fail;542if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))543goto fail;544if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))545goto fail;546if (!unpack_nameX(e, AA_STRUCTEND, NULL))547goto fail;548}549550if (unpack_nameX(e, AA_STRUCT, "capsx")) {551/* optional extended caps mediation mask */552if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))553goto fail;554if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))555goto fail;556}557558if (!unpack_rlimits(e, profile))559goto fail;560561/* get file rules */562profile->file.dfa = unpack_dfa(e);563if (IS_ERR(profile->file.dfa)) {564error = PTR_ERR(profile->file.dfa);565profile->file.dfa = NULL;566goto fail;567}568569if (!unpack_u32(e, &profile->file.start, "dfa_start"))570/* default start state */571profile->file.start = DFA_START;572573if (!unpack_trans_table(e, profile))574goto fail;575576if (!unpack_nameX(e, AA_STRUCTEND, NULL))577goto fail;578579return profile;580581fail:582if (profile)583name = NULL;584else if (!name)585name = "unknown";586audit_iface(profile, name, "failed to unpack profile", e, error);587aa_put_profile(profile);588589return ERR_PTR(error);590}591592/**593* verify_head - unpack serialized stream header594* @e: serialized data read head (NOT NULL)595* @ns: Returns - namespace if one is specified else NULL (NOT NULL)596*597* Returns: error or 0 if header is good598*/599static int verify_header(struct aa_ext *e, const char **ns)600{601int error = -EPROTONOSUPPORT;602/* get the interface version */603if (!unpack_u32(e, &e->version, "version")) {604audit_iface(NULL, NULL, "invalid profile format", e, error);605return error;606}607608/* check that the interface version is currently supported */609if (e->version != 5) {610audit_iface(NULL, NULL, "unsupported interface version", e,611error);612return error;613}614615/* read the namespace if present */616if (!unpack_str(e, ns, "namespace"))617*ns = NULL;618619return 0;620}621622static bool verify_xindex(int xindex, int table_size)623{624int index, xtype;625xtype = xindex & AA_X_TYPE_MASK;626index = xindex & AA_X_INDEX_MASK;627if (xtype == AA_X_TABLE && index > table_size)628return 0;629return 1;630}631632/* verify dfa xindexes are in range of transition tables */633static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)634{635int i;636for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {637if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))638return 0;639if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))640return 0;641}642return 1;643}644645/**646* verify_profile - Do post unpack analysis to verify profile consistency647* @profile: profile to verify (NOT NULL)648*649* Returns: 0 if passes verification else error650*/651static int verify_profile(struct aa_profile *profile)652{653if (aa_g_paranoid_load) {654if (profile->file.dfa &&655!verify_dfa_xindex(profile->file.dfa,656profile->file.trans.size)) {657audit_iface(profile, NULL, "Invalid named transition",658NULL, -EPROTO);659return -EPROTO;660}661}662663return 0;664}665666/**667* aa_unpack - unpack packed binary profile data loaded from user space668* @udata: user data copied to kmem (NOT NULL)669* @size: the size of the user data670* @ns: Returns namespace profile is in if specified else NULL (NOT NULL)671*672* Unpack user data and return refcounted allocated profile or ERR_PTR673*674* Returns: profile else error pointer if fails to unpack675*/676struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)677{678struct aa_profile *profile = NULL;679int error;680struct aa_ext e = {681.start = udata,682.end = udata + size,683.pos = udata,684};685686error = verify_header(&e, ns);687if (error)688return ERR_PTR(error);689690profile = unpack_profile(&e);691if (IS_ERR(profile))692return profile;693694error = verify_profile(profile);695if (error) {696aa_put_profile(profile);697profile = ERR_PTR(error);698}699700/* return refcount */701return profile;702}703704705