summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-06-15 03:02:23 -0700
committerDavid S. Miller <davem@davemloft.net>2009-06-15 03:02:23 -0700
commit9cbc1cb8cd46ce1f7645b9de249b2ce8460129bb (patch)
tree8d104ec2a459346b99413b0b77421ca7b9936c1a /security
parentca44d6e60f9de26281fda203f58b570e1748c015 (diff)
parent45e3e1935e2857c54783291107d33323b3ef33c8 (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: Documentation/feature-removal-schedule.txt drivers/scsi/fcoe/fcoe.c net/core/drop_monitor.c net/core/net-traces.c
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig22
-rw-r--r--security/Makefile3
-rw-r--r--security/commoncap.c32
-rw-r--r--security/inode.c2
-rw-r--r--security/integrity/ima/ima_audit.c32
-rw-r--r--security/integrity/ima/ima_crypto.c4
-rw-r--r--security/integrity/ima/ima_fs.c12
-rw-r--r--security/integrity/ima/ima_iint.c2
-rw-r--r--security/integrity/ima/ima_init.c4
-rw-r--r--security/integrity/ima/ima_main.c86
-rw-r--r--security/integrity/ima/ima_policy.c48
-rw-r--r--security/lsm_audit.c386
-rw-r--r--security/root_plug.c12
-rw-r--r--security/security.c3
-rw-r--r--security/selinux/avc.c2
-rw-r--r--security/selinux/hooks.c24
-rw-r--r--security/selinux/include/security.h7
-rw-r--r--security/selinux/nlmsgtab.c2
-rw-r--r--security/selinux/selinuxfs.c8
-rw-r--r--security/selinux/ss/services.c30
-rw-r--r--security/smack/smack.h108
-rw-r--r--security/smack/smack_access.c143
-rw-r--r--security/smack/smack_lsm.c405
-rw-r--r--security/smack/smackfs.c76
-rw-r--r--security/tomoyo/common.c119
-rw-r--r--security/tomoyo/common.h134
-rw-r--r--security/tomoyo/domain.c240
-rw-r--r--security/tomoyo/file.c156
-rw-r--r--security/tomoyo/realpath.c23
-rw-r--r--security/tomoyo/tomoyo.c10
-rw-r--r--security/tomoyo/tomoyo.h13
31 files changed, 1702 insertions, 446 deletions
diff --git a/security/Kconfig b/security/Kconfig
index bb244774e9d7..d23c839038f0 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -110,28 +110,8 @@ config SECURITY_ROOTPLUG
See <http://www.linuxjournal.com/article.php?sid=6279> for
more information about this module.
-
- If you are unsure how to answer this question, answer N.
-
-config SECURITY_DEFAULT_MMAP_MIN_ADDR
- int "Low address space to protect from user allocation"
- depends on SECURITY
- default 0
- help
- This is the portion of low virtual memory which should be protected
- from userspace allocation. Keeping a user from writing to low pages
- can help reduce the impact of kernel NULL pointer bugs.
-
- For most ia64, ppc64 and x86 users with lots of address space
- a value of 65536 is reasonable and should cause no problems.
- On arm and other archs it should not be higher than 32768.
- Programs which use vm86 functionality would either need additional
- permissions from either the LSM or the capabilities module or have
- this protection disabled.
-
- This value can be changed after boot using the
- /proc/sys/vm/mmap_min_addr tunable.
+ If you are unsure how to answer this question, answer N.
source security/selinux/Kconfig
source security/smack/Kconfig
diff --git a/security/Makefile b/security/Makefile
index fa77021d9778..c67557cdaa85 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -16,6 +16,9 @@ obj-$(CONFIG_SECURITYFS) += inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
+ifeq ($(CONFIG_AUDIT),y)
+obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o
+endif
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
diff --git a/security/commoncap.c b/security/commoncap.c
index beac0258c2a8..48b7e0228fa3 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -28,6 +28,28 @@
#include <linux/prctl.h>
#include <linux/securebits.h>
+/*
+ * If a non-root user executes a setuid-root binary in
+ * !secure(SECURE_NOROOT) mode, then we raise capabilities.
+ * However if fE is also set, then the intent is for only
+ * the file capabilities to be applied, and the setuid-root
+ * bit is left on either to change the uid (plausible) or
+ * to get full privilege on a kernel without file capabilities
+ * support. So in that case we do not raise capabilities.
+ *
+ * Warn if that happens, once per boot.
+ */
+static void warn_setuid_and_fcaps_mixed(char *fname)
+{
+ static int warned;
+ if (!warned) {
+ printk(KERN_INFO "warning: `%s' has both setuid-root and"
+ " effective capabilities. Therefore not raising all"
+ " capabilities.\n", fname);
+ warned = 1;
+ }
+}
+
int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
NETLINK_CB(skb).eff_cap = current_cap();
@@ -464,6 +486,15 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
if (!issecure(SECURE_NOROOT)) {
/*
+ * If the legacy file capability is set, then don't set privs
+ * for a setuid root binary run by a non-root user. Do set it
+ * for a root user just to cause least surprise to an admin.
+ */
+ if (effective && new->uid != 0 && new->euid == 0) {
+ warn_setuid_and_fcaps_mixed(bprm->filename);
+ goto skip;
+ }
+ /*
* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we override the
* capability sets for the file.
@@ -478,6 +509,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
if (new->euid == 0)
effective = true;
}
+skip:
/* Don't let someone trace a set[ug]id/setpcap binary with the revised
* credentials unless they have the appropriate permit
diff --git a/security/inode.c b/security/inode.c
index f3b91bfbe4cb..f7496c6a022b 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -287,7 +287,7 @@ void securityfs_remove(struct dentry *dentry)
{
struct dentry *parent;
- if (!dentry)
+ if (!dentry || IS_ERR(dentry))
return;
parent = dentry->d_parent;
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
index 1e082bb987be..ff513ff737f5 100644
--- a/security/integrity/ima/ima_audit.c
+++ b/security/integrity/ima/ima_audit.c
@@ -22,18 +22,9 @@ static int ima_audit;
static int __init ima_audit_setup(char *str)
{
unsigned long audit;
- int rc, result = 0;
- char *op = "ima_audit";
- char *cause;
- rc = strict_strtoul(str, 0, &audit);
- if (rc || audit > 1)
- result = 1;
- else
- ima_audit = audit;
- cause = ima_audit ? "enabled" : "not_enabled";
- integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
- op, cause, result, 0);
+ if (!strict_strtoul(str, 0, &audit))
+ ima_audit = audit ? 1 : 0;
return 1;
}
__setup("ima_audit=", ima_audit_setup);
@@ -50,23 +41,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
- current->pid, current->cred->uid,
+ current->pid, current_cred()->uid,
audit_get_loginuid(current),
audit_get_sessionid(current));
audit_log_task_context(ab);
- switch (audit_msgno) {
- case AUDIT_INTEGRITY_DATA:
- case AUDIT_INTEGRITY_METADATA:
- case AUDIT_INTEGRITY_PCR:
- case AUDIT_INTEGRITY_STATUS:
- audit_log_format(ab, " op=%s cause=%s", op, cause);
- break;
- case AUDIT_INTEGRITY_HASH:
- audit_log_format(ab, " op=%s hash=%s", op, cause);
- break;
- default:
- audit_log_format(ab, " op=%s", op);
- }
+ audit_log_format(ab, " op=");
+ audit_log_string(ab, op);
+ audit_log_format(ab, " cause=");
+ audit_log_string(ab, cause);
audit_log_format(ab, " comm=");
audit_log_untrustedstring(ab, current->comm);
if (fname) {
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 50d572b74caf..63003a63aaee 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -103,7 +103,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest)
return rc;
}
-static void ima_pcrread(int idx, u8 *pcr)
+static void __init ima_pcrread(int idx, u8 *pcr)
{
if (!ima_used_chip)
return;
@@ -115,7 +115,7 @@ static void ima_pcrread(int idx, u8 *pcr)
/*
* Calculate the boot aggregate hash
*/
-int ima_calc_boot_aggregate(char *digest)
+int __init ima_calc_boot_aggregate(char *digest)
{
struct hash_desc desc;
struct scatterlist sg;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ffbe259700b1..6bfc7eaebfda 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -15,6 +15,7 @@
* implemenents security file system for reporting
* current measurement list and IMA statistics
*/
+#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/rculist.h>
@@ -84,8 +85,8 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
* against concurrent list-extension
*/
rcu_read_lock();
- qe = list_entry(rcu_dereference(qe->later.next),
- struct ima_queue_entry, later);
+ qe = list_entry_rcu(qe->later.next,
+ struct ima_queue_entry, later);
rcu_read_unlock();
(*pos)++;
@@ -283,6 +284,9 @@ static atomic_t policy_opencount = ATOMIC_INIT(1);
*/
int ima_open_policy(struct inode * inode, struct file * filp)
{
+ /* No point in being allowed to open it if you aren't going to write */
+ if (!(filp->f_flags & O_WRONLY))
+ return -EACCES;
if (atomic_dec_and_test(&policy_opencount))
return 0;
return -EBUSY;
@@ -315,7 +319,7 @@ static struct file_operations ima_measure_policy_ops = {
.release = ima_release_policy
};
-int ima_fs_init(void)
+int __init ima_fs_init(void)
{
ima_dir = securityfs_create_dir("ima", NULL);
if (IS_ERR(ima_dir))
@@ -349,7 +353,7 @@ int ima_fs_init(void)
goto out;
ima_policy = securityfs_create_file("policy",
- S_IRUSR | S_IRGRP | S_IWUSR,
+ S_IWUSR,
ima_dir, NULL,
&ima_measure_policy_ops);
if (IS_ERR(ima_policy))
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index ec79f1ee992c..b8dd693f8790 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -196,7 +196,7 @@ static void init_once(void *foo)
kref_set(&iint->refcount, 1);
}
-void ima_iintcache_init(void)
+void __init ima_iintcache_init(void)
{
iint_cache =
kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 0b0bb8c978cc..a40da7ae5900 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -38,7 +38,7 @@ int ima_used_chip;
* a different value.) Violations add a zero entry to the measurement
* list and extend the aggregate PCR value with ff...ff's.
*/
-static void ima_add_boot_aggregate(void)
+static void __init ima_add_boot_aggregate(void)
{
struct ima_template_entry *entry;
const char *op = "add_boot_aggregate";
@@ -71,7 +71,7 @@ err_out:
audit_cause, result, 0);
}
-int ima_init(void)
+int __init ima_init(void)
{
u8 pcr_i[IMA_DIGEST_SIZE];
int rc;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f4e7266f5aee..6f611874d10e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -29,20 +29,8 @@ int ima_initialized;
char *ima_hash = "sha1";
static int __init hash_setup(char *str)
{
- const char *op = "hash_setup";
- const char *hash = "sha1";
- int result = 0;
- int audit_info = 0;
-
- if (strncmp(str, "md5", 3) == 0) {
- hash = "md5";
- ima_hash = str;
- } else if (strncmp(str, "sha1", 4) != 0) {
- hash = "invalid_hash_type";
- result = 1;
- }
- integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
- result, audit_info);
+ if (strncmp(str, "md5", 3) == 0)
+ ima_hash = "md5";
return 1;
}
__setup("ima_hash=", hash_setup);
@@ -128,10 +116,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
{
int rc = 0;
- if (IS_ERR(file)) {
- pr_info("%s dentry_open failed\n", filename);
- return rc;
- }
iint->opencount++;
iint->readcount++;
@@ -141,6 +125,15 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
return rc;
}
+static void ima_update_counts(struct ima_iint_cache *iint, int mask)
+{
+ iint->opencount++;
+ if ((mask & MAY_WRITE) || (mask == 0))
+ iint->writecount++;
+ else if (mask & (MAY_READ | MAY_EXEC))
+ iint->readcount++;
+}
+
/**
* ima_path_check - based on policy, collect/store measurement.
* @path: contains a pointer to the path to be measured
@@ -156,10 +149,10 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
* - Opening a file for read when already open for write,
* could result in a file measurement error.
*
- * Return 0 on success, an error code on failure.
- * (Based on the results of appraise_measurement().)
+ * Always return 0 and audit dentry_open failures.
+ * (Return code will be based upon measurement appraisal.)
*/
-int ima_path_check(struct path *path, int mask)
+int ima_path_check(struct path *path, int mask, int update_counts)
{
struct inode *inode = path->dentry->d_inode;
struct ima_iint_cache *iint;
@@ -173,11 +166,8 @@ int ima_path_check(struct path *path, int mask)
return 0;
mutex_lock(&iint->mutex);
- iint->opencount++;
- if ((mask & MAY_WRITE) || (mask == 0))
- iint->writecount++;
- else if (mask & (MAY_READ | MAY_EXEC))
- iint->readcount++;
+ if (update_counts)
+ ima_update_counts(iint, mask);
rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
if (rc < 0)
@@ -196,7 +186,19 @@ int ima_path_check(struct path *path, int mask)
struct dentry *dentry = dget(path->dentry);
struct vfsmount *mnt = mntget(path->mnt);
- file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
+ file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE,
+ current_cred());
+ if (IS_ERR(file)) {
+ int audit_info = 0;
+
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+ dentry->d_name.name,
+ "add_measurement",
+ "dentry_open failed",
+ 1, audit_info);
+ file = NULL;
+ goto out;
+ }
rc = get_path_measurement(iint, file, dentry->d_name.name);
}
out:
@@ -206,6 +208,7 @@ out:
kref_put(&iint->refcount, iint_free);
return 0;
}
+EXPORT_SYMBOL_GPL(ima_path_check);
static int process_measurement(struct file *file, const unsigned char *filename,
int mask, int function)
@@ -234,7 +237,16 @@ out:
return rc;
}
-static void opencount_get(struct file *file)
+/*
+ * ima_opens_get - increment file counts
+ *
+ * - for IPC shm and shmat file.
+ * - for nfsd exported files.
+ *
+ * Increment the counts for these files to prevent unnecessary
+ * imbalance messages.
+ */
+void ima_counts_get(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
struct ima_iint_cache *iint;
@@ -246,8 +258,14 @@ static void opencount_get(struct file *file)
return;
mutex_lock(&iint->mutex);
iint->opencount++;
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+ iint->readcount++;
+
+ if (file->f_mode & FMODE_WRITE)
+ iint->writecount++;
mutex_unlock(&iint->mutex);
}
+EXPORT_SYMBOL_GPL(ima_counts_get);
/**
* ima_file_mmap - based on policy, collect/store measurement.
@@ -272,18 +290,6 @@ int ima_file_mmap(struct file *file, unsigned long prot)
return 0;
}
-/*
- * ima_shm_check - IPC shm and shmat create/fput a file
- *
- * Maintain the opencount for these files to prevent unnecessary
- * imbalance messages.
- */
-void ima_shm_check(struct file *file)
-{
- opencount_get(file);
- return;
-}
-
/**
* ima_bprm_check - based on policy, collect/store measurement.
* @bprm: contains the linux_binprm structure
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index b5291ad5ef56..e1278399b345 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -45,24 +45,30 @@ struct ima_measure_rule_entry {
} lsm[MAX_LSM_RULES];
};
-/* Without LSM specific knowledge, the default policy can only be
+/*
+ * Without LSM specific knowledge, the default policy can only be
* written in terms of .action, .func, .mask, .fsmagic, and .uid
*/
+
+/*
+ * The minimum rule set to allow for full TCB coverage. Measures all files
+ * opened or mmap for exec and everything read by root. Dangerous because
+ * normal users can easily run the machine out of memory simply building
+ * and running executables.
+ */
static struct ima_measure_rule_entry default_rules[] = {
- {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
- .flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
- {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
- .flags = IMA_FSMAGIC},
- {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
{.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
- .flags = IMA_FUNC | IMA_MASK | IMA_UID}
+ .flags = IMA_FUNC | IMA_MASK | IMA_UID},
};
static LIST_HEAD(measure_default_rules);
@@ -71,6 +77,14 @@ static struct list_head *ima_measure;
static DEFINE_MUTEX(ima_measure_mutex);
+static bool ima_use_tcb __initdata;
+static int __init default_policy_setup(char *str)
+{
+ ima_use_tcb = 1;
+ return 1;
+}
+__setup("ima_tcb", default_policy_setup);
+
/**
* ima_match_rules - determine whether an inode matches the measure rule.
* @rule: a pointer to a rule
@@ -96,7 +110,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
- int rc;
+ int rc = 0;
u32 osid, sid;
if (!rule->lsm[i].rule)
@@ -109,7 +123,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
security_inode_getsecid(inode, &osid);
rc = security_filter_rule_match(osid,
rule->lsm[i].type,
- AUDIT_EQUAL,
+ Audit_equal,
rule->lsm[i].rule,
NULL);
break;
@@ -119,7 +133,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
security_task_getsecid(tsk, &sid);
rc = security_filter_rule_match(sid,
rule->lsm[i].type,
- AUDIT_EQUAL,
+ Audit_equal,
rule->lsm[i].rule,
NULL);
default:
@@ -164,11 +178,17 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
* ima_measure points to either the measure_default_rules or the
* the new measure_policy_rules.
*/
-void ima_init_policy(void)
+void __init ima_init_policy(void)
{
- int i;
+ int i, entries;
+
+ /* if !ima_use_tcb set entries = 0 so we load NO default rules */
+ if (ima_use_tcb)
+ entries = ARRAY_SIZE(default_rules);
+ else
+ entries = 0;
- for (i = 0; i < ARRAY_SIZE(default_rules); i++)
+ for (i = 0; i < entries; i++)
list_add_tail(&default_rules[i].list, &measure_default_rules);
ima_measure = &measure_default_rules;
}
@@ -227,7 +247,7 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
entry->lsm[lsm_rule].type = audit_type;
result = security_filter_rule_init(entry->lsm[lsm_rule].type,
- AUDIT_EQUAL, args,
+ Audit_equal, args,
&entry->lsm[lsm_rule].rule);
return result;
}
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
new file mode 100644
index 000000000000..94b868494b31
--- /dev/null
+++ b/security/lsm_audit.c
@@ -0,0 +1,386 @@
+/*
+ * common LSM auditing functions
+ *
+ * Based on code written for SELinux by :
+ * Stephen Smalley, <sds@epoch.ncsc.mil>
+ * James Morris <jmorris@redhat.com>
+ * Author : Etienne Basset, <etienne.basset@ensta.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <net/sock.h>
+#include <linux/un.h>
+#include <net/af_unix.h>
+#include <linux/audit.h>
+#include <linux/ipv6.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/dccp.h>
+#include <linux/sctp.h>
+#include <linux/lsm_audit.h>
+
+/**
+ * ipv4_skb_to_auditdata : fill auditdata from skb
+ * @skb : the skb
+ * @ad : the audit data to fill
+ * @proto : the layer 4 protocol
+ *
+ * return 0 on success
+ */
+int ipv4_skb_to_auditdata(struct sk_buff *skb,
+ struct common_audit_data *ad, u8 *proto)
+{
+ int ret = 0;
+ struct iphdr *ih;
+
+ ih = ip_hdr(skb);
+ if (ih == NULL)
+ return -EINVAL;
+
+ ad->u.net.v4info.saddr = ih->saddr;
+ ad->u.net.v4info.daddr = ih->daddr;
+
+ if (proto)
+ *proto = ih->protocol;
+ /* non initial fragment */
+ if (ntohs(ih->frag_off) & IP_OFFSET)
+ return 0;
+
+ switch (ih->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr *th = tcp_hdr(skb);
+ if (th == NULL)
+ break;
+
+ ad->u.net.sport = th->source;
+ ad->u.net.dport = th->dest;
+ break;
+ }
+ case IPPROTO_UDP: {
+ struct udphdr *uh = udp_hdr(skb);
+ if (uh == NULL)
+ break;
+
+ ad->u.net.sport = uh->source;
+ ad->u.net.dport = uh->dest;
+ break;
+ }
+ case IPPROTO_DCCP: {
+ struct dccp_hdr *dh = dccp_hdr(skb);
+ if (dh == NULL)
+ break;
+
+ ad->u.net.sport = dh->dccph_sport;
+ ad->u.net.dport = dh->dccph_dport;
+ break;
+ }
+ case IPPROTO_SCTP: {
+ struct sctphdr *sh = sctp_hdr(skb);
+ if (sh == NULL)
+ break;
+ ad->u.net.sport = sh->source;
+ ad->u.net.dport = sh->dest;
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * ipv6_skb_to_auditdata : fill auditdata from skb
+ * @skb : the skb
+ * @ad : the audit data to fill
+ * @proto : the layer 4 protocol
+ *
+ * return 0 on success
+ */
+int ipv6_skb_to_auditdata(struct sk_buff *skb,
+ struct common_audit_data *ad, u8 *proto)
+{
+ int offset, ret = 0;
+ struct ipv6hdr *ip6;
+ u8 nexthdr;
+
+ ip6 = ipv6_hdr(skb);
+ if (ip6 == NULL)
+ return -EINVAL;
+ ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
+ ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+ ret = 0;
+ /* IPv6 can have several extension header before the Transport header
+ * skip them */
+ offset = skb_network_offset(skb);
+ offset += sizeof(*ip6);
+ nexthdr = ip6->nexthdr;
+ offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+ if (offset < 0)
+ return 0;
+ if (proto)
+ *proto = nexthdr;
+ switch (nexthdr) {
+ case IPPROTO_TCP: {
+ struct tcphdr _tcph, *th;
+
+ th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+ if (th == NULL)
+ break;
+
+ ad->u.net.sport = th->source;
+ ad->u.net.dport = th->dest;
+ break;
+ }
+ case IPPROTO_UDP: {
+ struct udphdr _udph, *uh;
+
+ uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+ if (uh == NULL)
+ break;
+
+ ad->u.net.sport = uh->source;
+ ad->u.net.dport = uh->dest;
+ break;
+ }
+ case IPPROTO_DCCP: {
+ struct dccp_hdr _dccph, *dh;
+
+ dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+ if (dh == NULL)
+ break;
+
+ ad->u.net.sport = dh->dccph_sport;
+ ad->u.net.dport = dh->dccph_dport;
+ break;
+ }
+ case IPPROTO_SCTP: {
+ struct sctphdr _sctph, *sh;
+
+ sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
+ if (sh == NULL)
+ break;
+ ad->u.net.sport = sh->source;
+ ad->u.net.dport = sh->dest;
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+#endif
+
+
+static inline void print_ipv6_addr(struct audit_buffer *ab,
+ struct in6_addr *addr, __be16 port,
+ char *name1, char *name2)
+{
+ if (!ipv6_addr_any(addr))
+ audit_log_format(ab, " %s=%pI6", name1, addr);
+ if (port)
+ audit_log_format(ab, " %s=%d", name2, ntohs(port));
+}
+
+static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
+ __be16 port, char *name1, char *name2)
+{
+ if (addr)
+ audit_log_format(ab, " %s=%pI4", name1, &addr);
+ if (port)
+ audit_log_format(ab, " %s=%d", name2, ntohs(port));
+}
+
+/**
+ * dump_common_audit_data - helper to dump common audit data
+ * @a : common audit data
+ *
+ */
+static void dump_common_audit_data(struct audit_buffer *ab,
+ struct common_audit_data *a)
+{
+ struct inode *inode = NULL;
+ struct task_struct *tsk = current;
+
+ if (a->tsk)
+ tsk = a->tsk;
+ if (tsk && tsk->pid) {
+ audit_log_format(ab, " pid=%d comm=", tsk->pid);
+ audit_log_untrustedstring(ab, tsk->comm);
+ }
+
+ switch (a->type) {
+ case LSM_AUDIT_DATA_IPC:
+ audit_log_format(ab, " key=%d ", a->u.ipc_id);
+ break;
+ case LSM_AUDIT_DATA_CAP:
+ audit_log_format(ab, " capability=%d ", a->u.cap);
+ break;
+ case LSM_AUDIT_DATA_FS:
+ if (a->u.fs.path.dentry) {
+ struct dentry *dentry = a->u.fs.path.dentry;
+ if (a->u.fs.path.mnt) {
+ audit_log_d_path(ab, "path=", &a->u.fs.path);
+ } else {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab,
+ dentry->d_name.name);
+ }
+ inode = dentry->d_inode;
+ } else if (a->u.fs.inode) {
+ struct dentry *dentry;
+ inode = a->u.fs.inode;
+ dentry = d_find_alias(inode);
+ if (dentry) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab,
+ dentry->d_name.name);
+ dput(dentry);
+ }
+ }
+ if (inode)
+ audit_log_format(ab, " dev=%s ino=%lu",
+ inode->i_sb->s_id,
+ inode->i_ino);
+ break;
+ case LSM_AUDIT_DATA_TASK:
+ tsk = a->u.tsk;
+ if (tsk && tsk->pid) {
+ audit_log_format(ab, " pid=%d comm=", tsk->pid);
+ audit_log_untrustedstring(ab, tsk->comm);
+ }
+ break;
+ case LSM_AUDIT_DATA_NET:
+ if (a->u.net.sk) {
+ struct sock *sk = a->u.net.sk;
+ struct unix_sock *u;
+ int len = 0;
+ char *p = NULL;
+
+ switch (sk->sk_family) {
+ case AF_INET: {
+ struct inet_sock *inet = inet_sk(sk);
+
+ print_ipv4_addr(ab, inet->rcv_saddr,
+ inet->sport,
+ "laddr", "lport");
+ print_ipv4_addr(ab, inet->daddr,
+ inet->dport,
+ "faddr", "fport");
+ break;
+ }
+ case AF_INET6: {
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *inet6 = inet6_sk(sk);
+
+ print_ipv6_addr(ab, &inet6->rcv_saddr,
+ inet->sport,
+ "laddr", "lport");
+ print_ipv6_addr(ab, &inet6->daddr,
+ inet->dport,
+ "faddr", "fport");
+ break;
+ }
+ case AF_UNIX:
+ u = unix_sk(sk);