1 /* 2 * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, version 2. 7 * 8 * Author: 9 * Casey Schaufler <casey@schaufler-ca.com> 10 * 11 */ 12 13 #include <linux/types.h> 14 #include <linux/slab.h> 15 #include <linux/fs.h> 16 #include <linux/sched.h> 17 #include "smack.h" 18 19 struct smack_known smack_known_huh = { 20 .smk_known = "?", 21 .smk_secid = 2, 22 .smk_cipso = NULL, 23 }; 24 25 struct smack_known smack_known_hat = { 26 .smk_known = "^", 27 .smk_secid = 3, 28 .smk_cipso = NULL, 29 }; 30 31 struct smack_known smack_known_star = { 32 .smk_known = "*", 33 .smk_secid = 4, 34 .smk_cipso = NULL, 35 }; 36 37 struct smack_known smack_known_floor = { 38 .smk_known = "_", 39 .smk_secid = 5, 40 .smk_cipso = NULL, 41 }; 42 43 struct smack_known smack_known_invalid = { 44 .smk_known = "", 45 .smk_secid = 6, 46 .smk_cipso = NULL, 47 }; 48 49 struct smack_known smack_known_web = { 50 .smk_known = "@", 51 .smk_secid = 7, 52 .smk_cipso = NULL, 53 }; 54 55 LIST_HEAD(smack_known_list); 56 57 /* 58 * The initial value needs to be bigger than any of the 59 * known values above. 60 */ 61 static u32 smack_next_secid = 10; 62 63 /* 64 * what events do we log 65 * can be overwritten at run-time by /smack/logging 66 */ 67 int log_policy = SMACK_AUDIT_DENIED; 68 69 /** 70 * smk_access_entry - look up matching access rule 71 * @subject_label: a pointer to the subject's Smack label 72 * @object_label: a pointer to the object's Smack label 73 * @rule_list: the list of rules to search 74 * 75 * This function looks up the subject/object pair in the 76 * access rule list and returns the access mode. If no 77 * entry is found returns -ENOENT. 78 * 79 * NOTE: 80 * 81 * Earlier versions of this function allowed for labels that 82 * were not on the label list. This was done to allow for 83 * labels to come over the network that had never been seen 84 * before on this host. Unless the receiving socket has the 85 * star label this will always result in a failure check. The 86 * star labeled socket case is now handled in the networking 87 * hooks so there is no case where the label is not on the 88 * label list. Checking to see if the address of two labels 89 * is the same is now a reliable test. 90 * 91 * Do the object check first because that is more 92 * likely to differ. 93 */ 94 int smk_access_entry(char *subject_label, char *object_label, 95 struct list_head *rule_list) 96 { 97 int may = -ENOENT; 98 struct smack_rule *srp; 99 100 list_for_each_entry_rcu(srp, rule_list, list) { 101 if (srp->smk_object == object_label && 102 srp->smk_subject == subject_label) { 103 may = srp->smk_access; 104 break; 105 } 106 } 107 108 return may; 109 } 110 111 /** 112 * smk_access - determine if a subject has a specific access to an object 113 * @subject_label: a pointer to the subject's Smack label 114 * @object_label: a pointer to the object's Smack label 115 * @request: the access requested, in "MAY" format 116 * @a : a pointer to the audit data 117 * 118 * This function looks up the subject/object pair in the 119 * access rule list and returns 0 if the access is permitted, 120 * non zero otherwise. 121 * 122 * Smack labels are shared on smack_list 123 */ 124 int smk_access(char *subject_label, char *object_label, int request, 125 struct smk_audit_info *a) 126 { 127 struct smack_known *skp; 128 int may = MAY_NOT; 129 int rc = 0; 130 131 /* 132 * Hardcoded comparisons. 133 * 134 * A star subject can't access any object. 135 */ 136 if (subject_label == smack_known_star.smk_known) { 137 rc = -EACCES; 138 goto out_audit; 139 } 140 /* 141 * An internet object can be accessed by any subject. 142 * Tasks cannot be assigned the internet label. 143 * An internet subject can access any object. 144 */ 145 if (object_label == smack_known_web.smk_known || 146 subject_label == smack_known_web.smk_known) 147 goto out_audit; 148 /* 149 * A star object can be accessed by any subject. 150 */ 151 if (object_label == smack_known_star.smk_known) 152 goto out_audit; 153 /* 154 * An object can be accessed in any way by a subject 155 * with the same label. 156 */ 157 if (subject_label == object_label) 158 goto out_audit; 159 /* 160 * A hat subject can read any object. 161 * A floor object can be read by any subject. 162 */ 163 if ((request & MAY_ANYREAD) == request) { 164 if (object_label == smack_known_floor.smk_known) 165 goto out_audit; 166 if (subject_label == smack_known_hat.smk_known) 167 goto out_audit; 168 } 169 /* 170 * Beyond here an explicit relationship is required. 171 * If the requested access is contained in the available 172 * access (e.g. read is included in readwrite) it's 173 * good. A negative response from smk_access_entry() 174 * indicates there is no entry for this pair. 175 */ 176 skp = smk_find_entry(subject_label); 177 rcu_read_lock(); 178 may = smk_access_entry(subject_label, object_label, &skp->smk_rules); 179 rcu_read_unlock(); 180 181 if (may > 0 && (request & may) == request) 182 goto out_audit; 183 184 rc = -EACCES; 185 out_audit: 186 #ifdef CONFIG_AUDIT 187 if (a) 188 smack_log(subject_label, object_label, request, rc, a); 189 #endif 190 return rc; 191 } 192 193 /** 194 * smk_curacc - determine if current has a specific access to an object 195 * @obj_label: a pointer to the object's Smack label 196 * @mode: the access requested, in "MAY" format 197 * @a : common audit data 198 * 199 * This function checks the current subject label/object label pair 200 * in the access rule list and returns 0 if the access is permitted, 201 * non zero otherwise. It allows that current may have the capability 202 * to override the rules. 203 */ 204 int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) 205 { 206 struct task_smack *tsp = current_security(); 207 char *sp = smk_of_task(tsp); 208 int may; 209 int rc; 210 211 /* 212 * Check the global rule list 213 */ 214 rc = smk_access(sp, obj_label, mode, NULL); 215 if (rc == 0) { 216 /* 217 * If there is an entry in the task's rule list 218 * it can further restrict access. 219 */ 220 may = smk_access_entry(sp, obj_label, &tsp->smk_rules); 221 if (may < 0) 222 goto out_audit; 223 if ((mode & may) == mode) 224 goto out_audit; 225 rc = -EACCES; 226 } 227 228 /* 229 * Return if a specific label has been designated as the 230 * only one that gets privilege and current does not 231 * have that label. 232 */ 233 if (smack_onlycap != NULL && smack_onlycap != sp) 234 goto out_audit; 235 236 if (capable(CAP_MAC_OVERRIDE)) 237 rc = 0; 238 239 out_audit: 240 #ifdef CONFIG_AUDIT 241 if (a) 242 smack_log(sp, obj_label, mode, rc, a); 243 #endif 244 return rc; 245 } 246 247 #ifdef CONFIG_AUDIT 248 /** 249 * smack_str_from_perm : helper to transalate an int to a 250 * readable string 251 * @string : the string to fill 252 * @access : the int 253 * 254 */ 255 static inline void smack_str_from_perm(char *string, int access) 256 { 257 int i = 0; 258 if (access & MAY_READ) 259 string[i++] = 'r'; 260 if (access & MAY_WRITE) 261 string[i++] = 'w'; 262 if (access & MAY_EXEC) 263 string[i++] = 'x'; 264 if (access & MAY_APPEND) 265 string[i++] = 'a'; 266 string[i] = '\0'; 267 } 268 /** 269 * smack_log_callback - SMACK specific information 270 * will be called by generic audit code 271 * @ab : the audit_buffer 272 * @a : audit_data 273 * 274 */ 275 static void smack_log_callback(struct audit_buffer *ab, void *a) 276 { 277 struct common_audit_data *ad = a; 278 struct smack_audit_data *sad = ad->smack_audit_data; 279 audit_log_format(ab, "lsm=SMACK fn=%s action=%s", 280 ad->smack_audit_data->function, 281 sad->result ? "denied" : "granted"); 282 audit_log_format(ab, " subject="); 283 audit_log_untrustedstring(ab, sad->subject); 284 audit_log_format(ab, " object="); 285 audit_log_untrustedstring(ab, sad->object); 286 audit_log_format(ab, " requested=%s", sad->request); 287 } 288 289 /** 290 * smack_log - Audit the granting or denial of permissions. 291 * @subject_label : smack label of the requester 292 * @object_label : smack label of the object being accessed 293 * @request: requested permissions 294 * @result: result from smk_access 295 * @a: auxiliary audit data 296 * 297 * Audit the granting or denial of permissions in accordance 298 * with the policy. 299 */ 300 void smack_log(char *subject_label, char *object_label, int request, 301 int result, struct smk_audit_info *ad) 302 { 303 char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; 304 struct smack_audit_data *sad; 305 struct common_audit_data *a = &ad->a; 306 307 /* check if we have to log the current event */ 308 if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) 309 return; 310 if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) 311 return; 312 313 sad = a->smack_audit_data; 314 315 if (sad->function == NULL) 316 sad->function = "unknown"; 317 318 /* end preparing the audit data */ 319 smack_str_from_perm(request_buffer, request); 320 sad->subject = subject_label; 321 sad->object = object_label; 322 sad->request = request_buffer; 323 sad->result = result; 324 325 common_lsm_audit(a, smack_log_callback, NULL); 326 } 327 #else /* #ifdef CONFIG_AUDIT */ 328 void smack_log(char *subject_label, char *object_label, int request, 329 int result, struct smk_audit_info *ad) 330 { 331 } 332 #endif 333 334 static DEFINE_MUTEX(smack_known_lock); 335 336 /** 337 * smk_find_entry - find a label on the list, return the list entry 338 * @string: a text string that might be a Smack label 339 * 340 * Returns a pointer to the entry in the label list that 341 * matches the passed string. 342 */ 343 struct smack_known *smk_find_entry(const char *string) 344 { 345 struct smack_known *skp; 346 347 list_for_each_entry_rcu(skp, &smack_known_list, list) { 348 if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) 349 return skp; 350 } 351 352 return NULL; 353 } 354 355 /** 356 * smk_parse_smack - parse smack label from a text string 357 * @string: a text string that might contain a Smack label 358 * @len: the maximum size, or zero if it is NULL terminated. 359 * @smack: parsed smack label, or NULL if parse error 360 */ 361 void smk_parse_smack(const char *string, int len, char *smack) 362 { 363 int found; 364 int i; 365 366 if (len <= 0 || len > SMK_MAXLEN) 367 len = SMK_MAXLEN; 368 369 for (i = 0, found = 0; i < SMK_LABELLEN; i++) { 370 if (found) 371 smack[i] = '\0'; 372 else if (i >= len || string[i] > '~' || string[i] <= ' ' || 373 string[i] == '/' || string[i] == '"' || 374 string[i] == '\\' || string[i] == '\'') { 375 smack[i] = '\0'; 376 found = 1; 377 } else 378 smack[i] = string[i]; 379 } 380 } 381 382 /** 383 * smk_import_entry - import a label, return the list entry 384 * @string: a text string that might be a Smack label 385 * @len: the maximum size, or zero if it is NULL terminated. 386 * 387 * Returns a pointer to the entry in the label list that 388 * matches the passed string, adding it if necessary. 389 */ 390 struct smack_known *smk_import_entry(const char *string, int len) 391 { 392 struct smack_known *skp; 393 char smack[SMK_LABELLEN]; 394 395 smk_parse_smack(string, len, smack); 396 if (smack[0] == '\0') 397 return NULL; 398 399 mutex_lock(&smack_known_lock); 400 401 skp = smk_find_entry(smack); 402 403 if (skp == NULL) { 404 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 405 if (skp != NULL) { 406 strncpy(skp->smk_known, smack, SMK_MAXLEN); 407 skp->smk_secid = smack_next_secid++; 408 skp->smk_cipso = NULL; 409 INIT_LIST_HEAD(&skp->smk_rules); 410 spin_lock_init(&skp->smk_cipsolock); 411 mutex_init(&skp->smk_rules_lock); 412 /* 413 * Make sure that the entry is actually 414 * filled before putting it on the list. 415 */ 416 list_add_rcu(&skp->list, &smack_known_list); 417 } 418 } 419 420 mutex_unlock(&smack_known_lock); 421 422 return skp; 423 } 424 425 /** 426 * smk_import - import a smack label 427 * @string: a text string that might be a Smack label 428 * @len: the maximum size, or zero if it is NULL terminated. 429 * 430 * Returns a pointer to the label in the label list that 431 * matches the passed string, adding it if necessary. 432 */ 433 char *smk_import(const char *string, int len) 434 { 435 struct smack_known *skp; 436 437 /* labels cannot begin with a '-' */ 438 if (string[0] == '-') 439 return NULL; 440 skp = smk_import_entry(string, len); 441 if (skp == NULL) 442 return NULL; 443 return skp->smk_known; 444 } 445 446 /** 447 * smack_from_secid - find the Smack label associated with a secid 448 * @secid: an integer that might be associated with a Smack label 449 * 450 * Returns a pointer to the appropriate Smack label if there is one, 451 * otherwise a pointer to the invalid Smack label. 452 */ 453 char *smack_from_secid(const u32 secid) 454 { 455 struct smack_known *skp; 456 457 rcu_read_lock(); 458 list_for_each_entry_rcu(skp, &smack_known_list, list) { 459 if (skp->smk_secid == secid) { 460 rcu_read_unlock(); 461 return skp->smk_known; 462 } 463 } 464 465 /* 466 * If we got this far someone asked for the translation 467 * of a secid that is not on the list. 468 */ 469 rcu_read_unlock(); 470 return smack_known_invalid.smk_known; 471 } 472 473 /** 474 * smack_to_secid - find the secid associated with a Smack label 475 * @smack: the Smack label 476 * 477 * Returns the appropriate secid if there is one, 478 * otherwise 0 479 */ 480 u32 smack_to_secid(const char *smack) 481 { 482 struct smack_known *skp; 483 484 rcu_read_lock(); 485 list_for_each_entry_rcu(skp, &smack_known_list, list) { 486 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 487 rcu_read_unlock(); 488 return skp->smk_secid; 489 } 490 } 491 rcu_read_unlock(); 492 return 0; 493 } 494 495 /** 496 * smack_from_cipso - find the Smack label associated with a CIPSO option 497 * @level: Bell & LaPadula level from the network 498 * @cp: Bell & LaPadula categories from the network 499 * 500 * This is a simple lookup in the label table. 501 * 502 * Return the matching label from the label list or NULL. 503 */ 504 char *smack_from_cipso(u32 level, char *cp) 505 { 506 struct smack_known *kp; 507 char *final = NULL; 508 509 rcu_read_lock(); 510 list_for_each_entry(kp, &smack_known_list, list) { 511 if (kp->smk_cipso == NULL) 512 continue; 513 514 spin_lock_bh(&kp->smk_cipsolock); 515 516 if (kp->smk_cipso->smk_level == level && 517 memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) 518 final = kp->smk_known; 519 520 spin_unlock_bh(&kp->smk_cipsolock); 521 522 if (final != NULL) 523 break; 524 } 525 rcu_read_unlock(); 526 527 return final; 528 } 529 530 /** 531 * smack_to_cipso - find the CIPSO option to go with a Smack label 532 * @smack: a pointer to the smack label in question 533 * @cp: where to put the result 534 * 535 * Returns zero if a value is available, non-zero otherwise. 536 */ 537 int smack_to_cipso(const char *smack, struct smack_cipso *cp) 538 { 539 struct smack_known *kp; 540 int found = 0; 541 542 rcu_read_lock(); 543 list_for_each_entry_rcu(kp, &smack_known_list, list) { 544 if (kp->smk_known == smack || 545 strcmp(kp->smk_known, smack) == 0) { 546 found = 1; 547 break; 548 } 549 } 550 rcu_read_unlock(); 551 552 if (found == 0 || kp->smk_cipso == NULL) 553 return -ENOENT; 554 555 memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); 556 return 0; 557 } 558