aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2008-12-31 12:54:12 -0500
committerPaul Moore <paul.moore@hp.com>2008-12-31 12:54:12 -0500
commit6d3dc07cbb1e88deed2e8710e215f232a56b1dce (patch)
tree4c294d1ddac8c9f417bcd406771993aa58106f6d /security/smack/smackfs.c
parent277d342fc423fca5e66e677fe629d1b2f8f1b9e2 (diff)
smack: Add support for unlabeled network hosts and networks
Add support for unlabeled network hosts and networks. Relies heavily on Paul Moore's netlabel support. Creates a new entry in /smack called netlabel. Writes to /smack/netlabel take the form: A.B.C.D LABEL or A.B.C.D/N LABEL where A.B.C.D is a network address, N is an integer between 0-32, and LABEL is the Smack label to be used. If /N is omitted /32 is assumed. N designates the netmask for the address. Entries are matched by the most specific address/mask pair. 0.0.0.0/0 will match everything, while 192.168.1.117/32 will match exactly one host. A new system label "@", pronounced "web", is defined. Processes can not be assigned the web label. An address assigned the web label can be written to by any process, and packets coming from a web address can be written to any socket. Use of the web label is a violation of any strict MAC policy, but the web label has been requested many times. The nltype entry has been removed from /smack. It did not work right and the netlabel interface can be used to specify that all hosts be treated as unlabeled. CIPSO labels on incoming packets will be honored, even from designated single label hosts. Single label hosts can only be written to by processes with labels that can write to the label of the host. Packets sent to single label hosts will always be unlabeled. Once added a single label designation cannot be removed, however the label may be changed. The behavior of the ambient label remains unchanged. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Paul Moore <paul.moore@hp.com>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c364
1 files changed, 235 insertions, 129 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 594e934f1385..bf107a389ac1 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -20,6 +20,7 @@
20#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
21#include <linux/security.h> 21#include <linux/security.h>
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <net/net_namespace.h>
23#include <net/netlabel.h> 24#include <net/netlabel.h>
24#include <net/cipso_ipv4.h> 25#include <net/cipso_ipv4.h>
25#include <linux/seq_file.h> 26#include <linux/seq_file.h>
@@ -38,7 +39,7 @@ enum smk_inos {
38 SMK_DOI = 5, /* CIPSO DOI */ 39 SMK_DOI = 5, /* CIPSO DOI */
39 SMK_DIRECT = 6, /* CIPSO level indicating direct label */ 40 SMK_DIRECT = 6, /* CIPSO level indicating direct label */
40 SMK_AMBIENT = 7, /* internet ambient label */ 41 SMK_AMBIENT = 7, /* internet ambient label */
41 SMK_NLTYPE = 8, /* label scheme to use by default */ 42 SMK_NETLBLADDR = 8, /* single label hosts */
42 SMK_ONLYCAP = 9, /* the only "capable" label */ 43 SMK_ONLYCAP = 9, /* the only "capable" label */
43}; 44};
44 45
@@ -48,6 +49,7 @@ enum smk_inos {
48static DEFINE_MUTEX(smack_list_lock); 49static DEFINE_MUTEX(smack_list_lock);
49static DEFINE_MUTEX(smack_cipso_lock); 50static DEFINE_MUTEX(smack_cipso_lock);
50static DEFINE_MUTEX(smack_ambient_lock); 51static DEFINE_MUTEX(smack_ambient_lock);
52static DEFINE_MUTEX(smk_netlbladdr_lock);
51 53
52/* 54/*
53 * This is the "ambient" label for network traffic. 55 * This is the "ambient" label for network traffic.
@@ -57,12 +59,6 @@ static DEFINE_MUTEX(smack_ambient_lock);
57char *smack_net_ambient = smack_known_floor.smk_known; 59char *smack_net_ambient = smack_known_floor.smk_known;
58 60
59/* 61/*
60 * This is the default packet marking scheme for network traffic.
61 * It can be reset via smackfs/nltype
62 */
63int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
64
65/*
66 * This is the level in a CIPSO header that indicates a 62 * This is the level in a CIPSO header that indicates a
67 * smack label is contained directly in the category set. 63 * smack label is contained directly in the category set.
68 * It can be reset via smackfs/direct 64 * It can be reset via smackfs/direct
@@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
79 */ 75 */
80char *smack_onlycap; 76char *smack_onlycap;
81 77
78/*
79 * Certain IP addresses may be designated as single label hosts.
80 * Packets are sent there unlabeled, but only from tasks that
81 * can write to the specified label.
82 */
83struct smk_netlbladdr *smack_netlbladdrs;
84
82static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 85static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
83struct smk_list_entry *smack_list; 86struct smk_list_entry *smack_list;
84 87
@@ -104,6 +107,24 @@ struct smk_list_entry *smack_list;
104#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) 107#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
105#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) 108#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
106 109
110/**
111 * smk_netlabel_audit_set - fill a netlbl_audit struct
112 * @nap: structure to fill
113 */
114static void smk_netlabel_audit_set(struct netlbl_audit *nap)
115{
116 nap->loginuid = audit_get_loginuid(current);
117 nap->sessionid = audit_get_sessionid(current);
118 nap->secid = smack_to_secid(current_security());
119}
120
121/*
122 * Values for parsing single label host rules
123 * "1.2.3.4 X"
124 * "192.168.138.129/32 abcdefghijklmnopqrstuvw"
125 */
126#define SMK_NETLBLADDRMIN 9
127#define SMK_NETLBLADDRMAX 42
107 128
108/* 129/*
109 * Seq_file read operations for /smack/load 130 * Seq_file read operations for /smack/load
@@ -344,13 +365,11 @@ static void smk_cipso_doi(void)
344{ 365{
345 int rc; 366 int rc;
346 struct cipso_v4_doi *doip; 367 struct cipso_v4_doi *doip;
347 struct netlbl_audit audit_info; 368 struct netlbl_audit nai;
348 369
349 audit_info.loginuid = audit_get_loginuid(current); 370 smk_netlabel_audit_set(&nai);
350 audit_info.sessionid = audit_get_sessionid(current);
351 audit_info.secid = smack_to_secid(current_security());
352 371
353 rc = netlbl_cfg_map_del(NULL, PF_UNSPEC, NULL, NULL, &audit_info); 372 rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
354 if (rc != 0) 373 if (rc != 0)
355 printk(KERN_WARNING "%s:%d remove rc = %d\n", 374 printk(KERN_WARNING "%s:%d remove rc = %d\n",
356 __func__, __LINE__, rc); 375 __func__, __LINE__, rc);
@@ -365,15 +384,14 @@ static void smk_cipso_doi(void)
365 for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) 384 for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
366 doip->tags[rc] = CIPSO_V4_TAG_INVALID; 385 doip->tags[rc] = CIPSO_V4_TAG_INVALID;
367 386
368 rc = netlbl_cfg_cipsov4_add(doip, &audit_info); 387 rc = netlbl_cfg_cipsov4_add(doip, &nai);
369 if (rc != 0) { 388 if (rc != 0) {
370 printk(KERN_WARNING "%s:%d cipso add rc = %d\n", 389 printk(KERN_WARNING "%s:%d cipso add rc = %d\n",
371 __func__, __LINE__, rc); 390 __func__, __LINE__, rc);
372 kfree(doip); 391 kfree(doip);
373 return; 392 return;
374 } 393 }
375 rc = netlbl_cfg_cipsov4_map_add(doip->doi, 394 rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai);
376 NULL, NULL, NULL, &audit_info);
377 if (rc != 0) { 395 if (rc != 0) {
378 printk(KERN_WARNING "%s:%d map add rc = %d\n", 396 printk(KERN_WARNING "%s:%d map add rc = %d\n",
379 __func__, __LINE__, rc); 397 __func__, __LINE__, rc);
@@ -388,22 +406,19 @@ static void smk_cipso_doi(void)
388static void smk_unlbl_ambient(char *oldambient) 406static void smk_unlbl_ambient(char *oldambient)
389{ 407{
390 int rc; 408 int rc;
391 struct netlbl_audit audit_info; 409 struct netlbl_audit nai;
392 410
393 audit_info.loginuid = audit_get_loginuid(current); 411 smk_netlabel_audit_set(&nai);
394 audit_info.sessionid = audit_get_sessionid(current);
395 audit_info.secid = smack_to_secid(current_security());
396 412
397 if (oldambient != NULL) { 413 if (oldambient != NULL) {
398 rc = netlbl_cfg_map_del(oldambient, 414 rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai);
399 PF_UNSPEC, NULL, NULL, &audit_info);
400 if (rc != 0) 415 if (rc != 0)
401 printk(KERN_WARNING "%s:%d remove rc = %d\n", 416 printk(KERN_WARNING "%s:%d remove rc = %d\n",
402 __func__, __LINE__, rc); 417 __func__, __LINE__, rc);
403 } 418 }
404 419
405 rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, 420 rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
406 PF_INET, NULL, NULL, &audit_info); 421 NULL, NULL, &nai);
407 if (rc != 0) 422 if (rc != 0)
408 printk(KERN_WARNING "%s:%d add rc = %d\n", 423 printk(KERN_WARNING "%s:%d add rc = %d\n",
409 __func__, __LINE__, rc); 424 __func__, __LINE__, rc);
@@ -614,6 +629,201 @@ static const struct file_operations smk_cipso_ops = {
614 .release = seq_release, 629 .release = seq_release,
615}; 630};
616 631
632/*
633 * Seq_file read operations for /smack/netlabel
634 */
635
636static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
637{
638 if (*pos == SEQ_READ_FINISHED)
639 return NULL;
640
641 return smack_netlbladdrs;
642}
643
644static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
645{
646 struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
647
648 if (skp == NULL)
649 *pos = SEQ_READ_FINISHED;
650
651 return skp;
652}
653/*
654#define BEMASK 0x80000000
655*/
656#define BEMASK 0x00000001
657#define BEBITS (sizeof(__be32) * 8)
658
659/*
660 * Print host/label pairs
661 */
662static int netlbladdr_seq_show(struct seq_file *s, void *v)
663{
664 struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
665 unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
666 __be32 bebits;
667 int maskn = 0;
668
669 for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1)
670 if ((skp->smk_mask.s_addr & bebits) == 0)
671 break;
672
673 seq_printf(s, "%u.%u.%u.%u/%d %s\n",
674 hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
675
676 return 0;
677}
678
679static void netlbladdr_seq_stop(struct seq_file *s, void *v)
680{
681 /* No-op */
682}
683
684static struct seq_operations netlbladdr_seq_ops = {
685 .start = netlbladdr_seq_start,
686 .stop = netlbladdr_seq_stop,
687 .next = netlbladdr_seq_next,
688 .show = netlbladdr_seq_show,
689};
690
691/**
692 * smk_open_netlbladdr - open() for /smack/netlabel
693 * @inode: inode structure representing file
694 * @file: "netlabel" file pointer
695 *
696 * Connect our netlbladdr_seq_* operations with /smack/netlabel
697 * file_operations
698 */
699static int smk_open_netlbladdr(struct inode *inode, struct file *file)
700{
701 return seq_open(file, &netlbladdr_seq_ops);
702}
703
704/**
705 * smk_write_netlbladdr - write() for /smack/netlabel
706 * @filp: file pointer, not actually used
707 * @buf: where to get the data from
708 * @count: bytes sent
709 * @ppos: where to start
710 *
711 * Accepts only one netlbladdr per write call.
712 * Returns number of bytes written or error code, as appropriate
713 */
714static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
715 size_t count, loff_t *ppos)
716{
717 struct smk_netlbladdr *skp;
718 struct sockaddr_in newname;
719 char smack[SMK_LABELLEN];
720 char *sp;
721 char data[SMK_NETLBLADDRMAX];
722 char *host = (char *)&newname.sin_addr.s_addr;
723 int rc;
724 struct netlbl_audit audit_info;
725 struct in_addr mask;
726 unsigned int m;
727 __be32 bebits = BEMASK;
728 __be32 nsa;
729
730 /*
731 * Must have privilege.
732 * No partial writes.
733 * Enough data must be present.
734 * "<addr/mask, as a.b.c.d/e><space><label>"
735 * "<addr, as a.b.c.d><space><label>"
736 */
737 if (!capable(CAP_MAC_ADMIN))
738 return -EPERM;
739 if (*ppos != 0)
740 return -EINVAL;
741 if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX)
742 return -EINVAL;
743 if (copy_from_user(data, buf, count) != 0)
744 return -EFAULT;
745
746 data[count] = '\0';
747
748 rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s",
749 &host[0], &host[1], &host[2], &host[3], &m, smack);
750 if (rc != 6) {
751 rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
752 &host[0], &host[1], &host[2], &host[3], smack);
753 if (rc != 5)
754 return -EINVAL;
755 m = BEBITS;
756 }
757 if (m > BEBITS)
758 return -EINVAL;
759
760 sp = smk_import(smack, 0);
761 if (sp == NULL)
762 return -EINVAL;
763
764 for (mask.s_addr = 0; m > 0; m--) {
765 mask.s_addr |= bebits;
766 bebits <<= 1;
767 }
768 /*
769 * Only allow one writer at a time. Writes should be
770 * quite rare and small in any case.
771 */
772 mutex_lock(&smk_netlbladdr_lock);
773
774 nsa = newname.sin_addr.s_addr;
775 for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
776 if (skp->smk_host.sin_addr.s_addr == nsa &&
777 skp->smk_mask.s_addr == mask.s_addr)
778 break;
779
780 smk_netlabel_audit_set(&audit_info);
781
782 if (skp == NULL) {
783 skp = kzalloc(sizeof(*skp), GFP_KERNEL);
784 if (skp == NULL)
785 rc = -ENOMEM;
786 else {
787 rc = 0;
788 skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
789 skp->smk_mask.s_addr = mask.s_addr;
790 skp->smk_next = smack_netlbladdrs;
791 skp->smk_label = sp;
792 smack_netlbladdrs = skp;
793 }
794 } else {
795 rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
796 &skp->smk_host.sin_addr, &skp->smk_mask,
797 PF_INET, &audit_info);
798 skp->smk_label = sp;
799 }
800
801 /*
802 * Now tell netlabel about the single label nature of
803 * this host so that incoming packets get labeled.
804 */
805
806 if (rc == 0)
807 rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
808 &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
809 smack_to_secid(skp->smk_label), &audit_info);
810
811 if (rc == 0)
812 rc = count;
813
814 mutex_unlock(&smk_netlbladdr_lock);
815
816 return rc;
817}
818
819static const struct file_operations smk_netlbladdr_ops = {
820 .open = smk_open_netlbladdr,
821 .read = seq_read,
822 .llseek = seq_lseek,
823 .write = smk_write_netlbladdr,
824 .release = seq_release,
825};
826
617/** 827/**
618 * smk_read_doi - read() for /smack/doi 828 * smk_read_doi - read() for /smack/doi
619 * @filp: file pointer, not actually used 829 * @filp: file pointer, not actually used
@@ -902,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = {
902 .write = smk_write_onlycap, 1112 .write = smk_write_onlycap,
903}; 1113};
904 1114
905struct option_names {
906 int o_number;
907 char *o_name;
908 char *o_alias;
909};
910
911static struct option_names netlbl_choices[] = {
912 { NETLBL_NLTYPE_RIPSO,
913 NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
914 { NETLBL_NLTYPE_CIPSOV4,
915 NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
916 { NETLBL_NLTYPE_CIPSOV4,
917 NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
918 { NETLBL_NLTYPE_CIPSOV6,
919 NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
920 { NETLBL_NLTYPE_UNLABELED,
921 NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
922};
923
924/**
925 * smk_read_nltype - read() for /smack/nltype
926 * @filp: file pointer, not actually used
927 * @buf: where to put the result
928 * @count: maximum to send along
929 * @ppos: where to start
930 *
931 * Returns number of bytes read or error code, as appropriate
932 */
933static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
934 size_t count, loff_t *ppos)
935{
936 char bound[40];
937 ssize_t rc;
938 int i;
939
940 if (count < SMK_LABELLEN)
941 return -EINVAL;
942
943 if (*ppos != 0)
944 return 0;
945
946 sprintf(bound, "unknown");
947
948 for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
949 if (smack_net_nltype == netlbl_choices[i].o_number) {
950 sprintf(bound, "%s", netlbl_choices[i].o_name);
951 break;
952 }
953
954 rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
955
956 return rc;
957}
958
959/**
960 * smk_write_nltype - write() for /smack/nltype
961 * @filp: file pointer, not actually used
962 * @buf: where to get the data from
963 * @count: bytes sent
964 * @ppos: where to start
965 *
966 * Returns number of bytes written or error code, as appropriate
967 */
968static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
969 size_t count, loff_t *ppos)
970{
971 char bound[40];
972 char *cp;
973 int i;
974
975 if (!capable(CAP_MAC_ADMIN))
976 return -EPERM;
977
978 if (count >= 40)
979 return -EINVAL;
980
981 if (copy_from_user(bound, buf, count) != 0)
982 return -EFAULT;
983
984 bound[count] = '\0';
985 cp = strchr(bound, ' ');
986 if (cp != NULL)
987 *cp = '\0';
988 cp = strchr(bound, '\n');
989 if (cp != NULL)
990 *cp = '\0';
991
992 for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
993 if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
994 strcmp(bound, netlbl_choices[i].o_alias) == 0) {
995 smack_net_nltype = netlbl_choices[i].o_number;
996 return count;
997 }
998 /*
999 * Not a valid choice.
1000 */
1001 return -EINVAL;
1002}
1003
1004static const struct file_operations smk_nltype_ops = {
1005 .read = smk_read_nltype,
1006 .write = smk_write_nltype,
1007};
1008
1009/** 1115/**
1010 * smk_fill_super - fill the /smackfs superblock 1116 * smk_fill_super - fill the /smackfs superblock
1011 * @sb: the empty superblock 1117 * @sb: the empty superblock
@@ -1032,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
1032 {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, 1138 {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
1033 [SMK_AMBIENT] = 1139 [SMK_AMBIENT] =
1034 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, 1140 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
1035 [SMK_NLTYPE] = 1141 [SMK_NETLBLADDR] =
1036 {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, 1142 {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
1037 [SMK_ONLYCAP] = 1143 [SMK_ONLYCAP] =
1038 {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, 1144 {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
1039 /* last one */ {""} 1145 /* last one */ {""}