diff mbox series

[6a/10] CaitSith: Add policy management functions.

Message ID 5ab69bca-866e-c389-b46b-795f7308db35@I-love.SAKURA.ne.jp (mailing list archive)
State Rejected
Delegated to: Paul Moore
Headers show
Series [6a/10] CaitSith: Add policy management functions. | expand

Commit Message

Tetsuo Handa Nov. 2, 2022, 5:29 p.m. UTC
This file implements similar functions provided by security/tomoyo/common.c
and security/tomoyo/securityfs_if.c files.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
Reposting "[PATCH 06/10] CaitSith: Add policy management functions." as two patches due to
"BOUNCE linux-security-module@vger.kernel.org: Message too long (>100000 chars)" failure.
This is the former part.

 security/caitsith/policy_io.c | 1901 +++++++++++++++++++++++++++++++++
 1 file changed, 1901 insertions(+)
 create mode 100644 security/caitsith/policy_io.c
diff mbox series

Patch

diff --git a/security/caitsith/policy_io.c b/security/caitsith/policy_io.c
new file mode 100644
index 000000000000..27e2ec57f3b8
--- /dev/null
+++ b/security/caitsith/policy_io.c
@@ -0,0 +1,1901 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * policy_io.c
+ *
+ * Copyright (C) 2005-2012  NTT DATA CORPORATION
+ *
+ * Version: 0.2.10   2021/06/06
+ */
+
+#include "caitsith.h"
+
+/***** SECTION1: Constants definition *****/
+
+/* Define this to enable debug mode. */
+/* #define DEBUG_CONDITION */
+
+#ifdef DEBUG_CONDITION
+#define dprintk printk
+#else
+#define dprintk(...) do { } while (0)
+#endif
+
+/* String table for operation. */
+static const char * const cs_mac_keywords[CS_MAX_MAC_INDEX] = {
+	[CS_MAC_EXECUTE]    = "execute",
+	[CS_MAC_READ]       = "read",
+	[CS_MAC_WRITE]      = "write",
+	[CS_MAC_APPEND]     = "append",
+	[CS_MAC_CREATE]     = "create",
+	[CS_MAC_UNLINK]     = "unlink",
+#ifdef CONFIG_SECURITY_CAITSITH_GETATTR
+	[CS_MAC_GETATTR]    = "getattr",
+#endif
+	[CS_MAC_MKDIR]      = "mkdir",
+	[CS_MAC_RMDIR]      = "rmdir",
+	[CS_MAC_MKFIFO]     = "mkfifo",
+	[CS_MAC_MKSOCK]     = "mksock",
+	[CS_MAC_TRUNCATE]   = "truncate",
+	[CS_MAC_SYMLINK]    = "symlink",
+	[CS_MAC_MKBLOCK]    = "mkblock",
+	[CS_MAC_MKCHAR]     = "mkchar",
+	[CS_MAC_LINK]       = "link",
+	[CS_MAC_RENAME]     = "rename",
+	[CS_MAC_CHMOD]      = "chmod",
+	[CS_MAC_CHOWN]      = "chown",
+	[CS_MAC_CHGRP]      = "chgrp",
+	[CS_MAC_IOCTL]      = "ioctl",
+	[CS_MAC_CHROOT]     = "chroot",
+	[CS_MAC_MOUNT]      = "mount",
+	[CS_MAC_UMOUNT]     = "unmount",
+	[CS_MAC_PIVOT_ROOT] = "pivot_root",
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+	[CS_MAC_INET_STREAM_BIND]       = "inet_stream_bind",
+	[CS_MAC_INET_STREAM_LISTEN]     = "inet_stream_listen",
+	[CS_MAC_INET_STREAM_CONNECT]    = "inet_stream_connect",
+	[CS_MAC_INET_STREAM_ACCEPT]     = "inet_stream_accept",
+	[CS_MAC_INET_DGRAM_BIND]        = "inet_dgram_bind",
+	[CS_MAC_INET_DGRAM_SEND]        = "inet_dgram_send",
+	[CS_MAC_INET_RAW_BIND]          = "inet_raw_bind",
+	[CS_MAC_INET_RAW_SEND]          = "inet_raw_send",
+	[CS_MAC_UNIX_STREAM_BIND]       = "unix_stream_bind",
+	[CS_MAC_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
+	[CS_MAC_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
+	[CS_MAC_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",
+	[CS_MAC_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
+	[CS_MAC_UNIX_DGRAM_SEND]        = "unix_dgram_send",
+	[CS_MAC_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
+	[CS_MAC_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
+	[CS_MAC_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
+	[CS_MAC_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",
+#endif
+#ifdef CONFIG_SECURITY_CAITSITH_ENVIRON
+	[CS_MAC_ENVIRON] = "environ",
+#endif
+	[CS_MAC_MODIFY_POLICY]      = "modify_policy",
+#ifdef CONFIG_SECURITY_CAITSITH_CAPABILITY
+	[CS_MAC_USE_NETLINK_SOCKET] = "use_netlink_socket",
+	[CS_MAC_USE_PACKET_SOCKET]  = "use_packet_socket",
+#endif
+#ifdef CONFIG_SECURITY_CAITSITH_AUTO_DOMAIN_TRANSITION
+	[CS_MAC_AUTO_DOMAIN_TRANSITION]   = "auto_domain_transition",
+#endif
+#ifdef CONFIG_SECURITY_CAITSITH_MANUAL_DOMAIN_TRANSITION
+	[CS_MAC_MANUAL_DOMAIN_TRANSITION] = "manual_domain_transition",
+#endif
+};
+
+/* String table for grouping keywords. */
+static const char * const cs_group_name[CS_MAX_GROUP] = {
+	[CS_STRING_GROUP] = "string_group",
+	[CS_NUMBER_GROUP] = "number_group",
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+	[CS_IP_GROUP]     = "ip_group",
+#endif
+};
+
+/* String table for stat info. */
+static const char * const cs_memory_headers[CS_MAX_MEMORY_STAT] = {
+	[CS_MEMORY_POLICY] = "policy",
+	[CS_MEMORY_AUDIT]  = "audit",
+	[CS_MEMORY_QUERY]  = "query",
+};
+
+#define F(bit) (1ULL << bit)
+
+#define CS_ALL_OK				\
+	(F(CS_MAC_EXECUTE) |			\
+	 F(CS_MAC_READ) |			\
+	 F(CS_MAC_WRITE) |			\
+	 F(CS_MAC_APPEND) |			\
+	 F(CS_MAC_CREATE) |			\
+	 F(CS_MAC_UNLINK) |			\
+	 F(CS_MAC_GETATTR) |			\
+	 F(CS_MAC_MKDIR) |			\
+	 F(CS_MAC_RMDIR) |			\
+	 F(CS_MAC_MKFIFO) |			\
+	 F(CS_MAC_MKSOCK) |			\
+	 F(CS_MAC_TRUNCATE) |			\
+	 F(CS_MAC_SYMLINK) |			\
+	 F(CS_MAC_MKBLOCK) |			\
+	 F(CS_MAC_MKCHAR) |			\
+	 F(CS_MAC_LINK) |			\
+	 F(CS_MAC_RENAME) |			\
+	 F(CS_MAC_CHMOD) |			\
+	 F(CS_MAC_CHOWN) |			\
+	 F(CS_MAC_CHGRP) |			\
+	 F(CS_MAC_IOCTL) |			\
+	 F(CS_MAC_CHROOT) |			\
+	 F(CS_MAC_MOUNT) |			\
+	 F(CS_MAC_UMOUNT) |			\
+	 F(CS_MAC_PIVOT_ROOT) |			\
+	 F(CS_MAC_INET_STREAM_BIND) |		\
+	 F(CS_MAC_INET_STREAM_LISTEN) |		\
+	 F(CS_MAC_INET_STREAM_CONNECT) |	\
+	 F(CS_MAC_INET_STREAM_ACCEPT) |		\
+	 F(CS_MAC_INET_DGRAM_BIND) |		\
+	 F(CS_MAC_INET_DGRAM_SEND) |		\
+	 F(CS_MAC_INET_RAW_BIND) |		\
+	 F(CS_MAC_INET_RAW_SEND) |		\
+	 F(CS_MAC_UNIX_STREAM_BIND) |		\
+	 F(CS_MAC_UNIX_STREAM_LISTEN) |		\
+	 F(CS_MAC_UNIX_STREAM_CONNECT) |	\
+	 F(CS_MAC_UNIX_STREAM_ACCEPT) |		\
+	 F(CS_MAC_UNIX_DGRAM_BIND) |		\
+	 F(CS_MAC_UNIX_DGRAM_SEND) |		\
+	 F(CS_MAC_UNIX_SEQPACKET_BIND) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_LISTEN) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_CONNECT) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_ACCEPT) |	\
+	 F(CS_MAC_ENVIRON) |			\
+	 F(CS_MAC_MODIFY_POLICY) |		\
+	 F(CS_MAC_USE_NETLINK_SOCKET) |		\
+	 F(CS_MAC_USE_PACKET_SOCKET) |		\
+	 F(CS_MAC_AUTO_DOMAIN_TRANSITION) |	\
+	 F(CS_MAC_MANUAL_DOMAIN_TRANSITION))
+
+#define CS_PATH_SELF_OK				\
+	(F(CS_MAC_EXECUTE) |			\
+	 F(CS_MAC_READ) |			\
+	 F(CS_MAC_WRITE) |			\
+	 F(CS_MAC_APPEND) |			\
+	 F(CS_MAC_UNLINK) |			\
+	 F(CS_MAC_GETATTR) |			\
+	 F(CS_MAC_RMDIR) |			\
+	 F(CS_MAC_TRUNCATE) |			\
+	 F(CS_MAC_CHMOD) |			\
+	 F(CS_MAC_CHOWN) |			\
+	 F(CS_MAC_CHGRP) |			\
+	 F(CS_MAC_IOCTL) |			\
+	 F(CS_MAC_CHROOT) |			\
+	 F(CS_MAC_UMOUNT) |			\
+	 F(CS_MAC_ENVIRON))
+
+#define CS_PATH_PARENT_OK			\
+	(F(CS_MAC_CREATE) |			\
+	 F(CS_MAC_MKDIR) |			\
+	 F(CS_MAC_MKFIFO) |			\
+	 F(CS_MAC_MKSOCK) |			\
+	 F(CS_MAC_SYMLINK) |			\
+	 F(CS_MAC_MKBLOCK) |			\
+	 F(CS_MAC_MKCHAR))
+
+#define CS_PATH_OK (CS_PATH_SELF_OK | CS_PATH_PARENT_OK)
+
+#define CS_RENAME_OR_LINK_OK (F(CS_MAC_LINK) | F(CS_MAC_RENAME))
+
+#define CS_EXECUTE_OR_ENVIRON_OK (F(CS_MAC_EXECUTE) | F(CS_MAC_ENVIRON))
+
+#define CS_MKDEV_OK (F(CS_MAC_MKBLOCK) | F(CS_MAC_MKCHAR))
+
+#define CS_PATH_PERM_OK				\
+	(F(CS_MAC_MKDIR) |			\
+	 F(CS_MAC_MKBLOCK) |			\
+	 F(CS_MAC_MKCHAR) |			\
+	 F(CS_MAC_MKFIFO) |			\
+	 F(CS_MAC_MKSOCK) |			\
+	 F(CS_MAC_CREATE) |			\
+	 F(CS_MAC_CHMOD))
+
+#define CS_IP_SOCKET_OK				\
+	(F(CS_MAC_INET_STREAM_BIND) |		\
+	 F(CS_MAC_INET_STREAM_LISTEN) |		\
+	 F(CS_MAC_INET_STREAM_CONNECT) |	\
+	 F(CS_MAC_INET_STREAM_ACCEPT) |		\
+	 F(CS_MAC_INET_DGRAM_BIND) |		\
+	 F(CS_MAC_INET_DGRAM_SEND))
+
+#define CS_RAW_SOCKET_OK			\
+	(F(CS_MAC_INET_RAW_BIND) |		\
+	 F(CS_MAC_INET_RAW_SEND))
+
+#define CS_INET_SOCKET_OK (CS_IP_SOCKET_OK | CS_RAW_SOCKET_OK)
+
+#define CS_UNIX_SOCKET_OK			\
+	(F(CS_MAC_UNIX_STREAM_BIND) |		\
+	 F(CS_MAC_UNIX_STREAM_LISTEN) |		\
+	 F(CS_MAC_UNIX_STREAM_CONNECT) |	\
+	 F(CS_MAC_UNIX_STREAM_ACCEPT) |		\
+	 F(CS_MAC_UNIX_DGRAM_BIND) |		\
+	 F(CS_MAC_UNIX_DGRAM_SEND) |		\
+	 F(CS_MAC_UNIX_SEQPACKET_BIND) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_LISTEN) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_CONNECT) |	\
+	 F(CS_MAC_UNIX_SEQPACKET_ACCEPT))
+
+enum cs_var_type {
+	CS_TYPE_INVALID,
+	CS_TYPE_NUMBER,
+	CS_TYPE_STRING,
+	CS_TYPE_IPADDR,
+	CS_TYPE_FILEPERM,
+	CS_TYPE_FILETYPE,
+	CS_TYPE_ASSIGN,
+} __packed;
+
+/* String table for conditions. */
+static const struct {
+	const char * const keyword;
+	const enum cs_var_type left_type;
+	const enum cs_var_type right_type;
+	const enum cs_conditions_index cmd;
+	const u64 available;
+} cs_conditions[] = {
+	{ "addr",                    CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG0,            CS_UNIX_SOCKET_OK },
+	{ "argc",                    CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_EXEC_ARGC,             CS_EXECUTE_OR_ENVIRON_OK },
+	{ "block",                   CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_BLOCK_DEV,      CS_ALL_OK },
+	{ "char",                    CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_CHAR_DEV,       CS_ALL_OK },
+	{ "cmd",                     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            F(CS_MAC_IOCTL) },
+	{ "data",                    CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG3,            F(CS_MAC_MOUNT) },
+	{ "dev_major",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG1,            CS_MKDEV_OK },
+	{ "dev_minor",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG2,            CS_MKDEV_OK },
+	{ "directory",               CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_DIRECTORY,      CS_ALL_OK },
+	{ "domain",                  CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG0,            F(CS_MAC_MANUAL_DOMAIN_TRANSITION) },
+	{ "envc",                    CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_EXEC_ENVC,             CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec",                    CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG1,            CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.fsmagic",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.gid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_GID,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.ino",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_INO,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.major",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.minor",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.fsmagic",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.gid",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_GID,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.ino",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_INO,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.major",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.minor",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.perm",        CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_PERM,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.parent.uid",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_UID,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.perm",               CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_PERM,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.type",               CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_TYPE,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "exec.uid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_UID,
+	  CS_EXECUTE_OR_ENVIRON_OK },
+	{ "fifo",                    CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_FIFO,           CS_ALL_OK },
+	{ "file",                    CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_FILE,           CS_ALL_OK },
+	{ "flags",                   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            F(CS_MAC_MOUNT) | F(CS_MAC_UMOUNT) },
+	{ "fstype",                  CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG2,            F(CS_MAC_MOUNT) },
+	{ "gid",                     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            F(CS_MAC_CHGRP) },
+	{ "group_execute",           CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_GROUP_EXECUTE,    CS_ALL_OK },
+	{ "group_read",              CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_GROUP_READ,       CS_ALL_OK },
+	{ "group_write",             CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_GROUP_WRITE,      CS_ALL_OK },
+	{ "ip",                      CS_TYPE_IPADDR,   CS_TYPE_INVALID,
+	  CS_COND_IPARG,            CS_INET_SOCKET_OK },
+	{ "name",                    CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG2,            F(CS_MAC_ENVIRON) },
+	{ "new_path",                CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG1,            CS_RENAME_OR_LINK_OK },
+	{ "new_path.dev_major",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.dev_minor",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.fsmagic",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.gid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.ino",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.major",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.minor",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.parent.fsmagic", CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.gid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_GID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.ino",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_INO,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.major",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.minor",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.perm",    CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_PERM,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.parent.uid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_UID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "new_path.perm",           CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.type",           CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_TYPE,
+	  F(CS_MAC_RENAME) },
+	{ "new_path.uid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_RENAME) },
+	{ "new_root",                CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG0,            F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.dev_major",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.dev_minor",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.fsmagic",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.gid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.ino",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.major",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.minor",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.fsmagic", CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.gid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.ino",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.major",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.minor",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.perm",    CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.parent.uid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.perm",           CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.type",           CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_TYPE,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "new_root.uid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "old_path",                CS_TYPE_STRING,    CS_TYPE_STRING,
+	  CS_COND_SARG0,            CS_RENAME_OR_LINK_OK },
+	{ "old_path.dev_major",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.dev_minor",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.fsmagic",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.gid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_GID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.ino",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_INO,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.major",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.minor",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.fsmagic", CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.gid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_GID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.ino",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_INO,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.major",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.minor",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.perm",    CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_PERM,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.parent.uid",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_UID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.perm",           CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_PERM,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.type",           CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_TYPE,
+	  CS_RENAME_OR_LINK_OK },
+	{ "old_path.uid",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_UID,
+	  CS_RENAME_OR_LINK_OK },
+	{ "others_execute",          CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OTHERS_EXECUTE,   CS_ALL_OK },
+	{ "others_read",             CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OTHERS_READ,      CS_ALL_OK },
+	{ "others_write",            CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OTHERS_WRITE,     CS_ALL_OK },
+	{ "owner_execute",           CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OWNER_EXECUTE,    CS_ALL_OK },
+	{ "owner_read",              CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OWNER_READ,       CS_ALL_OK },
+	{ "owner_write",             CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_OWNER_WRITE,      CS_ALL_OK },
+	{ "path",                    CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG0,            CS_PATH_OK },
+	{ "path.dev_major",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  CS_PATH_SELF_OK },
+	{ "path.dev_minor",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  CS_PATH_SELF_OK },
+	{ "path.fsmagic",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_PATH_SELF_OK },
+	{ "path.gid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_GID,
+	  CS_PATH_SELF_OK },
+	{ "path.ino",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_INO,
+	  CS_PATH_SELF_OK },
+	{ "path.major",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_PATH_SELF_OK },
+	{ "path.minor",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_PATH_SELF_OK },
+	{ "path.parent.fsmagic",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  CS_PATH_OK },
+	{ "path.parent.gid",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_GID,
+	  CS_PATH_OK },
+	{ "path.parent.ino",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_INO,
+	  CS_PATH_OK },
+	{ "path.parent.major",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MAJOR,
+	  CS_PATH_OK },
+	{ "path.parent.minor",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MINOR,
+	  CS_PATH_OK },
+	{ "path.parent.perm",        CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_PERM,
+	  CS_PATH_OK },
+	{ "path.parent.uid",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_UID,
+	  CS_PATH_OK },
+	{ "path.perm",               CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_PERM,
+	  CS_PATH_SELF_OK },
+	{ "path.type",               CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_TYPE,
+	  CS_PATH_SELF_OK },
+	{ "path.uid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_UID,
+	  CS_PATH_SELF_OK },
+	{ "perm",                    CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_COND_NARG0,            CS_PATH_PERM_OK },
+	{ "port",                    CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            CS_IP_SOCKET_OK },
+	{ "proto",                   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            CS_RAW_SOCKET_OK },
+	{ "put_old",                 CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG1,            F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.dev_major",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.dev_minor",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.fsmagic",         CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.gid",             CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.ino",             CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.major",           CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.minor",           CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.fsmagic",  CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.gid",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.ino",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.major",    CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.minor",    CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.perm",     CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.parent.uid",      CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.perm",            CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.type",            CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_TYPE,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "put_old.uid",             CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_PIVOT_ROOT) },
+	{ "setgid",                  CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_SETGID,           CS_ALL_OK },
+	{ "setuid",                  CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_SETUID,           CS_ALL_OK },
+	{ "socket",                  CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_SOCKET,         CS_ALL_OK },
+	{ "source",                  CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG0,            F(CS_MAC_MOUNT) },
+	{ "source.dev_major",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.dev_minor",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.fsmagic",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_MOUNT) },
+	{ "source.gid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_MOUNT) },
+	{ "source.ino",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_MOUNT) },
+	{ "source.major",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.minor",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.fsmagic",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.gid",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.ino",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.major",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.minor",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.perm",      CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_MOUNT) },
+	{ "source.parent.uid",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 16 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_MOUNT) },
+	{ "source.perm",             CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_MOUNT) },
+	{ "source.type",             CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_TYPE,
+	  F(CS_MAC_MOUNT) },
+	{ "source.uid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_MOUNT) },
+	{ "sticky",                  CS_TYPE_INVALID,  CS_TYPE_FILEPERM,
+	  CS_MODE_STICKY,           CS_ALL_OK },
+	{ "symlink",                 CS_TYPE_INVALID,  CS_TYPE_FILETYPE,
+	  CS_OBJ_IS_SYMLINK,        CS_ALL_OK },
+	{ "target",                  CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG1,            F(CS_MAC_MOUNT) | F(CS_MAC_SYMLINK) },
+	{ "target.dev_major",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.dev_minor",        CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_DEV_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.fsmagic",          CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_MOUNT) },
+	{ "target.gid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_MOUNT) },
+	{ "target.ino",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_MOUNT) },
+	{ "target.major",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.minor",            CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.fsmagic",   CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_FSMAGIC,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.gid",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_GID,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.ino",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_INO,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.major",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MAJOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.minor",     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_MINOR,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.perm",      CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_MOUNT) },
+	{ "target.parent.uid",       CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 48 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_MOUNT) },
+	{ "target.perm",             CS_TYPE_FILEPERM, CS_TYPE_FILEPERM,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_PERM,
+	  F(CS_MAC_MOUNT) },
+	{ "target.type",             CS_TYPE_FILETYPE, CS_TYPE_FILETYPE,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_TYPE,
+	  F(CS_MAC_MOUNT) },
+	{ "target.uid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_PATH_ATTRIBUTE_START + 32 + CS_PATH_ATTRIBUTE_UID,
+	  F(CS_MAC_MOUNT) },
+	{ "task.domain",             CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_SELF_DOMAIN,           CS_ALL_OK },
+	{ "task.egid",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_EGID,             CS_ALL_OK },
+	{ "task.euid",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_EUID,             CS_ALL_OK },
+	{ "task.exe",                CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_SELF_EXE,              CS_ALL_OK },
+	{ "task.fsgid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_FSGID,            CS_ALL_OK },
+	{ "task.fsuid",              CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_FSUID,            CS_ALL_OK },
+	{ "task.gid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_GID,              CS_ALL_OK },
+	{ "task.pid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_PID,              CS_ALL_OK },
+	{ "task.ppid",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_PPID,             CS_ALL_OK },
+	{ "task.sgid",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_SGID,             CS_ALL_OK },
+	{ "task.suid",               CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_SUID,             CS_ALL_OK },
+	{ "task.uid",                CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_SELF_UID,              CS_ALL_OK },
+	{ "transition",              CS_TYPE_ASSIGN,   CS_TYPE_INVALID,
+	  CS_TRANSIT_DOMAIN,
+	  F(CS_MAC_EXECUTE) | F(CS_MAC_AUTO_DOMAIN_TRANSITION) |
+	  CS_INET_SOCKET_OK | CS_UNIX_SOCKET_OK },
+	{ "uid",                     CS_TYPE_NUMBER,   CS_TYPE_NUMBER,
+	  CS_COND_NARG0,            F(CS_MAC_CHOWN) },
+	{ "value",                   CS_TYPE_STRING,   CS_TYPE_STRING,
+	  CS_COND_SARG3,            F(CS_MAC_ENVIRON) },
+};
+
+/***** SECTION2: Structure definition *****/
+
+struct iattr;
+
+/* Structure for query. */
+struct cs_query {
+	struct list_head list;
+	struct cs_acl_info *acl;
+	char *query;
+	size_t query_len;
+	unsigned int serial;
+	u8 timer;
+	u8 answer;
+	u8 retry;
+	enum cs_mac_index acl_type;
+};
+
+/* Structure for audit log. */
+struct cs_log {
+	struct list_head list;
+	char *log;
+	int size;
+	enum cs_matching_result result;
+};
+
+/* Structure for holding single condition component. */
+struct cs_cond_tmp {
+	enum cs_conditions_index left;
+	enum cs_conditions_index right;
+	bool is_not;
+	u8 radix;
+	enum cs_var_type type;
+	struct cs_group *group;
+	const struct cs_path_info *path;
+	struct in6_addr ipv6[2];
+	unsigned long value[2];
+	unsigned long argv;
+	const struct cs_path_info *envp;
+};
+
+/***** SECTION3: Prototype definition section *****/
+
+static bool cs_correct_domain(const unsigned char *domainname);
+static bool cs_correct_word(const char *string);
+static bool cs_flush(struct cs_io_buffer *head);
+static bool cs_print_condition(struct cs_io_buffer *head,
+			       const struct cs_condition *cond);
+static bool cs_memory_ok(const void *ptr);
+static bool cs_read_acl(struct cs_io_buffer *head,
+			const struct cs_acl_info *acl);
+static bool cs_read_group(struct cs_io_buffer *head);
+static bool cs_select_acl(struct cs_io_buffer *head, const char *data);
+static bool cs_set_lf(struct cs_io_buffer *head);
+static bool cs_str_starts(char **src, const char *find);
+static char *cs_init_log(struct cs_request_info *r);
+static char *cs_print_bprm(struct linux_binprm *bprm,
+			   struct cs_page_dump *dump);
+static char *cs_print_trailer(struct cs_request_info *r);
+static char *cs_read_token(struct cs_io_buffer *head);
+static const char *cs_yesno(const unsigned int value);
+static const struct cs_path_info *cs_get_dqword(char *start);
+static const struct cs_path_info *cs_get_name(const char *name);
+static int cs_open(struct inode *inode, struct file *file);
+static int cs_parse_policy(struct cs_io_buffer *head, char *line);
+static int cs_release(struct inode *inode, struct file *file);
+static int cs_supervisor(struct cs_request_info *r);
+static int cs_update_group(struct cs_io_buffer *head,
+			   const enum cs_group_id type);
+static int cs_write_answer(struct cs_io_buffer *head);
+static int cs_write_audit_quota(char *data);
+static int cs_write_memory_quota(char *data);
+static int cs_write_pid(struct cs_io_buffer *head);
+static int cs_write_policy(struct cs_io_buffer *head);
+static ssize_t cs_read(struct file *file, char __user *buf, size_t count,
+		       loff_t *ppos);
+static ssize_t cs_read_self(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos);
+static ssize_t cs_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *ppos);
+static struct cs_condition *cs_get_condition(struct cs_io_buffer *head);
+static struct cs_domain_info *cs_find_domain(const char *domainname);
+static struct cs_acl_info *cs_find_acl_by_qid(unsigned int serial,
+					      enum cs_mac_index *type);
+static struct cs_group *cs_get_group(struct cs_io_buffer *head,
+				     const enum cs_group_id idx);
+static enum cs_value_type cs_parse_ulong(unsigned long *result, char **str);
+static unsigned int cs_poll(struct file *file, poll_table *wait);
+static void __init cs_create_entry(const char *name, const umode_t mode,
+				   struct dentry *parent, const u8 key);
+static void __init cs_load_builtin_policy(void);
+static void __init cs_securityfs_init(void);
+static void cs_convert_time(time64_t time, struct cs_time *stamp);
+static void cs_io_printf(struct cs_io_buffer *head, const char *fmt, ...)
+	__printf(2, 3);
+static void cs_normalize_line(unsigned char *buffer);
+static void cs_read_log(struct cs_io_buffer *head);
+static void cs_read_pid(struct cs_io_buffer *head);
+static void cs_read_policy(struct cs_io_buffer *head);
+static void cs_read_query(struct cs_io_buffer *head);
+static void *cs_commit_ok(void *data, const unsigned int size);
+static bool cs_read_quota(struct cs_io_buffer *head);
+static void cs_read_stat(struct cs_io_buffer *head);
+static void cs_read_version(struct cs_io_buffer *head);
+static void cs_set_space(struct cs_io_buffer *head);
+static void cs_set_string(struct cs_io_buffer *head, const char *string);
+static void cs_update_stat(const u8 index);
+static void cs_write_log(struct cs_request_info *r);
+
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+static enum cs_conditions_index cs_parse_ipaddr(char *address,
+						struct in6_addr ipv6[2]);
+static void cs_print_ipv4(struct cs_io_buffer *head, const u32 *ip);
+static void cs_print_ipv6(struct cs_io_buffer *head,
+			  const struct in6_addr *ip);
+static void cs_print_ip(struct cs_io_buffer *head,
+			struct cs_ip_group *member);
+#endif
+
+#ifdef CONFIG_SECURITY_CAITSITH_MANUAL_DOMAIN_TRANSITION
+static ssize_t cs_write_self(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos);
+#endif
+
+/***** SECTION4: Standalone functions section *****/
+
+/**
+ * cs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
+ *
+ * @time:  Seconds since 1970/01/01 00:00:00.
+ * @stamp: Pointer to "struct cs_time".
+ *
+ * Returns nothing.
+ */
+static void cs_convert_time(time64_t time, struct cs_time *stamp)
+{
+	struct tm tm;
+
+	time64_to_tm(time, 0, &tm);
+	stamp->sec = tm.tm_sec;
+	stamp->min = tm.tm_min;
+	stamp->hour = tm.tm_hour;
+	stamp->day = tm.tm_mday;
+	stamp->month = tm.tm_mon + 1;
+	stamp->year = tm.tm_year + 1900;
+}
+
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+
+/**
+ * cs_print_ipv4 - Print an IPv4 address.
+ *
+ * @head: Pointer to "struct cs_io_buffer".
+ * @ip:   Pointer to "u32" in network byte order.
+ *
+ * Returns nothing.
+ */
+static void cs_print_ipv4(struct cs_io_buffer *head, const u32 *ip)
+{
+	cs_io_printf(head, "%pI4", ip);
+}
+
+/**
+ * cs_print_ipv6 - Print an IPv6 address.
+ *
+ * @head: Pointer to "struct cs_io_buffer".
+ * @ip:   Pointer to "struct in6_addr".
+ *
+ * Returns nothing.
+ */
+static void cs_print_ipv6(struct cs_io_buffer *head,
+			  const struct in6_addr *ip)
+{
+	cs_io_printf(head, "%pI6c", ip);
+}
+
+/**
+ * cs_print_ip - Print an IP address.
+ *
+ * @head:   Pointer to "struct cs_io_buffer".
+ * @member: Pointer to "struct cs_ip_group".
+ *
+ * Returns nothing.
+ */
+static void cs_print_ip(struct cs_io_buffer *head,
+			struct cs_ip_group *member)
+{
+	u8 i;
+
+	for (i = 0; i < 2; i++) {
+		if (member->is_ipv6)
+			cs_print_ipv6(head, &member->ip[i]);
+		else
+			cs_print_ipv4(head, (const u32 *) &member->ip[i]);
+		if (i)
+			break;
+		if (!memcmp(&member->ip[0], &member->ip[1], 16))
+			break;
+		cs_set_string(head, "-");
+	}
+}
+
+#endif
+
+/***** SECTION5: Variables definition section *****/
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(cs_policy_lock);
+
+/* Has /sbin/init started? */
+bool cs_policy_loaded;
+
+/* List of "struct cs_group". */
+struct list_head cs_group_list[CS_MAX_GROUP];
+/* Policy version. Currently only 20120401 is defined. */
+static unsigned int cs_policy_version;
+
+/* List of "struct cs_condition". */
+LIST_HEAD(cs_condition_list);
+
+/* Wait queue for kernel -> userspace notification. */
+static DECLARE_WAIT_QUEUE_HEAD(cs_query_wait);
+/* Wait queue for userspace -> kernel notification. */
+static DECLARE_WAIT_QUEUE_HEAD(cs_answer_wait);
+
+/* The list for "struct cs_query". */
+static LIST_HEAD(cs_query_list);
+
+/* Lock for manipulating cs_query_list. */
+static DEFINE_SPINLOCK(cs_query_list_lock);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/caitsith/query
+ * interface.
+ */
+static atomic_t cs_query_observers = ATOMIC_INIT(0);
+
+/* Wait queue for /sys/kernel/security/caitsith/audit interface. */
+static DECLARE_WAIT_QUEUE_HEAD(cs_log_wait);
+
+/* The list for "struct cs_log". */
+static LIST_HEAD(cs_log);
+
+/* Lock for "struct list_head cs_log". */
+static DEFINE_SPINLOCK(cs_log_lock);
+
+/* Length of "struct list_head cs_log". */
+static unsigned int cs_log_count[CS_MAX_MATCHING];
+/* Quota for audit logs. */
+static unsigned int cs_log_quota[CS_MAX_LOG_QUOTA][CS_MAX_MATCHING];
+
+/* Memoy currently used by policy/audit log/query. */
+unsigned int cs_memory_used[CS_MAX_MEMORY_STAT];
+
+/* Memory quota for "policy"/"audit log"/"query". */
+static unsigned int cs_memory_quota[CS_MAX_MEMORY_STAT];
+
+/* The list for "struct cs_name". */
+struct list_head cs_name_list[CS_MAX_HASH];
+
+/* Counter for number of updates. */
+static atomic_t cs_stat_updated[CS_MAX_POLICY_STAT];
+
+/* Timestamp counter for last updated. */
+static time64_t cs_stat_modified[CS_MAX_POLICY_STAT];
+
+/* Operations for /sys/kernel/security/caitsith/self_domain interface. */
+static const struct file_operations cs_self_operations = {
+#ifdef CONFIG_SECURITY_CAITSITH_MANUAL_DOMAIN_TRANSITION
+	.write = cs_write_self,
+#endif
+	.read  = cs_read_self,
+};
+
+/* Operations for /sys/kernel/security/caitsith/ interface. */
+static const struct file_operations cs_operations = {
+	.open    = cs_open,
+	.release = cs_release,
+	.poll    = cs_poll,
+	.read    = cs_read,
+	.write   = cs_write,
+};
+
+/***** SECTION6: Dependent functions section *****/
+
+/**
+ * list_for_each_cookie - iterate over a list with cookie.
+ *
+ * @pos:  Pointer to "struct list_head".
+ * @head: Pointer to "struct list_head".
+ */
+#define list_for_each_cookie(pos, head)					\
+	for (pos = pos ? pos : srcu_dereference((head)->next, &cs_ss);	\
+	     pos != (head); pos = srcu_dereference(pos->next, &cs_ss))
+
+/**
+ * cs_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ *
+ * Returns nothing.
+ */
+void cs_warn_oom(const char *function)
+{
+	/* Reduce error messages. */
+	static pid_t cs_last_pid;
+	const pid_t pid = current->pid;
+
+	if (cs_last_pid != pid) {
+		pr_warn("ERROR: Out of memory at %s.\n", function);
+		cs_last_pid = pid;
+	}
+	if (!cs_policy_loaded)
+		panic("MAC Initialization failed.\n");
+}
+
+/**
+ * cs_memory_ok - Check memory quota.
+ *
+ * @ptr:  Pointer to allocated memory. Maybe NULL.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ *
+ * Caller holds cs_policy_lock mutex.
+ */
+static bool cs_memory_ok(const void *ptr)
+{
+	if (ptr) {
+		const size_t s = ksize(ptr);
+
+		cs_memory_used[CS_MEMORY_POLICY] += s;
+		if (!cs_memory_quota[CS_MEMORY_POLICY] ||
+		    cs_memory_used[CS_MEMORY_POLICY] <=
+		    cs_memory_quota[CS_MEMORY_POLICY])
+			return true;
+		cs_memory_used[CS_MEMORY_POLICY] -= s;
+	}
+	cs_warn_oom(__func__);
+	return false;
+}
+
+/**
+ * cs_get_name - Allocate memory for string data.
+ *
+ * @name: The string to store into the permernent memory. Maybe NULL.
+ *
+ * Returns pointer to "struct cs_path_info" on success, NULL otherwise.
+ */
+static const struct cs_path_info *cs_get_name(const char *name)
+{
+	struct cs_name *ptr;
+	unsigned int hash;
+	int len;
+	int allocated_len;
+	struct list_head *head;
+
+	if (!name)
+		return NULL;
+	len = strlen(name) + 1;
+	hash = full_name_hash(NULL, name, len - 1);
+	head = &cs_name_list[hash_long(hash, CS_HASH_BITS)];
+	if (mutex_lock_killable(&cs_policy_lock))
+		return NULL;
+	list_for_each_entry(ptr, head, head.list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
+		    atomic_read(&ptr->head.users) == CS_GC_IN_PROGRESS)
+			continue;
+		atomic_inc(&ptr->head.users);
+		goto out;
+	}
+	allocated_len = sizeof(*ptr) + len;
+	ptr = kzalloc(allocated_len, GFP_NOFS);
+	if (cs_memory_ok(ptr)) {
+		ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+		memmove((char *) ptr->entry.name, name, len);
+		atomic_set(&ptr->head.users, 1);
+		cs_fill_path_info(&ptr->entry);
+		ptr->size = allocated_len;
+		list_add_tail(&ptr->head.list, head);
+	} else {
+		kfree(ptr);
+		ptr = NULL;
+	}
+out:
+	mutex_unlock(&cs_policy_lock);
+	return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * cs_read_token - Read a word from a line.
+ *
+ * @head: Pointer to "struct cs_io_buffer".
+ *
+ * Returns a word on success, "" otherwise.
+ *
+ * To allow the caller to skip NULL check, this function returns "" rather than
+ * NULL if there is no more words to read.
+ */
+static char *cs_read_token(struct cs_io_buffer *head)
+{
+	char *pos = head->w.data;
+	char *del = strchr(pos, ' ');
+
+	if (del)
+		*del++ = '\0';
+	else
+		del = pos + strlen(pos);
+	head->w.data = del;
+	return pos;
+}
+
+/**
+ * cs_correct_word - Check whether the given string follows the naming rules.
+ *
+ * @string: The string to check.
+ *
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool cs_correct_word(const char *string)
+{
+	u8 recursion = 20;
+	const char *const start = string;
+	u8 in_repetition = 0;
+
+	if (!*string)
+		goto out;
+	while (*string) {
+		unsigned char c = *string++;
+
+		if (in_repetition && c == '/')
+			goto out;
+		if (c <= ' ' || c >= 127)
+			goto out;
+		if (c != '\\')
+			continue;
+		c = *string++;
+		if (c >= '0' && c <= '3') {
+			unsigned char d;
+			unsigned char e;
+
+			d = *string++;
+			if (d < '0' || d > '7')
+				goto out;
+			e = *string++;
+			if (e < '0' || e > '7')
+				goto out;
+			c = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
+			if (c <= ' ' || c >= 127 || c == '\\')
+				continue;
+			goto out;
+		}
+		switch (c) {
+		case '+':   /* "\+" */
+		case '?':   /* "\?" */
+		case 'x':   /* "\x" */
+		case 'a':   /* "\a" */
+		case '-':   /* "\-" */
+			continue;
+		}
+		/* Reject too deep wildcard that consumes too much stack. */
+		if (!recursion--)
+			goto out;
+		switch (c) {
+		case '*':   /* "\*" */
+		case '@':   /* "\@" */
+		case '$':   /* "\$" */
+		case 'X':   /* "\X" */
+		case 'A':   /* "\A" */
+			continue;
+		case '{':   /* "/\{" */
+			if (string - 3 < start || *(string - 3) != '/')
+				goto out;
+			in_repetition = 1;
+			continue;
+		case '}':   /* "\}/" */
+			if (in_repetition != 1 || *string++ != '/')
+				goto out;
+			in_repetition = 0;
+			continue;
+		case '(':   /* "/\(" */
+			if (string - 3 < start || *(string - 3) != '/')
+				goto out;
+			in_repetition = 2;
+			continue;
+		case ')':   /* "\)/" */
+			if (in_repetition != 2 || *string++ != '/')
+				goto out;
+			in_repetition = 0;
+			continue;
+		}
+		goto out;
+	}
+	if (in_repetition)
+		goto out;
+	return true;
+out:
+	return false;
+}
+
+/**
+ * cs_commit_ok - Allocate memory and check memory quota.
+ *
+ * @data: Data to copy from.
+ * @size: Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ *
+ * Caller holds cs_policy_lock mutex.
+ */
+static void *cs_commit_ok(void *data, const unsigned int size)
+{
+	void *ptr = kmalloc(size, GFP_NOFS);
+
+	if (cs_memory_ok(ptr)) {
+		memmove(ptr, data, size);
+		memset(data, 0, size);
+		return ptr;
+	}
+	kfree(ptr);
+	return NULL;
+}
+
+/**
+ * cs_get_group - Allocate memory for "struct cs_string_group"/"struct cs_number_group"/"struct cs_ip_group".
+ *
+ * @head: Pointer to "struct cs_io_buffer".
+ * @idx:  Index number.
+ *
+ * Returns pointer to "struct cs_group" on success, NULL otherwise.
+ */
+static struct cs_group *cs_get_group(struct cs_io_buffer *head,
+				     const enum cs_group_id idx)
+{
+	struct cs_group e = { };
+	struct cs_group *group = NULL;
+	struct list_head *list;
+	const char *group_name = cs_read_token(head);
+	bool found = false;
+
+	if (!cs_correct_word(group_name) || idx >= CS_MAX_GROUP)
+		return NULL;
+	e.group_name = cs_get_name(group_name);
+	if (!e.group_name)
+		return NULL;
+	if (mutex_lock_killable(&cs_policy_lock))
+		goto out;
+	list = &cs_group_list[idx];
+	list_for_each_entry(group, list, head.list) {
+		if (e.group_name != group->group_name ||
+		    atomic_read(&group->head.users) == CS_GC_IN_PROGRESS)
+			continue;
+		atomic_inc(&group->head.users);
+		found = true;
+		break;
+	}
+	if (!found) {
+		struct cs_group *entry = cs_commit_ok(&e, sizeof(e));
+
+		if (entry) {
+			INIT_LIST_HEAD(&entry->member_list);
+			atomic_set(&entry->head.users, 1);
+			list_add_tail_rcu(&entry->head.list, list);
+			group = entry;
+			found = true;
+		}
+	}
+	mutex_unlock(&cs_policy_lock);
+out:
+	cs_put_name(e.group_name);
+	return found ? group : NULL;
+}
+
+/**
+ * cs_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str:    Pointer to string to parse.
+ *
+ * Returns one of values in "enum cs_value_type".
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+static enum cs_value_type cs_parse_ulong(unsigned long *result, char **str)
+{
+	const char *cp = *str;
+	char *ep;
+	int base = 10;
+
+	if (*cp == '0') {
+		char c = *(cp + 1);
+
+		if (c == 'x' || c == 'X') {
+			base = 16;
+			cp += 2;
+		} else if (c >= '0' && c <= '7') {
+			base = 8;
+			cp++;
+		}
+	}
+	*result = simple_strtoul(cp, &ep, base);
+	if (cp == ep)
+		return CS_VALUE_TYPE_INVALID;
+	*str = ep;
+	switch (base) {
+	case 16:
+		return CS_VALUE_TYPE_HEXADECIMAL;
+	case 8:
+		return CS_VALUE_TYPE_OCTAL;
+	default:
+		return CS_VALUE_TYPE_DECIMAL;
+	}
+}
+
+/**
+ * cs_get_dqword - cs_get_name() for a quoted string.
+ *
+ * @start: String to parse.
+ *
+ * Returns pointer to "struct cs_path_info" on success, NULL otherwise.
+ */
+static const struct cs_path_info *cs_get_dqword(char *start)
+{
+	char *cp = start + strlen(start) - 1;
+
+	if (cp == start || *start++ != '"' || *cp != '"')
+		return NULL;
+	*cp = '\0';
+	if (*start && !cs_correct_word(start))
+		return NULL;
+	return cs_get_name(start);
+}
+
+/**
+ * cs_same_condition - Check for duplicated "struct cs_condition" entry.
+ *
+ * @a: Pointer to "struct cs_condition".
+ * @b: Pointer to "struct cs_condition".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool cs_same_condition(const struct cs_condition *a,
+				     const struct cs_condition *b)
+{
+	return a->size == b->size &&
+		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
+}
+
+/**
+ * cs_commit_condition - Commit "struct cs_condition".
+ *
+ * @entry: Pointer to "struct cs_condition".
+ *
+ * Returns pointer to "struct cs_condition" on success, NULL otherwise.
+ *
+ * This function merges duplicated entries. This function returns NULL if
+ * @entry is not duplicated but memory quota for policy has exceeded.
+ */
+static struct cs_condition *cs_commit_condition(struct cs_condition *entry)
+{
+	struct cs_condition *ptr = kmemdup(entry, entry->size, GFP_NOFS);
+	bool found = false;
+
+	if (ptr) {
+		kfree(entry);
+		entry = ptr;
+	}
+	if (mutex_lock_killable(&cs_policy_lock)) {
+		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+		ptr = NULL;
+		found = true;
+		goto out;
+	}
+	list_for_each_entry(ptr, &cs_condition_list, head.list) {
+		if (!cs_same_condition(ptr, entry) ||
+		    atomic_read(&ptr->head.users) == CS_GC_IN_PROGRESS)
+			continue;
+		/* Same entry found. Share this entry. */
+		atomic_inc(&ptr->head.users);
+		found = true;
+		break;
+	}
+	if (!found) {
+		if (cs_memory_ok(entry)) {
+			atomic_set(&entry->head.users, 1);
+			list_add(&entry->head.list, &cs_condition_list);
+		} else {
+			found = true;
+			ptr = NULL;
+		}
+	}
+	mutex_unlock(&cs_policy_lock);
+out:
+	if (found) {
+		cs_del_condition(&entry->head.list);
+		kfree(entry);
+		entry = ptr;
+	}
+	return entry;
+}
+
+/**
+ * cs_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+static bool cs_correct_domain(const unsigned char *domainname)
+{
+	if (!cs_correct_word(domainname))
+		return false;
+	while (*domainname) {
+		if (*domainname++ != '\\')
+			continue;
+		if (*domainname < '0' || *domainname++ > '3')
+			return false;
+	}
+	return true;
+}
+
+/**
+ * cs_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Returns nothing.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ */
+static void cs_normalize_line(unsigned char *buffer)
+{
+	unsigned char *sp = buffer;
+	unsigned char *dp = buffer;
+	bool first = true;
+
+	while (*sp && (*sp <= ' ' || *sp >= 127))
+		sp++;
+	while (*sp) {
+		if (!first)
+			*dp++ = ' ';
+		first = false;
+		while (*sp > ' ' && *sp < 127)
+			*dp++ = *sp++;
+		while (*sp && (*sp <= ' ' || *sp >= 127))
+			sp++;
+	}
+	*dp = '\0';
+}
+
+/**
+ * cs_parse_values - Parse an numeric argument.
+ *
+ * @value: Values to parse.
+ * @v:     Pointer to "unsigned long".
+ *
+ * Returns "enum cs_value_type" if @value is a single value, bitwise-OR-ed
+ * value if @value is value range.
+ */
+static u8 cs_parse_values(char *value, unsigned long v[2])
+{
+	enum cs_value_type radix1 = cs_parse_ulong(&v[0], &value);
+	enum cs_value_type radix2;
+
+	if (radix1 == CS_VALUE_TYPE_INVALID)
+		return CS_VALUE_TYPE_INVALID;
+	if (!*value) {
+		v[1] = v[0];
+		return radix1;
+	}
+	if (*value++ != '-')
+		return CS_VALUE_TYPE_INVALID;
+	radix2 = cs_parse_ulong(&v[1], &value);
+	if (radix2 == CS_VALUE_TYPE_INVALID || *value || v[0] > v[1])
+		return CS_VALUE_TYPE_INVALID;
+	return radix1 | (radix2 << 2);
+}
+
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+
+/**
+ * cs_parse_ipaddr - Parse an IP address.
+ *
+ * @address: Address to parse.
+ * @ipv6:    Pointer to "struct in6_addr".
+ *
+ * Returns one of values in "enum cs_conditions_index".
+ */
+static enum cs_conditions_index cs_parse_ipaddr(char *address,
+						struct in6_addr ipv6[2])
+{
+	const char *end;
+
+	if (!strchr(address, ':') &&
+	    in4_pton(address, -1, ipv6[0].s6_addr, '-', &end) > 0) {
+		if (!*end) {
+			ipv6[0].s6_addr32[0] = ipv6[0].s6_addr32[0];
+			ipv6[1].s6_addr32[0] = ipv6[0].s6_addr32[0];
+			return CS_IMM_IPV4ADDR_ENTRY1;
+		}
+		if (*end++ != '-' ||
+		    in4_pton(end, -1, ipv6[1].s6_addr, '\0', &end) <= 0 ||
+		    *end || memcmp(&ipv6[0], &ipv6[1], 4) >= 0)
+			return CS_INVALID_CONDITION;
+		return CS_IMM_IPV4ADDR_ENTRY2;
+	}
+	if (in6_pton(address, -1, ipv6[0].s6_addr, '-', &end) > 0) {
+		if (!*end) {
+			ipv6[1] = ipv6[0];
+			return CS_IMM_IPV6ADDR_ENTRY1;
+		}
+		if (*end++ != '-' ||
+		    in6_pton(end, -1, ipv6[1].s6_addr, '\0', &end) <= 0 ||
+		    *end || memcmp(&ipv6[0], &ipv6[1], 16) >= 0)
+			return CS_INVALID_CONDITION;
+		return CS_IMM_IPV6ADDR_ENTRY2;
+	}
+	return CS_INVALID_CONDITION;
+}
+
+#endif
+
+/**
+ * cs_parse_lefthand - Parse special lefthand conditions.
+ *
+ * @word: Keyword to search.
+ * @mac:  One of values in "enum cs_mac_index".
+ * @tmp:  Pointer to "struct cs_cond_tmp".
+ *
+ * Returns one of values in "enum cs_conditions_index".
+ */
+static enum cs_conditions_index cs_parse_lefthand
+(char *word, const enum cs_mac_index mac, struct cs_cond_tmp *tmp)
+{
+	if (mac == CS_MAC_EXECUTE || mac == CS_MAC_ENVIRON) {
+		tmp->type = CS_TYPE_STRING;
+		if (!strncmp(word, "argv[", 5)) {
+			word += 5;
+			if (cs_parse_ulong(&tmp->argv, &word) ==
+			    CS_VALUE_TYPE_DECIMAL && !strcmp(word, "]"))
+				return CS_ARGV_ENTRY;
+		} else if (!strncmp(word, "envp[\"", 6)) {
+			char *end = word + strlen(word) - 2;
+
+			if (!strcmp(end, "\"]")) {
+				*end = '\0';
+				tmp->envp = cs_get_name(word + 6);
+				if (tmp->envp)
+					return CS_ENVP_ENTRY;
+			}
+		}
+	}
+	return CS_INVALID_CONDITION;
+}
+
+/**
+ * cs_parse_righthand - Parse special righthand conditions.
+ *
+ * @word: Keyword to search.
+ * @head: Pointer to "struct cs_io_buffer".
+ * @tmp:  Pointer to "struct cs_cond_tmp".
+ *
+ * Returns one of values in "enum cs_conditions_index".
+ */
+static enum cs_conditions_index cs_parse_righthand
+(char *word, struct cs_io_buffer *head, struct cs_cond_tmp *tmp)
+{
+	const enum cs_var_type type = tmp->type;
+
+	dprintk(KERN_WARNING "%u: tmp->left=%u type=%u\n",
+		__LINE__, tmp->left, type);
+	if (type == CS_TYPE_ASSIGN) {
+		if (tmp->is_not)
+			goto out;
+		if (!strcmp(word, "NULL"))
+			goto null_word;
+		tmp->path = cs_get_dqword(word);
+		if (tmp->path && tmp->path->const_len == tmp->path->total_len)
+			return CS_IMM_NAME_ENTRY;
+		goto out;
+	}
+	if (word[0] == '@' && word[1]) {
+		enum cs_group_id g;
+
+		if (type == CS_TYPE_NUMBER || type == CS_TYPE_FILEPERM)
+			g = CS_NUMBER_GROUP;
+		else if (type == CS_TYPE_STRING)
+			g = CS_STRING_GROUP;
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+		else if (type == CS_TYPE_IPADDR)
+			g = CS_IP_GROUP;
+#endif
+		else
+			goto out;
+		head->w.data = word + 1;
+		tmp->group = cs_get_group(head, g);
+		if (tmp->group)
+			return CS_IMM_GROUP;
+		goto out;
+	}
+	if (type == CS_TYPE_NUMBER || type == CS_TYPE_FILEPERM) {
+		tmp->radix = cs_parse_values(word, tmp->value);
+		if (tmp->radix == CS_VALUE_TYPE_INVALID)
+			goto out;
+		if (tmp->radix >> 2)
+			return CS_IMM_NUMBER_ENTRY2;
+		else
+			return CS_IMM_NUMBER_ENTRY1;
+	}
+	if (type == CS_TYPE_STRING) {
+		dprintk(KERN_WARNING "%u: word='%s'\n", __LINE__, word);
+		if (!strcmp(word, "NULL"))
+			goto null_word;
+		tmp->path = cs_get_dqword(word);
+		dprintk(KERN_WARNING "%u: tmp->path=%p\n", __LINE__,
+			tmp->path);
+		if (tmp->path)
+			return CS_IMM_NAME_ENTRY;
+		goto out;
+	}
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+	if (type == CS_TYPE_IPADDR)
+		return cs_parse_ipaddr(word, tmp->ipv6);
+#endif
+out:
+	dprintk(KERN_WARNING "%u: righthand failed\n", __LINE__);
+	return CS_INVALID_CONDITION;
+null_word:
+	tmp->path = &cs_null_name;
+	return CS_IMM_NAME_ENTRY;
+}
+
+/**
+ * cs_condindex - Get condition's index.
+ *
+ * @word: Name of condition.
+ * @mac:  One of values in "enum cs_mac_index".
+ * @tmp:  Pointer to "struct cs_cond_tmp".
+ * @left: True if lefthand part, false otherwise.
+ *
+ * Returns one of values in "enum cs_condition_index".
+ */
+static enum cs_conditions_index cs_condindex(const char *word,
+					     const enum cs_mac_index mac,
+					     struct cs_cond_tmp *tmp,
+					     const bool lefthand)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs_conditions); i++) {
+		if (!(cs_conditions[i].available & F(mac)) ||
+		    strcmp(cs_conditions[i].keyword, word))
+			continue;
+		tmp->type = lefthand ? cs_conditions[i].left_type :
+			cs_conditions[i].right_type;
+		if (tmp->type != CS_TYPE_INVALID)
+			return cs_conditions[i].cmd;
+		break;
+	}
+	return CS_INVALID_CONDITION;
+}
+
+/**
+ * cs_parse_cond - Parse single condition.
+ *
+ * @tmp:  Pointer to "struct cs_cond_tmp".
+ * @head: Pointer to "struct cs_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool cs_parse_cond(struct cs_cond_tmp *tmp,
+			  struct cs_io_buffer *head)
+{
+	char *left = head->w.data;
+	char *right;
+	const enum cs_mac_index mac = head->w.acl_index;
+	enum cs_var_type type = CS_TYPE_STRING;
+
+	dprintk(KERN_WARNING "%u: type=%u word='%s'\n",
+		__LINE__, mac, left);
+	right = strchr(left, '=');
+	if (!right || right == left)
+		return false;
+	*right++ = '\0';
+	tmp->is_not = (*(right - 2) == '!');
+	if (tmp->is_not)
+		*(right - 2) = '\0';
+	if (!*left || !*right)
+		return false;
+	tmp->left = cs_condindex(left, mac, tmp, true);
+	dprintk(KERN_WARNING "%u: tmp->left=%u\n", __LINE__, tmp->left);
+	if (tmp->left == CS_INVALID_CONDITION) {
+		tmp->left = cs_parse_lefthand(left, mac, tmp);
+		dprintk(KERN_WARNING "%u: tmp->left=%u\n", __LINE__,
+			tmp->left);
+		if (tmp->left == CS_INVALID_CONDITION)
+			return false;
+	} else {
+		type = tmp->type;
+	}
+	dprintk(KERN_WARNING "%u: tmp->type=%u\n", __LINE__, tmp->type);
+	tmp->right = cs_condindex(right, mac, tmp, false);
+	dprintk(KERN_WARNING "%u: tmp->right=%u tmp->type=%u\n",
+		__LINE__, tmp->right, tmp->type);
+	if (tmp->right != CS_INVALID_CONDITION && type != tmp->type &&
+	    !(type == CS_TYPE_FILEPERM && tmp->type == CS_TYPE_NUMBER))
+		return false;
+	if (tmp->right == CS_INVALID_CONDITION)
+		tmp->right = cs_parse_righthand(right, head, tmp);
+	dprintk(KERN_WARNING "%u: tmp->right=%u tmp->type=%u\n",
+		__LINE__, tmp->right, tmp->type);
+	return tmp->right != CS_INVALID_CONDITION;
+}
+
+/**
+ * cs_get_condition - Parse condition part.
+ *
+ * @head: Pointer to "struct cs_io_buffer".
+ *
+ * Returns pointer to "struct cs_condition" on success, NULL otherwise.
+ */
+static struct cs_condition *cs_get_condition(struct cs_io_buffer *head)
+{
+	struct cs_condition *entry = kzalloc(PAGE_SIZE, GFP_NOFS);
+	union cs_condition_element *condp;
+	struct cs_cond_tmp tmp;
+	const enum cs_mac_index type = head->w.acl_index;
+	bool transit_domain_done = head->w.is_deny ||
+		!(F(type) &
+		  (F(CS_MAC_EXECUTE) | F(CS_MAC_AUTO_DOMAIN_TRANSITION) |
+		   CS_INET_SOCKET_OK | CS_UNIX_SOCKET_OK));
+	char *pos = head->w.data;
+
+	if (!entry)
+		return NULL;
+	condp = (union cs_condition_element *) (entry + 1);
+	while (1) {
+		memset(&tmp, 0, sizeof(tmp));
+		/*
+		 * tmp.left = CS_INVALID_CONDITION;
+		 * tmp.right = CS_INVALID_CONDITION;
+		 */
+		while (*pos == ' ')
+			pos++;
+		if (!*pos)
+			break;
+		if ((u8 *) condp >= ((u8 *) entry) + PAGE_SIZE
+		    - (sizeof(*condp) + sizeof(struct in6_addr) * 2))
+			goto out;
+		{
+			char *next = strchr(pos, ' ');
+
+			if (next)
+				*next++ = '\0';
+			else
+				next = "";
+			head->w.data = pos;
+			pos = next;
+		}
+		if (!cs_parse_cond(&tmp, head))
+			goto out;
+		if (tmp.left == CS_TRANSIT_DOMAIN) {
+			if (transit_domain_done)
+				goto out;
+			transit_domain_done = true;
+		}
+		condp->is_not = tmp.is_not;
+		condp->left = tmp.left;
+		condp->right = tmp.right;
+		condp->radix = tmp.radix;
+		condp++;
+		if (tmp.left == CS_ARGV_ENTRY) {
+			condp->value = tmp.argv;
+			condp++;
+		} else if (tmp.left == CS_ENVP_ENTRY) {
+			condp->path = tmp.envp;
+			condp++;
+		}
+		if (tmp.right == CS_IMM_GROUP) {
+			condp->group = tmp.group;
+			condp++;
+		} else if (tmp.right == CS_IMM_NAME_ENTRY) {
+			condp->path = tmp.path;
+			condp++;
+		} else if (tmp.right == CS_IMM_NUMBER_ENTRY1 ||
+			   tmp.right == CS_IMM_NUMBER_ENTRY2) {
+			condp->value = tmp.value[0];
+			condp++;
+			if (tmp.right == CS_IMM_NUMBER_ENTRY2) {
+				condp->value = tmp.value[1];
+				condp++;
+			}
+#ifdef CONFIG_SECURITY_CAITSITH_NETWORK
+		} else if (tmp.right == CS_IMM_IPV4ADDR_ENTRY1 ||
+			   tmp.right == CS_IMM_IPV4ADDR_ENTRY2) {
+			condp->ip = *(u32 *) &tmp.ipv6[0];
+			condp++;
+			if (tmp.right == CS_IMM_IPV4ADDR_ENTRY2) {
+				condp->ip = *(u32 *) &tmp.ipv6[1];
+				condp++;
+			}
+		} else if (tmp.right == CS_IMM_IPV6ADDR_ENTRY1 ||
+			   tmp.right == CS_IMM_IPV6ADDR_ENTRY2) {
+			*(struct in6_addr *) condp = tmp.ipv6[0];
+			condp = (void *) (((u8 *) condp) +
+					  sizeof(struct in6_addr));
+			if (tmp.right == CS_IMM_IPV6ADDR_ENTRY2) {
+				*(struct in6_addr *) condp = tmp.ipv6[1];
+				condp = (void *) (((u8 *) condp) +
+						  sizeof(struct in6_addr));
+			}
+#endif
+		}
+	}
+#ifdef CONFIG_SECURITY_CAITSITH_AUTO_DOMAIN_TRANSITION
+	if (!transit_domain_done && type == CS_MAC_AUTO_DOMAIN_TRANSITION)
+		goto out;
+#endif
+	entry->size = (void *) condp - (void *) entry;
+	return cs_commit_condition(entry);
+out:
+	dprintk(KERN_WARNING
+		"%u: bad condition: type=%u env='%s' path='%s' group='%s'\n",
+		__LINE__, type, tmp.envp ? tmp.envp->name : "",
+		tmp.path ? tmp.path->name : "",
+		tmp.group ? tmp.group->group_name->name : "");
+	cs_put_name(tmp.envp);
+	if (tmp.path != &cs_null_name)
+		cs_put_name(tmp.path);
+	cs_put_group(tmp.group);
+	entry->size = (void *) condp - (void *) entry;
+	cs_del_condition(&entry->head.list);
+	kfree(entry);
+	return NULL;
+}