diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/Kconfig linux-2.6.22/security/Kconfig --- linux-2.6.22-base/security/Kconfig 2007-07-08 16:32:17.000000000 -0700 +++ linux-2.6.22/security/Kconfig 2007-07-10 01:08:05.000000000 -0700 @@ -94,6 +94,7 @@ config SECURITY_ROOTPLUG If you are unsure how to answer this question, answer N. source security/selinux/Kconfig +source security/smack/Kconfig endmenu diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/Makefile linux-2.6.22/security/Makefile --- linux-2.6.22-base/security/Makefile 2007-07-08 16:32:17.000000000 -0700 +++ linux-2.6.22/security/Makefile 2007-07-10 01:08:05.000000000 -0700 @@ -4,6 +4,7 @@ obj-$(CONFIG_KEYS) += keys/ subdir-$(CONFIG_SECURITY_SELINUX) += selinux +subdir-$(CONFIG_SECURITY_SMACK) += smack # if we don't select a security model, use the default capabilities ifneq ($(CONFIG_SECURITY),y) @@ -14,5 +15,6 @@ endif obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o +obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/smack/Kconfig linux-2.6.22/security/smack/Kconfig --- linux-2.6.22-base/security/smack/Kconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.22/security/smack/Kconfig 2007-07-10 01:08:05.000000000 -0700 @@ -0,0 +1,10 @@ +config SECURITY_SMACK + bool "Simplified Mandatory Access Control Kernel Support" + depends on NETLABEL && SECURITY_NETWORK + default n + help + This selects the Simplified Mandatory Access Control Kernel. + SMACK is useful for sensitivity, integrity, and a variety + of other madatory security schemes. + If you are unsure how to answer this question, answer N. + diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/smack/Makefile linux-2.6.22/security/smack/Makefile --- linux-2.6.22-base/security/smack/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.22/security/smack/Makefile 2007-07-10 01:08:05.000000000 -0700 @@ -0,0 +1,8 @@ +# +# Makefile for the SMACK LSM +# + +obj-$(CONFIG_SECURITY_SMACK) := smack.o + +smack-y := smack_lsm.o smack_access.o smackfs.o + diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/smack/smack_access.c linux-2.6.22/security/smack/smack_access.c --- linux-2.6.22-base/security/smack/smack_access.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.22/security/smack/smack_access.c 2007-07-24 15:36:18.000000000 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2007 Casey Schaufler <[EMAIL PROTECTED]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * Author: + * Casey Schaufler <[EMAIL PROTECTED]> + * + */ + +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include "smack.h" + +extern struct smk_list_entry *smack_list; + +static int smk_get_access(smack_t sub, smack_t obj) +{ + struct smk_list_entry *sp = smack_list; + + for (; sp != NULL; sp = sp->smk_next) + if (sp->smk_rule.smk_subject == sub && + sp->smk_rule.smk_object == obj) + return sp->smk_rule.smk_access; + /* + * No access is explicitly defined for this pair. + */ + return MAY_NOT; +} + +int smk_access(smack_t *sub_label, smack_t *obj_label, int request) +{ + smack_t sub = *sub_label; + smack_t obj = *obj_label; + /* + * Hardcoded comparisons. + * + * A star subject can't access any object. + */ + if (sub == SMK_STAR) + return -EACCES; + /* + * A star object can be accessed by any subject. + */ + if (obj == SMK_STAR) + return 0; + /* + * An object can be accessed in any way by a subject + * with the same label. + */ + if (sub == obj) + return 0; + /* + * A hat subject can read any object. + * A floor object can be read by any subject. + */ + if (sub == SMK_HAT && ((request & MAY_ANYREAD) == request)) + return 0; + + if (obj == SMK_FLOOR && ((request & MAY_ANYREAD) == request)) + return 0; + /* + * Beyond here an explicit relationship is required. + * If the requested access is contained in the available + * access (e.g. read is included in readwrite) it's + * good. + * + * Yes, that is supposed to be a single ampersand. + */ + if ((request & smk_get_access(sub, obj)) == request) + return 0; + + return -EACCES; +} + +int smk_curacc(smack_t *obj_label, u32 mode) +{ + struct task_smack *tsp = current->security; + int rc; + + rc = smk_access(&tsp->smk_task, obj_label, mode); + if (rc == 0) + return 0; + + if (capable(CAP_MAC_OVERRIDE)) + return 0; + + return rc; +} + +/* + * The value that this adds is that everything after any + * character that's not allowed in a smack will be null + */ +smack_t smk_from_string(char *str) +{ + smack_t smack = 0LL; + char *cp; + int i; + + for (cp = (char *)&smack, i = 0; i < sizeof(smack_t); str++,cp++,i++) { + if (*str <= ' ' || *str > '~') + return smack; + *cp = *str; + } + /* + * Too long. + */ + return SMK_INVALID; +} diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/smack/smackfs.c linux-2.6.22/security/smack/smackfs.c --- linux-2.6.22-base/security/smack/smackfs.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.22/security/smack/smackfs.c 2007-07-24 21:51:30.000000000 -0700 @@ -0,0 +1,994 @@ +/* + * Copyright (C) 2007 Casey Schaufler <[EMAIL PROTECTED]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * Author: + * Casey Schaufler <[EMAIL PROTECTED]> + * + * Special thanks to the authors of selinuxfs. They had a good idea. + * + * Karl MacMillan <[EMAIL PROTECTED]> + * James Morris <[EMAIL PROTECTED]> + * + */ + +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/security.h> +#include <linux/mutex.h> +#include <net/netlabel.h> +#include "../../net/netlabel/netlabel_domainhash.h" +#include <net/cipso_ipv4.h> +#include "smack.h" + +/* + * smackfs pseudo filesystem. + */ + + +enum smk_inos { + SMK_ROOT_INO = 2, + SMK_LOAD = 3, /* load policy */ + SMK_LINKS = 4, /* symlinks */ + SMK_CIPSO = 5, /* load label -> CIPSO mapping */ + SMK_DOI = 6, /* CIPSO DOI */ + SMK_DIRECT = 7, /* CIPSO level indicating direct label */ + SMK_AMBIENT = 8, /* internet ambient label */ + SMK_NLTYPE = 9, /* label scheme to use by default */ + SMK_TMP = 100, /* MUST BE LAST! /smack/tmp */ +}; + +/* + * This is the "ambient" label for network traffic. + * If it isn't somehow marked, use this. + * It can be reset via smackfs/ambient + */ +smack_t smack_net_ambient = SMK_FLOOR; + +/* + * This is the default packet marking scheme for network traffic. + * It can be reset via smackfs/nltype + */ +int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4; + +/* + * This is the level in a CIPSO header that indicates a + * smack label is contained directly in the category set. + * It can be reset via smackfs/direct + */ +int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; +static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; + +static struct smk_cipso_entry smack_cipso_floor = { + .smk_next = NULL, + .smk_smack = SMK_FLOOR, + .smk_level = 0, + .smk_catset = 0LL, +}; +struct smk_cipso_entry *smack_cipso = &smack_cipso_floor; +static DEFINE_MUTEX(smack_cipso_lock); + +static int smack_list_count; +struct smk_list_entry *smack_list; +static DEFINE_MUTEX(smack_list_lock); + +/* + * 'ssssssss oooooooo mmmm\n\0' + */ +#define SMACK_RULE_LINE_SIZE (2 * (sizeof(smack_t) + 1) + 6) + +static ssize_t smk_read_load(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t bytes; + struct smk_list_entry *slp = smack_list; + struct smack_rule *srp; + char *result; + char *cp; + int realbytes = 0; + + bytes = SMACK_RULE_LINE_SIZE * smack_list_count; + if (bytes == 0) + return 0; + + result = kzalloc(bytes, GFP_KERNEL); + if (result == NULL) + return -ENOMEM; + + for (cp = result; slp != NULL; slp = slp->smk_next) { + srp = &slp->smk_rule; + sprintf(cp, "%-8s %-8s", + (char *)&srp->smk_subject, (char *)&srp->smk_object); + cp += strlen(cp); + if (srp->smk_access != 0) + *cp++ = ' '; + if ((srp->smk_access & MAY_READ) != 0) + *cp++ = 'r'; + if ((srp->smk_access & MAY_WRITE) != 0) + *cp++ = 'w'; + if ((srp->smk_access & MAY_EXEC) != 0) + *cp++ = 'x'; + if ((srp->smk_access & MAY_APPEND) != 0) + *cp++ = 'a'; + *cp++ = '\n'; + } + *cp++ = '\0'; + realbytes = strlen(result); + + bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes); + + kfree(result); + + return bytes; +} + +/* + * For purposes of SMACK: + * append is a form of write + * exec is a form of read + * This isn't reflected here, but I thought I should mention it. + */ + +static void smk_set_access(struct smack_rule *srp) +{ + struct smk_list_entry *sp; + struct smk_list_entry *newp; + + mutex_lock(&smack_list_lock); + + for (sp = smack_list; sp != NULL; sp = sp->smk_next) + if (sp->smk_rule.smk_subject == srp->smk_subject && + sp->smk_rule.smk_object == srp->smk_object) { + sp->smk_rule.smk_access = srp->smk_access; + break; + } + + if (sp == NULL) { + newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL); + newp->smk_rule = *srp; + newp->smk_next = smack_list; + smack_list = newp; + smack_list_count++; + } + + mutex_unlock(&smack_list_lock); + + return; +} + + +static ssize_t smk_write_load(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct smack_rule rule; + ssize_t rc = count; + char *data = NULL; + char modestr[8]; + char *cp; + + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + /* + * No partial writes. + */ + if (*ppos != 0) + return -EINVAL; + + /* + * 80 characters per line ought to be enough. + */ + if (count > SMACK_LIST_MAX * 80) + return -ENOMEM; + + data = kzalloc(count + 1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + if (copy_from_user(data, buf, count) != 0) { + kfree(data); + return -EFAULT; + } + + *(data + count) = '\0'; + + for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) { + if (*++cp == '\0') + break; + if (sscanf(cp, "%7s %7s %7s\n", + (char *)&rule.smk_subject, + (char *)&rule.smk_object, modestr) != 3) { + printk("%s:%d bad scan\n", + __FUNCTION__, __LINE__); + break; + } + rule.smk_subject = + smk_from_string((char *)&rule.smk_subject); + if (rule.smk_subject == SMK_INVALID) + break; + rule.smk_object = + smk_from_string((char *)&rule.smk_object); + if (rule.smk_object == SMK_INVALID) + break; + rule.smk_access = 0; + if (strchr(modestr, 'r') || strchr(modestr, 'R')) + rule.smk_access |= MAY_READ; + if (strchr(modestr, 'w') || strchr(modestr, 'W')) + rule.smk_access |= MAY_WRITE; + if (strchr(modestr, 'x') || strchr(modestr, 'X')) + rule.smk_access |= MAY_EXEC; + if (strchr(modestr, 'a') || strchr(modestr, 'A')) + rule.smk_access |= MAY_APPEND; + smk_set_access(&rule); + printk("%s:%d rule %s %s 0x%x\n", + __FUNCTION__, __LINE__, + (char *)&rule.smk_subject, + (char *)&rule.smk_object, + rule.smk_access); + } + + kfree(data); + return rc; +} + +static struct file_operations smk_load_ops = { + .read = smk_read_load, + .write = smk_write_load, +}; + +static char *smk_digit(char *cp) +{ + for (; *cp != '\0'; cp++) + if (*cp >= '0' && *cp <= '9') + return cp; + + return NULL; +} + +static int smk_cipso_doied; +static int smk_cipso_written; + +/* + * This code reaches too deeply into netlabel internals + * for comfort, however there is no netlabel KAPI that + * allows for kernel based initialization of a CIPSO DOI. + * Until Paul and Casey can work out an appropriate + * interface Smack will do it this way. + */ +static void smk_cipso_doi(void) +{ + int rc; + struct cipso_v4_doi *doip; + struct netlbl_dom_map *ndmp; + struct netlbl_audit audit_info; + + if (smk_cipso_doied != 0) + return; + smk_cipso_doied = 1; + + doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL); + if (doip == NULL) + panic("smack: Failed to initialize cipso DOI.\n"); + doip->map.std = NULL; + + ndmp = kmalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL); + if (ndmp == NULL) + panic("smack: Failed to initialize cipso ndmp.\n"); + + doip->doi = smk_cipso_doi_value; + doip->type = CIPSO_V4_MAP_PASS; + doip->tags[0] = CIPSO_V4_TAG_RBITMAP; + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) + doip->tags[rc] = CIPSO_V4_TAG_INVALID; + + rc = cipso_v4_doi_add(doip); + if (rc != 0) + printk("%s:%d add doi rc = %d\n", __FUNCTION__, __LINE__, rc); + + ndmp->domain = NULL; + ndmp->type = NETLBL_NLTYPE_CIPSOV4; + ndmp->type_def.cipsov4 = doip; + + rc = netlbl_domhsh_remove_default(&audit_info); + if (rc != 0) + printk("%s:%d remove rc = %d\n", __FUNCTION__, __LINE__, rc); + + rc = netlbl_domhsh_add_default(ndmp, &audit_info); + if (rc != 0) + printk("%s:%d add rc = %d\n", __FUNCTION__, __LINE__, rc); +} + +/* + * label level[/cat[,cat]] + */ +static ssize_t smk_read_cipso(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t bytes; + struct smk_cipso_entry *slp = smack_cipso; + char sep; + char *result; + char *cp; + char *cbp; + int realbytes = 0; + int cat = -1; + unsigned char m; + + smk_cipso_doi(); + + result = kzalloc(smk_cipso_written, GFP_KERNEL); + if (result == NULL) + return -ENOMEM; + cp = result; + + for (slp = smack_cipso; slp != NULL; slp = slp->smk_next) { + sprintf(cp, "%-8s %3d", (char *)&slp->smk_smack,slp->smk_level); + cp += strlen(cp); + cat = 1; + sep = '/'; + for (cbp = (char *)&slp->smk_catset; *cbp != 0; cbp++) { + for (m = 0x80; m != 0; m >>= 1) { + if ((m & *cbp) != 0) { + sprintf(cp, "%c%d", sep, cat); + cp += strlen(cp); + sep = ','; + } + cat++; + } + } + *cp++ = '\n'; + } + *cp++ = '\0'; + realbytes = strlen(result); + + bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes); + + kfree(result); + + return bytes; +} + +static ssize_t smk_write_cipso(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct smk_cipso_entry *scp; + smack_t mapsmack; + smack_t mapcatset; + int maplevel; + ssize_t rc = count; + char *data = NULL; + char *cp; + char *eolp; + char *linep; + int cat; + int i; + + smk_cipso_doi(); + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + /* + * No partial writes. + */ + if (*ppos != 0) + return -EINVAL; + /* + * 80 characters per line ought to be enough. + */ + if (count > SMACK_LIST_MAX * 80) + return -ENOMEM; + + data = kzalloc(count + 1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + if (copy_from_user(data, buf, count) != 0) { + kfree(data); + return -EFAULT; + } + + *(data + count) = '\0'; + smk_cipso_written += count; + + for (eolp = strchr(data, '\n'), linep = data; + eolp != NULL && rc >= 0; + linep = eolp + 1, eolp = strchr(linep, '\n')) { + + if (eolp == linep) + continue; + *eolp = '\0'; + + mapsmack = smk_from_string(linep); + mapcatset = 0ll; + + if (mapsmack == SMK_INVALID) + continue; + + cp = smk_digit(linep + strlen((char *)&mapsmack)); + if (cp == NULL) + continue; + + i = sscanf(cp, "%d", &maplevel); + if (i != 1) + continue; + + cp = strchr(cp, '/'); + if (cp != NULL) { + cp = smk_digit(cp); + if (cp == NULL) + continue; + + do { + i = sscanf(cp, "%d", &cat); + if (i != 1) + break; + if (cat > SMACK_CIPSO_MAXCAT) { + i = 0; + break; + } + smack_catset_bit(cat, &mapcatset); + + cp = strchr(cp, ','); + if (cp != NULL) + cp = smk_digit(cp); + } while (cp != NULL); + } + + if (i != 1) + continue; + + mutex_lock(&smack_cipso_lock); + + for (scp = smack_cipso; scp != NULL; scp = scp->smk_next) + if (mapsmack == scp->smk_smack) + break; + + if (scp == NULL) { + scp = kzalloc(sizeof(struct smk_cipso_entry), + GFP_KERNEL); + if (scp == NULL) + rc = -ENOMEM; + else { + scp->smk_next = smack_cipso; + scp->smk_smack = mapsmack; + scp->smk_level = maplevel; + scp->smk_catset = mapcatset; + smack_cipso = scp; + /* + * Add this to ensure that there are + * enough bytes for the regurgitation + */ + smk_cipso_written += sizeof(smack_t); + } + } + + mutex_unlock(&smack_cipso_lock); + } + + kfree(data); + return rc; +} + +static struct file_operations smk_cipso_ops = { + .read = smk_read_cipso, + .write = smk_write_cipso, +}; + +static ssize_t smk_read_doi(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + ssize_t rc; + + if (*ppos != 0) + return 0; + + sprintf(temp, "%d", smk_cipso_doi_value); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +} + +static ssize_t smk_write_doi(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + int i; + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + + if (count > sizeof(temp)) + return -EINVAL; + + if (copy_from_user(temp, buf, count) != 0) + return -EFAULT; + + if (sscanf(temp, "%d", &i) != 1) + return -EINVAL; + + smk_cipso_doi_value = i; + + return count; +} + +static struct file_operations smk_doi_ops = { + .read = smk_read_doi, + .write = smk_write_doi, +}; + +static ssize_t smk_read_direct(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + ssize_t rc; + + if (*ppos != 0) + return 0; + + sprintf(temp, "%d", smack_cipso_direct); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + + return rc; +} + +static ssize_t smk_write_direct(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[80]; + int i; + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + + if (count > sizeof(temp)) + return -EINVAL; + + if (copy_from_user(temp, buf, count) != 0) + return -EFAULT; + + if (sscanf(temp, "%d", &i) != 1) + return -EINVAL; + + smack_cipso_direct = i; + + return count; +} + +static struct file_operations smk_direct_ops = { + .read = smk_read_direct, + .write = smk_write_direct, +}; + +static ssize_t smk_read_ambient(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rc; + + if (count < sizeof(smack_t)) + return -EINVAL; + + if (*ppos != 0) + return 0; + + rc = simple_read_from_buffer(buf, count, ppos, &smack_net_ambient, + sizeof(smack_t)); + + return rc; +} + +static ssize_t smk_write_ambient(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + smack_t smack; + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + + if (count > sizeof(smack_t)) + return -EINVAL; + + if (copy_from_user(&smack, buf, count) != 0) + return -EFAULT; + + smack = smk_from_buffer(&smack, count); + if (smack == SMK_INVALID) + return -EINVAL; + /* + * Better check to be sure this is OK. + */ + smack_net_ambient = smack; + + return count; +} + +static struct file_operations smk_ambient_ops = { + .read = smk_read_ambient, + .write = smk_write_ambient, +}; + +struct option_names { + int o_number; + char *o_name; + char *o_alias; +}; + +static struct option_names netlbl_choices[] = { + { NETLBL_NLTYPE_RIPSO, + NETLBL_NLTYPE_RIPSO_NAME, "ripso" }, + { NETLBL_NLTYPE_CIPSOV4, + NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" }, + { NETLBL_NLTYPE_CIPSOV4, + NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" }, + { NETLBL_NLTYPE_CIPSOV6, + NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" }, + { NETLBL_NLTYPE_UNLABELED, + NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" }, +}; +#define NCHOICES (sizeof(netlbl_choices) / sizeof(struct option_names)) + +static ssize_t smk_read_nltype(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char bound[40]; + ssize_t rc; + int i; + + if (count < sizeof(smack_t)) + return -EINVAL; + + if (*ppos != 0) + return 0; + + sprintf(bound, "unknown"); + + for (i = 0; i < NCHOICES; i++) + if (smack_net_nltype == netlbl_choices[i].o_number) { + sprintf(bound, "%s", netlbl_choices[i].o_name); + break; + } + + rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound)); + + return rc; +} + +static ssize_t smk_write_nltype(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char bound[40]; + char *cp; + int i; + + if (!capable(CAP_MAC_OVERRIDE)) + return -EPERM; + + if (count >= 40) + return -EINVAL; + + if (copy_from_user(bound, buf, count) != 0) + return -EFAULT; + + bound[count] = '\0'; + cp = strchr(bound, ' '); + if (cp != NULL) + *cp = '\0'; + cp = strchr(bound, '\n'); + if (cp != NULL) + *cp = '\0'; + + for (i = 0; i < NCHOICES; i++) + if ((strcmp(bound, netlbl_choices[i].o_name) == 0) || + (strcmp(bound, netlbl_choices[i].o_alias) == 0)) { + smack_net_nltype = netlbl_choices[i].o_number; + return count; + } + /* + * Not a valid choice. + */ + return -EINVAL; +} + +static struct file_operations smk_nltype_ops = { + .read = smk_read_nltype, + .write = smk_write_nltype, +}; + +/* + * mapping for symlinks + */ +#define SMK_TMPPATH_SIZE 32 +#define SMK_TMPPATH_ROOT "/moldy/" + +struct smk_link { + struct smk_link *sl_next; + int sl_inum; + char sl_name[SMK_TMPPATH_SIZE]; + char sl_target[SMK_TMPPATH_SIZE]; +}; + +static struct super_block *smk_sb = NULL; +static struct smk_link *smk_links = NULL; +static int smk_links_count = 0; + +static void *smackfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct task_smack *tsp = current->security; + smack_t *sp = &tsp->smk_task; + char *cp; + int inum = dentry->d_inode->i_ino; + struct smk_link *slp; + + for (slp = smk_links; slp != NULL; slp = slp->sl_next) + if (slp->sl_inum == inum) + break; + + if (slp == NULL) { + printk("%s:%d failed\n", __FUNCTION__, __LINE__); + return NULL; + } + cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL); + if (cp == NULL) + return NULL; + + strcpy(cp, slp->sl_target); + strcat(cp, (char *)sp); + nd_set_link(nd, cp); + /* + * Unlike the relink below, hang on to the memory allocated + * because nd_set_link passes it along. + */ + return NULL; +} + +static int smackfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) +{ + smack_t *csp = smk_of_task(current); + char *cp; + int len; + int inum = dentry->d_inode->i_ino; + struct smk_link *slp; + + for (slp = smk_links; slp != NULL; slp = slp->sl_next) + if (slp->sl_inum == inum) + break; + + if (slp == NULL) { + printk("%s:%d failed\n", __FUNCTION__, __LINE__); + return -EACCES; + } + + cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL); + if (cp == NULL) + return -ENOMEM; + + strcpy(cp, slp->sl_target); + strcat(cp, (char *)csp); + len = strlen(cp); + len = (len > buflen) ? buflen : len; + + if (copy_to_user(buffer, cp, len) != 0) + len = -EFAULT; + + kfree(cp); + return len; +} + +static void smackfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) +{ + kfree(nd_get_link(nd)); +} + +static struct inode_operations smackfs_symlink_inode_operations = { + .readlink = smackfs_readlink, + .follow_link = smackfs_follow_link, + .put_link = smackfs_put_link, +}; + +static void smk_add_symlink(char *name, char *target) +{ + static int inum = SMK_TMP; + struct inode *inode; + struct dentry *dentry; + struct smk_link *slp; + + for (slp = smk_links; slp != NULL; slp = slp->sl_next) { + if (strcmp(slp->sl_name, name) != 0) + continue; + strcpy(slp->sl_target, target); + return; + } + + slp = kzalloc(sizeof(struct smk_link), GFP_KERNEL); + if (slp == NULL) + return; + + dentry = d_alloc_name(smk_sb->s_root, name); + if (dentry == NULL) { + printk("%s:%d link dentry failed\n", __FUNCTION__, __LINE__); + return; + } + + inode = new_inode(smk_sb); + if (inode == NULL) { + printk("%s:%d link inode failed\n", __FUNCTION__, __LINE__); + return; + } + + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blocks = 0; + inode->i_atime = CURRENT_TIME; + inode->i_mtime = inode->i_atime; + inode->i_ctime = inode->i_atime; + inode->i_ino = inum++; + inode->i_op = &smackfs_symlink_inode_operations; + d_add(dentry, inode); + + strcpy(slp->sl_name, name); + strcpy(slp->sl_target, target); + slp->sl_inum = inode->i_ino; + slp->sl_next = smk_links; + smk_links = slp; + smk_links_count++; + + return; +} + +static ssize_t smk_read_links(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t bytes = sizeof(struct smk_link) * smk_links_count; + struct smk_link *slp; + char *result; + char *cp; + + + result = kzalloc(bytes, GFP_KERNEL); + if (result == NULL) + return -ENOMEM; + *result = '\0'; + + for (slp = smk_links, cp = result; slp != NULL; slp = slp->sl_next) { + sprintf(cp, "%s %s\n", slp->sl_name, slp->sl_target); + cp += strlen(slp->sl_name) + strlen(slp->sl_target); + } + + bytes = simple_read_from_buffer(buf,count,ppos,result,strlen(result)); + + kfree(result); + + return bytes; +} + +static ssize_t smk_write_links(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rc = count; + char *data; + char *cp; + char name[SMK_TMPPATH_SIZE]; + char target[SMK_TMPPATH_SIZE]; + + /* + * No partial writes. + */ + if (*ppos != 0) + return -EINVAL; + /* + * 80 characters per line ought to be enough. + */ + if (count > SMACK_LIST_MAX * 80) + return -ENOMEM; + + data = kzalloc(count + 1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + if (copy_from_user(data, buf, count) != 0) { + kfree(data); + return -EFAULT; + } + + *(data + count) = '\0'; + + for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) { + if (*++cp == '\0') + break; + if (sscanf(cp, "%14s %30s\n", name, target) != 2) { + printk("%s:%d bad scan\n", + __FUNCTION__, __LINE__); + break; + } + smk_add_symlink(name, target); + printk("%s:%d add %s -> %s\n", + __FUNCTION__, __LINE__, name, target); + } + + kfree(data); + return rc; +} + +static struct file_operations smk_links_ops = { + .read = smk_read_links, + .write = smk_write_links, +}; + +static int smk_fill_super(struct super_block *sb, void * data, int silent) +{ + int rc; + struct inode *root_inode; + + static struct tree_descr smack_files[] = { + [SMK_LOAD] = {"load", &smk_load_ops, S_IRUGO|S_IWUSR}, + [SMK_LINKS] = {"links", &smk_links_ops, S_IRUGO|S_IWUSR}, + [SMK_CIPSO] = {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR}, + [SMK_DOI] = {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR}, + [SMK_DIRECT] = {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, + [SMK_AMBIENT] = {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, + [SMK_NLTYPE] = {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, + /* last one */ {""} + }; + + /* + * There will be only one smackfs. Casey says so. + */ + smk_sb = sb; + + rc = simple_fill_super(sb, SMACK_MAGIC, smack_files); + if (rc != 0) { + printk(KERN_ERR "%s failed %d while creating inodes\n", + __FUNCTION__, rc); + return rc; + } + + root_inode = sb->s_root->d_inode; + root_inode->i_security = new_inode_smack(SMK_FLOOR); + + /* + * Create a directory for /smack/tmp + */ + smk_add_symlink("tmp", SMK_TMPPATH_ROOT); + + return 0; +} + +static int smk_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) +{ + return get_sb_single(fs_type, flags, data, smk_fill_super, mnt); +} + +static struct file_system_type smk_fs_type = { + .name = "smackfs", + .get_sb = smk_get_sb, + .kill_sb = kill_litter_super, +}; + +static struct vfsmount *smackfs_mount; + +static int __init init_smk_fs(void) +{ + int err; + + err = register_filesystem(&smk_fs_type); + if (!err) { + smackfs_mount = kern_mount(&smk_fs_type); + if (IS_ERR(smackfs_mount)) { + printk(KERN_ERR "smackfs: could not mount!\n"); + err = PTR_ERR(smackfs_mount); + smackfs_mount = NULL; + } + } + + mutex_init(&smack_list_lock); + mutex_init(&smack_cipso_lock); + return err; +} + +__initcall(init_smk_fs); diff -uprN -X linux-2.6.22-base/Documentation/dontdiff linux-2.6.22-base/security/smack/smack.h linux-2.6.22/security/smack/smack.h --- linux-2.6.22-base/security/smack/smack.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.22/security/smack/smack.h 2007-07-24 16:16:27.000000000 -0700 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2007 Casey Schaufler <[EMAIL PROTECTED]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * Author: + * Casey Schaufler <[EMAIL PROTECTED]> + * + */ + +#ifndef _SECURITY_SMACK_H +#define _SECURITY_SMACK_H + +#include <linux/capability.h> +#include <net/netlabel.h> + +/* + * A smack_t contains an 8 byte string, 7 characters + * and a terminating NULL. Yes, it's short and 12.5% + * wasted. + * + * There is likely to be experimentation with alternative + * representations, perhaps a u32 so that it's the same + * as what's used in Other LSM MAC schemes, or an array + * of 20 chars so that the names aren't so tightly constrained. + */ +typedef u64 smack_t; + +struct superblock_smack { + smack_t smk_root; + smack_t smk_floor; + smack_t smk_hat; + smack_t smk_default; + int smk_initialized; +}; + +/* + * Task smack data + */ +struct task_smack { + smack_t smk_task; /* label of the task */ +}; + +/* + * Socket smack data + */ +struct socket_smack { + smack_t smk_out; /* label to associate with outbound packets */ + smack_t smk_in; /* label to check on incoming packets */ + smack_t smk_packet; /* label of incoming packet on request */ +}; + +/* + * Inode smack data + */ +struct inode_smack { + smack_t smk_inode; /* label of the fso */ + struct mutex smk_lock; /* initialization lock */ + int smk_flags; /* smack inode flags */ +}; + +#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ + +/* + * A label access rule. + */ +struct smack_rule { + smack_t smk_subject; + smack_t smk_object; + int smk_access; +}; + +/* + * An entry in the table of permitted label accesses. + */ +struct smk_list_entry { + struct smk_list_entry *smk_next; + struct smack_rule smk_rule; +}; + +/* + * An entry in the table mapping smack values to + * CIPSO level/category-set values. + */ +struct smk_cipso_entry { + struct smk_cipso_entry *smk_next; + int smk_level; /* for CIPSO */ + smack_t smk_smack; + smack_t smk_catset; +}; + +/* + * Mount options + */ +#define SMK_FSDEFAULT "smackfsdef=" +#define SMK_FSFLOOR "smackfsfloor=" +#define SMK_FSHAT "smackfshat=" +#define SMK_FSROOT "smackfsroot=" + +/* + * xattr names + */ +#define XATTR_SMACK_SUFFIX "SMACK64" +#define XATTR_SMACK_IPIN "SMACK64IPIN" +#define XATTR_SMACK_IPOUT "SMACK64IPOUT" +#define XATTR_SMACK_PACKET "SMACK64PACKET" +#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX + +/* + * smackfs macic number + */ +#define SMACK_MAGIC 0x43415d53 /* "SMAC" */ + +/* + * A limit on the number of entries in the lists + * makes some of the list administration easier. + */ +#define SMACK_LIST_MAX 10000 + +/* + * CIPSO defaults. + */ +#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ +#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ +#define SMACK_CIPSO_MAXCAT 63 /* Bigger gets harder */ + +/* + * Pre-defined smack label values. + */ +#define SMK_INVALID 0x00LL /* NULLSTRING */ +#define SMK_HAT 0x5ELL /* "^" */ +#define SMK_FLOOR 0x5FLL /* "_" */ +#define SMK_STAR 0x2ALL /* "*" */ +#define SMK_HUH 0x3FLL /* "?" */ +#define SMK_UNSET 0x5445534e55LL /* "UNSET" */ +/* + * There's a place in the CIPSO initialization that + * wants this. + */ +#define SMK32_FLOOR 0x5F /* "_" */ + +#define SMK_MAXLEN (sizeof(smack_t) - 1) /* NULL terminated */ +/* + * Just to make the common cases easier to deal with + */ +#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) +#define MAY_ANYREAD (MAY_READ | MAY_EXEC) +#define MAY_ANYWRITE (MAY_WRITE | MAY_APPEND) +#define MAY_READWRITE (MAY_READ | MAY_WRITE) +#define MAY_NOT 0 + +/* + * There are not enough CAP bits available to make this + * real, so Casey borrowed the capability that looks to + * him like it has the best balance of similarity amd + * low use. + */ +#define CAP_MAC_OVERRIDE CAP_LINUX_IMMUTABLE + +/* + * These functions are in smack_lsm.c + */ +struct inode_smack *new_inode_smack(smack_t); + +/* + * These functions are in smack_access.c + */ +int smk_access(smack_t *, smack_t *, int); +int smk_curacc(smack_t *, u32); +smack_t smk_from_string(char *); + +/* + * Stricly for CIPSO level manipulation. + * Set the category bit number in a smack_t. + */ +static inline void smack_catset_bit(int cat, smack_t *catsetp) +{ + char *cp = (char *)catsetp; + + if (cat > sizeof(smack_t) * 8) + return; + + cp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); +} + +/* + * Present a pointer to the smack label in a task blob. + */ +static inline smack_t *smk_of_task(const struct task_struct *tsp) +{ + struct task_smack *stp = tsp->security; + return &stp->smk_task; +} + +/* + * Present a pointer to the smack label in an inode blob. + */ +static inline smack_t *smk_of_inode(const struct inode *isp) +{ + struct inode_smack *sip = isp->i_security; + return &sip->smk_inode; +} + +/* + * allocate a new smack label. + */ +static inline smack_t *new_smack_t(smack_t value) +{ + smack_t *bp; + + bp = kzalloc(sizeof(smack_t), GFP_KERNEL); + if (bp != NULL) + *bp = value; + + return bp; +} + +/* + * Copy a smack label from the buffer. The smack label may + * actually be shorter than size. In any case, null pad + * beyond the end. + */ +static inline smack_t smk_from_buffer(const void *value, int size) +{ + smack_t smack; + char *from = (char *)value; + char *to = (char *)&smack; + int found; + int i; + + for (i = 0, found = 0; i < sizeof(smack_t); i++, to++) { + if (found) + *to = '\0'; + else if (i >= size || *from > '~' || *from <= ' ') { + *to = '\0'; + found = 1; + } + else + *to = *from++; + } + return smack; +} + +#endif /* _SECURITY_SMACK_H */
Casey Schaufler [EMAIL PROTECTED] - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/