1*e06f75a6SJohn Johansen /* 2*e06f75a6SJohn Johansen * AppArmor security module 3*e06f75a6SJohn Johansen * 4*e06f75a6SJohn Johansen * This file contains AppArmor dfa based regular expression matching engine 5*e06f75a6SJohn Johansen * 6*e06f75a6SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 7*e06f75a6SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 8*e06f75a6SJohn Johansen * 9*e06f75a6SJohn Johansen * This program is free software; you can redistribute it and/or 10*e06f75a6SJohn Johansen * modify it under the terms of the GNU General Public License as 11*e06f75a6SJohn Johansen * published by the Free Software Foundation, version 2 of the 12*e06f75a6SJohn Johansen * License. 13*e06f75a6SJohn Johansen */ 14*e06f75a6SJohn Johansen 15*e06f75a6SJohn Johansen #include <linux/errno.h> 16*e06f75a6SJohn Johansen #include <linux/kernel.h> 17*e06f75a6SJohn Johansen #include <linux/mm.h> 18*e06f75a6SJohn Johansen #include <linux/slab.h> 19*e06f75a6SJohn Johansen #include <linux/vmalloc.h> 20*e06f75a6SJohn Johansen #include <linux/err.h> 21*e06f75a6SJohn Johansen #include <linux/kref.h> 22*e06f75a6SJohn Johansen 23*e06f75a6SJohn Johansen #include "include/apparmor.h" 24*e06f75a6SJohn Johansen #include "include/match.h" 25*e06f75a6SJohn Johansen 26*e06f75a6SJohn Johansen /** 27*e06f75a6SJohn Johansen * unpack_table - unpack a dfa table (one of accept, default, base, next check) 28*e06f75a6SJohn Johansen * @blob: data to unpack (NOT NULL) 29*e06f75a6SJohn Johansen * @bsize: size of blob 30*e06f75a6SJohn Johansen * 31*e06f75a6SJohn Johansen * Returns: pointer to table else NULL on failure 32*e06f75a6SJohn Johansen * 33*e06f75a6SJohn Johansen * NOTE: must be freed by kvfree (not kmalloc) 34*e06f75a6SJohn Johansen */ 35*e06f75a6SJohn Johansen static struct table_header *unpack_table(char *blob, size_t bsize) 36*e06f75a6SJohn Johansen { 37*e06f75a6SJohn Johansen struct table_header *table = NULL; 38*e06f75a6SJohn Johansen struct table_header th; 39*e06f75a6SJohn Johansen size_t tsize; 40*e06f75a6SJohn Johansen 41*e06f75a6SJohn Johansen if (bsize < sizeof(struct table_header)) 42*e06f75a6SJohn Johansen goto out; 43*e06f75a6SJohn Johansen 44*e06f75a6SJohn Johansen /* loaded td_id's start at 1, subtract 1 now to avoid doing 45*e06f75a6SJohn Johansen * it every time we use td_id as an index 46*e06f75a6SJohn Johansen */ 47*e06f75a6SJohn Johansen th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1; 48*e06f75a6SJohn Johansen th.td_flags = be16_to_cpu(*(u16 *) (blob + 2)); 49*e06f75a6SJohn Johansen th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8)); 50*e06f75a6SJohn Johansen blob += sizeof(struct table_header); 51*e06f75a6SJohn Johansen 52*e06f75a6SJohn Johansen if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || 53*e06f75a6SJohn Johansen th.td_flags == YYTD_DATA8)) 54*e06f75a6SJohn Johansen goto out; 55*e06f75a6SJohn Johansen 56*e06f75a6SJohn Johansen tsize = table_size(th.td_lolen, th.td_flags); 57*e06f75a6SJohn Johansen if (bsize < tsize) 58*e06f75a6SJohn Johansen goto out; 59*e06f75a6SJohn Johansen 60*e06f75a6SJohn Johansen table = kvmalloc(tsize); 61*e06f75a6SJohn Johansen if (table) { 62*e06f75a6SJohn Johansen *table = th; 63*e06f75a6SJohn Johansen if (th.td_flags == YYTD_DATA8) 64*e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 65*e06f75a6SJohn Johansen u8, byte_to_byte); 66*e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA16) 67*e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 68*e06f75a6SJohn Johansen u16, be16_to_cpu); 69*e06f75a6SJohn Johansen else if (th.td_flags == YYTD_DATA32) 70*e06f75a6SJohn Johansen UNPACK_ARRAY(table->td_data, blob, th.td_lolen, 71*e06f75a6SJohn Johansen u32, be32_to_cpu); 72*e06f75a6SJohn Johansen else 73*e06f75a6SJohn Johansen goto fail; 74*e06f75a6SJohn Johansen } 75*e06f75a6SJohn Johansen 76*e06f75a6SJohn Johansen out: 77*e06f75a6SJohn Johansen /* if table was vmalloced make sure the page tables are synced 78*e06f75a6SJohn Johansen * before it is used, as it goes live to all cpus. 79*e06f75a6SJohn Johansen */ 80*e06f75a6SJohn Johansen if (is_vmalloc_addr(table)) 81*e06f75a6SJohn Johansen vm_unmap_aliases(); 82*e06f75a6SJohn Johansen return table; 83*e06f75a6SJohn Johansen fail: 84*e06f75a6SJohn Johansen kvfree(table); 85*e06f75a6SJohn Johansen return NULL; 86*e06f75a6SJohn Johansen } 87*e06f75a6SJohn Johansen 88*e06f75a6SJohn Johansen /** 89*e06f75a6SJohn Johansen * verify_dfa - verify that transitions and states in the tables are in bounds. 90*e06f75a6SJohn Johansen * @dfa: dfa to test (NOT NULL) 91*e06f75a6SJohn Johansen * @flags: flags controlling what type of accept table are acceptable 92*e06f75a6SJohn Johansen * 93*e06f75a6SJohn Johansen * Assumes dfa has gone through the first pass verification done by unpacking 94*e06f75a6SJohn Johansen * NOTE: this does not valid accept table values 95*e06f75a6SJohn Johansen * 96*e06f75a6SJohn Johansen * Returns: %0 else error code on failure to verify 97*e06f75a6SJohn Johansen */ 98*e06f75a6SJohn Johansen static int verify_dfa(struct aa_dfa *dfa, int flags) 99*e06f75a6SJohn Johansen { 100*e06f75a6SJohn Johansen size_t i, state_count, trans_count; 101*e06f75a6SJohn Johansen int error = -EPROTO; 102*e06f75a6SJohn Johansen 103*e06f75a6SJohn Johansen /* check that required tables exist */ 104*e06f75a6SJohn Johansen if (!(dfa->tables[YYTD_ID_DEF] && 105*e06f75a6SJohn Johansen dfa->tables[YYTD_ID_BASE] && 106*e06f75a6SJohn Johansen dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) 107*e06f75a6SJohn Johansen goto out; 108*e06f75a6SJohn Johansen 109*e06f75a6SJohn Johansen /* accept.size == default.size == base.size */ 110*e06f75a6SJohn Johansen state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 111*e06f75a6SJohn Johansen if (ACCEPT1_FLAGS(flags)) { 112*e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT]) 113*e06f75a6SJohn Johansen goto out; 114*e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) 115*e06f75a6SJohn Johansen goto out; 116*e06f75a6SJohn Johansen } 117*e06f75a6SJohn Johansen if (ACCEPT2_FLAGS(flags)) { 118*e06f75a6SJohn Johansen if (!dfa->tables[YYTD_ID_ACCEPT2]) 119*e06f75a6SJohn Johansen goto out; 120*e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) 121*e06f75a6SJohn Johansen goto out; 122*e06f75a6SJohn Johansen } 123*e06f75a6SJohn Johansen if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) 124*e06f75a6SJohn Johansen goto out; 125*e06f75a6SJohn Johansen 126*e06f75a6SJohn Johansen /* next.size == chk.size */ 127*e06f75a6SJohn Johansen trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; 128*e06f75a6SJohn Johansen if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) 129*e06f75a6SJohn Johansen goto out; 130*e06f75a6SJohn Johansen 131*e06f75a6SJohn Johansen /* if equivalence classes then its table size must be 256 */ 132*e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC] && 133*e06f75a6SJohn Johansen dfa->tables[YYTD_ID_EC]->td_lolen != 256) 134*e06f75a6SJohn Johansen goto out; 135*e06f75a6SJohn Johansen 136*e06f75a6SJohn Johansen if (flags & DFA_FLAG_VERIFY_STATES) { 137*e06f75a6SJohn Johansen for (i = 0; i < state_count; i++) { 138*e06f75a6SJohn Johansen if (DEFAULT_TABLE(dfa)[i] >= state_count) 139*e06f75a6SJohn Johansen goto out; 140*e06f75a6SJohn Johansen /* TODO: do check that DEF state recursion terminates */ 141*e06f75a6SJohn Johansen if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { 142*e06f75a6SJohn Johansen printk(KERN_ERR "AppArmor DFA next/check upper " 143*e06f75a6SJohn Johansen "bounds error\n"); 144*e06f75a6SJohn Johansen goto out; 145*e06f75a6SJohn Johansen } 146*e06f75a6SJohn Johansen } 147*e06f75a6SJohn Johansen 148*e06f75a6SJohn Johansen for (i = 0; i < trans_count; i++) { 149*e06f75a6SJohn Johansen if (NEXT_TABLE(dfa)[i] >= state_count) 150*e06f75a6SJohn Johansen goto out; 151*e06f75a6SJohn Johansen if (CHECK_TABLE(dfa)[i] >= state_count) 152*e06f75a6SJohn Johansen goto out; 153*e06f75a6SJohn Johansen } 154*e06f75a6SJohn Johansen } 155*e06f75a6SJohn Johansen 156*e06f75a6SJohn Johansen error = 0; 157*e06f75a6SJohn Johansen out: 158*e06f75a6SJohn Johansen return error; 159*e06f75a6SJohn Johansen } 160*e06f75a6SJohn Johansen 161*e06f75a6SJohn Johansen /** 162*e06f75a6SJohn Johansen * dfa_free - free a dfa allocated by aa_dfa_unpack 163*e06f75a6SJohn Johansen * @dfa: the dfa to free (MAYBE NULL) 164*e06f75a6SJohn Johansen * 165*e06f75a6SJohn Johansen * Requires: reference count to dfa == 0 166*e06f75a6SJohn Johansen */ 167*e06f75a6SJohn Johansen static void dfa_free(struct aa_dfa *dfa) 168*e06f75a6SJohn Johansen { 169*e06f75a6SJohn Johansen if (dfa) { 170*e06f75a6SJohn Johansen int i; 171*e06f75a6SJohn Johansen 172*e06f75a6SJohn Johansen for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { 173*e06f75a6SJohn Johansen kvfree(dfa->tables[i]); 174*e06f75a6SJohn Johansen dfa->tables[i] = NULL; 175*e06f75a6SJohn Johansen } 176*e06f75a6SJohn Johansen kfree(dfa); 177*e06f75a6SJohn Johansen } 178*e06f75a6SJohn Johansen } 179*e06f75a6SJohn Johansen 180*e06f75a6SJohn Johansen /** 181*e06f75a6SJohn Johansen * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa) 182*e06f75a6SJohn Johansen * @kr: kref callback for freeing of a dfa (NOT NULL) 183*e06f75a6SJohn Johansen */ 184*e06f75a6SJohn Johansen void aa_dfa_free_kref(struct kref *kref) 185*e06f75a6SJohn Johansen { 186*e06f75a6SJohn Johansen struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count); 187*e06f75a6SJohn Johansen dfa_free(dfa); 188*e06f75a6SJohn Johansen } 189*e06f75a6SJohn Johansen 190*e06f75a6SJohn Johansen /** 191*e06f75a6SJohn Johansen * aa_dfa_unpack - unpack the binary tables of a serialized dfa 192*e06f75a6SJohn Johansen * @blob: aligned serialized stream of data to unpack (NOT NULL) 193*e06f75a6SJohn Johansen * @size: size of data to unpack 194*e06f75a6SJohn Johansen * @flags: flags controlling what type of accept tables are acceptable 195*e06f75a6SJohn Johansen * 196*e06f75a6SJohn Johansen * Unpack a dfa that has been serialized. To find information on the dfa 197*e06f75a6SJohn Johansen * format look in Documentation/apparmor.txt 198*e06f75a6SJohn Johansen * Assumes the dfa @blob stream has been aligned on a 8 byte boundry 199*e06f75a6SJohn Johansen * 200*e06f75a6SJohn Johansen * Returns: an unpacked dfa ready for matching or ERR_PTR on failure 201*e06f75a6SJohn Johansen */ 202*e06f75a6SJohn Johansen struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) 203*e06f75a6SJohn Johansen { 204*e06f75a6SJohn Johansen int hsize; 205*e06f75a6SJohn Johansen int error = -ENOMEM; 206*e06f75a6SJohn Johansen char *data = blob; 207*e06f75a6SJohn Johansen struct table_header *table = NULL; 208*e06f75a6SJohn Johansen struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); 209*e06f75a6SJohn Johansen if (!dfa) 210*e06f75a6SJohn Johansen goto fail; 211*e06f75a6SJohn Johansen 212*e06f75a6SJohn Johansen kref_init(&dfa->count); 213*e06f75a6SJohn Johansen 214*e06f75a6SJohn Johansen error = -EPROTO; 215*e06f75a6SJohn Johansen 216*e06f75a6SJohn Johansen /* get dfa table set header */ 217*e06f75a6SJohn Johansen if (size < sizeof(struct table_set_header)) 218*e06f75a6SJohn Johansen goto fail; 219*e06f75a6SJohn Johansen 220*e06f75a6SJohn Johansen if (ntohl(*(u32 *) data) != YYTH_MAGIC) 221*e06f75a6SJohn Johansen goto fail; 222*e06f75a6SJohn Johansen 223*e06f75a6SJohn Johansen hsize = ntohl(*(u32 *) (data + 4)); 224*e06f75a6SJohn Johansen if (size < hsize) 225*e06f75a6SJohn Johansen goto fail; 226*e06f75a6SJohn Johansen 227*e06f75a6SJohn Johansen dfa->flags = ntohs(*(u16 *) (data + 12)); 228*e06f75a6SJohn Johansen data += hsize; 229*e06f75a6SJohn Johansen size -= hsize; 230*e06f75a6SJohn Johansen 231*e06f75a6SJohn Johansen while (size > 0) { 232*e06f75a6SJohn Johansen table = unpack_table(data, size); 233*e06f75a6SJohn Johansen if (!table) 234*e06f75a6SJohn Johansen goto fail; 235*e06f75a6SJohn Johansen 236*e06f75a6SJohn Johansen switch (table->td_id) { 237*e06f75a6SJohn Johansen case YYTD_ID_ACCEPT: 238*e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT1_FLAGS(flags))) 239*e06f75a6SJohn Johansen goto fail; 240*e06f75a6SJohn Johansen break; 241*e06f75a6SJohn Johansen case YYTD_ID_ACCEPT2: 242*e06f75a6SJohn Johansen if (!(table->td_flags & ACCEPT2_FLAGS(flags))) 243*e06f75a6SJohn Johansen goto fail; 244*e06f75a6SJohn Johansen break; 245*e06f75a6SJohn Johansen case YYTD_ID_BASE: 246*e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA32) 247*e06f75a6SJohn Johansen goto fail; 248*e06f75a6SJohn Johansen break; 249*e06f75a6SJohn Johansen case YYTD_ID_DEF: 250*e06f75a6SJohn Johansen case YYTD_ID_NXT: 251*e06f75a6SJohn Johansen case YYTD_ID_CHK: 252*e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA16) 253*e06f75a6SJohn Johansen goto fail; 254*e06f75a6SJohn Johansen break; 255*e06f75a6SJohn Johansen case YYTD_ID_EC: 256*e06f75a6SJohn Johansen if (table->td_flags != YYTD_DATA8) 257*e06f75a6SJohn Johansen goto fail; 258*e06f75a6SJohn Johansen break; 259*e06f75a6SJohn Johansen default: 260*e06f75a6SJohn Johansen goto fail; 261*e06f75a6SJohn Johansen } 262*e06f75a6SJohn Johansen /* check for duplicate table entry */ 263*e06f75a6SJohn Johansen if (dfa->tables[table->td_id]) 264*e06f75a6SJohn Johansen goto fail; 265*e06f75a6SJohn Johansen dfa->tables[table->td_id] = table; 266*e06f75a6SJohn Johansen data += table_size(table->td_lolen, table->td_flags); 267*e06f75a6SJohn Johansen size -= table_size(table->td_lolen, table->td_flags); 268*e06f75a6SJohn Johansen table = NULL; 269*e06f75a6SJohn Johansen } 270*e06f75a6SJohn Johansen 271*e06f75a6SJohn Johansen error = verify_dfa(dfa, flags); 272*e06f75a6SJohn Johansen if (error) 273*e06f75a6SJohn Johansen goto fail; 274*e06f75a6SJohn Johansen 275*e06f75a6SJohn Johansen return dfa; 276*e06f75a6SJohn Johansen 277*e06f75a6SJohn Johansen fail: 278*e06f75a6SJohn Johansen kvfree(table); 279*e06f75a6SJohn Johansen dfa_free(dfa); 280*e06f75a6SJohn Johansen return ERR_PTR(error); 281*e06f75a6SJohn Johansen } 282*e06f75a6SJohn Johansen 283*e06f75a6SJohn Johansen /** 284*e06f75a6SJohn Johansen * aa_dfa_match_len - traverse @dfa to find state @str stops at 285*e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 286*e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 287*e06f75a6SJohn Johansen * @str: the string of bytes to match against the dfa (NOT NULL) 288*e06f75a6SJohn Johansen * @len: length of the string of bytes to match 289*e06f75a6SJohn Johansen * 290*e06f75a6SJohn Johansen * aa_dfa_match_len will match @str against the dfa and return the state it 291*e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 292*e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 293*e06f75a6SJohn Johansen * 294*e06f75a6SJohn Johansen * This function will happily match again the 0 byte and only finishes 295*e06f75a6SJohn Johansen * when @len input is consumed. 296*e06f75a6SJohn Johansen * 297*e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 298*e06f75a6SJohn Johansen */ 299*e06f75a6SJohn Johansen unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 300*e06f75a6SJohn Johansen const char *str, int len) 301*e06f75a6SJohn Johansen { 302*e06f75a6SJohn Johansen u16 *def = DEFAULT_TABLE(dfa); 303*e06f75a6SJohn Johansen u32 *base = BASE_TABLE(dfa); 304*e06f75a6SJohn Johansen u16 *next = NEXT_TABLE(dfa); 305*e06f75a6SJohn Johansen u16 *check = CHECK_TABLE(dfa); 306*e06f75a6SJohn Johansen unsigned int state = start, pos; 307*e06f75a6SJohn Johansen 308*e06f75a6SJohn Johansen if (state == 0) 309*e06f75a6SJohn Johansen return 0; 310*e06f75a6SJohn Johansen 311*e06f75a6SJohn Johansen /* current state is <state>, matching character *str */ 312*e06f75a6SJohn Johansen if (dfa->tables[YYTD_ID_EC]) { 313*e06f75a6SJohn Johansen /* Equivalence class table defined */ 314*e06f75a6SJohn Johansen u8 *equiv = EQUIV_TABLE(dfa); 315*e06f75a6SJohn Johansen /* default is direct to next state */ 316*e06f75a6SJohn Johansen for (; len; len--) { 317*e06f75a6SJohn Johansen pos = base[state] + equiv[(u8) *str++]; 318*e06f75a6SJohn Johansen if (check[pos] == state) 319*e06f75a6SJohn Johansen state = next[pos]; 320*e06f75a6SJohn Johansen else 321*e06f75a6SJohn Johansen state = def[state]; 322*e06f75a6SJohn Johansen } 323*e06f75a6SJohn Johansen } else { 324*e06f75a6SJohn Johansen /* default is direct to next state */ 325*e06f75a6SJohn Johansen for (; len; len--) { 326*e06f75a6SJohn Johansen pos = base[state] + (u8) *str++; 327*e06f75a6SJohn Johansen if (check[pos] == state) 328*e06f75a6SJohn Johansen state = next[pos]; 329*e06f75a6SJohn Johansen else 330*e06f75a6SJohn Johansen state = def[state]; 331*e06f75a6SJohn Johansen } 332*e06f75a6SJohn Johansen } 333*e06f75a6SJohn Johansen 334*e06f75a6SJohn Johansen return state; 335*e06f75a6SJohn Johansen } 336*e06f75a6SJohn Johansen 337*e06f75a6SJohn Johansen /** 338*e06f75a6SJohn Johansen * aa_dfa_next_state - traverse @dfa to find state @str stops at 339*e06f75a6SJohn Johansen * @dfa: the dfa to match @str against (NOT NULL) 340*e06f75a6SJohn Johansen * @start: the state of the dfa to start matching in 341*e06f75a6SJohn Johansen * @str: the null terminated string of bytes to match against the dfa (NOT NULL) 342*e06f75a6SJohn Johansen * 343*e06f75a6SJohn Johansen * aa_dfa_next_state will match @str against the dfa and return the state it 344*e06f75a6SJohn Johansen * finished matching in. The final state can be used to look up the accepting 345*e06f75a6SJohn Johansen * label, or as the start state of a continuing match. 346*e06f75a6SJohn Johansen * 347*e06f75a6SJohn Johansen * Returns: final state reached after input is consumed 348*e06f75a6SJohn Johansen */ 349*e06f75a6SJohn Johansen unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 350*e06f75a6SJohn Johansen const char *str) 351*e06f75a6SJohn Johansen { 352*e06f75a6SJohn Johansen return aa_dfa_match_len(dfa, start, str, strlen(str)); 353*e06f75a6SJohn Johansen } 354