aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavi Arnaut <davi.arnaut@gmail.com>2006-03-23 05:59:25 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-23 10:38:03 -0500
commit6bb08da4773f584a7b4a838b6b770d7d18033af7 (patch)
tree5d19e8bb1c1f17e2e270f55bc238b326d5a6a3f6
parent61808c2bbba127ecd9786401c55ea4c394aa0240 (diff)
[PATCH] Bug fixes and cleanup for the BSD Secure Levels LSM
This patch address several issues in the current BSD Secure Levels code: o plaintext_to_sha1: Missing check for a NULL return from __get_free_page o passwd_write_file: A page is leaked if the password is wrong. o fix securityfs registration order o seclvl_init is a mess and can't properly tolerate failures, failure path is upside down (deldif and delf should be switched) Cleanups: o plaintext_to_sha1: Use buffers passed in o passwd_write_file: Use kmalloc() instead of get_zeroed_page() o passwd_write_file: hashedPassword comparison is just memcmp o s/ENOSYS/EINVAL/ o misc (akpm: after some discussion it appears that the BSD secure levels feature should be scheduled for removal. But for now, let's fix these problems up). Signed-off-by: Davi Arnaut <davi.arnaut@gmail.com> Cc: Michael Halcrow <mhalcrow@us.ibm.com> Cc: Chris Wright <chrisw@sous-sol.org> Cc: Stephen Smalley <sds@epoch.ncsc.mil> Cc: James Morris <jmorris@namei.org> Cc: Serge Hallyn <serue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--security/seclvl.c210
1 files changed, 113 insertions, 97 deletions
diff --git a/security/seclvl.c b/security/seclvl.c
index 8529ea6f7aa8..441beaf1bbc1 100644
--- a/security/seclvl.c
+++ b/security/seclvl.c
@@ -8,6 +8,7 @@
8 * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com> 8 * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
9 * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com> 9 * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
10 * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com> 10 * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com>
11 * Copyright (c) 2006 Davi E. M. Arnaut <davi.arnaut@gmail.com>
11 * 12 *
12 * This program is free software; you can redistribute it and/or modify 13 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
@@ -31,6 +32,7 @@
31#include <linux/kobject.h> 32#include <linux/kobject.h>
32#include <linux/crypto.h> 33#include <linux/crypto.h>
33#include <asm/scatterlist.h> 34#include <asm/scatterlist.h>
35#include <linux/scatterlist.h>
34#include <linux/gfp.h> 36#include <linux/gfp.h>
35#include <linux/sysfs.h> 37#include <linux/sysfs.h>
36 38
@@ -194,35 +196,27 @@ static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
194 * people... 196 * people...
195 */ 197 */
196static int 198static int
197plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len) 199plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
198{ 200{
199 char *pgVirtAddr;
200 struct crypto_tfm *tfm; 201 struct crypto_tfm *tfm;
201 struct scatterlist sg[1]; 202 struct scatterlist sg;
202 if (len > PAGE_SIZE) { 203 if (len > PAGE_SIZE) {
203 seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d " 204 seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
204 "characters). Largest possible is %lu " 205 "characters). Largest possible is %lu "
205 "bytes.\n", len, PAGE_SIZE); 206 "bytes.\n", len, PAGE_SIZE);
206 return -ENOMEM; 207 return -EINVAL;
207 } 208 }
208 tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP); 209 tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
209 if (tfm == NULL) { 210 if (tfm == NULL) {
210 seclvl_printk(0, KERN_ERR, 211 seclvl_printk(0, KERN_ERR,
211 "Failed to load transform for SHA1\n"); 212 "Failed to load transform for SHA1\n");
212 return -ENOSYS; 213 return -EINVAL;
213 } 214 }
214 // Just get a new page; don't play around with page boundaries 215 sg_init_one(&sg, (u8 *)plaintext, len);
215 // and scatterlists.
216 pgVirtAddr = (char *)__get_free_page(GFP_KERNEL);
217 sg[0].page = virt_to_page(pgVirtAddr);
218 sg[0].offset = 0;
219 sg[0].length = len;
220 strncpy(pgVirtAddr, plaintext, len);
221 crypto_digest_init(tfm); 216 crypto_digest_init(tfm);
222 crypto_digest_update(tfm, sg, 1); 217 crypto_digest_update(tfm, &sg, 1);
223 crypto_digest_final(tfm, hash); 218 crypto_digest_final(tfm, hash);
224 crypto_free_tfm(tfm); 219 crypto_free_tfm(tfm);
225 free_page((unsigned long)pgVirtAddr);
226 return 0; 220 return 0;
227} 221}
228 222
@@ -234,11 +228,9 @@ static ssize_t
234passwd_write_file(struct file * file, const char __user * buf, 228passwd_write_file(struct file * file, const char __user * buf,
235 size_t count, loff_t *ppos) 229 size_t count, loff_t *ppos)
236{ 230{
237 int i; 231 char *p;
238 unsigned char tmp[SHA1_DIGEST_SIZE];
239 char *page;
240 int rc;
241 int len; 232 int len;
233 unsigned char tmp[SHA1_DIGEST_SIZE];
242 234
243 if (!*passwd && !*sha1_passwd) { 235 if (!*passwd && !*sha1_passwd) {
244 seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the " 236 seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
@@ -251,38 +243,39 @@ passwd_write_file(struct file * file, const char __user * buf,
251 return -EINVAL; 243 return -EINVAL;
252 } 244 }
253 245
254 if (count < 0 || count >= PAGE_SIZE) 246 if (count >= PAGE_SIZE)
255 return -EINVAL; 247 return -EINVAL;
256 if (*ppos != 0) 248 if (*ppos != 0)
257 return -EINVAL; 249 return -EINVAL;
258 page = (char *)get_zeroed_page(GFP_KERNEL); 250 p = kmalloc(count, GFP_KERNEL);
259 if (!page) 251 if (!p)
260 return -ENOMEM; 252 return -ENOMEM;
261 len = -EFAULT; 253 len = -EFAULT;
262 if (copy_from_user(page, buf, count)) 254 if (copy_from_user(p, buf, count))
263 goto out; 255 goto out;
264 256
265 len = strlen(page); 257 len = count;
266 /* ``echo "secret" > seclvl/passwd'' includes a newline */ 258 /* ``echo "secret" > seclvl/passwd'' includes a newline */
267 if (page[len - 1] == '\n') 259 if (p[len - 1] == '\n')
268 len--; 260 len--;
269 /* Hash the password, then compare the hashed values */ 261 /* Hash the password, then compare the hashed values */
270 if ((rc = plaintext_to_sha1(tmp, page, len))) { 262 if ((len = plaintext_to_sha1(tmp, p, len))) {
271 seclvl_printk(0, KERN_ERR, "Error hashing password: rc = " 263 seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
272 "[%d]\n", rc); 264 "[%d]\n", len);
273 return rc; 265 goto out;
274 }
275 for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
276 if (hashedPassword[i] != tmp[i])
277 return -EPERM;
278 } 266 }
267
268 len = -EPERM;
269 if (memcmp(hashedPassword, tmp, SHA1_DIGEST_SIZE))
270 goto out;
271
279 seclvl_printk(0, KERN_INFO, 272 seclvl_printk(0, KERN_INFO,
280 "Password accepted; seclvl reduced to 0.\n"); 273 "Password accepted; seclvl reduced to 0.\n");
281 seclvl = 0; 274 seclvl = 0;
282 len = count; 275 len = count;
283 276
284out: 277out:
285 free_page((unsigned long)page); 278 kfree (p);
286 return len; 279 return len;
287} 280}
288 281
@@ -295,13 +288,11 @@ static struct file_operations passwd_file_ops = {
295 */ 288 */
296static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child) 289static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
297{ 290{
298 if (seclvl >= 0) { 291 if (seclvl >= 0 && child->pid == 1) {
299 if (child->pid == 1) { 292 seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
300 seclvl_printk(1, KERN_WARNING, "Attempt to ptrace " 293 "the init process dissallowed in "
301 "the init process dissallowed in " 294 "secure level %d\n", seclvl);
302 "secure level %d\n", seclvl); 295 return -EPERM;
303 return -EPERM;
304 }
305 } 296 }
306 return 0; 297 return 0;
307} 298}
@@ -312,55 +303,54 @@ static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
312 */ 303 */
313static int seclvl_capable(struct task_struct *tsk, int cap) 304static int seclvl_capable(struct task_struct *tsk, int cap)
314{ 305{
306 int rc = 0;
307
315 /* init can do anything it wants */ 308 /* init can do anything it wants */
316 if (tsk->pid == 1) 309 if (tsk->pid == 1)
317 return 0; 310 return 0;
318 311
319 switch (seclvl) { 312 if (seclvl > 0) {
320 case 2: 313 rc = -EPERM;
321 /* fall through */ 314
322 case 1: 315 if (cap == CAP_LINUX_IMMUTABLE)
323 if (cap == CAP_LINUX_IMMUTABLE) {
324 seclvl_printk(1, KERN_WARNING, "Attempt to modify " 316 seclvl_printk(1, KERN_WARNING, "Attempt to modify "
325 "the IMMUTABLE and/or APPEND extended " 317 "the IMMUTABLE and/or APPEND extended "
326 "attribute on a file with the IMMUTABLE " 318 "attribute on a file with the IMMUTABLE "
327 "and/or APPEND extended attribute set " 319 "and/or APPEND extended attribute set "
328 "denied in seclvl [%d]\n", seclvl); 320 "denied in seclvl [%d]\n", seclvl);
329 return -EPERM; 321 else if (cap == CAP_SYS_RAWIO)
330 } else if (cap == CAP_SYS_RAWIO) { // Somewhat broad...
331 seclvl_printk(1, KERN_WARNING, "Attempt to perform " 322 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
332 "raw I/O while in secure level [%d] " 323 "raw I/O while in secure level [%d] "
333 "denied\n", seclvl); 324 "denied\n", seclvl);
334 return -EPERM; 325 else if (cap == CAP_NET_ADMIN)
335 } else if (cap == CAP_NET_ADMIN) {
336 seclvl_printk(1, KERN_WARNING, "Attempt to perform " 326 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
337 "network administrative task while " 327 "network administrative task while "
338 "in secure level [%d] denied\n", seclvl); 328 "in secure level [%d] denied\n", seclvl);
339 return -EPERM; 329 else if (cap == CAP_SETUID)
340 } else if (cap == CAP_SETUID) {
341 seclvl_printk(1, KERN_WARNING, "Attempt to setuid " 330 seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
342 "while in secure level [%d] denied\n", 331 "while in secure level [%d] denied\n",
343 seclvl); 332 seclvl);
344 return -EPERM; 333 else if (cap == CAP_SETGID)
345 } else if (cap == CAP_SETGID) {
346 seclvl_printk(1, KERN_WARNING, "Attempt to setgid " 334 seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
347 "while in secure level [%d] denied\n", 335 "while in secure level [%d] denied\n",
348 seclvl); 336 seclvl);
349 } else if (cap == CAP_SYS_MODULE) { 337 else if (cap == CAP_SYS_MODULE)
350 seclvl_printk(1, KERN_WARNING, "Attempt to perform " 338 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
351 "a module operation while in secure " 339 "a module operation while in secure "
352 "level [%d] denied\n", seclvl); 340 "level [%d] denied\n", seclvl);
353 return -EPERM; 341 else
354 } 342 rc = 0;
355 break;
356 default:
357 break;
358 } 343 }
359 /* from dummy.c */ 344
360 if (cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0) 345 if (!rc) {
361 return 0; /* capability granted */ 346 if (!(cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0))
362 seclvl_printk(1, KERN_WARNING, "Capability denied\n"); 347 rc = -EPERM;
363 return -EPERM; /* capability denied */ 348 }
349
350 if (rc)
351 seclvl_printk(1, KERN_WARNING, "Capability denied\n");
352
353 return rc;
364} 354}
365 355
366/** 356/**
@@ -466,12 +456,9 @@ static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
466static void seclvl_file_free_security(struct file *filp) 456static void seclvl_file_free_security(struct file *filp)
467{ 457{
468 struct dentry *dentry = filp->f_dentry; 458 struct dentry *dentry = filp->f_dentry;
469 struct inode *inode = NULL;
470 459
471 if (dentry) { 460 if (dentry)
472 inode = dentry->d_inode; 461 seclvl_bd_release(dentry->d_inode);
473 seclvl_bd_release(inode);
474 }
475} 462}
476 463
477/** 464/**
@@ -479,9 +466,7 @@ static void seclvl_file_free_security(struct file *filp)
479 */ 466 */
480static int seclvl_umount(struct vfsmount *mnt, int flags) 467static int seclvl_umount(struct vfsmount *mnt, int flags)
481{ 468{
482 if (current->pid == 1) 469 if (current->pid != 1 && seclvl == 2) {
483 return 0;
484 if (seclvl == 2) {
485 seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure " 470 seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
486 "level %d\n", seclvl); 471 "level %d\n", seclvl);
487 return -EPERM; 472 return -EPERM;
@@ -505,8 +490,9 @@ static struct security_operations seclvl_ops = {
505static int processPassword(void) 490static int processPassword(void)
506{ 491{
507 int rc = 0; 492 int rc = 0;
508 hashedPassword[0] = '\0';
509 if (*passwd) { 493 if (*passwd) {
494 char *p;
495
510 if (*sha1_passwd) { 496 if (*sha1_passwd) {
511 seclvl_printk(0, KERN_ERR, "Error: Both " 497 seclvl_printk(0, KERN_ERR, "Error: Both "
512 "passwd and sha1_passwd " 498 "passwd and sha1_passwd "
@@ -514,12 +500,16 @@ static int processPassword(void)
514 "exclusive.\n"); 500 "exclusive.\n");
515 return -EINVAL; 501 return -EINVAL;
516 } 502 }
517 if ((rc = plaintext_to_sha1(hashedPassword, passwd, 503
518 strlen(passwd)))) { 504 p = kstrdup(passwd, GFP_KERNEL);
505 if (p == NULL)
506 return -ENOMEM;
507
508 if ((rc = plaintext_to_sha1(hashedPassword, p, strlen(p))))
519 seclvl_printk(0, KERN_ERR, "Error: SHA1 support not " 509 seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
520 "in kernel\n"); 510 "in kernel\n");
521 return rc; 511
522 } 512 kfree (p);
523 /* All static data goes to the BSS, which zero's the 513 /* All static data goes to the BSS, which zero's the
524 * plaintext password out for us. */ 514 * plaintext password out for us. */
525 } else if (*sha1_passwd) { // Base 16 515 } else if (*sha1_passwd) { // Base 16
@@ -542,7 +532,7 @@ static int processPassword(void)
542 sha1_passwd[i + 2] = tmp; 532 sha1_passwd[i + 2] = tmp;
543 } 533 }
544 } 534 }
545 return 0; 535 return rc;
546} 536}
547 537
548/** 538/**
@@ -552,28 +542,46 @@ struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
552 542
553static int seclvlfs_register(void) 543static int seclvlfs_register(void)
554{ 544{
545 int rc = 0;
546
555 dir_ino = securityfs_create_dir("seclvl", NULL); 547 dir_ino = securityfs_create_dir("seclvl", NULL);
556 if (!dir_ino) 548
557 return -EFAULT; 549 if (IS_ERR(dir_ino))
550 return PTR_ERR(dir_ino);
558 551
559 seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR, 552 seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
560 dir_ino, &seclvl, &seclvl_file_ops); 553 dir_ino, &seclvl, &seclvl_file_ops);
561 if (!seclvl_ino) 554 if (IS_ERR(seclvl_ino)) {
555 rc = PTR_ERR(seclvl_ino);
562 goto out_deldir; 556 goto out_deldir;
557 }
563 if (*passwd || *sha1_passwd) { 558 if (*passwd || *sha1_passwd) {
564 passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR, 559 passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
565 dir_ino, NULL, &passwd_file_ops); 560 dir_ino, NULL, &passwd_file_ops);
566 if (!passwd_ino) 561 if (IS_ERR(passwd_ino)) {
562 rc = PTR_ERR(passwd_ino);
567 goto out_delf; 563 goto out_delf;
564 }
568 } 565 }
569 return 0; 566 return rc;
567
568out_delf:
569 securityfs_remove(seclvl_ino);
570 570
571out_deldir: 571out_deldir:
572 securityfs_remove(dir_ino); 572 securityfs_remove(dir_ino);
573out_delf: 573
574 return rc;
575}
576
577static void seclvlfs_unregister(void)
578{
574 securityfs_remove(seclvl_ino); 579 securityfs_remove(seclvl_ino);
575 580
576 return -EFAULT; 581 if (*passwd || *sha1_passwd)
582 securityfs_remove(passwd_ino);
583
584 securityfs_remove(dir_ino);
577} 585}
578 586
579/** 587/**
@@ -582,6 +590,8 @@ out_delf:
582static int __init seclvl_init(void) 590static int __init seclvl_init(void)
583{ 591{
584 int rc = 0; 592 int rc = 0;
593 static char once;
594
585 if (verbosity < 0 || verbosity > 1) { 595 if (verbosity < 0 || verbosity > 1) {
586 printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 " 596 printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
587 "are valid values\n", verbosity); 597 "are valid values\n", verbosity);
@@ -600,6 +610,11 @@ static int __init seclvl_init(void)
600 "module parameter(s): rc = [%d]\n", rc); 610 "module parameter(s): rc = [%d]\n", rc);
601 goto exit; 611 goto exit;
602 } 612 }
613
614 if ((rc = seclvlfs_register())) {
615 seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
616 goto exit;
617 }
603 /* register ourselves with the security framework */ 618 /* register ourselves with the security framework */
604 if (register_security(&seclvl_ops)) { 619 if (register_security(&seclvl_ops)) {
605 seclvl_printk(0, KERN_ERR, 620 seclvl_printk(0, KERN_ERR,
@@ -611,20 +626,24 @@ static int __init seclvl_init(void)
611 seclvl_printk(0, KERN_ERR, "seclvl: Failure " 626 seclvl_printk(0, KERN_ERR, "seclvl: Failure "
612 "registering with primary security " 627 "registering with primary security "
613 "module.\n"); 628 "module.\n");
629 seclvlfs_unregister();
614 goto exit; 630 goto exit;
615 } /* if primary module registered */ 631 } /* if primary module registered */
616 secondary = 1; 632 secondary = 1;
617 } /* if we registered ourselves with the security framework */ 633 } /* if we registered ourselves with the security framework */
618 if ((rc = seclvlfs_register())) { 634
619 seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
620 goto exit;
621 }
622 seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n"); 635 seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
636
637 if (once) {
638 once = 1;
639 seclvl_printk(0, KERN_INFO, "seclvl is going away. It has been "
640 "buggy for ages. Also, be warned that "
641 "Securelevels are useless.");
642 }
623 exit: 643 exit:
624 if (rc) { 644 if (rc)
625 printk(KERN_ERR "seclvl: Error during initialization: rc = " 645 printk(KERN_ERR "seclvl: Error during initialization: rc = "
626 "[%d]\n", rc); 646 "[%d]\n", rc);
627 }
628 return rc; 647 return rc;
629} 648}
630 649
@@ -633,17 +652,14 @@ static int __init seclvl_init(void)
633 */ 652 */
634static void __exit seclvl_exit(void) 653static void __exit seclvl_exit(void)
635{ 654{
636 securityfs_remove(seclvl_ino); 655 seclvlfs_unregister();
637 if (*passwd || *sha1_passwd) 656
638 securityfs_remove(passwd_ino); 657 if (secondary)
639 securityfs_remove(dir_ino);
640 if (secondary == 1) {
641 mod_unreg_security(MY_NAME, &seclvl_ops); 658 mod_unreg_security(MY_NAME, &seclvl_ops);
642 } else if (unregister_security(&seclvl_ops)) { 659 else if (unregister_security(&seclvl_ops))
643 seclvl_printk(0, KERN_INFO, 660 seclvl_printk(0, KERN_INFO,
644 "seclvl: Failure unregistering with the " 661 "seclvl: Failure unregistering with the "
645 "kernel\n"); 662 "kernel\n");
646 }
647} 663}
648 664
649module_init(seclvl_init); 665module_init(seclvl_init);