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 * Even though Smack labels are usually shared on smack_list 81 * labels that come in off the network can't be imported 82 * and added to the list for locking reasons. 83 * 84 * Therefore, it is necessary to check the contents of the labels, 85 * not just the pointer values. Of course, in most cases the labels 86 * will be on the list, so checking the pointers may be a worthwhile 87 * optimization. 88 */ 89 int smk_access_entry(char *subject_label, char *object_label, 90 struct list_head *rule_list) 91 { 92 int may = -ENOENT; 93 struct smack_rule *srp; 94 95 list_for_each_entry_rcu(srp, rule_list, list) { 96 if (srp->smk_subject == subject_label || 97 strcmp(srp->smk_subject, subject_label) == 0) { 98 if (srp->smk_object == object_label || 99 strcmp(srp->smk_object, object_label) == 0) { 100 may = srp->smk_access; 101 break; 102 } 103 } 104 } 105 106 return may; 107 } 108 109 /** 110 * smk_access - determine if a subject has a specific access to an object 111 * @subject_label: a pointer to the subject's Smack label 112 * @object_label: a pointer to the object's Smack label 113 * @request: the access requested, in "MAY" format 114 * @a : a pointer to the audit data 115 * 116 * This function looks up the subject/object pair in the 117 * access rule list and returns 0 if the access is permitted, 118 * non zero otherwise. 119 * 120 * Even though Smack labels are usually shared on smack_list 121 * labels that come in off the network can't be imported 122 * and added to the list for locking reasons. 123 * 124 * Therefore, it is necessary to check the contents of the labels, 125 * not just the pointer values. Of course, in most cases the labels 126 * will be on the list, so checking the pointers may be a worthwhile 127 * optimization. 128 */ 129 int smk_access(char *subject_label, char *object_label, int request, 130 struct smk_audit_info *a) 131 { 132 int may = MAY_NOT; 133 int rc = 0; 134 135 /* 136 * Hardcoded comparisons. 137 * 138 * A star subject can't access any object. 139 */ 140 if (subject_label == smack_known_star.smk_known || 141 strcmp(subject_label, smack_known_star.smk_known) == 0) { 142 rc = -EACCES; 143 goto out_audit; 144 } 145 /* 146 * An internet object can be accessed by any subject. 147 * Tasks cannot be assigned the internet label. 148 * An internet subject can access any object. 149 */ 150 if (object_label == smack_known_web.smk_known || 151 subject_label == smack_known_web.smk_known || 152 strcmp(object_label, smack_known_web.smk_known) == 0 || 153 strcmp(subject_label, smack_known_web.smk_known) == 0) 154 goto out_audit; 155 /* 156 * A star object can be accessed by any subject. 157 */ 158 if (object_label == smack_known_star.smk_known || 159 strcmp(object_label, smack_known_star.smk_known) == 0) 160 goto out_audit; 161 /* 162 * An object can be accessed in any way by a subject 163 * with the same label. 164 */ 165 if (subject_label == object_label || 166 strcmp(subject_label, object_label) == 0) 167 goto out_audit; 168 /* 169 * A hat subject can read any object. 170 * A floor object can be read by any subject. 171 */ 172 if ((request & MAY_ANYREAD) == request) { 173 if (object_label == smack_known_floor.smk_known || 174 strcmp(object_label, smack_known_floor.smk_known) == 0) 175 goto out_audit; 176 if (subject_label == smack_known_hat.smk_known || 177 strcmp(subject_label, smack_known_hat.smk_known) == 0) 178 goto out_audit; 179 } 180 /* 181 * Beyond here an explicit relationship is required. 182 * If the requested access is contained in the available 183 * access (e.g. read is included in readwrite) it's 184 * good. A negative response from smk_access_entry() 185 * indicates there is no entry for this pair. 186 */ 187 rcu_read_lock(); 188 may = smk_access_entry(subject_label, object_label, &smack_rule_list); 189 rcu_read_unlock(); 190 191 if (may > 0 && (request & may) == request) 192 goto out_audit; 193 194 rc = -EACCES; 195 out_audit: 196 #ifdef CONFIG_AUDIT 197 if (a) 198 smack_log(subject_label, object_label, request, rc, a); 199 #endif 200 return rc; 201 } 202 203 /** 204 * smk_curacc - determine if current has a specific access to an object 205 * @obj_label: a pointer to the object's Smack label 206 * @mode: the access requested, in "MAY" format 207 * @a : common audit data 208 * 209 * This function checks the current subject label/object label pair 210 * in the access rule list and returns 0 if the access is permitted, 211 * non zero otherwise. It allows that current may have the capability 212 * to override the rules. 213 */ 214 int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) 215 { 216 struct task_smack *tsp = current_security(); 217 char *sp = smk_of_task(tsp); 218 int may; 219 int rc; 220 221 /* 222 * Check the global rule list 223 */ 224 rc = smk_access(sp, obj_label, mode, NULL); 225 if (rc == 0) { 226 /* 227 * If there is an entry in the task's rule list 228 * it can further restrict access. 229 */ 230 may = smk_access_entry(sp, obj_label, &tsp->smk_rules); 231 if (may < 0) 232 goto out_audit; 233 if ((mode & may) == mode) 234 goto out_audit; 235 rc = -EACCES; 236 } 237 238 /* 239 * Return if a specific label has been designated as the 240 * only one that gets privilege and current does not 241 * have that label. 242 */ 243 if (smack_onlycap != NULL && smack_onlycap != sp) 244 goto out_audit; 245 246 if (capable(CAP_MAC_OVERRIDE)) 247 rc = 0; 248 249 out_audit: 250 #ifdef CONFIG_AUDIT 251 if (a) 252 smack_log(sp, obj_label, mode, rc, a); 253 #endif 254 return rc; 255 } 256 257 #ifdef CONFIG_AUDIT 258 /** 259 * smack_str_from_perm : helper to transalate an int to a 260 * readable string 261 * @string : the string to fill 262 * @access : the int 263 * 264 */ 265 static inline void smack_str_from_perm(char *string, int access) 266 { 267 int i = 0; 268 if (access & MAY_READ) 269 string[i++] = 'r'; 270 if (access & MAY_WRITE) 271 string[i++] = 'w'; 272 if (access & MAY_EXEC) 273 string[i++] = 'x'; 274 if (access & MAY_APPEND) 275 string[i++] = 'a'; 276 string[i] = '\0'; 277 } 278 /** 279 * smack_log_callback - SMACK specific information 280 * will be called by generic audit code 281 * @ab : the audit_buffer 282 * @a : audit_data 283 * 284 */ 285 static void smack_log_callback(struct audit_buffer *ab, void *a) 286 { 287 struct common_audit_data *ad = a; 288 struct smack_audit_data *sad = &ad->smack_audit_data; 289 audit_log_format(ab, "lsm=SMACK fn=%s action=%s", 290 ad->smack_audit_data.function, 291 sad->result ? "denied" : "granted"); 292 audit_log_format(ab, " subject="); 293 audit_log_untrustedstring(ab, sad->subject); 294 audit_log_format(ab, " object="); 295 audit_log_untrustedstring(ab, sad->object); 296 audit_log_format(ab, " requested=%s", sad->request); 297 } 298 299 /** 300 * smack_log - Audit the granting or denial of permissions. 301 * @subject_label : smack label of the requester 302 * @object_label : smack label of the object being accessed 303 * @request: requested permissions 304 * @result: result from smk_access 305 * @a: auxiliary audit data 306 * 307 * Audit the granting or denial of permissions in accordance 308 * with the policy. 309 */ 310 void smack_log(char *subject_label, char *object_label, int request, 311 int result, struct smk_audit_info *ad) 312 { 313 char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; 314 struct smack_audit_data *sad; 315 struct common_audit_data *a = &ad->a; 316 317 /* check if we have to log the current event */ 318 if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) 319 return; 320 if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) 321 return; 322 323 if (a->smack_audit_data.function == NULL) 324 a->smack_audit_data.function = "unknown"; 325 326 /* end preparing the audit data */ 327 sad = &a->smack_audit_data; 328 smack_str_from_perm(request_buffer, request); 329 sad->subject = subject_label; 330 sad->object = object_label; 331 sad->request = request_buffer; 332 sad->result = result; 333 a->lsm_pre_audit = smack_log_callback; 334 335 common_lsm_audit(a); 336 } 337 #else /* #ifdef CONFIG_AUDIT */ 338 void smack_log(char *subject_label, char *object_label, int request, 339 int result, struct smk_audit_info *ad) 340 { 341 } 342 #endif 343 344 static DEFINE_MUTEX(smack_known_lock); 345 346 /** 347 * smk_import_entry - import a label, return the list entry 348 * @string: a text string that might be a Smack label 349 * @len: the maximum size, or zero if it is NULL terminated. 350 * 351 * Returns a pointer to the entry in the label list that 352 * matches the passed string, adding it if necessary. 353 */ 354 struct smack_known *smk_import_entry(const char *string, int len) 355 { 356 struct smack_known *skp; 357 char smack[SMK_LABELLEN]; 358 int found; 359 int i; 360 361 if (len <= 0 || len > SMK_MAXLEN) 362 len = SMK_MAXLEN; 363 364 for (i = 0, found = 0; i < SMK_LABELLEN; i++) { 365 if (found) 366 smack[i] = '\0'; 367 else if (i >= len || string[i] > '~' || string[i] <= ' ' || 368 string[i] == '/' || string[i] == '"' || 369 string[i] == '\\' || string[i] == '\'') { 370 smack[i] = '\0'; 371 found = 1; 372 } else 373 smack[i] = string[i]; 374 } 375 376 if (smack[0] == '\0') 377 return NULL; 378 379 mutex_lock(&smack_known_lock); 380 381 found = 0; 382 list_for_each_entry_rcu(skp, &smack_known_list, list) { 383 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 384 found = 1; 385 break; 386 } 387 } 388 389 if (found == 0) { 390 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 391 if (skp != NULL) { 392 strncpy(skp->smk_known, smack, SMK_MAXLEN); 393 skp->smk_secid = smack_next_secid++; 394 skp->smk_cipso = NULL; 395 spin_lock_init(&skp->smk_cipsolock); 396 /* 397 * Make sure that the entry is actually 398 * filled before putting it on the list. 399 */ 400 list_add_rcu(&skp->list, &smack_known_list); 401 } 402 } 403 404 mutex_unlock(&smack_known_lock); 405 406 return skp; 407 } 408 409 /** 410 * smk_import - import a smack label 411 * @string: a text string that might be a Smack label 412 * @len: the maximum size, or zero if it is NULL terminated. 413 * 414 * Returns a pointer to the label in the label list that 415 * matches the passed string, adding it if necessary. 416 */ 417 char *smk_import(const char *string, int len) 418 { 419 struct smack_known *skp; 420 421 /* labels cannot begin with a '-' */ 422 if (string[0] == '-') 423 return NULL; 424 skp = smk_import_entry(string, len); 425 if (skp == NULL) 426 return NULL; 427 return skp->smk_known; 428 } 429 430 /** 431 * smack_from_secid - find the Smack label associated with a secid 432 * @secid: an integer that might be associated with a Smack label 433 * 434 * Returns a pointer to the appropriate Smack label if there is one, 435 * otherwise a pointer to the invalid Smack label. 436 */ 437 char *smack_from_secid(const u32 secid) 438 { 439 struct smack_known *skp; 440 441 rcu_read_lock(); 442 list_for_each_entry_rcu(skp, &smack_known_list, list) { 443 if (skp->smk_secid == secid) { 444 rcu_read_unlock(); 445 return skp->smk_known; 446 } 447 } 448 449 /* 450 * If we got this far someone asked for the translation 451 * of a secid that is not on the list. 452 */ 453 rcu_read_unlock(); 454 return smack_known_invalid.smk_known; 455 } 456 457 /** 458 * smack_to_secid - find the secid associated with a Smack label 459 * @smack: the Smack label 460 * 461 * Returns the appropriate secid if there is one, 462 * otherwise 0 463 */ 464 u32 smack_to_secid(const char *smack) 465 { 466 struct smack_known *skp; 467 468 rcu_read_lock(); 469 list_for_each_entry_rcu(skp, &smack_known_list, list) { 470 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 471 rcu_read_unlock(); 472 return skp->smk_secid; 473 } 474 } 475 rcu_read_unlock(); 476 return 0; 477 } 478 479 /** 480 * smack_from_cipso - find the Smack label associated with a CIPSO option 481 * @level: Bell & LaPadula level from the network 482 * @cp: Bell & LaPadula categories from the network 483 * @result: where to put the Smack value 484 * 485 * This is a simple lookup in the label table. 486 * 487 * This is an odd duck as far as smack handling goes in that 488 * it sends back a copy of the smack label rather than a pointer 489 * to the master list. This is done because it is possible for 490 * a foreign host to send a smack label that is new to this 491 * machine and hence not on the list. That would not be an 492 * issue except that adding an entry to the master list can't 493 * be done at that point. 494 */ 495 void smack_from_cipso(u32 level, char *cp, char *result) 496 { 497 struct smack_known *kp; 498 char *final = NULL; 499 500 rcu_read_lock(); 501 list_for_each_entry(kp, &smack_known_list, list) { 502 if (kp->smk_cipso == NULL) 503 continue; 504 505 spin_lock_bh(&kp->smk_cipsolock); 506 507 if (kp->smk_cipso->smk_level == level && 508 memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) 509 final = kp->smk_known; 510 511 spin_unlock_bh(&kp->smk_cipsolock); 512 } 513 rcu_read_unlock(); 514 if (final == NULL) 515 final = smack_known_huh.smk_known; 516 strncpy(result, final, SMK_MAXLEN); 517 return; 518 } 519 520 /** 521 * smack_to_cipso - find the CIPSO option to go with a Smack label 522 * @smack: a pointer to the smack label in question 523 * @cp: where to put the result 524 * 525 * Returns zero if a value is available, non-zero otherwise. 526 */ 527 int smack_to_cipso(const char *smack, struct smack_cipso *cp) 528 { 529 struct smack_known *kp; 530 int found = 0; 531 532 rcu_read_lock(); 533 list_for_each_entry_rcu(kp, &smack_known_list, list) { 534 if (kp->smk_known == smack || 535 strcmp(kp->smk_known, smack) == 0) { 536 found = 1; 537 break; 538 } 539 } 540 rcu_read_unlock(); 541 542 if (found == 0 || kp->smk_cipso == NULL) 543 return -ENOENT; 544 545 memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); 546 return 0; 547 } 548