aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wright <chrisw@sous-sol.org>2006-09-29 04:59:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 12:18:10 -0400
commit3bc1fa8ae18f281b40903cce94baba10c3cf9d88 (patch)
tree9097244b28cbf4eba16368803272af0fc70224d5
parentcd1c6a48ac16b360746f9f111895931d332c35dd (diff)
[PATCH] LSM: remove BSD secure level security module
This code has suffered from broken core design and lack of developer attention. Broken security modules are too dangerous to leave around. It is time to remove this one. Signed-off-by: Chris Wright <chrisw@sous-sol.org> Acked-by: Michael Halcrow <mhalcrow@us.ibm.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: Davi Arnaut <davi.arnaut@gmail.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: James Morris <jmorris@namei.org> Acked-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/seclvl.txt97
-rw-r--r--security/Kconfig12
-rw-r--r--security/Makefile1
-rw-r--r--security/seclvl.c671
4 files changed, 0 insertions, 781 deletions
diff --git a/Documentation/seclvl.txt b/Documentation/seclvl.txt
deleted file mode 100644
index 97274d122d0e..000000000000
--- a/Documentation/seclvl.txt
+++ /dev/null
@@ -1,97 +0,0 @@
1BSD Secure Levels Linux Security Module
2Michael A. Halcrow <mike@halcrow.us>
3
4
5Introduction
6
7Under the BSD Secure Levels security model, sets of policies are
8associated with levels. Levels range from -1 to 2, with -1 being the
9weakest and 2 being the strongest. These security policies are
10enforced at the kernel level, so not even the superuser is able to
11disable or circumvent them. This hardens the machine against attackers
12who gain root access to the system.
13
14
15Levels and Policies
16
17Level -1 (Permanently Insecure):
18 - Cannot increase the secure level
19
20Level 0 (Insecure):
21 - Cannot ptrace the init process
22
23Level 1 (Default):
24 - /dev/mem and /dev/kmem are read-only
25 - IMMUTABLE and APPEND extended attributes, if set, may not be unset
26 - Cannot load or unload kernel modules
27 - Cannot write directly to a mounted block device
28 - Cannot perform raw I/O operations
29 - Cannot perform network administrative tasks
30 - Cannot setuid any file
31
32Level 2 (Secure):
33 - Cannot decrement the system time
34 - Cannot write to any block device, whether mounted or not
35 - Cannot unmount any mounted filesystems
36
37
38Compilation
39
40To compile the BSD Secure Levels LSM, seclvl.ko, enable the
41SECURITY_SECLVL configuration option. This is found under Security
42options -> BSD Secure Levels in the kernel configuration menu.
43
44
45Basic Usage
46
47Once the machine is in a running state, with all the necessary modules
48loaded and all the filesystems mounted, you can load the seclvl.ko
49module:
50
51# insmod seclvl.ko
52
53The module defaults to secure level 1, except when compiled directly
54into the kernel, in which case it defaults to secure level 0. To raise
55the secure level to 2, the administrator writes ``2'' to the
56seclvl/seclvl file under the sysfs mount point (assumed to be /sys in
57these examples):
58
59# echo -n "2" > /sys/seclvl/seclvl
60
61Alternatively, you can initialize the module at secure level 2 with
62the initlvl module parameter:
63
64# insmod seclvl.ko initlvl=2
65
66At this point, it is impossible to remove the module or reduce the
67secure level. If the administrator wishes to have the option of doing
68so, he must provide a module parameter, sha1_passwd, that specifies
69the SHA1 hash of the password that can be used to reduce the secure
70level to 0.
71
72To generate this SHA1 hash, the administrator can use OpenSSL:
73
74# echo -n "boogabooga" | openssl sha1
75abeda4e0f33defa51741217592bf595efb8d289c
76
77In order to use password-instigated secure level reduction, the SHA1
78crypto module must be loaded or compiled into the kernel:
79
80# insmod sha1.ko
81
82The administrator can then insmod the seclvl module, including the
83SHA1 hash of the password:
84
85# insmod seclvl.ko
86 sha1_passwd=abeda4e0f33defa51741217592bf595efb8d289c
87
88To reduce the secure level, write the password to seclvl/passwd under
89your sysfs mount point:
90
91# echo -n "boogabooga" > /sys/seclvl/passwd
92
93The September 2004 edition of Sys Admin Magazine has an article about
94the BSD Secure Levels LSM. I encourage you to refer to that article
95for a more in-depth treatment of this security module:
96
97http://www.samag.com/documents/s=9304/sam0409a/0409a.htm
diff --git a/security/Kconfig b/security/Kconfig
index 67785df264e5..460e5c9cf496 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -93,18 +93,6 @@ config SECURITY_ROOTPLUG
93 93
94 If you are unsure how to answer this question, answer N. 94 If you are unsure how to answer this question, answer N.
95 95
96config SECURITY_SECLVL
97 tristate "BSD Secure Levels"
98 depends on SECURITY
99 select CRYPTO
100 select CRYPTO_SHA1
101 help
102 Implements BSD Secure Levels as an LSM. See
103 <file:Documentation/seclvl.txt> for instructions on how to use this
104 module.
105
106 If you are unsure how to answer this question, answer N.
107
108source security/selinux/Kconfig 96source security/selinux/Kconfig
109 97
110endmenu 98endmenu
diff --git a/security/Makefile b/security/Makefile
index 8cbbf2f36709..ef87df2f50a4 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -16,4 +16,3 @@ obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
16obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o 16obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
17obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o 17obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
18obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o 18obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
19obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
diff --git a/security/seclvl.c b/security/seclvl.c
deleted file mode 100644
index 8f6291991fbc..000000000000
--- a/security/seclvl.c
+++ /dev/null
@@ -1,671 +0,0 @@
1/**
2 * BSD Secure Levels LSM
3 *
4 * Maintainers:
5 * Michael A. Halcrow <mike@halcrow.us>
6 * Serge Hallyn <hallyn@cs.wm.edu>
7 *
8 * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
9 * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
10 * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com>
11 * Copyright (c) 2006 Davi E. M. Arnaut <davi.arnaut@gmail.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 */
18
19#include <linux/err.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/security.h>
25#include <linux/netlink.h>
26#include <linux/fs.h>
27#include <linux/namei.h>
28#include <linux/mount.h>
29#include <linux/capability.h>
30#include <linux/time.h>
31#include <linux/proc_fs.h>
32#include <linux/kobject.h>
33#include <linux/crypto.h>
34#include <asm/scatterlist.h>
35#include <linux/scatterlist.h>
36#include <linux/gfp.h>
37#include <linux/sysfs.h>
38
39#define SHA1_DIGEST_SIZE 20
40
41/**
42 * Module parameter that defines the initial secure level.
43 *
44 * When built as a module, it defaults to seclvl 1, which is the
45 * behavior of BSD secure levels. Note that this default behavior
46 * wrecks havoc on a machine when the seclvl module is compiled into
47 * the kernel. In that case, we default to seclvl 0.
48 */
49#ifdef CONFIG_SECURITY_SECLVL_MODULE
50static int initlvl = 1;
51#else
52static int initlvl;
53#endif
54module_param(initlvl, int, 0);
55MODULE_PARM_DESC(initlvl, "Initial secure level (defaults to 1)");
56
57/* Module parameter that defines the verbosity level */
58static int verbosity;
59module_param(verbosity, int, 0);
60MODULE_PARM_DESC(verbosity, "Initial verbosity level (0 or 1; defaults to "
61 "0, which is Quiet)");
62
63/**
64 * Optional password which can be passed in to bring seclvl to 0
65 * (i.e., for halt/reboot). Defaults to NULL (the passwd attribute
66 * file will not be registered in sysfs).
67 *
68 * This gets converted to its SHA1 hash when stored. It's probably
69 * not a good idea to use this parameter when loading seclvl from a
70 * script; use sha1_passwd instead.
71 */
72
73#define MAX_PASSWD_SIZE 32
74static char passwd[MAX_PASSWD_SIZE];
75module_param_string(passwd, passwd, sizeof(passwd), 0);
76MODULE_PARM_DESC(passwd,
77 "Plaintext of password that sets seclvl=0 when written to "
78 "(sysfs mount point)/seclvl/passwd\n");
79
80/**
81 * SHA1 hashed version of the optional password which can be passed in
82 * to bring seclvl to 0 (i.e., for halt/reboot). Must be in
83 * hexadecimal format (40 characters). Defaults to NULL (the passwd
84 * attribute file will not be registered in sysfs).
85 *
86 * Use the sha1sum utility to generate the SHA1 hash of a password:
87 *
88 * echo -n "secret" | sha1sum
89 */
90#define MAX_SHA1_PASSWD 41
91static char sha1_passwd[MAX_SHA1_PASSWD];
92module_param_string(sha1_passwd, sha1_passwd, sizeof(sha1_passwd), 0);
93MODULE_PARM_DESC(sha1_passwd,
94 "SHA1 hash (40 hexadecimal characters) of password that "
95 "sets seclvl=0 when plaintext password is written to "
96 "(sysfs mount point)/seclvl/passwd\n");
97
98static int hideHash = 1;
99module_param(hideHash, int, 0);
100MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs "
101 "will return the SHA1-hashed value of the password that "
102 "lowers the secure level to 0.\n");
103
104#define MY_NAME "seclvl"
105
106/**
107 * This time-limits log writes to one per second.
108 */
109#define seclvl_printk(verb, type, fmt, arg...) \
110 do { \
111 if (verbosity >= verb) { \
112 static unsigned long _prior; \
113 unsigned long _now = jiffies; \
114 if ((_now - _prior) > HZ) { \
115 printk(type "%s: %s: " fmt, \
116 MY_NAME, __FUNCTION__ , \
117 ## arg); \
118 _prior = _now; \
119 } \
120 } \
121 } while (0)
122
123/**
124 * The actual security level. Ranges between -1 and 2 inclusive.
125 */
126static int seclvl;
127
128/**
129 * flag to keep track of how we were registered
130 */
131static int secondary;
132
133/**
134 * Verifies that the requested secure level is valid, given the current
135 * secure level.
136 */
137static int seclvl_sanity(int reqlvl)
138{
139 if ((reqlvl < -1) || (reqlvl > 2)) {
140 seclvl_printk(1, KERN_WARNING, "Attempt to set seclvl out of "
141 "range: [%d]\n", reqlvl);
142 return -EINVAL;
143 }
144 if ((seclvl == 0) && (reqlvl == -1))
145 return 0;
146 if (reqlvl < seclvl) {
147 seclvl_printk(1, KERN_WARNING, "Attempt to lower seclvl to "
148 "[%d]\n", reqlvl);
149 return -EPERM;
150 }
151 return 0;
152}
153
154/**
155 * security level advancement rules:
156 * Valid levels are -1 through 2, inclusive.
157 * From -1, stuck. [ in case compiled into kernel ]
158 * From 0 or above, can only increment.
159 */
160static void do_seclvl_advance(void *data, u64 val)
161{
162 int ret;
163 int newlvl = (int)val;
164
165 ret = seclvl_sanity(newlvl);
166 if (ret)
167 return;
168
169 if (newlvl > 2) {
170 seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
171 "[%d]\n", newlvl);
172 return;
173 }
174 if (seclvl == -1) {
175 seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
176 "seclvl [%d]\n", seclvl);
177 return;
178 }
179 seclvl = newlvl; /* would it be more "correct" to set *data? */
180 return;
181}
182
183static u64 seclvl_int_get(void *data)
184{
185 return *(int *)data;
186}
187
188DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n");
189
190static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
191
192/**
193 * Converts a block of plaintext of into its SHA1 hashed value.
194 *
195 * It would be nice if crypto had a wrapper to do this for us linear
196 * people...
197 */
198static int
199plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
200{
201 struct hash_desc desc;
202 struct scatterlist sg;
203 int err;
204
205 if (len > PAGE_SIZE) {
206 seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
207 "characters). Largest possible is %lu "
208 "bytes.\n", len, PAGE_SIZE);
209 return -EINVAL;
210 }
211 desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
212 if (IS_ERR(desc.tfm)) {
213 seclvl_printk(0, KERN_ERR,
214 "Failed to load transform for SHA1\n");
215 return -EINVAL;
216 }
217 sg_init_one(&sg, (u8 *)plaintext, len);
218 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
219 err = crypto_hash_digest(&desc, &sg, len, hash);
220 crypto_free_hash(desc.tfm);
221 return err;
222}
223
224/**
225 * Called whenever the user writes to the sysfs passwd handle to this kernel
226 * object. It hashes the password and compares the hashed results.
227 */
228static ssize_t
229passwd_write_file(struct file * file, const char __user * buf,
230 size_t count, loff_t *ppos)
231{
232 char *p;
233 int len;
234 unsigned char tmp[SHA1_DIGEST_SIZE];
235
236 if (!*passwd && !*sha1_passwd) {
237 seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
238 "seclvl module, but neither a plain text "
239 "password nor a SHA1 hashed password was "
240 "passed in as a module parameter! This is a "
241 "bug, since it should not be possible to be in "
242 "this part of the module; please tell a "
243 "maintainer about this event.\n");
244 return -EINVAL;
245 }
246
247 if (count >= PAGE_SIZE)
248 return -EINVAL;
249 if (*ppos != 0)
250 return -EINVAL;
251 p = kmalloc(count, GFP_KERNEL);
252 if (!p)
253 return -ENOMEM;
254 len = -EFAULT;
255 if (copy_from_user(p, buf, count))
256 goto out;
257
258 len = count;
259 /* ``echo "secret" > seclvl/passwd'' includes a newline */
260 if (p[len - 1] == '\n')
261 len--;
262 /* Hash the password, then compare the hashed values */
263 if ((len = plaintext_to_sha1(tmp, p, len))) {
264 seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
265 "[%d]\n", len);
266 goto out;
267 }
268
269 len = -EPERM;
270 if (memcmp(hashedPassword, tmp, SHA1_DIGEST_SIZE))
271 goto out;
272
273 seclvl_printk(0, KERN_INFO,
274 "Password accepted; seclvl reduced to 0.\n");
275 seclvl = 0;
276 len = count;
277
278out:
279 kfree (p);
280 return len;
281}
282
283static struct file_operations passwd_file_ops = {
284 .write = passwd_write_file,
285};
286
287/**
288 * Explicitely disallow ptrace'ing the init process.
289 */
290static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
291{
292 if (seclvl >= 0 && child->pid == 1) {
293 seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
294 "the init process dissallowed in "
295 "secure level %d\n", seclvl);
296 return -EPERM;
297 }
298 return 0;
299}
300
301/**
302 * Capability checks for seclvl. The majority of the policy
303 * enforcement for seclvl takes place here.
304 */
305static int seclvl_capable(struct task_struct *tsk, int cap)
306{
307 int rc = 0;
308
309 /* init can do anything it wants */
310 if (tsk->pid == 1)
311 return 0;
312
313 if (seclvl > 0) {
314 rc = -EPERM;
315
316 if (cap == CAP_LINUX_IMMUTABLE)
317 seclvl_printk(1, KERN_WARNING, "Attempt to modify "
318 "the IMMUTABLE and/or APPEND extended "
319 "attribute on a file with the IMMUTABLE "
320 "and/or APPEND extended attribute set "
321 "denied in seclvl [%d]\n", seclvl);
322 else if (cap == CAP_SYS_RAWIO)
323 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
324 "raw I/O while in secure level [%d] "
325 "denied\n", seclvl);
326 else if (cap == CAP_NET_ADMIN)
327 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
328 "network administrative task while "
329 "in secure level [%d] denied\n", seclvl);
330 else if (cap == CAP_SETUID)
331 seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
332 "while in secure level [%d] denied\n",
333 seclvl);
334 else if (cap == CAP_SETGID)
335 seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
336 "while in secure level [%d] denied\n",
337 seclvl);
338 else if (cap == CAP_SYS_MODULE)
339 seclvl_printk(1, KERN_WARNING, "Attempt to perform "
340 "a module operation while in secure "
341 "level [%d] denied\n", seclvl);
342 else
343 rc = 0;
344 }
345
346 if (!rc) {
347 if (!(cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0))
348 rc = -EPERM;
349 }
350
351 if (rc)
352 seclvl_printk(1, KERN_WARNING, "Capability denied\n");
353
354 return rc;
355}
356
357/**
358 * Disallow reversing the clock in seclvl > 1
359 */
360static int seclvl_settime(struct timespec *tv, struct timezone *tz)
361{
362 if (tv && seclvl > 1) {
363 struct timespec now;
364 now = current_kernel_time();
365 if (tv->tv_sec < now.tv_sec ||
366 (tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
367 seclvl_printk(1, KERN_WARNING, "Attempt to decrement "
368 "time in secure level %d denied: "
369 "current->pid = [%d], "
370 "current->group_leader->pid = [%d]\n",
371 seclvl, current->pid,
372 current->group_leader->pid);
373 return -EPERM;
374 } /* if attempt to decrement time */
375 } /* if seclvl > 1 */
376 return 0;
377}
378
379/* claim the blockdev to exclude mounters, release on file close */
380static int seclvl_bd_claim(struct inode *inode)
381{
382 int holder;
383 struct block_device *bdev = NULL;
384 dev_t dev = inode->i_rdev;
385 bdev = open_by_devnum(dev, FMODE_WRITE);
386 if (bdev) {
387 if (bd_claim(bdev, &holder)) {
388 blkdev_put(bdev);
389 return -EPERM;
390 }
391 /* claimed, mark it to release on close */
392 inode->i_security = current;
393 }
394 return 0;
395}
396
397/* release the blockdev if you claimed it */
398static void seclvl_bd_release(struct inode *inode)
399{
400 if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
401 struct block_device *bdev = inode->i_bdev;
402 if (bdev) {
403 bd_release(bdev);
404 blkdev_put(bdev);
405 inode->i_security = NULL;
406 }
407 }
408}
409
410/**
411 * Security for writes to block devices is regulated by this seclvl
412 * function. Deny all writes to block devices in seclvl 2. In
413 * seclvl 1, we only deny writes to *mounted* block devices.
414 */
415static int
416seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
417{
418 if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
419 switch (seclvl) {
420 case 2:
421 seclvl_printk(1, KERN_WARNING, "Write to block device "
422 "denied in secure level [%d]\n", seclvl);
423 return -EPERM;
424 case 1:
425 if (seclvl_bd_claim(inode)) {
426 seclvl_printk(1, KERN_WARNING,
427 "Write to mounted block device "
428 "denied in secure level [%d]\n",
429 seclvl);
430 return -EPERM;
431 }
432 }
433 }
434 return 0;
435}
436
437/**
438 * The SUID and SGID bits cannot be set in seclvl >= 1
439 */
440static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
441{
442 if (seclvl > 0) {
443 if (iattr->ia_valid & ATTR_MODE)
444 if (iattr->ia_mode & S_ISUID ||
445 iattr->ia_mode & S_ISGID) {
446 seclvl_printk(1, KERN_WARNING, "Attempt to "
447 "modify SUID or SGID bit "
448 "denied in seclvl [%d]\n",
449 seclvl);
450 return -EPERM;
451 }
452 }
453 return 0;
454}
455
456/* release busied block devices */
457static void seclvl_file_free_security(struct file *filp)
458{
459 struct dentry *dentry = filp->f_dentry;
460
461 if (dentry)
462 seclvl_bd_release(dentry->d_inode);
463}
464
465/**
466 * Cannot unmount in secure level 2
467 */
468static int seclvl_umount(struct vfsmount *mnt, int flags)
469{
470 if (current->pid != 1 && seclvl == 2) {
471 seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
472 "level %d\n", seclvl);
473 return -EPERM;
474 }
475 return 0;
476}
477
478static struct security_operations seclvl_ops = {
479 .ptrace = seclvl_ptrace,
480 .capable = seclvl_capable,
481 .inode_permission = seclvl_inode_permission,
482 .inode_setattr = seclvl_inode_setattr,
483 .file_free_security = seclvl_file_free_security,
484 .settime = seclvl_settime,
485 .sb_umount = seclvl_umount,
486};
487
488/**
489 * Process the password-related module parameters
490 */
491static int processPassword(void)
492{
493 int rc = 0;
494 if (*passwd) {
495 char *p;
496
497 if (*sha1_passwd) {
498 seclvl_printk(0, KERN_ERR, "Error: Both "
499 "passwd and sha1_passwd "
500 "were set, but they are mutually "
501 "exclusive.\n");
502 return -EINVAL;
503 }
504
505 p = kstrdup(passwd, GFP_KERNEL);
506 if (p == NULL)
507 return -ENOMEM;
508
509 if ((rc = plaintext_to_sha1(hashedPassword, p, strlen(p))))
510 seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
511 "in kernel\n");
512
513 kfree (p);
514 /* All static data goes to the BSS, which zero's the
515 * plaintext password out for us. */
516 } else if (*sha1_passwd) { // Base 16
517 int i;
518 i = strlen(sha1_passwd);
519 if (i != (SHA1_DIGEST_SIZE * 2)) {
520 seclvl_printk(0, KERN_ERR, "Received [%d] bytes; "
521 "expected [%d] for the hexadecimal "
522 "representation of the SHA1 hash of "
523 "the password.\n",
524 i, (SHA1_DIGEST_SIZE * 2));
525 return -EINVAL;
526 }
527 while ((i -= 2) + 2) {
528 unsigned char tmp;
529 tmp = sha1_passwd[i + 2];
530 sha1_passwd[i + 2] = '\0';
531 hashedPassword[i / 2] = (unsigned char)
532 simple_strtol(&sha1_passwd[i], NULL, 16);
533 sha1_passwd[i + 2] = tmp;
534 }
535 }
536 return rc;
537}
538
539/**
540 * securityfs registrations
541 */
542struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
543
544static int seclvlfs_register(void)
545{
546 int rc = 0;
547
548 dir_ino = securityfs_create_dir("seclvl", NULL);
549
550 if (IS_ERR(dir_ino))
551 return PTR_ERR(dir_ino);
552
553 seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
554 dir_ino, &seclvl, &seclvl_file_ops);
555 if (IS_ERR(seclvl_ino)) {
556 rc = PTR_ERR(seclvl_ino);
557 goto out_deldir;
558 }
559 if (*passwd || *sha1_passwd) {
560 passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
561 dir_ino, NULL, &passwd_file_ops);
562 if (IS_ERR(passwd_ino)) {
563 rc = PTR_ERR(passwd_ino);
564 goto out_delf;
565 }
566 }
567 return rc;
568
569out_delf:
570 securityfs_remove(seclvl_ino);
571
572out_deldir:
573 securityfs_remove(dir_ino);
574
575 return rc;
576}
577
578static void seclvlfs_unregister(void)
579{
580 securityfs_remove(seclvl_ino);
581
582 if (*passwd || *sha1_passwd)
583 securityfs_remove(passwd_ino);
584
585 securityfs_remove(dir_ino);
586}
587
588/**
589 * Initialize the seclvl module.
590 */
591static int __init seclvl_init(void)
592{
593 int rc = 0;
594 static char once;
595
596 if (verbosity < 0 || verbosity > 1) {
597 printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
598 "are valid values\n", verbosity);
599 rc = -EINVAL;
600 goto exit;
601 }
602 if (initlvl < -1 || initlvl > 2) {
603 seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
604 "[%d].\n", initlvl);
605 rc = -EINVAL;
606 goto exit;
607 }
608 seclvl = initlvl;
609 if ((rc = processPassword())) {
610 seclvl_printk(0, KERN_ERR, "Error processing the password "
611 "module parameter(s): rc = [%d]\n", rc);
612 goto exit;
613 }
614
615 if ((rc = seclvlfs_register())) {
616 seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
617 goto exit;
618 }
619 /* register ourselves with the security framework */
620 if (register_security(&seclvl_ops)) {
621 seclvl_printk(0, KERN_ERR,
622 "seclvl: Failure registering with the "
623 "kernel.\n");
624 /* try registering with primary module */
625 rc = mod_reg_security(MY_NAME, &seclvl_ops);
626 if (rc) {
627 seclvl_printk(0, KERN_ERR, "seclvl: Failure "
628 "registering with primary security "
629 "module.\n");
630 seclvlfs_unregister();
631 goto exit;
632 } /* if primary module registered */
633 secondary = 1;
634 } /* if we registered ourselves with the security framework */
635
636 seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
637
638 if (once) {
639 once = 1;
640 seclvl_printk(0, KERN_INFO, "seclvl is going away. It has been "
641 "buggy for ages. Also, be warned that "
642 "Securelevels are useless.");
643 }
644 exit:
645 if (rc)
646 printk(KERN_ERR "seclvl: Error during initialization: rc = "
647 "[%d]\n", rc);
648 return rc;
649}
650
651/**
652 * Remove the seclvl module.
653 */
654static void __exit seclvl_exit(void)
655{
656 seclvlfs_unregister();
657
658 if (secondary)
659 mod_unreg_security(MY_NAME, &seclvl_ops);
660 else if (unregister_security(&seclvl_ops))
661 seclvl_printk(0, KERN_INFO,
662 "seclvl: Failure unregistering with the "
663 "kernel\n");
664}
665
666module_init(seclvl_init);
667module_exit(seclvl_exit);
668
669MODULE_AUTHOR("Michael A. Halcrow <mike@halcrow.us>");
670MODULE_DESCRIPTION("LSM implementation of the BSD Secure Levels");
671MODULE_LICENSE("GPL");