Smack consists of three major components:
- The kernel
- - A start-up script and a few modified applications
+ - Basic utilities, which are helpful but not required
- Configuration data
The kernel component of Smack is implemented as a Linux
works best with file systems that support extended attributes,
although xattr support is not strictly required.
It is safe to run a Smack kernel under a "vanilla" distribution.
+
Smack kernels use the CIPSO IP option. Some network
configurations are intolerant of IP options and can impede
access to systems that use them as Smack does.
-The startup script etc-init.d-smack should be installed
-in /etc/init.d/smack and should be invoked early in the
-start-up process. On Fedora rc5.d/S02smack is recommended.
-This script ensures that certain devices have the correct
-Smack attributes and loads the Smack configuration if
-any is defined. This script invokes two programs that
-ensure configuration data is properly formatted. These
-programs are /usr/sbin/smackload and /usr/sin/smackcipso.
-The system will run just fine without these programs,
-but it will be difficult to set access rules properly.
-
-A version of "ls" that provides a "-M" option to display
-Smack labels on long listing is available.
+The current git repositories for Smack user space are:
-A hacked version of sshd that allows network logins by users
-with specific Smack labels is available. This version does
-not work for scp. You must set the /etc/ssh/sshd_config
-line:
- UsePrivilegeSeparation no
+ git@gitorious.org:meego-platform-security/smackutil.git
+ git@gitorious.org:meego-platform-security/libsmack.git
-The format of /etc/smack/usr is:
+These should make and install on most modern distributions.
+There are three commands included in smackutil:
- username smack
+smackload - properly formats data for writing to /smack/load
+smackcipso - properly formats data for writing to /smack/cipso
+chsmack - display or set Smack extended attribute values
In keeping with the intent of Smack, configuration data is
minimal and not strictly required. The most important
configuration step is mounting the smackfs pseudo filesystem.
+If smackutil is installed the startup script will take care
+of this, but it can be manually as well.
Add this line to /etc/fstab:
and create the /smack directory for mounting.
-Smack uses extended attributes (xattrs) to store file labels.
-The command to set a Smack label on a file is:
+Smack uses extended attributes (xattrs) to store labels on filesystem
+objects. The attributes are stored in the extended attribute security
+name space. A process must have CAP_MAC_ADMIN to change any of these
+attributes.
+
+The extended attributes that Smack uses are:
+
+SMACK64
+ Used to make access control decisions. In almost all cases
+ the label given to a new filesystem object will be the label
+ of the process that created it.
+SMACK64EXEC
+ The Smack label of a process that execs a program file with
+ this attribute set will run with this attribute's value.
+SMACK64MMAP
+ Don't allow the file to be mmapped by a process whose Smack
+ label does not allow all of the access permitted to a process
+ with the label contained in this attribute. This is a very
+ specific use case for shared libraries.
+SMACK64TRANSMUTE
+ Can only have the value "TRUE". If this attribute is present
+ on a directory when an object is created in the directory and
+ the Smack rule (more below) that permitted the write access
+ to the directory includes the transmute ("t") mode the object
+ gets the label of the directory instead of the label of the
+ creating process. If the object being created is a directory
+ the SMACK64TRANSMUTE attribute is set as well.
+SMACK64IPIN
+ This attribute is only available on file descriptors for sockets.
+ Use the Smack label in this attribute for access control
+ decisions on packets being delivered to this socket.
+SMACK64IPOUT
+ This attribute is only available on file descriptors for sockets.
+ Use the Smack label in this attribute for access control
+ decisions on packets coming from this socket.
+
+There are multiple ways to set a Smack label on a file:
# attr -S -s SMACK64 -V "value" path
+ # chsmack -a value path
-NOTE: Smack labels are limited to 23 characters. The attr command
- does not enforce this restriction and can be used to set
- invalid Smack labels on files.
-
-If you don't do anything special all users will get the floor ("_")
-label when they log in. If you do want to log in via the hacked ssh
-at other labels use the attr command to set the smack value on the
-home directory and its contents.
+A process can see the smack label it is running with by
+reading /proc/self/attr/current. A process with CAP_MAC_ADMIN
+can set the process smack by writing there.
+
+Most Smack configuration is accomplished by writing to files
+in the smackfs filesystem. This pseudo-filesystem is usually
+mounted on /smack.
+
+access
+ This interface reports whether a subject with the specified
+ Smack label has a particular access to an object with a
+ specified Smack label. Write a fixed format access rule to
+ this file. The next read will indicate whether the access
+ would be permitted. The text will be either "1" indicating
+ access, or "0" indicating denial.
+access2
+ This interface reports whether a subject with the specified
+ Smack label has a particular access to an object with a
+ specified Smack label. Write a long format access rule to
+ this file. The next read will indicate whether the access
+ would be permitted. The text will be either "1" indicating
+ access, or "0" indicating denial.
+ambient
+ This contains the Smack label applied to unlabeled network
+ packets.
+cipso
+ This interface allows a specific CIPSO header to be assigned
+ to a Smack label. The format accepted on write is:
+ "%24s%4d%4d"["%4d"]...
+ The first string is a fixed Smack label. The first number is
+ the level to use. The second number is the number of categories.
+ The following numbers are the categories.
+ "level-3-cats-5-19 3 2 5 19"
+cipso2
+ This interface allows a specific CIPSO header to be assigned
+ to a Smack label. The format accepted on write is:
+ "%s%4d%4d"["%4d"]...
+ The first string is a long Smack label. The first number is
+ the level to use. The second number is the number of categories.
+ The following numbers are the categories.
+ "level-3-cats-5-19 3 2 5 19"
+direct
+ This contains the CIPSO level used for Smack direct label
+ representation in network packets.
+doi
+ This contains the CIPSO domain of interpretation used in
+ network packets.
+load
+ This interface allows access control rules in addition to
+ the system defined rules to be specified. The format accepted
+ on write is:
+ "%24s%24s%5s"
+ where the first string is the subject label, the second the
+ object label, and the third the requested access. The access
+ string may contain only the characters "rwxat-", and specifies
+ which sort of access is allowed. The "-" is a placeholder for
+ permissions that are not allowed. The string "r-x--" would
+ specify read and execute access. Labels are limited to 23
+ characters in length.
+load2
+ This interface allows access control rules in addition to
+ the system defined rules to be specified. The format accepted
+ on write is:
+ "%s %s %s"
+ where the first string is the subject label, the second the
+ object label, and the third the requested access. The access
+ string may contain only the characters "rwxat-", and specifies
+ which sort of access is allowed. The "-" is a placeholder for
+ permissions that are not allowed. The string "r-x--" would
+ specify read and execute access.
+load-self
+ This interface allows process specific access rules to be
+ defined. These rules are only consulted if access would
+ otherwise be permitted, and are intended to provide additional
+ restrictions on the process. The format is the same as for
+ the load interface.
+load-self2
+ This interface allows process specific access rules to be
+ defined. These rules are only consulted if access would
+ otherwise be permitted, and are intended to provide additional
+ restrictions on the process. The format is the same as for
+ the load2 interface.
+logging
+ This contains the Smack logging state.
+mapped
+ This contains the CIPSO level used for Smack mapped label
+ representation in network packets.
+netlabel
+ This interface allows specific internet addresses to be
+ treated as single label hosts. Packets are sent to single
+ label hosts without CIPSO headers, but only from processes
+ that have Smack write access to the host label. All packets
+ received from single label hosts are given the specified
+ label. The format accepted on write is:
+ "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label".
+onlycap
+ This contains the label processes must have for CAP_MAC_ADMIN
+ and CAP_MAC_OVERRIDE to be effective. If this file is empty
+ these capabilities are effective at for processes with any
+ label. The value is set by writing the desired label to the
+ file or cleared by writing "-" to the file.
You can add access rules in /etc/smack/accesses. They take the form:
kind of access permitted a subject with subjectlabel on an
object with objectlabel. If there is no rule no access is allowed.
-A process can see the smack label it is running with by
-reading /proc/self/attr/current. A privileged process can
-set the process smack by writing there.
-
Look for additional programs on http://schaufler-ca.com
From the Smack Whitepaper:
ever performed on them is comparison for equality. Smack labels cannot
contain unprintable characters, the "/" (slash), the "\" (backslash), the "'"
(quote) and '"' (double-quote) characters.
-Smack labels cannot begin with a '-', which is reserved for special options.
+Smack labels cannot begin with a '-'. This is reserved for special options.
There are some predefined labels:
^ Pronounced "hat", a single circumflex character.
* Pronounced "star", a single asterisk character.
? Pronounced "huh", a single question mark character.
- @ Pronounced "Internet", a single at sign character.
+ @ Pronounced "web", a single at sign character.
Every task on a Smack system is assigned a label. System tasks, such as
init(8) and systems daemons, are run with the floor ("_") label. User tasks
Where subject-label is the Smack label of the task, object-label is the Smack
label of the thing being accessed, and access is a string specifying the sort
-of access allowed. The Smack labels are limited to 23 characters. The access
-specification is searched for letters that describe access modes:
+of access allowed. The access specification is searched for letters that
+describe access modes:
a: indicates that append access should be granted.
r: indicates that read access should be granted.
w: indicates that write access should be granted.
x: indicates that execute access should be granted.
+ t: indicates that the rule requests transmutation.
Uppercase values for the specification letters are allowed as well.
Access mode specifications can be in any order. Examples of acceptable rules
Spaces are not allowed in labels. Since a subject always has access to files
with the same label specifying a rule for that case is pointless. Only
-valid letters (rwxaRWXA) and the dash ('-') character are allowed in
+valid letters (rwxatRWXAT) and the dash ('-') character are allowed in
access specifications. The dash is a placeholder, so "a-r" is the same
as "ar". A lone dash is used to specify that no access should be allowed.
containing directory but not to the differently labeled file. This is an
artifact of the file name being data in the directory, not a part of the file.
+If a directory is marked as transmuting (SMACK64TRANSMUTE=TRUE) and the
+access rule that allows a process to create an object in that directory
+includes 't' access the label assigned to the new object will be that
+of the directory, not the creating process. This makes it much easier
+for two processes with different labels to share data without granting
+access to all of their files.
+
IPC objects, message queues, semaphore sets, and memory segments exist in flat
namespaces and access requests are only required to match the object in
question.
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/pipe_fs_i.h>
-#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <linux/audit.h>
#include <linux/magic.h>
static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
{
int rc;
- char in[SMK_LABELLEN];
+ char *buffer;
+ char *result = NULL;
if (ip->i_op->getxattr == NULL)
return NULL;
- rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN);
- if (rc < 0)
+ buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
+ if (buffer == NULL)
return NULL;
- return smk_import(in, rc);
+ rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
+ if (rc > 0)
+ result = smk_import(buffer, rc);
+
+ kfree(buffer);
+
+ return result;
}
/**
* check label validity here so import wont fail on
* post_setxattr
*/
- if (size == 0 || size >= SMK_LABELLEN ||
+ if (size == 0 || size >= SMK_LONGLABEL ||
smk_import(value, size) == NULL)
rc = -EINVAL;
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
}
/**
- * smack_set_catset - convert a capset to netlabel mls categories
- * @catset: the Smack categories
- * @sap: where to put the netlabel categories
- *
- * Allocates and fills attr.mls.cat
- */
-static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
-{
- unsigned char *cp;
- unsigned char m;
- int cat;
- int rc;
- int byte;
-
- if (!catset)
- return;
-
- sap->flags |= NETLBL_SECATTR_MLS_CAT;
- sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
- sap->attr.mls.cat->startbit = 0;
-
- for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++)
- for (m = 0x80; m != 0; m >>= 1, cat++) {
- if ((m & *cp) == 0)
- continue;
- rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat,
- cat, GFP_ATOMIC);
- }
-}
-
-/**
- * smack_to_secattr - fill a secattr from a smack value
- * @smack: the smack value
- * @nlsp: where the result goes
- *
- * Casey says that CIPSO is good enough for now.
- * It can be used to effect.
- * It can also be abused to effect when necessary.
- * Apologies to the TSIG group in general and GW in particular.
- */
-static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
-{
- struct smack_cipso cipso;
- int rc;
-
- nlsp->domain = smack;
- nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
-
- rc = smack_to_cipso(smack, &cipso);
- if (rc == 0) {
- nlsp->attr.mls.lvl = cipso.smk_level;
- smack_set_catset(cipso.smk_catset, nlsp);
- } else {
- nlsp->attr.mls.lvl = smack_cipso_direct;
- smack_set_catset(smack, nlsp);
- }
-}
-
-/**
* smack_netlabel - Set the secattr on a socket
* @sk: the socket
* @labeled: socket label scheme
*/
static int smack_netlabel(struct sock *sk, int labeled)
{
+ struct smack_known *skp;
struct socket_smack *ssp = sk->sk_security;
- struct netlbl_lsm_secattr secattr;
int rc = 0;
/*
labeled == SMACK_UNLABELED_SOCKET)
netlbl_sock_delattr(sk);
else {
- netlbl_secattr_init(&secattr);
- smack_to_secattr(ssp->smk_out, &secattr);
- rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
- netlbl_secattr_destroy(&secattr);
+ skp = smk_find_entry(ssp->smk_out);
+ rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);
}
bh_unlock_sock(sk);
struct socket *sock;
int rc = 0;
- if (value == NULL || size > SMK_LABELLEN || size == 0)
+ if (value == NULL || size > SMK_LONGLABEL || size == 0)
return -EACCES;
sp = smk_import(value, size);
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
- if (value == NULL || size == 0 || size >= SMK_LABELLEN)
+ if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
return -EINVAL;
if (strcmp(name, "current") != 0)
static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
struct socket_smack *ssp)
{
- struct smack_known *skp;
- char smack[SMK_LABELLEN];
+ struct smack_known *kp;
char *sp;
- int pcat;
+ int found = 0;
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
/*
* If there are flags but no level netlabel isn't
* behaving the way we expect it to.
*
- * Get the categories, if any
+ * Look it up in the label table
* Without guidance regarding the smack value
* for the packet fall back on the network
* ambient value.
*/
- memset(smack, '\0', SMK_LABELLEN);
- if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
- for (pcat = -1;;) {
- pcat = netlbl_secattr_catmap_walk(
- sap->attr.mls.cat, pcat + 1);
- if (pcat < 0)
- break;
- smack_catset_bit(pcat, smack);
- }
- /*
- * If it is CIPSO using smack direct mapping
- * we are already done. WeeHee.
- */
- if (sap->attr.mls.lvl == smack_cipso_direct) {
- /*
- * The label sent is usually on the label list.
- *
- * If it is not we may still want to allow the
- * delivery.
- *
- * If the recipient is accepting all packets
- * because it is using the star ("*") label
- * for SMACK64IPIN provide the web ("@") label
- * so that a directed response will succeed.
- * This is not very correct from a MAC point
- * of view, but gets around the problem that
- * locking prevents adding the newly discovered
- * label to the list.
- * The case where the recipient is not using
- * the star label should obviously fail.
- * The easy way to do this is to provide the
- * star label as the subject label.
- */
- skp = smk_find_entry(smack);
- if (skp != NULL)
- return skp->smk_known;
- if (ssp != NULL &&
- ssp->smk_in == smack_known_star.smk_known)
- return smack_known_web.smk_known;
- return smack_known_star.smk_known;
+ rcu_read_lock();
+ list_for_each_entry(kp, &smack_known_list, list) {
+ if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl)
+ continue;
+ if (memcmp(sap->attr.mls.cat,
+ kp->smk_netlabel.attr.mls.cat,
+ SMK_CIPSOLEN) != 0)
+ continue;
+ found = 1;
+ break;
}
- /*
- * Look it up in the supplied table if it is not
- * a direct mapping.
- */
- sp = smack_from_cipso(sap->attr.mls.lvl, smack);
- if (sp != NULL)
- return sp;
+ rcu_read_unlock();
+
+ if (found)
+ return kp->smk_known;
+
if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
return smack_known_web.smk_known;
return smack_known_star.smk_known;
struct request_sock *req)
{
u16 family = sk->sk_family;
+ struct smack_known *skp;
struct socket_smack *ssp = sk->sk_security;
struct netlbl_lsm_secattr secattr;
struct sockaddr_in addr;
struct iphdr *hdr;
char *sp;
+ char *hsp;
int rc;
struct smk_audit_info ad;
#ifdef CONFIG_AUDIT
hdr = ip_hdr(skb);
addr.sin_addr.s_addr = hdr->saddr;
rcu_read_lock();
- if (smack_host_label(&addr) == NULL) {
- rcu_read_unlock();
- netlbl_secattr_init(&secattr);
- smack_to_secattr(sp, &secattr);
- rc = netlbl_req_setattr(req, &secattr);
- netlbl_secattr_destroy(&secattr);
- } else {
- rcu_read_unlock();
+ hsp = smack_host_label(&addr);
+ rcu_read_unlock();
+
+ if (hsp == NULL) {
+ skp = smk_find_entry(sp);
+ rc = netlbl_req_setattr(req, &skp->smk_netlabel);
+ } else
netlbl_req_delattr(req);
- }
return rc;
}
static __init void init_smack_known_list(void)
{
/*
- * Initialize CIPSO locks
- */
- spin_lock_init(&smack_known_huh.smk_cipsolock);
- spin_lock_init(&smack_known_hat.smk_cipsolock);
- spin_lock_init(&smack_known_star.smk_cipsolock);
- spin_lock_init(&smack_known_floor.smk_cipsolock);
- spin_lock_init(&smack_known_invalid.smk_cipsolock);
- spin_lock_init(&smack_known_web.smk_cipsolock);
- /*
* Initialize rule list locks
*/
mutex_init(&smack_known_huh.smk_rules_lock);
#include <linux/mutex.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
-#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <linux/seq_file.h>
#include <linux/ctype.h>
SMK_LOGGING = 10, /* logging */
SMK_LOAD_SELF = 11, /* task specific rules */
SMK_ACCESSES = 12, /* access policy */
+ SMK_MAPPED = 13, /* CIPSO level indicating mapped label */
+ SMK_LOAD2 = 14, /* load policy with long labels */
+ SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */
+ SMK_ACCESS2 = 16, /* make an access check with long labels */
+ SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
};
/*
* If it isn't somehow marked, use this.
* It can be reset via smackfs/ambient
*/
-char *smack_net_ambient = smack_known_floor.smk_known;
+char *smack_net_ambient;
/*
* This is the level in a CIPSO header that indicates a
int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
/*
+ * This is the level in a CIPSO header that indicates a
+ * secid is contained directly in the category set.
+ * It can be reset via smackfs/mapped
+ */
+int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT;
+
+/*
* Unless a process is running with this label even
* having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no label is
/*
* Rule lists are maintained for each label.
- * This master list is just for reading /smack/load.
+ * This master list is just for reading /smack/load and /smack/load2.
*/
struct smack_master_list {
struct list_head list;
#define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN)
#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
+/*
+ * Stricly for CIPSO level manipulation.
+ * Set the category bit number in a smack label sized buffer.
+ */
+static inline void smack_catset_bit(unsigned int cat, char *catsetp)
+{
+ if (cat == 0 || cat > (SMK_CIPSOLEN * 8))
+ return;
+
+ catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
+}
+
/**
* smk_netlabel_audit_set - fill a netlbl_audit struct
* @nap: structure to fill
}
/*
- * Values for parsing single label host rules
+ * Value for parsing single label host rules
* "1.2.3.4 X"
- * "192.168.138.129/32 abcdefghijklmnopqrstuvw"
*/
#define SMK_NETLBLADDRMIN 9
-#define SMK_NETLBLADDRMAX 42
/**
* smk_set_access - add a rule to the rule list
}
/**
- * smk_parse_rule - parse Smack rule from load string
- * @data: string to be parsed whose size is SMK_LOADLEN
+ * smk_fill_rule - Fill Smack rule from strings
+ * @subject: subject label string
+ * @object: object label string
+ * @access: access string
* @rule: Smack rule
* @import: if non-zero, import labels
+ *
+ * Returns 0 on success, -1 on failure
*/
-static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
+static int smk_fill_rule(const char *subject, const char *object,
+ const char *access, struct smack_rule *rule,
+ int import)
{
- char smack[SMK_LABELLEN];
+ int rc = -1;
+ int done;
+ const char *cp;
struct smack_known *skp;
if (import) {
- rule->smk_subject = smk_import(data, 0);
+ rule->smk_subject = smk_import(subject, 0);
if (rule->smk_subject == NULL)
return -1;
- rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+ rule->smk_object = smk_import(object, 0);
if (rule->smk_object == NULL)
return -1;
} else {
- smk_parse_smack(data, 0, smack);
- skp = smk_find_entry(smack);
+ cp = smk_parse_smack(subject, 0);
+ if (cp == NULL)
+ return -1;
+ skp = smk_find_entry(cp);
+ kfree(cp);
if (skp == NULL)
return -1;
rule->smk_subject = skp->smk_known;
- smk_parse_smack(data + SMK_LABELLEN, 0, smack);
- skp = smk_find_entry(smack);
+ cp = smk_parse_smack(object, 0);
+ if (cp == NULL)
+ return -1;
+ skp = smk_find_entry(cp);
+ kfree(cp);
if (skp == NULL)
return -1;
rule->smk_object = skp->smk_known;
rule->smk_access = 0;
- switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
- case '-':
- break;
- case 'r':
- case 'R':
- rule->smk_access |= MAY_READ;
- break;
- default:
- return -1;
+ for (cp = access, done = 0; *cp && !done; cp++) {
+ switch (*cp) {
+ case '-':
+ break;
+ case 'r':
+ case 'R':
+ rule->smk_access |= MAY_READ;
+ break;
+ case 'w':
+ case 'W':
+ rule->smk_access |= MAY_WRITE;
+ break;
+ case 'x':
+ case 'X':
+ rule->smk_access |= MAY_EXEC;
+ break;
+ case 'a':
+ case 'A':
+ rule->smk_access |= MAY_APPEND;
+ break;
+ case 't':
+ case 'T':
+ rule->smk_access |= MAY_TRANSMUTE;
+ break;
+ default:
+ done = 1;
+ break;
+ }
}
+ rc = 0;
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
- case '-':
- break;
- case 'w':
- case 'W':
- rule->smk_access |= MAY_WRITE;
- break;
- default:
- return -1;
- }
+ return rc;
+}
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
- case '-':
- break;
- case 'x':
- case 'X':
- rule->smk_access |= MAY_EXEC;
- break;
- default:
- return -1;
- }
+/**
+ * smk_parse_rule - parse Smack rule from load string
+ * @data: string to be parsed whose size is SMK_LOADLEN
+ * @rule: Smack rule
+ * @import: if non-zero, import labels
+ *
+ * Returns 0 on success, -1 on errors.
+ */
+static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
+{
+ int rc;
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
- case '-':
- break;
- case 'a':
- case 'A':
- rule->smk_access |= MAY_APPEND;
- break;
- default:
- return -1;
- }
+ rc = smk_fill_rule(data, data + SMK_LABELLEN,
+ data + SMK_LABELLEN + SMK_LABELLEN, rule, import);
+ return rc;
+}
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
- case '-':
- break;
- case 't':
- case 'T':
- rule->smk_access |= MAY_TRANSMUTE;
- break;
- default:
- return -1;
- }
+/**
+ * smk_parse_long_rule - parse Smack rule from rule string
+ * @data: string to be parsed, null terminated
+ * @rule: Smack rule
+ * @import: if non-zero, import labels
+ *
+ * Returns 0 on success, -1 on failure
+ */
+static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
+ int import)
+{
+ char *subject;
+ char *object;
+ char *access;
+ int datalen;
+ int rc = -1;
- return 0;
+ /*
+ * This is probably inefficient, but safe.
+ */
+ datalen = strlen(data);
+ subject = kzalloc(datalen, GFP_KERNEL);
+ if (subject == NULL)
+ return -1;
+ object = kzalloc(datalen, GFP_KERNEL);
+ if (object == NULL)
+ goto free_out_s;
+ access = kzalloc(datalen, GFP_KERNEL);
+ if (access == NULL)
+ goto free_out_o;
+
+ if (sscanf(data, "%s %s %s", subject, object, access) == 3)
+ rc = smk_fill_rule(subject, object, access, rule, import);
+
+ kfree(access);
+free_out_o:
+ kfree(object);
+free_out_s:
+ kfree(subject);
+ return rc;
}
+#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
+#define SMK_LONG_FMT 1 /* Variable long label format */
/**
- * smk_write_load_list - write() for any /smack/load
+ * smk_write_rules_list - write() for any /smack rule file
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start - must be 0
* @rule_list: the list of rules to write to
* @rule_lock: lock for the rule list
+ * @format: /smack/load or /smack/load2 format.
*
* Get one smack access rule from above.
- * The format is exactly:
- * char subject[SMK_LABELLEN]
- * char object[SMK_LABELLEN]
- * char access[SMK_ACCESSLEN]
- *
- * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
+ * The format for SMK_LONG_FMT is:
+ * "subject<whitespace>object<whitespace>access[<whitespace>...]"
+ * The format for SMK_FIXED24_FMT is exactly:
+ * "subject object rwxat"
*/
-static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos,
- struct list_head *rule_list,
- struct mutex *rule_lock)
+static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos,
+ struct list_head *rule_list,
+ struct mutex *rule_lock, int format)
{
struct smack_master_list *smlp;
struct smack_known *skp;
struct smack_rule *rule;
char *data;
+ int datalen;
int rc = -EINVAL;
int load = 0;
*/
if (*ppos != 0)
return -EINVAL;
- /*
- * Minor hack for backward compatibility
- */
- if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
- return -EINVAL;
- data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
+ if (format == SMK_FIXED24_FMT) {
+ /*
+ * Minor hack for backward compatibility
+ */
+ if (count != SMK_OLOADLEN && count != SMK_LOADLEN)
+ return -EINVAL;
+ datalen = SMK_LOADLEN;
+ } else
+ datalen = count + 1;
+
+ data = kzalloc(datalen, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
goto out;
}
- /*
- * More on the minor hack for backward compatibility
- */
- if (count == (SMK_OLOADLEN))
- data[SMK_OLOADLEN] = '-';
-
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
if (rule == NULL) {
rc = -ENOMEM;
goto out;
}
- if (smk_parse_rule(data, rule, 1))
- goto out_free_rule;
+ if (format == SMK_LONG_FMT) {
+ /*
+ * Be sure the data string is terminated.
+ */
+ data[count] = '\0';
+ if (smk_parse_long_rule(data, rule, 1))
+ goto out_free_rule;
+ } else {
+ /*
+ * More on the minor hack for backward compatibility
+ */
+ if (count == (SMK_OLOADLEN))
+ data[SMK_OLOADLEN] = '-';
+ if (smk_parse_rule(data, rule, 1))
+ goto out_free_rule;
+ }
+
if (rule_list == NULL) {
load = 1;
rc = count;
/*
- * If this is "load" as opposed to "load-self" and a new rule
+ * If this is a global as opposed to self and a new rule
* it needs to get added for reporting.
* smk_set_access returns true if there was already a rule
* for the subject/object pair, and false if it was new.
*/
- if (load && !smk_set_access(rule, rule_list, rule_lock)) {
- smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
- if (smlp != NULL) {
- smlp->smk_rule = rule;
- list_add_rcu(&smlp->list, &smack_rule_list);
- } else
- rc = -ENOMEM;
+ if (!smk_set_access(rule, rule_list, rule_lock)) {
+ if (load) {
+ smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
+ if (smlp != NULL) {
+ smlp->smk_rule = rule;
+ list_add_rcu(&smlp->list, &smack_rule_list);
+ } else
+ rc = -ENOMEM;
+ }
goto out;
}
/* No-op */
}
-/*
- * Seq_file read operations for /smack/load
- */
-
-static void *load_seq_start(struct seq_file *s, loff_t *pos)
-{
- return smk_seq_start(s, pos, &smack_rule_list);
-}
-
-static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
{
- return smk_seq_next(s, v, pos, &smack_rule_list);
-}
-
-static int load_seq_show(struct seq_file *s, void *v)
-{
- struct list_head *list = v;
- struct smack_master_list *smlp =
- list_entry(list, struct smack_master_list, list);
- struct smack_rule *srp = smlp->smk_rule;
+ /*
+ * Don't show any rules with label names too long for
+ * interface file (/smack/load or /smack/load2)
+ * because you should expect to be able to write
+ * anything you read back.
+ */
+ if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max)
+ return;
- seq_printf(s, "%s %s", (char *)srp->smk_subject,
- (char *)srp->smk_object);
+ seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object);
seq_putc(s, ' ');
seq_putc(s, '-');
seq_putc(s, '\n');
+}
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load2_seq_start(struct seq_file *s, loff_t *pos)
+{
+ return smk_seq_start(s, pos, &smack_rule_list);
+}
+
+static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ return smk_seq_next(s, v, pos, &smack_rule_list);
+}
+
+static int load_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_master_list *smlp =
+ list_entry(list, struct smack_master_list, list);
+
+ smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN);
return 0;
}
static const struct seq_operations load_seq_ops = {
- .start = load_seq_start,
- .next = load_seq_next,
+ .start = load2_seq_start,
+ .next = load2_seq_next,
.show = load_seq_show,
.stop = smk_seq_stop,
};
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
- return smk_write_load_list(file, buf, count, ppos, NULL, NULL);
+ return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
+ SMK_FIXED24_FMT);
}
static const struct file_operations smk_load_ops = {
printk(KERN_WARNING "%s:%d remove rc = %d\n",
__func__, __LINE__, rc);
}
+ if (smack_net_ambient == NULL)
+ smack_net_ambient = smack_known_floor.smk_known;
rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
NULL, NULL, &nai);
struct list_head *list = v;
struct smack_known *skp =
list_entry(list, struct smack_known, list);
- struct smack_cipso *scp = skp->smk_cipso;
- char *cbp;
+ struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
- int cat = 1;
int i;
- unsigned char m;
- if (scp == NULL)
+ /*
+ * Don't show a label that could not have been set using
+ * /smack/cipso. This is in support of the notion that
+ * anything read from /smack/cipso ought to be writeable
+ * to /smack/cipso.
+ *
+ * /smack/cipso2 should be used instead.
+ */
+ if (strlen(skp->smk_known) >= SMK_LABELLEN)
return 0;
- seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
+ seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
- cbp = scp->smk_catset;
- for (i = 0; i < SMK_LABELLEN; i++)
- for (m = 0x80; m != 0; m >>= 1) {
- if (m & cbp[i]) {
- seq_printf(s, "%c%d", sep, cat);
- sep = ',';
- }
- cat++;
- }
+ for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0;
+ i = netlbl_secattr_catmap_walk(cmp, i + 1)) {
+ seq_printf(s, "%c%d", sep, i);
+ sep = ',';
+ }
seq_putc(s, '\n');
}
/**
- * smk_write_cipso - write() for /smack/cipso
+ * smk_set_cipso - do the work for write() for cipso and cipso2
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start
+ * @format: /smack/cipso or /smack/cipso2
*
* Accepts only one cipso rule per write call.
* Returns number of bytes written or error code, as appropriate
*/
-static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos, int format)
{
struct smack_known *skp;
- struct smack_cipso *scp = NULL;
- char mapcatset[SMK_LABELLEN];
+ struct netlbl_lsm_secattr ncats;
+ char mapcatset[SMK_CIPSOLEN];
int maplevel;
- int cat;
+ unsigned int cat;
int catlen;
ssize_t rc = -EINVAL;
char *data = NULL;
return -EPERM;
if (*ppos != 0)
return -EINVAL;
- if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)
+ if (format == SMK_FIXED24_FMT &&
+ (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX))
return -EINVAL;
data = kzalloc(count + 1, GFP_KERNEL);
goto unlockedout;
}
- /* labels cannot begin with a '-' */
- if (data[0] == '-') {
- rc = -EINVAL;
- goto unlockedout;
- }
data[count] = '\0';
rule = data;
/*
if (skp == NULL)
goto out;
- rule += SMK_LABELLEN;
+ if (format == SMK_FIXED24_FMT)
+ rule += SMK_LABELLEN;
+ else
+ rule += strlen(skp->smk_known);
+
ret = sscanf(rule, "%d", &maplevel);
if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
goto out;
if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
goto out;
- if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
+ if (format == SMK_FIXED24_FMT &&
+ count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
goto out;
memset(mapcatset, 0, sizeof(mapcatset));
for (i = 0; i < catlen; i++) {
rule += SMK_DIGITLEN;
- ret = sscanf(rule, "%d", &cat);
+ ret = sscanf(rule, "%u", &cat);
if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL)
goto out;
smack_catset_bit(cat, mapcatset);
}
- if (skp->smk_cipso == NULL) {
- scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
- if (scp == NULL) {
- rc = -ENOMEM;
- goto out;
- }
+ rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN);
+ if (rc >= 0) {
+ netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat);
+ skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat;
+ skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
+ rc = count;
}
- spin_lock_bh(&skp->smk_cipsolock);
-
- if (scp == NULL)
- scp = skp->smk_cipso;
- else
- skp->smk_cipso = scp;
-
- scp->smk_level = maplevel;
- memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset));
-
- spin_unlock_bh(&skp->smk_cipsolock);
-
- rc = count;
out:
mutex_unlock(&smack_cipso_lock);
unlockedout:
return rc;
}
+/**
+ * smk_write_cipso - write() for /smack/cipso
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Accepts only one cipso rule per write call.
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return smk_set_cipso(file, buf, count, ppos, SMK_FIXED24_FMT);
+}
+
static const struct file_operations smk_cipso_ops = {
.open = smk_open_cipso,
.read = seq_read,
};
/*
+ * Seq_file read operations for /smack/cipso2
+ */
+
+/*
+ * Print cipso labels in format:
+ * label level[/cat[,cat]]
+ */
+static int cipso2_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_known *skp =
+ list_entry(list, struct smack_known, list);
+ struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
+ char sep = '/';
+ int i;
+
+ seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
+
+ for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0;
+ i = netlbl_secattr_catmap_walk(cmp, i + 1)) {
+ seq_printf(s, "%c%d", sep, i);
+ sep = ',';
+ }
+
+ seq_putc(s, '\n');
+
+ return 0;
+}
+
+static const struct seq_operations cipso2_seq_ops = {
+ .start = cipso_seq_start,
+ .next = cipso_seq_next,
+ .show = cipso2_seq_show,
+ .stop = smk_seq_stop,
+};
+
+/**
+ * smk_open_cipso2 - open() for /smack/cipso2
+ * @inode: inode structure representing file
+ * @file: "cipso2" file pointer
+ *
+ * Connect our cipso_seq_* operations with /smack/cipso2
+ * file_operations
+ */
+static int smk_open_cipso2(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &cipso2_seq_ops);
+}
+
+/**
+ * smk_write_cipso2 - write() for /smack/cipso2
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Accepts only one cipso rule per write call.
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_cipso2(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return smk_set_cipso(file, buf, count, ppos, SMK_LONG_FMT);
+}
+
+static const struct file_operations smk_cipso2_ops = {
+ .open = smk_open_cipso2,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_cipso2,
+ .release = seq_release,
+};
+
+/*
* Seq_file read operations for /smack/netlabel
*/
{
struct smk_netlbladdr *skp;
struct sockaddr_in newname;
- char smack[SMK_LABELLEN];
+ char *smack;
char *sp;
- char data[SMK_NETLBLADDRMAX + 1];
+ char *data;
char *host = (char *)&newname.sin_addr.s_addr;
int rc;
struct netlbl_audit audit_info;
return -EPERM;
if (*ppos != 0)
return -EINVAL;
- if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX)
+ if (count < SMK_NETLBLADDRMIN)
return -EINVAL;
- if (copy_from_user(data, buf, count) != 0)
- return -EFAULT;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ rc = -EFAULT;
+ goto free_data_out;
+ }
+
+ smack = kzalloc(count + 1, GFP_KERNEL);
+ if (smack == NULL) {
+ rc = -ENOMEM;
+ goto free_data_out;
+ }
data[count] = '\0';
if (rc != 6) {
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
&host[0], &host[1], &host[2], &host[3], smack);
- if (rc != 5)
- return -EINVAL;
+ if (rc != 5) {
+ rc = -EINVAL;
+ goto free_out;
+ }
m = BEBITS;
}
- if (m > BEBITS)
- return -EINVAL;
+ if (m > BEBITS) {
+ rc = -EINVAL;
+ goto free_out;
+ }
- /* if smack begins with '-', its an option, don't import it */
+ /*
+ * If smack begins with '-', it is an option, don't import it
+ */
if (smack[0] != '-') {
sp = smk_import(smack, 0);
- if (sp == NULL)
- return -EINVAL;
+ if (sp == NULL) {
+ rc = -EINVAL;
+ goto free_out;
+ }
} else {
/* check known options */
if (strcmp(smack, smack_cipso_option) == 0)
sp = (char *)smack_cipso_option;
- else
- return -EINVAL;
+ else {
+ rc = -EINVAL;
+ goto free_out;
+ }
}
for (temp_mask = 0; m > 0; m--) {
mutex_unlock(&smk_netlbladdr_lock);
+free_out:
+ kfree(smack);
+free_data_out:
+ kfree(data);
+
return rc;
}
static ssize_t smk_write_direct(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct smack_known *skp;
char temp[80];
int i;
if (sscanf(temp, "%d", &i) != 1)
return -EINVAL;
- smack_cipso_direct = i;
+ /*
+ * Don't do anything if the value hasn't actually changed.
+ * If it is changing reset the level on entries that were
+ * set up to be direct when they were created.
+ */
+ if (smack_cipso_direct != i) {
+ mutex_lock(&smack_known_lock);
+ list_for_each_entry_rcu(skp, &smack_known_list, list)
+ if (skp->smk_netlabel.attr.mls.lvl ==
+ smack_cipso_direct)
+ skp->smk_netlabel.attr.mls.lvl = i;
+ smack_cipso_direct = i;
+ mutex_unlock(&smack_known_lock);
+ }
return count;
}
};
/**
+ * smk_read_mapped - read() for /smack/mapped
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_mapped(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_mapped);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * smk_write_mapped - write() for /smack/mapped
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_mapped(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_known *skp;
+ char temp[80];
+ int i;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (count >= sizeof(temp) || count == 0)
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ temp[count] = '\0';
+
+ if (sscanf(temp, "%d", &i) != 1)
+ return -EINVAL;
+
+ /*
+ * Don't do anything if the value hasn't actually changed.
+ * If it is changing reset the level on entries that were
+ * set up to be mapped when they were created.
+ */
+ if (smack_cipso_mapped != i) {
+ mutex_lock(&smack_known_lock);
+ list_for_each_entry_rcu(skp, &smack_known_list, list)
+ if (skp->smk_netlabel.attr.mls.lvl ==
+ smack_cipso_mapped)
+ skp->smk_netlabel.attr.mls.lvl = i;
+ smack_cipso_mapped = i;
+ mutex_unlock(&smack_known_lock);
+ }
+
+ return count;
+}
+
+static const struct file_operations smk_mapped_ops = {
+ .read = smk_read_mapped,
+ .write = smk_write_mapped,
+ .llseek = default_llseek,
+};
+
+/**
* smk_read_ambient - read() for /smack/ambient
* @filp: file pointer, not actually used
* @buf: where to put the result
static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char in[SMK_LABELLEN];
char *oldambient;
- char *smack;
+ char *smack = NULL;
+ char *data;
+ int rc = count;
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
- if (count >= SMK_LABELLEN)
- return -EINVAL;
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
- if (copy_from_user(in, buf, count) != 0)
- return -EFAULT;
+ if (copy_from_user(data, buf, count) != 0) {
+ rc = -EFAULT;
+ goto out;
+ }
- smack = smk_import(in, count);
- if (smack == NULL)
- return -EINVAL;
+ smack = smk_import(data, count);
+ if (smack == NULL) {
+ rc = -EINVAL;
+ goto out;
+ }
mutex_lock(&smack_ambient_lock);
mutex_unlock(&smack_ambient_lock);
- return count;
+out:
+ kfree(data);
+ return rc;
}
static const struct file_operations smk_ambient_ops = {
static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char in[SMK_LABELLEN];
+ char *data;
char *sp = smk_of_task(current->cred->security);
+ int rc = count;
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
if (smack_onlycap != NULL && smack_onlycap != sp)
return -EPERM;
- if (count >= SMK_LABELLEN)
- return -EINVAL;
-
- if (copy_from_user(in, buf, count) != 0)
- return -EFAULT;
+ data = kzalloc(count, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
/*
* Should the null string be passed in unset the onlycap value.
* smk_import only expects to return NULL for errors. It
* is usually the case that a nullstring or "\n" would be
* bad to pass to smk_import but in fact this is useful here.
+ *
+ * smk_import will also reject a label beginning with '-',
+ * so "-usecapabilities" will also work.
*/
- smack_onlycap = smk_import(in, count);
+ if (copy_from_user(data, buf, count) != 0)
+ rc = -EFAULT;
+ else
+ smack_onlycap = smk_import(data, count);
- return count;
+ kfree(data);
+ return rc;
}
static const struct file_operations smk_onlycap_ops = {
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
- seq_printf(s, "%s %s", (char *)srp->smk_subject,
- (char *)srp->smk_object);
-
- seq_putc(s, ' ');
-
- if (srp->smk_access & MAY_READ)
- seq_putc(s, 'r');
- if (srp->smk_access & MAY_WRITE)
- seq_putc(s, 'w');
- if (srp->smk_access & MAY_EXEC)
- seq_putc(s, 'x');
- if (srp->smk_access & MAY_APPEND)
- seq_putc(s, 'a');
- if (srp->smk_access & MAY_TRANSMUTE)
- seq_putc(s, 't');
- if (srp->smk_access == 0)
- seq_putc(s, '-');
-
- seq_putc(s, '\n');
+ smk_rule_show(s, srp, SMK_LABELLEN);
return 0;
}
/**
- * smk_open_load_self - open() for /smack/load-self
+ * smk_open_load_self - open() for /smack/load-self2
* @inode: inode structure representing file
* @file: "load" file pointer
*
{
struct task_smack *tsp = current_security();
- return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules,
- &tsp->smk_rules_lock);
+ return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
+ &tsp->smk_rules_lock, SMK_FIXED24_FMT);
}
static const struct file_operations smk_load_self_ops = {
};
/**
- * smk_write_access - handle access check transaction
+ * smk_user_access - handle access check transaction
* @file: file pointer
* @buf: data from user space
* @count: bytes sent
* @ppos: where to start - must be 0
*/
-static ssize_t smk_write_access(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t smk_user_access(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos, int format)
{
struct smack_rule rule;
char *data;
+ char *cod;
int res;
data = simple_transaction_get(file, buf, count);
if (IS_ERR(data))
return PTR_ERR(data);
- if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0))
+ if (format == SMK_FIXED24_FMT) {
+ if (count < SMK_LOADLEN)
+ return -EINVAL;
+ res = smk_parse_rule(data, &rule, 0);
+ } else {
+ /*
+ * Copy the data to make sure the string is terminated.
+ */
+ cod = kzalloc(count + 1, GFP_KERNEL);
+ if (cod == NULL)
+ return -ENOMEM;
+ memcpy(cod, data, count);
+ cod[count] = '\0';
+ res = smk_parse_long_rule(cod, &rule, 0);
+ kfree(cod);
+ }
+
+ if (res)
return -EINVAL;
res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
data[1] = '\0';
simple_transaction_set(file, 2);
- return SMK_LOADLEN;
+
+ if (format == SMK_FIXED24_FMT)
+ return SMK_LOADLEN;
+ return count;
+}
+
+/**
+ * smk_write_access - handle access check transaction
+ * @file: file pointer
+ * @buf: data from user space
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ */
+static ssize_t smk_write_access(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return smk_user_access(file, buf, count, ppos, SMK_FIXED24_FMT);
}
static const struct file_operations smk_access_ops = {
.llseek = generic_file_llseek,
};
+
+/*
+ * Seq_file read operations for /smack/load2
+ */
+
+static int load2_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_master_list *smlp =
+ list_entry(list, struct smack_master_list, list);
+
+ smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL);
+
+ return 0;
+}
+
+static const struct seq_operations load2_seq_ops = {
+ .start = load2_seq_start,
+ .next = load2_seq_next,
+ .show = load2_seq_show,
+ .stop = smk_seq_stop,
+};
+
+/**
+ * smk_open_load2 - open() for /smack/load2
+ * @inode: inode structure representing file
+ * @file: "load2" file pointer
+ *
+ * For reading, use load2_seq_* seq_file reading operations.
+ */
+static int smk_open_load2(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &load2_seq_ops);
+}
+
+/**
+ * smk_write_load2 - write() for /smack/load2
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ */
+static ssize_t smk_write_load2(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /*
+ * Must have privilege.
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
+ SMK_LONG_FMT);
+}
+
+static const struct file_operations smk_load2_ops = {
+ .open = smk_open_load2,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_load2,
+ .release = seq_release,
+};
+
+/*
+ * Seq_file read operations for /smack/load-self2
+ */
+
+static void *load_self2_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct task_smack *tsp = current_security();
+
+ return smk_seq_start(s, pos, &tsp->smk_rules);
+}
+
+static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct task_smack *tsp = current_security();
+
+ return smk_seq_next(s, v, pos, &tsp->smk_rules);
+}
+
+static int load_self2_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_rule *srp =
+ list_entry(list, struct smack_rule, list);
+
+ smk_rule_show(s, srp, SMK_LONGLABEL);
+
+ return 0;
+}
+
+static const struct seq_operations load_self2_seq_ops = {
+ .start = load_self2_seq_start,
+ .next = load_self2_seq_next,
+ .show = load_self2_seq_show,
+ .stop = smk_seq_stop,
+};
+
+/**
+ * smk_open_load_self2 - open() for /smack/load-self2
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For reading, use load_seq_* seq_file reading operations.
+ */
+static int smk_open_load_self2(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &load_self2_seq_ops);
+}
+
+/**
+ * smk_write_load_self2 - write() for /smack/load-self2
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ */
+static ssize_t smk_write_load_self2(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_smack *tsp = current_security();
+
+ return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
+ &tsp->smk_rules_lock, SMK_LONG_FMT);
+}
+
+static const struct file_operations smk_load_self2_ops = {
+ .open = smk_open_load_self2,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_load_self2,
+ .release = seq_release,
+};
+
+/**
+ * smk_write_access2 - handle access check transaction
+ * @file: file pointer
+ * @buf: data from user space
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ */
+static ssize_t smk_write_access2(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return smk_user_access(file, buf, count, ppos, SMK_LONG_FMT);
+}
+
+static const struct file_operations smk_access2_ops = {
+ .write = smk_write_access2,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
+ .llseek = generic_file_llseek,
+};
+
/**
* smk_fill_super - fill the /smackfs superblock
* @sb: the empty superblock
"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
[SMK_ACCESSES] = {
"access", &smk_access_ops, S_IRUGO|S_IWUGO},
+ [SMK_MAPPED] = {
+ "mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR},
+ [SMK_LOAD2] = {
+ "load2", &smk_load2_ops, S_IRUGO|S_IWUSR},
+ [SMK_LOAD_SELF2] = {
+ "load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO},
+ [SMK_ACCESS2] = {
+ "access2", &smk_access2_ops, S_IRUGO|S_IWUGO},
+ [SMK_CIPSO2] = {
+ "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR},
/* last one */
{""}
};
static struct vfsmount *smackfs_mount;
+static int __init smk_preset_netlabel(struct smack_known *skp)
+{
+ skp->smk_netlabel.domain = skp->smk_known;
+ skp->smk_netlabel.flags =
+ NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
+ return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
+ &skp->smk_netlabel, strlen(skp->smk_known));
+}
+
/**
* init_smk_fs - get the smackfs superblock
*
static int __init init_smk_fs(void)
{
int err;
+ int rc;
if (!security_module_enable(&smack_ops))
return 0;
smk_cipso_doi();
smk_unlbl_ambient(NULL);
+ rc = smk_preset_netlabel(&smack_known_floor);
+ if (err == 0 && rc < 0)
+ err = rc;
+ rc = smk_preset_netlabel(&smack_known_hat);
+ if (err == 0 && rc < 0)
+ err = rc;
+ rc = smk_preset_netlabel(&smack_known_huh);
+ if (err == 0 && rc < 0)
+ err = rc;
+ rc = smk_preset_netlabel(&smack_known_invalid);
+ if (err == 0 && rc < 0)
+ err = rc;
+ rc = smk_preset_netlabel(&smack_known_star);
+ if (err == 0 && rc < 0)
+ err = rc;
+ rc = smk_preset_netlabel(&smack_known_web);
+ if (err == 0 && rc < 0)
+ err = rc;
+
return err;
}