aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2008-02-05 01:29:50 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:20 -0500
commite114e473771c848c3cfec05f0123e70f1cdbdc99 (patch)
tree933b840f3ccac6860da56291c742094f9b5a20cb /security/smack/smackfs.c
parenteda61d32e8ad1d9102872f9a0abf3344bf9c5e67 (diff)
Smack: Simplified Mandatory Access Control Kernel
Smack is the Simplified Mandatory Access Control Kernel. Smack implements mandatory access control (MAC) using labels attached to tasks and data containers, including files, SVIPC, and other tasks. Smack is a kernel based scheme that requires an absolute minimum of application support and a very small amount of configuration data. Smack uses extended attributes and provides a set of general mount options, borrowing technics used elsewhere. Smack uses netlabel for CIPSO labeling. Smack provides a pseudo-filesystem smackfs that is used for manipulation of system Smack attributes. The patch, patches for ls and sshd, a README, a startup script, and x86 binaries for ls and sshd are also available on http://www.schaufler-ca.com Development has been done using Fedora Core 7 in a virtual machine environment and on an old Sony laptop. Smack provides mandatory access controls based on the label attached to a task and the label attached to the object it is attempting to access. Smack labels are deliberately short (1-23 characters) text strings. Single character labels using special characters are reserved for system use. The only operation applied to Smack labels is equality comparison. No wildcards or expressions, regular or otherwise, are used. Smack labels are composed of printable characters and may not include "/". A file always gets the Smack label of the task that created it. Smack defines and uses these labels: "*" - pronounced "star" "_" - pronounced "floor" "^" - pronounced "hat" "?" - pronounced "huh" The access rules enforced by Smack are, in order: 1. Any access requested by a task labeled "*" is denied. 2. A read or execute access requested by a task labeled "^" is permitted. 3. A read or execute access requested on an object labeled "_" is permitted. 4. Any access requested on an object labeled "*" is permitted. 5. Any access requested by a task on an object with the same label is permitted. 6. Any access requested that is explicitly defined in the loaded rule set is permitted. 7. Any other access is denied. Rules may be explicitly defined by writing subject,object,access triples to /smack/load. Smack rule sets can be easily defined that describe Bell&LaPadula sensitivity, Biba integrity, and a variety of interesting configurations. Smack rule sets can be modified on the fly to accommodate changes in the operating environment or even the time of day. Some practical use cases: Hierarchical levels. The less common of the two usual uses for MLS systems is to define hierarchical levels, often unclassified, confidential, secret, and so on. To set up smack to support this, these rules could be defined: C Unclass rx S C rx S Unclass rx TS S rx TS C rx TS Unclass rx A TS process can read S, C, and Unclass data, but cannot write it. An S process can read C and Unclass. Note that specifying that TS can read S and S can read C does not imply TS can read C, it has to be explicitly stated. Non-hierarchical categories. This is the more common of the usual uses for an MLS system. Since the default rule is that a subject cannot access an object with a different label no access rules are required to implement compartmentalization. A case that the Bell & LaPadula policy does not allow is demonstrated with this Smack access rule: A case that Bell&LaPadula does not allow that Smack does: ESPN ABC r ABC ESPN r On my portable video device I have two applications, one that shows ABC programming and the other ESPN programming. ESPN wants to show me sport stories that show up as news, and ABC will only provide minimal information about a sports story if ESPN is covering it. Each side can look at the other's info, neither can change the other. Neither can see what FOX is up to, which is just as well all things considered. Another case that I especially like: SatData Guard w Guard Publish w A program running with the Guard label opens a UDP socket and accepts messages sent by a program running with a SatData label. The Guard program inspects the message to ensure it is wholesome and if it is sends it to a program running with the Publish label. This program then puts the information passed in an appropriate place. Note that the Guard program cannot write to a Publish file system object because file system semanitic require read as well as write. The four cases (categories, levels, mutual read, guardbox) here are all quite real, and problems I've been asked to solve over the years. The first two are easy to do with traditonal MLS systems while the last two you can't without invoking privilege, at least for a while. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> Cc: Joshua Brindle <method@manicmethod.com> Cc: Paul Moore <paul.moore@hp.com> Cc: Stephen Smalley <sds@tycho.nsa.gov> Cc: Chris Wright <chrisw@sous-sol.org> Cc: James Morris <jmorris@namei.org> Cc: "Ahmed S. Darwish" <darwish.07@gmail.com> Cc: Andrew G. Morgan <morgan@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c981
1 files changed, 981 insertions, 0 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
new file mode 100644
index 000000000000..15aa37f65b39
--- /dev/null
+++ b/security/smack/smackfs.c
@@ -0,0 +1,981 @@
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 * Authors:
9 * Casey Schaufler <casey@schaufler-ca.com>
10 * Ahmed S. Darwish <darwish.07@gmail.com>
11 *
12 * Special thanks to the authors of selinuxfs.
13 *
14 * Karl MacMillan <kmacmillan@tresys.com>
15 * James Morris <jmorris@redhat.com>
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/vmalloc.h>
21#include <linux/security.h>
22#include <linux/mutex.h>
23#include <net/netlabel.h>
24#include <net/cipso_ipv4.h>
25#include <linux/seq_file.h>
26#include <linux/ctype.h>
27#include "smack.h"
28
29/*
30 * smackfs pseudo filesystem.
31 */
32
33enum smk_inos {
34 SMK_ROOT_INO = 2,
35 SMK_LOAD = 3, /* load policy */
36 SMK_CIPSO = 4, /* load label -> CIPSO mapping */
37 SMK_DOI = 5, /* CIPSO DOI */
38 SMK_DIRECT = 6, /* CIPSO level indicating direct label */
39 SMK_AMBIENT = 7, /* internet ambient label */
40 SMK_NLTYPE = 8, /* label scheme to use by default */
41};
42
43/*
44 * List locks
45 */
46static DEFINE_MUTEX(smack_list_lock);
47static DEFINE_MUTEX(smack_cipso_lock);
48
49/*
50 * This is the "ambient" label for network traffic.
51 * If it isn't somehow marked, use this.
52 * It can be reset via smackfs/ambient
53 */
54char *smack_net_ambient = smack_known_floor.smk_known;
55
56/*
57 * This is the default packet marking scheme for network traffic.
58 * It can be reset via smackfs/nltype
59 */
60int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
61
62/*
63 * This is the level in a CIPSO header that indicates a
64 * smack label is contained directly in the category set.
65 * It can be reset via smackfs/direct
66 */
67int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
68
69static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
70struct smk_list_entry *smack_list;
71
72#define SEQ_READ_FINISHED 1
73
74/*
75 * Disable concurrent writing open() operations
76 */
77static struct semaphore smack_write_sem;
78
79/*
80 * Values for parsing cipso rules
81 * SMK_DIGITLEN: Length of a digit field in a rule.
82 * SMK_CIPSOMEN: Minimum possible cipso rule length.
83 */
84#define SMK_DIGITLEN 4
85#define SMK_CIPSOMIN (SMK_MAXLEN + 2 * SMK_DIGITLEN)
86
87/*
88 * Seq_file read operations for /smack/load
89 */
90
91static void *load_seq_start(struct seq_file *s, loff_t *pos)
92{
93 if (*pos == SEQ_READ_FINISHED)
94 return NULL;
95
96 return smack_list;
97}
98
99static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
100{
101 struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
102
103 if (skp == NULL)
104 *pos = SEQ_READ_FINISHED;
105
106 return skp;
107}
108
109static int load_seq_show(struct seq_file *s, void *v)
110{
111 struct smk_list_entry *slp = (struct smk_list_entry *) v;
112 struct smack_rule *srp = &slp->smk_rule;
113
114 seq_printf(s, "%s %s", (char *)srp->smk_subject,
115 (char *)srp->smk_object);
116
117 seq_putc(s, ' ');
118
119 if (srp->smk_access & MAY_READ)
120 seq_putc(s, 'r');
121 if (srp->smk_access & MAY_WRITE)
122 seq_putc(s, 'w');
123 if (srp->smk_access & MAY_EXEC)
124 seq_putc(s, 'x');
125 if (srp->smk_access & MAY_APPEND)
126 seq_putc(s, 'a');
127 if (srp->smk_access == 0)
128 seq_putc(s, '-');
129
130 seq_putc(s, '\n');
131
132 return 0;
133}
134
135static void load_seq_stop(struct seq_file *s, void *v)
136{
137 /* No-op */
138}
139
140static struct seq_operations load_seq_ops = {
141 .start = load_seq_start,
142 .next = load_seq_next,
143 .show = load_seq_show,
144 .stop = load_seq_stop,
145};
146
147/**
148 * smk_open_load - open() for /smack/load
149 * @inode: inode structure representing file
150 * @file: "load" file pointer
151 *
152 * For reading, use load_seq_* seq_file reading operations.
153 */
154static int smk_open_load(struct inode *inode, struct file *file)
155{
156 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
157 return seq_open(file, &load_seq_ops);
158
159 if (down_interruptible(&smack_write_sem))
160 return -ERESTARTSYS;
161
162 return 0;
163}
164
165/**
166 * smk_release_load - release() for /smack/load
167 * @inode: inode structure representing file
168 * @file: "load" file pointer
169 *
170 * For a reading session, use the seq_file release
171 * implementation.
172 * Otherwise, we are at the end of a writing session so
173 * clean everything up.
174 */
175static int smk_release_load(struct inode *inode, struct file *file)
176{
177 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
178 return seq_release(inode, file);
179
180 up(&smack_write_sem);
181 return 0;
182}
183
184/**
185 * smk_set_access - add a rule to the rule list
186 * @srp: the new rule to add
187 *
188 * Looks through the current subject/object/access list for
189 * the subject/object pair and replaces the access that was
190 * there. If the pair isn't found add it with the specified
191 * access.
192 */
193static void smk_set_access(struct smack_rule *srp)
194{
195 struct smk_list_entry *sp;
196 struct smk_list_entry *newp;
197
198 mutex_lock(&smack_list_lock);
199
200 for (sp = smack_list; sp != NULL; sp = sp->smk_next)
201 if (sp->smk_rule.smk_subject == srp->smk_subject &&
202 sp->smk_rule.smk_object == srp->smk_object) {
203 sp->smk_rule.smk_access = srp->smk_access;
204 break;
205 }
206
207 if (sp == NULL) {
208 newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
209 newp->smk_rule = *srp;
210 newp->smk_next = smack_list;
211 smack_list = newp;
212 }
213
214 mutex_unlock(&smack_list_lock);
215
216 return;
217}
218
219/**
220 * smk_write_load - write() for /smack/load
221 * @filp: file pointer, not actually used
222 * @buf: where to get the data from
223 * @count: bytes sent
224 * @ppos: where to start - must be 0
225 *
226 * Get one smack access rule from above.
227 * The format is exactly:
228 * char subject[SMK_LABELLEN]
229 * char object[SMK_LABELLEN]
230 * char access[SMK_ACCESSKINDS]
231 *
232 * Anything following is commentary and ignored.
233 *
234 * writes must be SMK_LABELLEN+SMK_LABELLEN+4 bytes.
235 */
236#define MINIMUM_LOAD (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSKINDS)
237
238static ssize_t smk_write_load(struct file *file, const char __user *buf,
239 size_t count, loff_t *ppos)
240{
241 struct smack_rule rule;
242 char *data;
243 int rc = -EINVAL;
244
245 /*
246 * Must have privilege.
247 * No partial writes.
248 * Enough data must be present.
249 */
250 if (!capable(CAP_MAC_ADMIN))
251 return -EPERM;
252 if (*ppos != 0)
253 return -EINVAL;
254 if (count < MINIMUM_LOAD)
255 return -EINVAL;
256
257 data = kzalloc(count, GFP_KERNEL);
258 if (data == NULL)
259 return -ENOMEM;
260
261 if (copy_from_user(data, buf, count) != 0) {
262 rc = -EFAULT;
263 goto out;
264 }
265
266 rule.smk_subject = smk_import(data, 0);
267 if (rule.smk_subject == NULL)
268 goto out;
269
270 rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
271 if (rule.smk_object == NULL)
272 goto out;
273
274 rule.smk_access = 0;
275
276 switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
277 case '-':
278 break;
279 case 'r':
280 case 'R':
281 rule.smk_access |= MAY_READ;
282 break;
283 default:
284 goto out;
285 }
286
287 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
288 case '-':
289 break;
290 case 'w':
291 case 'W':
292 rule.smk_access |= MAY_WRITE;
293 break;
294 default:
295 goto out;
296 }
297
298 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
299 case '-':
300 break;
301 case 'x':
302 case 'X':
303 rule.smk_access |= MAY_EXEC;
304 break;
305 default:
306 goto out;
307 }
308
309 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
310 case '-':
311 break;
312 case 'a':
313 case 'A':
314 rule.smk_access |= MAY_READ;
315 break;
316 default:
317 goto out;
318 }
319
320 smk_set_access(&rule);
321 rc = count;
322
323out:
324 kfree(data);
325 return rc;
326}
327
328static const struct file_operations smk_load_ops = {
329 .open = smk_open_load,
330 .read = seq_read,
331 .llseek = seq_lseek,
332 .write = smk_write_load,
333 .release = smk_release_load,
334};
335
336/**
337 * smk_cipso_doi - initialize the CIPSO domain
338 */
339void smk_cipso_doi(void)
340{
341 int rc;
342 struct cipso_v4_doi *doip;
343 struct netlbl_audit audit_info;
344
345 rc = netlbl_cfg_map_del(NULL, &audit_info);
346 if (rc != 0)
347 printk(KERN_WARNING "%s:%d remove rc = %d\n",
348 __func__, __LINE__, rc);
349
350 doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
351 if (doip == NULL)
352 panic("smack: Failed to initialize cipso DOI.\n");
353 doip->map.std = NULL;
354 doip->doi = smk_cipso_doi_value;
355 doip->type = CIPSO_V4_MAP_PASS;
356 doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
357 for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
358 doip->tags[rc] = CIPSO_V4_TAG_INVALID;
359
360 rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
361 if (rc != 0)
362 printk(KERN_WARNING "%s:%d add rc = %d\n",
363 __func__, __LINE__, rc);
364}
365
366/*
367 * Seq_file read operations for /smack/cipso
368 */
369
370static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
371{
372 if (*pos == SEQ_READ_FINISHED)
373 return NULL;
374
375 return smack_known;
376}
377
378static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
379{
380 struct smack_known *skp = ((struct smack_known *) v)->smk_next;
381
382 /*
383 * Omit labels with no associated cipso value
384 */
385 while (skp != NULL && !skp->smk_cipso)
386 skp = skp->smk_next;
387
388 if (skp == NULL)
389 *pos = SEQ_READ_FINISHED;
390
391 return skp;
392}
393
394/*
395 * Print cipso labels in format:
396 * label level[/cat[,cat]]
397 */
398static int cipso_seq_show(struct seq_file *s, void *v)
399{
400 struct smack_known *skp = (struct smack_known *) v;
401 struct smack_cipso *scp = skp->smk_cipso;
402 char *cbp;
403 char sep = '/';
404 int cat = 1;
405 int i;
406 unsigned char m;
407
408 if (scp == NULL)
409 return 0;
410
411 seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
412
413 cbp = scp->smk_catset;
414 for (i = 0; i < SMK_LABELLEN; i++)
415 for (m = 0x80; m != 0; m >>= 1) {
416 if (m & cbp[i]) {
417 seq_printf(s, "%c%d", sep, cat);
418 sep = ',';
419 }
420 cat++;
421 }
422
423 seq_putc(s, '\n');
424
425 return 0;
426}
427
428static void cipso_seq_stop(struct seq_file *s, void *v)
429{
430 /* No-op */
431}
432
433static struct seq_operations cipso_seq_ops = {
434 .start = cipso_seq_start,
435 .stop = cipso_seq_stop,
436 .next = cipso_seq_next,
437 .show = cipso_seq_show,
438};
439
440/**
441 * smk_open_cipso - open() for /smack/cipso
442 * @inode: inode structure representing file
443 * @file: "cipso" file pointer
444 *
445 * Connect our cipso_seq_* operations with /smack/cipso
446 * file_operations
447 */
448static int smk_open_cipso(struct inode *inode, struct file *file)
449{
450 return seq_open(file, &cipso_seq_ops);
451}
452
453/**
454 * smk_write_cipso - write() for /smack/cipso
455 * @filp: file pointer, not actually used
456 * @buf: where to get the data from
457 * @count: bytes sent
458 * @ppos: where to start
459 *
460 * Accepts only one cipso rule per write call.
461 * Returns number of bytes written or error code, as appropriate
462 */
463static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
464 size_t count, loff_t *ppos)
465{
466 struct smack_known *skp;
467 struct smack_cipso *scp = NULL;
468 char mapcatset[SMK_LABELLEN];
469 int maplevel;
470 int cat;
471 int catlen;
472 ssize_t rc = -EINVAL;
473 char *data = NULL;
474 char *rule;
475 int ret;
476 int i;
477
478 /*
479 * Must have privilege.
480 * No partial writes.
481 * Enough data must be present.
482 */
483 if (!capable(CAP_MAC_ADMIN))
484 return -EPERM;
485 if (*ppos != 0)
486 return -EINVAL;
487 if (count <= SMK_CIPSOMIN)
488 return -EINVAL;
489
490 data = kzalloc(count + 1, GFP_KERNEL);
491 if (data == NULL)
492 return -ENOMEM;
493
494 if (copy_from_user(data, buf, count) != 0) {
495 rc = -EFAULT;
496 goto unlockedout;
497 }
498
499 data[count] = '\0';
500 rule = data;
501 /*
502 * Only allow one writer at a time. Writes should be
503 * quite rare and small in any case.
504 */
505 mutex_lock(&smack_cipso_lock);
506
507 skp = smk_import_entry(rule, 0);
508 if (skp == NULL)
509 goto out;
510
511 rule += SMK_LABELLEN;;
512 ret = sscanf(rule, "%d", &maplevel);
513 if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
514 goto out;
515
516 rule += SMK_DIGITLEN;
517 ret = sscanf(rule, "%d", &catlen);
518 if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
519 goto out;
520
521 if (count <= (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
522 goto out;
523
524 memset(mapcatset, 0, sizeof(mapcatset));
525
526 for (i = 0; i < catlen; i++) {
527 rule += SMK_DIGITLEN;
528 ret = sscanf(rule, "%d", &cat);
529 if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL)
530 goto out;
531
532 smack_catset_bit(cat, mapcatset);
533 }
534
535 if (skp->smk_cipso == NULL) {
536 scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
537 if (scp == NULL) {
538 rc = -ENOMEM;
539 goto out;
540 }
541 }
542
543 spin_lock_bh(&skp->smk_cipsolock);
544
545 if (scp == NULL)
546 scp = skp->smk_cipso;
547 else
548 skp->smk_cipso = scp;
549
550 scp->smk_level = maplevel;
551 memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset));
552
553 spin_unlock_bh(&skp->smk_cipsolock);
554
555 rc = count;
556out:
557 mutex_unlock(&smack_cipso_lock);
558unlockedout:
559 kfree(data);
560 return rc;
561}
562
563static const struct file_operations smk_cipso_ops = {
564 .open = smk_open_cipso,
565 .read = seq_read,
566 .llseek = seq_lseek,
567 .write = smk_write_cipso,
568 .release = seq_release,
569};
570
571/**
572 * smk_read_doi - read() for /smack/doi
573 * @filp: file pointer, not actually used
574 * @buf: where to put the result
575 * @count: maximum to send along
576 * @ppos: where to start
577 *
578 * Returns number of bytes read or error code, as appropriate
579 */
580static ssize_t smk_read_doi(struct file *filp, char __user *buf,
581 size_t count, loff_t *ppos)
582{
583 char temp[80];
584 ssize_t rc;
585
586 if (*ppos != 0)
587 return 0;
588
589 sprintf(temp, "%d", smk_cipso_doi_value);
590 rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
591
592 return rc;
593}
594
595/**
596 * smk_write_doi - write() for /smack/doi
597 * @filp: file pointer, not actually used
598 * @buf: where to get the data from
599 * @count: bytes sent
600 * @ppos: where to start
601 *
602 * Returns number of bytes written or error code, as appropriate
603 */
604static ssize_t smk_write_doi(struct file *file, const char __user *buf,
605 size_t count, loff_t *ppos)
606{
607 char temp[80];
608 int i;
609
610 if (!capable(CAP_MAC_ADMIN))
611 return -EPERM;
612
613 if (count >= sizeof(temp) || count == 0)
614 return -EINVAL;
615
616 if (copy_from_user(temp, buf, count) != 0)
617 return -EFAULT;
618
619 temp[count] = '\0';
620
621 if (sscanf(temp, "%d", &i) != 1)
622 return -EINVAL;
623
624 smk_cipso_doi_value = i;
625
626 smk_cipso_doi();
627
628 return count;
629}
630
631static const struct file_operations smk_doi_ops = {
632 .read = smk_read_doi,
633 .write = smk_write_doi,
634};
635
636/**
637 * smk_read_direct - read() for /smack/direct
638 * @filp: file pointer, not actually used
639 * @buf: where to put the result
640 * @count: maximum to send along
641 * @ppos: where to start
642 *
643 * Returns number of bytes read or error code, as appropriate
644 */
645static ssize_t smk_read_direct(struct file *filp, char __user *buf,
646 size_t count, loff_t *ppos)
647{
648 char temp[80];
649 ssize_t rc;
650
651 if (*ppos != 0)
652 return 0;
653
654 sprintf(temp, "%d", smack_cipso_direct);
655 rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
656
657 return rc;
658}
659
660/**
661 * smk_write_direct - write() for /smack/direct
662 * @filp: file pointer, not actually used
663 * @buf: where to get the data from
664 * @count: bytes sent
665 * @ppos: where to start
666 *
667 * Returns number of bytes written or error code, as appropriate
668 */
669static ssize_t smk_write_direct(struct file *file, const char __user *buf,
670 size_t count, loff_t *ppos)
671{
672 char temp[80];
673 int i;
674
675 if (!capable(CAP_MAC_ADMIN))
676 return -EPERM;
677
678 if (count >= sizeof(temp) || count == 0)
679 return -EINVAL;
680
681 if (copy_from_user(temp, buf, count) != 0)
682 return -EFAULT;
683
684 temp[count] = '\0';
685
686 if (sscanf(temp, "%d", &i) != 1)
687 return -EINVAL;
688
689 smack_cipso_direct = i;
690
691 return count;
692}
693
694static const struct file_operations smk_direct_ops = {
695 .read = smk_read_direct,
696 .write = smk_write_direct,
697};
698
699/**
700 * smk_read_ambient - read() for /smack/ambient
701 * @filp: file pointer, not actually used
702 * @buf: where to put the result
703 * @cn: maximum to send along
704 * @ppos: where to start
705 *
706 * Returns number of bytes read or error code, as appropriate
707 */
708static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
709 size_t cn, loff_t *ppos)
710{
711 ssize_t rc;
712 char out[SMK_LABELLEN];
713 int asize;
714
715 if (*ppos != 0)
716 return 0;
717 /*
718 * Being careful to avoid a problem in the case where
719 * smack_net_ambient gets changed in midstream.
720 * Since smack_net_ambient is always set with a value
721 * from the label list, including initially, and those
722 * never get freed, the worst case is that the pointer
723 * gets changed just after this strncpy, in which case
724 * the value passed up is incorrect. Locking around
725 * smack_net_ambient wouldn't be any better than this
726 * copy scheme as by the time the caller got to look
727 * at the ambient value it would have cleared the lock
728 * and been changed.
729 */
730 strncpy(out, smack_net_ambient, SMK_LABELLEN);
731 asize = strlen(out) + 1;
732
733 if (cn < asize)
734 return -EINVAL;
735
736 rc = simple_read_from_buffer(buf, cn, ppos, out, asize);
737
738 return rc;
739}
740
741/**
742 * smk_write_ambient - write() for /smack/ambient
743 * @filp: file pointer, not actually used
744 * @buf: where to get the data from
745 * @count: bytes sent
746 * @ppos: where to start
747 *
748 * Returns number of bytes written or error code, as appropriate
749 */
750static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
751 size_t count, loff_t *ppos)
752{
753 char in[SMK_LABELLEN];
754 char *smack;
755
756 if (!capable(CAP_MAC_ADMIN))
757 return -EPERM;
758
759 if (count >= SMK_LABELLEN)
760 return -EINVAL;
761
762 if (copy_from_user(in, buf, count) != 0)
763 return -EFAULT;
764
765 smack = smk_import(in, count);
766 if (smack == NULL)
767 return -EINVAL;
768
769 smack_net_ambient = smack;
770
771 return count;
772}
773
774static const struct file_operations smk_ambient_ops = {
775 .read = smk_read_ambient,
776 .write = smk_write_ambient,
777};
778
779struct option_names {
780 int o_number;
781 char *o_name;
782 char *o_alias;
783};
784
785static struct option_names netlbl_choices[] = {
786 { NETLBL_NLTYPE_RIPSO,
787 NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
788 { NETLBL_NLTYPE_CIPSOV4,
789 NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
790 { NETLBL_NLTYPE_CIPSOV4,
791 NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
792 { NETLBL_NLTYPE_CIPSOV6,
793 NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
794 { NETLBL_NLTYPE_UNLABELED,
795 NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
796};
797
798/**
799 * smk_read_nltype - read() for /smack/nltype
800 * @filp: file pointer, not actually used
801 * @buf: where to put the result
802 * @count: maximum to send along
803 * @ppos: where to start
804 *
805 * Returns number of bytes read or error code, as appropriate
806 */
807static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
808 size_t count, loff_t *ppos)
809{
810 char bound[40];
811 ssize_t rc;
812 int i;
813
814 if (count < SMK_LABELLEN)
815 return -EINVAL;
816
817 if (*ppos != 0)
818 return 0;
819
820 sprintf(bound, "unknown");
821
822 for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
823 if (smack_net_nltype == netlbl_choices[i].o_number) {
824 sprintf(bound, "%s", netlbl_choices[i].o_name);
825 break;
826 }
827
828 rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
829
830 return rc;
831}
832
833/**
834 * smk_write_nltype - write() for /smack/nltype
835 * @filp: file pointer, not actually used
836 * @buf: where to get the data from
837 * @count: bytes sent
838 * @ppos: where to start
839 *
840 * Returns number of bytes written or error code, as appropriate
841 */
842static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
843 size_t count, loff_t *ppos)
844{
845 char bound[40];
846 char *cp;
847 int i;
848
849 if (!capable(CAP_MAC_ADMIN))
850 return -EPERM;
851
852 if (count >= 40)
853 return -EINVAL;
854
855 if (copy_from_user(bound, buf, count) != 0)
856 return -EFAULT;
857
858 bound[count] = '\0';
859 cp = strchr(bound, ' ');
860 if (cp != NULL)
861 *cp = '\0';
862 cp = strchr(bound, '\n');
863 if (cp != NULL)
864 *cp = '\0';
865
866 for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
867 if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
868 strcmp(bound, netlbl_choices[i].o_alias) == 0) {
869 smack_net_nltype = netlbl_choices[i].o_number;
870 return count;
871 }
872 /*
873 * Not a valid choice.
874 */
875 return -EINVAL;
876}
877
878static const struct file_operations smk_nltype_ops = {
879 .read = smk_read_nltype,
880 .write = smk_write_nltype,
881};
882
883/**
884 * smk_fill_super - fill the /smackfs superblock
885 * @sb: the empty superblock
886 * @data: unused
887 * @silent: unused
888 *
889 * Fill in the well known entries for /smack
890 *
891 * Returns 0 on success, an error code on failure
892 */
893static int smk_fill_super(struct super_block *sb, void *data, int silent)
894{
895 int rc;
896 struct inode *root_inode;
897
898 static struct tree_descr smack_files[] = {
899 [SMK_LOAD] =
900 {"load", &smk_load_ops, S_IRUGO|S_IWUSR},
901 [SMK_CIPSO] =
902 {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
903 [SMK_DOI] =
904 {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
905 [SMK_DIRECT] =
906 {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
907 [SMK_AMBIENT] =
908 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
909 [SMK_NLTYPE] =
910 {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
911 /* last one */ {""}
912 };
913
914 rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
915 if (rc != 0) {
916 printk(KERN_ERR "%s failed %d while creating inodes\n",
917 __func__, rc);
918 return rc;
919 }
920
921 root_inode = sb->s_root->d_inode;
922 root_inode->i_security = new_inode_smack(smack_known_floor.smk_known);
923
924 return 0;
925}
926
927/**
928 * smk_get_sb - get the smackfs superblock
929 * @fs_type: passed along without comment
930 * @flags: passed along without comment
931 * @dev_name: passed along without comment
932 * @data: passed along without comment
933 * @mnt: passed along without comment
934 *
935 * Just passes everything along.
936 *
937 * Returns what the lower level code does.
938 */
939static int smk_get_sb(struct file_system_type *fs_type,
940 int flags, const char *dev_name, void *data,
941 struct vfsmount *mnt)
942{
943 return get_sb_single(fs_type, flags, data, smk_fill_super, mnt);
944}
945
946static struct file_system_type smk_fs_type = {
947 .name = "smackfs",
948 .get_sb = smk_get_sb,
949 .kill_sb = kill_litter_super,
950};
951
952static struct vfsmount *smackfs_mount;
953
954/**
955 * init_smk_fs - get the smackfs superblock
956 *
957 * register the smackfs
958 *
959 * Returns 0 unless the registration fails.
960 */
961static int __init init_smk_fs(void)
962{
963 int err;
964
965 err = register_filesystem(&smk_fs_type);
966 if (!err) {
967 smackfs_mount = kern_mount(&smk_fs_type);
968 if (IS_ERR(smackfs_mount)) {
969 printk(KERN_ERR "smackfs: could not mount!\n");
970 err = PTR_ERR(smackfs_mount);
971 smackfs_mount = NULL;
972 }
973 }
974
975 sema_init(&smack_write_sem, 1);
976 smk_cipso_doi();
977
978 return err;
979}
980
981__initcall(init_smk_fs);