lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4FA81F79.50408@schaufler-ca.com>
Date:	Mon, 07 May 2012 12:16:09 -0700
From:	Casey Schaufler <casey@...aufler-ca.com>
To:	Casey Schaufler <casey@...aufler-ca.com>
CC:	LSM <linux-security-module@...r.kernel.org>,
	LKLM <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH] Smack: allow for significantly longer Smack labels v4

On 5/6/2012 3:22 PM, Casey Schaufler wrote:
> V4 updated to current linux-security#next
> Targeted for git://gitorious.org/smack-next/kernel.git

Applied to git://gitorious.org/smack-next/kernel.git


>
> Modern application runtime environments like to use
> naming schemes that are structured and generated without
> human intervention. Even though the Smack limit of 23
> characters for a label name is perfectly rational for
> human use there have been complaints that the limit is
> a problem in environments where names are composed from
> a set or sources, including vendor, author, distribution
> channel and application name. Names like
>
> 	softwarehouse-pgwodehouse-coolappstore-mellowmuskrats
>
> are becoming harder to avoid. This patch introduces long
> label support in Smack. Labels are now limited to 255
> characters instead of the old 23.
>
> The primary reason for limiting the labels to 23 characters
> was so they could be directly contained in CIPSO category sets.
> This is still done were possible, but for labels that are too
> large a mapping is required. This is perfectly safe for communication
> that stays "on the box" and doesn't require much coordination
> between boxes beyond what would have been required to keep label
> names consistent.
>
> The bulk of this patch is in smackfs, adding and updating
> administrative interfaces. Because existing APIs can't be
> changed new ones that do much the same things as old ones
> have been introduced.
>
> The Smack specific CIPSO data representation has been removed
> and replaced with the data format used by netlabel. The CIPSO
> header is now computed when a label is imported rather than
> on use. This results in improved IP performance. The smack
> label is now allocated separately from the containing structure,
> allowing for larger strings. 
>
> Four new /smack interfaces have been introduced as four
> of the old interfaces strictly required labels be specified
> in fixed length arrays.
>
> The access interface is supplemented with the check interface:
> 	access  "Subject                 Object                  rwxat"
> 	access2 "Subject Object rwaxt"
>
> The load interface is supplemented with the rules interface:
> 	load   "Subject                 Object                  rwxat"
> 	load2  "Subject Object rwaxt"
>
> The load-self interface is supplemented with the self-rules interface:
> 	load-self   "Subject                 Object                  rwxat"
> 	load-self2  "Subject Object rwaxt"
>
> The cipso interface is supplemented with the wire interface:
> 	cipso  "Subject                  lvl cnt  c1  c2 ..."
> 	cipso2 "Subject lvl cnt  c1  c2 ..."
>
> The old interfaces are maintained for compatibility.
>
> Signed-off-by: Casey Schaufler <casey@...aufler-ca.com>
>
> ---
>
>  Documentation/security/Smack.txt |  204 +++++++--
>  security/smack/smack.h           |   56 +--
>  security/smack/smack_access.c    |  233 +++++-----
>  security/smack/smack_lsm.c       |  185 ++------
>  security/smack/smackfs.c         |  993 +++++++++++++++++++++++++++++---------
>  5 files changed, 1105 insertions(+), 566 deletions(-)
>
> diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt
> index d2f72ae..a416479 100644
> --- a/Documentation/security/Smack.txt
> +++ b/Documentation/security/Smack.txt
> @@ -15,7 +15,7 @@ at hand.
>  
>  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
> @@ -23,37 +23,28 @@ Security Modules (LSM) module. It requires netlabel and
>  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@...orious.org:meego-platform-security/smackutil.git
> +	git@...orious.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:
>  
> @@ -61,19 +52,148 @@ 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:
>  
> @@ -83,10 +203,6 @@ access is a combination of the letters rwxa which specify the
>  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:
> @@ -186,7 +302,7 @@ team. Smack labels are unstructured, case sensitive, and the only operation
>  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:
>  
> @@ -194,7 +310,7 @@ 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
> @@ -246,13 +362,14 @@ The format of an access rule is:
>  
>  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
> @@ -273,7 +390,7 @@ Examples of unacceptable rules are:
>  
>  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.
>  
> @@ -297,6 +414,13 @@ but not any of its attributes by the circumstance of having read access to the
>  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.
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index cf2594d..5e031a2 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -23,13 +23,19 @@
>  #include <linux/lsm_audit.h>
>  
>  /*
> + * Smack labels were limited to 23 characters for a long time.
> + */
> +#define SMK_LABELLEN	24
> +#define SMK_LONGLABEL	256
> +
> +/*
> + * Maximum number of bytes for the levels in a CIPSO IP option.
>   * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
>   * bigger than can be used, and 24 is the next lower multiple
>   * of 8, and there are too many issues if there isn't space set
>   * aside for the terminating null byte.
>   */
> -#define SMK_MAXLEN	23
> -#define SMK_LABELLEN	(SMK_MAXLEN+1)
> +#define SMK_CIPSOLEN	24
>  
>  struct superblock_smack {
>  	char		*smk_root;
> @@ -79,15 +85,6 @@ struct smack_rule {
>  };
>  
>  /*
> - * An entry in the table mapping smack values to
> - * CIPSO level/category-set values.
> - */
> -struct smack_cipso {
> -	int	smk_level;
> -	char	smk_catset[SMK_LABELLEN];
> -};
> -
> -/*
>   * An entry in the table identifying hosts.
>   */
>  struct smk_netlbladdr {
> @@ -114,22 +111,19 @@ struct smk_netlbladdr {
>   * interfaces don't. The secid should go away when all of
>   * these components have been repaired.
>   *
> - * If there is a cipso value associated with the label it
> - * gets stored here, too. This will most likely be rare as
> - * the cipso direct mapping in used internally.
> + * The cipso value associated with the label gets stored here, too.
>   *
>   * Keep the access rules for this subject label here so that
>   * the entire set of rules does not need to be examined every
>   * time.
>   */
>  struct smack_known {
> -	struct list_head	list;
> -	char			smk_known[SMK_LABELLEN];
> -	u32			smk_secid;
> -	struct smack_cipso	*smk_cipso;
> -	spinlock_t		smk_cipsolock;	/* for changing cipso map */
> -	struct list_head	smk_rules;	/* access rules */
> -	struct mutex		smk_rules_lock;	/* lock for the rules */
> +	struct list_head		list;
> +	char				*smk_known;
> +	u32				smk_secid;
> +	struct netlbl_lsm_secattr	smk_netlabel;	/* on wire labels */
> +	struct list_head		smk_rules;	/* access rules */
> +	struct mutex			smk_rules_lock;	/* lock for rules */
>  };
>  
>  /*
> @@ -166,6 +160,7 @@ struct smack_known {
>  #define SMACK_CIPSO_DOI_DEFAULT		3	/* Historical */
>  #define SMACK_CIPSO_DOI_INVALID		-1	/* Not a DOI */
>  #define SMACK_CIPSO_DIRECT_DEFAULT	250	/* Arbitrary */
> +#define SMACK_CIPSO_MAPPED_DEFAULT	251	/* Also arbitrary */
>  #define SMACK_CIPSO_MAXCATVAL		63	/* Bigger gets harder */
>  #define SMACK_CIPSO_MAXLEVEL            255     /* CIPSO 2.2 standard */
>  #define SMACK_CIPSO_MAXCATNUM           239     /* CIPSO 2.2 standard */
> @@ -216,10 +211,9 @@ struct inode_smack *new_inode_smack(char *);
>  int smk_access_entry(char *, char *, struct list_head *);
>  int smk_access(char *, char *, int, struct smk_audit_info *);
>  int smk_curacc(char *, u32, struct smk_audit_info *);
> -int smack_to_cipso(const char *, struct smack_cipso *);
> -char *smack_from_cipso(u32, char *);
>  char *smack_from_secid(const u32);
> -void smk_parse_smack(const char *string, int len, char *smack);
> +char *smk_parse_smack(const char *string, int len);
> +int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
>  char *smk_import(const char *, int);
>  struct smack_known *smk_import_entry(const char *, int);
>  struct smack_known *smk_find_entry(const char *);
> @@ -229,6 +223,7 @@ u32 smack_to_secid(const char *);
>   * Shared data.
>   */
>  extern int smack_cipso_direct;
> +extern int smack_cipso_mapped;
>  extern char *smack_net_ambient;
>  extern char *smack_onlycap;
>  extern const char *smack_cipso_option;
> @@ -240,24 +235,13 @@ extern struct smack_known smack_known_invalid;
>  extern struct smack_known smack_known_star;
>  extern struct smack_known smack_known_web;
>  
> +extern struct mutex	smack_known_lock;
>  extern struct list_head smack_known_list;
>  extern struct list_head smk_netlbladdr_list;
>  
>  extern struct security_operations smack_ops;
>  
>  /*
> - * Stricly for CIPSO level manipulation.
> - * Set the category bit number in a smack label sized buffer.
> - */
> -static inline void smack_catset_bit(int cat, char *catsetp)
> -{
> -	if (cat > SMK_LABELLEN * 8)
> -		return;
> -
> -	catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
> -}
> -
> -/*
>   * Is the directory transmuting?
>   */
>  static inline int smk_inode_transmutable(const struct inode *isp)
> diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
> index c8115f7..9f3705e 100644
> --- a/security/smack/smack_access.c
> +++ b/security/smack/smack_access.c
> @@ -19,37 +19,31 @@
>  struct smack_known smack_known_huh = {
>  	.smk_known	= "?",
>  	.smk_secid	= 2,
> -	.smk_cipso	= NULL,
>  };
>  
>  struct smack_known smack_known_hat = {
>  	.smk_known	= "^",
>  	.smk_secid	= 3,
> -	.smk_cipso	= NULL,
>  };
>  
>  struct smack_known smack_known_star = {
>  	.smk_known	= "*",
>  	.smk_secid	= 4,
> -	.smk_cipso	= NULL,
>  };
>  
>  struct smack_known smack_known_floor = {
>  	.smk_known	= "_",
>  	.smk_secid	= 5,
> -	.smk_cipso	= NULL,
>  };
>  
>  struct smack_known smack_known_invalid = {
>  	.smk_known	= "",
>  	.smk_secid	= 6,
> -	.smk_cipso	= NULL,
>  };
>  
>  struct smack_known smack_known_web = {
>  	.smk_known	= "@",
>  	.smk_secid	= 7,
> -	.smk_cipso	= NULL,
>  };
>  
>  LIST_HEAD(smack_known_list);
> @@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request,
>  }
>  #endif
>  
> -static DEFINE_MUTEX(smack_known_lock);
> +DEFINE_MUTEX(smack_known_lock);
>  
>  /**
>   * smk_find_entry - find a label on the list, return the list entry
> @@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string)
>  	struct smack_known *skp;
>  
>  	list_for_each_entry_rcu(skp, &smack_known_list, list) {
> -		if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0)
> +		if (strcmp(skp->smk_known, string) == 0)
>  			return skp;
>  	}
>  
> @@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string)
>   * smk_parse_smack - parse smack label from a text string
>   * @string: a text string that might contain a Smack label
>   * @len: the maximum size, or zero if it is NULL terminated.
> - * @smack: parsed smack label, or NULL if parse error
> + *
> + * Returns a pointer to the clean label, or NULL
>   */
> -void smk_parse_smack(const char *string, int len, char *smack)
> +char *smk_parse_smack(const char *string, int len)
>  {
> -	int found;
> +	char *smack;
>  	int i;
>  
> -	if (len <= 0 || len > SMK_MAXLEN)
> -		len = SMK_MAXLEN;
> -
> -	for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
> -		if (found)
> -			smack[i] = '\0';
> -		else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
> -			 string[i] == '/' || string[i] == '"' ||
> -			 string[i] == '\\' || string[i] == '\'') {
> -			smack[i] = '\0';
> -			found = 1;
> -		} else
> -			smack[i] = string[i];
> +	if (len <= 0)
> +		len = strlen(string) + 1;
> +
> +	/*
> +	 * Reserve a leading '-' as an indicator that
> +	 * this isn't a label, but an option to interfaces
> +	 * including /smack/cipso and /smack/cipso2
> +	 */
> +	if (string[0] == '-')
> +		return NULL;
> +
> +	for (i = 0; i < len; i++)
> +		if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
> +		    string[i] == '"' || string[i] == '\\' || string[i] == '\'')
> +			break;
> +
> +	if (i == 0 || i >= SMK_LONGLABEL)
> +		return NULL;
> +
> +	smack = kzalloc(i + 1, GFP_KERNEL);
> +	if (smack != NULL) {
> +		strncpy(smack, string, i + 1);
> +		smack[i] = '\0';
>  	}
> +	return smack;
> +}
> +
> +/**
> + * smk_netlbl_mls - convert a catset to netlabel mls categories
> + * @catset: the Smack categories
> + * @sap: where to put the netlabel categories
> + *
> + * Allocates and fills attr.mls
> + * Returns 0 on success, error code on failure.
> + */
> +int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
> +			int len)
> +{
> +	unsigned char *cp;
> +	unsigned char m;
> +	int cat;
> +	int rc;
> +	int byte;
> +
> +	sap->flags |= NETLBL_SECATTR_MLS_CAT;
> +	sap->attr.mls.lvl = level;
> +	sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> +	sap->attr.mls.cat->startbit = 0;
> +
> +	for (cat = 1, cp = catset, byte = 0; byte < len; 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);
> +			if (rc < 0) {
> +				netlbl_secattr_catmap_free(sap->attr.mls.cat);
> +				return rc;
> +			}
> +		}
> +
> +	return 0;
>  }
>  
>  /**
> @@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack)
>  struct smack_known *smk_import_entry(const char *string, int len)
>  {
>  	struct smack_known *skp;
> -	char smack[SMK_LABELLEN];
> +	char *smack;
> +	int slen;
> +	int rc;
>  
> -	smk_parse_smack(string, len, smack);
> -	if (smack[0] == '\0')
> +	smack = smk_parse_smack(string, len);
> +	if (smack == NULL)
>  		return NULL;
>  
>  	mutex_lock(&smack_known_lock);
>  
>  	skp = smk_find_entry(smack);
> +	if (skp != NULL)
> +		goto freeout;
>  
> -	if (skp == NULL) {
> -		skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
> -		if (skp != NULL) {
> -			strncpy(skp->smk_known, smack, SMK_MAXLEN);
> -			skp->smk_secid = smack_next_secid++;
> -			skp->smk_cipso = NULL;
> -			INIT_LIST_HEAD(&skp->smk_rules);
> -			spin_lock_init(&skp->smk_cipsolock);
> -			mutex_init(&skp->smk_rules_lock);
> -			/*
> -			 * Make sure that the entry is actually
> -			 * filled before putting it on the list.
> -			 */
> -			list_add_rcu(&skp->list, &smack_known_list);
> -		}
> -	}
> +	skp = kzalloc(sizeof(*skp), GFP_KERNEL);
> +	if (skp == NULL)
> +		goto freeout;
>  
> +	skp->smk_known = smack;
> +	skp->smk_secid = smack_next_secid++;
> +	skp->smk_netlabel.domain = skp->smk_known;
> +	skp->smk_netlabel.flags =
> +		NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
> +	/*
> +	 * If direct labeling works use it.
> +	 * Otherwise use mapped labeling.
> +	 */
> +	slen = strlen(smack);
> +	if (slen < SMK_CIPSOLEN)
> +		rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
> +			       &skp->smk_netlabel, slen);
> +	else
> +		rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
> +			       &skp->smk_netlabel, sizeof(skp->smk_secid));
> +
> +	if (rc >= 0) {
> +		INIT_LIST_HEAD(&skp->smk_rules);
> +		mutex_init(&skp->smk_rules_lock);
> +		/*
> +		 * Make sure that the entry is actually
> +		 * filled before putting it on the list.
> +		 */
> +		list_add_rcu(&skp->list, &smack_known_list);
> +		goto unlockout;
> +	}
> +	/*
> +	 * smk_netlbl_mls failed.
> +	 */
> +	kfree(skp);
> +	skp = NULL;
> +freeout:
> +	kfree(smack);
> +unlockout:
>  	mutex_unlock(&smack_known_lock);
>  
>  	return skp;
> @@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid)
>   */
>  u32 smack_to_secid(const char *smack)
>  {
> -	struct smack_known *skp;
> +	struct smack_known *skp = smk_find_entry(smack);
>  
> -	rcu_read_lock();
> -	list_for_each_entry_rcu(skp, &smack_known_list, list) {
> -		if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
> -			rcu_read_unlock();
> -			return skp->smk_secid;
> -		}
> -	}
> -	rcu_read_unlock();
> -	return 0;
> -}
> -
> -/**
> - * smack_from_cipso - find the Smack label associated with a CIPSO option
> - * @level: Bell & LaPadula level from the network
> - * @cp: Bell & LaPadula categories from the network
> - *
> - * This is a simple lookup in the label table.
> - *
> - * Return the matching label from the label list or NULL.
> - */
> -char *smack_from_cipso(u32 level, char *cp)
> -{
> -	struct smack_known *kp;
> -	char *final = NULL;
> -
> -	rcu_read_lock();
> -	list_for_each_entry(kp, &smack_known_list, list) {
> -		if (kp->smk_cipso == NULL)
> -			continue;
> -
> -		spin_lock_bh(&kp->smk_cipsolock);
> -
> -		if (kp->smk_cipso->smk_level == level &&
> -		    memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
> -			final = kp->smk_known;
> -
> -		spin_unlock_bh(&kp->smk_cipsolock);
> -
> -		if (final != NULL)
> -			break;
> -	}
> -	rcu_read_unlock();
> -
> -	return final;
> -}
> -
> -/**
> - * smack_to_cipso - find the CIPSO option to go with a Smack label
> - * @smack: a pointer to the smack label in question
> - * @cp: where to put the result
> - *
> - * Returns zero if a value is available, non-zero otherwise.
> - */
> -int smack_to_cipso(const char *smack, struct smack_cipso *cp)
> -{
> -	struct smack_known *kp;
> -	int found = 0;
> -
> -	rcu_read_lock();
> -	list_for_each_entry_rcu(kp, &smack_known_list, list) {
> -		if (kp->smk_known == smack ||
> -		    strcmp(kp->smk_known, smack) == 0) {
> -			found = 1;
> -			break;
> -		}
> -	}
> -	rcu_read_unlock();
> -
> -	if (found == 0 || kp->smk_cipso == NULL)
> -		return -ENOENT;
> -
> -	memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
> -	return 0;
> +	if (skp == NULL)
> +		return 0;
> +	return skp->smk_secid;
>  }
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 5f80075..952b1f4 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -30,7 +30,6 @@
>  #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>
> @@ -57,16 +56,23 @@
>  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;
>  }
>  
>  /**
> @@ -825,7 +831,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
>  		 * 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) {
> @@ -1824,65 +1830,6 @@ static char *smack_host_label(struct sockaddr_in *sip)
>  }
>  
>  /**
> - * 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
> @@ -1894,8 +1841,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
>   */
>  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;
>  
>  	/*
> @@ -1913,10 +1860,8 @@ static int smack_netlabel(struct sock *sk, int labeled)
>  	    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);
> @@ -1989,7 +1934,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
>  	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);
> @@ -2785,7 +2730,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
>  	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)
> @@ -2921,10 +2866,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
>  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) {
>  		/*
> @@ -2932,59 +2876,27 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
>  		 * 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;
> @@ -3184,11 +3096,13 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  				   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
> @@ -3235,16 +3149,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  	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;
>  }
> @@ -3669,15 +3581,6 @@ struct security_operations smack_ops = {
>  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);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 038811c..1810c9a 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -22,7 +22,6 @@
>  #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>
> @@ -45,6 +44,11 @@ enum smk_inos {
>  	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 */
>  };
>  
>  /*
> @@ -60,7 +64,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
>   * 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
> @@ -70,6 +74,13 @@ char *smack_net_ambient = smack_known_floor.smk_known;
>  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
> @@ -89,7 +100,7 @@ LIST_HEAD(smk_netlbladdr_list);
>  
>  /*
>   * 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;
> @@ -125,6 +136,18 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION;
>  #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
> @@ -137,12 +160,10 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
>  }
>  
>  /*
> - * 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
> @@ -188,33 +209,47 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *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;
> @@ -222,90 +257,127 @@ static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
>  
>  	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;
>  
> @@ -315,13 +387,18 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
>  	 */
>  	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;
>  
> @@ -330,20 +407,29 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
>  		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;
> @@ -354,18 +440,20 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
>  
>  	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;
>  	}
>  
> @@ -421,29 +509,18 @@ static void smk_seq_stop(struct seq_file *s, void *v)
>  	/* 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, ' ');
>  
> @@ -461,13 +538,36 @@ static int load_seq_show(struct seq_file *s, void *v)
>  		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,
>  };
> @@ -504,7 +604,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
>  	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 = {
> @@ -574,6 +675,8 @@ static void smk_unlbl_ambient(char *oldambient)
>  			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);
> @@ -605,27 +708,28 @@ static int cipso_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 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');
>  
> @@ -653,23 +757,24 @@ static int smk_open_cipso(struct inode *inode, struct file *file)
>  }
>  
>  /**
> - * 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;
> @@ -686,7 +791,8 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
>  		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);
> @@ -698,11 +804,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
>  		goto unlockedout;
>  	}
>  
> -	/* labels cannot begin with a '-' */
> -	if (data[0] == '-') {
> -		rc = -EINVAL;
> -		goto unlockedout;
> -	}
>  	data[count] = '\0';
>  	rule = data;
>  	/*
> @@ -715,7 +816,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
>  	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;
> @@ -725,41 +830,29 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
>  	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:
> @@ -767,6 +860,22 @@ 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,
> @@ -776,6 +885,80 @@ static const struct file_operations smk_cipso_ops = {
>  };
>  
>  /*
> + * 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
>   */
>  
> @@ -887,9 +1070,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
>  {
>  	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;
> @@ -911,10 +1094,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
>  		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';
>  
> @@ -923,24 +1119,34 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
>  	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--) {
> @@ -1006,6 +1212,11 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
>  
>  	mutex_unlock(&smk_netlbladdr_lock);
>  
> +free_out:
> +	kfree(smack);
> +free_data_out:
> +	kfree(data);
> +
>  	return rc;
>  }
>  
> @@ -1119,6 +1330,7 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf,
>  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;
>  
> @@ -1136,7 +1348,20 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf,
>  	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;
>  }
> @@ -1148,6 +1373,84 @@ static const struct file_operations smk_direct_ops = {
>  };
>  
>  /**
> + * 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
> @@ -1195,22 +1498,28 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
>  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);
>  
> @@ -1220,7 +1529,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
>  
>  	mutex_unlock(&smack_ambient_lock);
>  
> -	return count;
> +out:
> +	kfree(data);
> +	return rc;
>  }
>  
>  static const struct file_operations smk_ambient_ops = {
> @@ -1271,8 +1582,9 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
>  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;
> @@ -1285,11 +1597,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
>  	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.
> @@ -1297,10 +1607,17 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
>  	 * 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 = {
> @@ -1398,25 +1715,7 @@ static int load_self_seq_show(struct seq_file *s, void *v)
>  	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;
>  }
> @@ -1430,7 +1729,7 @@ static const struct seq_operations load_self_seq_ops = {
>  
>  
>  /**
> - * 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
>   *
> @@ -1454,8 +1753,8 @@ static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
>  {
>  	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 = {
> @@ -1467,24 +1766,42 @@ 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,
> @@ -1493,7 +1810,23 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf,
>  	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 = {
> @@ -1503,6 +1836,163 @@ 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
> @@ -1539,6 +2029,16 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
>  			"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 */
>  			{""}
>  	};
> @@ -1581,6 +2081,15 @@ static struct file_system_type smk_fs_type = {
>  
>  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
>   *
> @@ -1597,6 +2106,7 @@ static struct vfsmount *smackfs_mount;
>  static int __init init_smk_fs(void)
>  {
>  	int err;
> +	int rc;
>  
>  	if (!security_module_enable(&smack_ops))
>  		return 0;
> @@ -1614,6 +2124,25 @@ static int __init init_smk_fs(void)
>  	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;
>  }
>  
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ