Commit f39d420f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem updates from James Morris:
 "In this update, Smack learns to love IPv6 and to mount a filesystem
  with a transmutable hierarchy (i.e.  security labels are inherited
  from parent directory upon creation rather than creating process).

  The rest of the changes are maintenance"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (37 commits)
  tpm/tpm_i2c_infineon: Remove unused header file
  tpm: tpm_i2c_infinion: Don't modify i2c_client->driver
  evm: audit integrity metadata failures
  integrity: move integrity_audit_msg()
  evm: calculate HMAC after initializing posix acl on tmpfs
  maintainers:  add Dmitry Kasatkin
  Smack: Fix the bug smackcipso can't set CIPSO correctly
  Smack: Fix possible NULL pointer dereference at smk_netlbl_mls()
  Smack: Add smkfstransmute mount option
  Smack: Improve access check performance
  Smack: Local IPv6 port based controls
  tpm: fix regression caused by section type conflict of tpm_dev_release() in ppc builds
  maintainers: Remove Kent from maintainers
  tpm: move TPM_DIGEST_SIZE defintion
  tpm_tis: missing platform_driver_unregister() on error in init_tis()
  security: clarify cap_inode_getsecctx description
  apparmor: no need to delay vfree()
  apparmor: fix fully qualified name parsing
  apparmor: fix setprocattr arg processing for onexec
  apparmor: localize getting the security context to a few macros
  ...
parents fe489bf4 572e5b01
...@@ -1129,11 +1129,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1129,11 +1129,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
The builtin appraise policy appraises all files The builtin appraise policy appraises all files
owned by uid=0. owned by uid=0.
ima_audit= [IMA]
Format: { "0" | "1" }
0 -- integrity auditing messages. (Default)
1 -- enable informational integrity auditing messages.
ima_hash= [IMA] ima_hash= [IMA]
Format: { "sha1" | "md5" } Format: { "sha1" | "md5" }
default: "sha1" default: "sha1"
...@@ -1160,6 +1155,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1160,6 +1155,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
int_pln_enable [x86] Enable power limit notification interrupt int_pln_enable [x86] Enable power limit notification interrupt
integrity_audit=[IMA]
Format: { "0" | "1" }
0 -- basic integrity auditing messages. (Default)
1 -- additional integrity auditing messages.
intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option
on on
Enable intel iommu driver. Enable intel iommu driver.
......
...@@ -4001,7 +4001,8 @@ S: Maintained ...@@ -4001,7 +4001,8 @@ S: Maintained
F: arch/ia64/ F: arch/ia64/
IBM Power in-Nest Crypto Acceleration IBM Power in-Nest Crypto Acceleration
M: Kent Yoder <key@linux.vnet.ibm.com> M: Marcelo Henrique Cerri <mhcerri@linux.vnet.ibm.com>
M: Fionnuala Gunter <fin@linux.vnet.ibm.com>
L: linux-crypto@vger.kernel.org L: linux-crypto@vger.kernel.org
S: Supported S: Supported
F: drivers/crypto/nx/ F: drivers/crypto/nx/
...@@ -4130,6 +4131,7 @@ F: drivers/ipack/ ...@@ -4130,6 +4131,7 @@ F: drivers/ipack/
INTEGRITY MEASUREMENT ARCHITECTURE (IMA) INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@us.ibm.com> M: Mimi Zohar <zohar@us.ibm.com>
M: Dmitry Kasatkin <d.kasatkin@samsung.com>
S: Supported S: Supported
F: security/integrity/ima/ F: security/integrity/ima/
...@@ -8282,7 +8284,8 @@ S: Odd fixes ...@@ -8282,7 +8284,8 @@ S: Odd fixes
F: drivers/media/usb/tm6000/ F: drivers/media/usb/tm6000/
TPM DEVICE DRIVER TPM DEVICE DRIVER
M: Kent Yoder <key@linux.vnet.ibm.com> M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
M: Ashley Lai <ashley@ashleylai.com>
M: Rajiv Andrade <mail@srajiv.net> M: Rajiv Andrade <mail@srajiv.net>
W: http://tpmdd.sourceforge.net W: http://tpmdd.sourceforge.net
M: Marcel Selhorst <tpmdd@selhorst.net> M: Marcel Selhorst <tpmdd@selhorst.net>
......
...@@ -1472,7 +1472,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); ...@@ -1472,7 +1472,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
* Once all references to platform device are down to 0, * Once all references to platform device are down to 0,
* release all allocated structures. * release all allocated structures.
*/ */
static void tpm_dev_release(struct device *dev) void tpm_dev_release(struct device *dev)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
......
...@@ -272,7 +272,6 @@ typedef union { ...@@ -272,7 +272,6 @@ typedef union {
struct tpm_output_header out; struct tpm_output_header out;
} tpm_cmd_header; } tpm_cmd_header;
#define TPM_DIGEST_SIZE 20
struct tpm_pcrread_out { struct tpm_pcrread_out {
u8 pcr_result[TPM_DIGEST_SIZE]; u8 pcr_result[TPM_DIGEST_SIZE];
} __packed; } __packed;
...@@ -333,6 +332,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *, ...@@ -333,6 +332,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *); const struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *); extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *); extern int tpm_release(struct inode *, struct file *);
extern void tpm_dev_release(struct device *dev);
extern void tpm_dev_vendor_release(struct tpm_chip *); extern void tpm_dev_vendor_release(struct tpm_chip *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t, extern ssize_t tpm_write(struct file *, const char __user *, size_t,
loff_t *); loff_t *);
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/wait.h> #include <linux/wait.h>
#include "tpm.h" #include "tpm.h"
...@@ -74,7 +73,6 @@ struct tpm_inf_dev { ...@@ -74,7 +73,6 @@ struct tpm_inf_dev {
}; };
static struct tpm_inf_dev tpm_dev; static struct tpm_inf_dev tpm_dev;
static struct i2c_driver tpm_tis_i2c_driver;
/* /*
* iic_tpm_read() - read from TPM register * iic_tpm_read() - read from TPM register
...@@ -744,11 +742,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client, ...@@ -744,11 +742,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
return -ENODEV; return -ENODEV;
} }
client->driver = &tpm_tis_i2c_driver;
tpm_dev.client = client; tpm_dev.client = client;
rc = tpm_tis_i2c_init(&client->dev); rc = tpm_tis_i2c_init(&client->dev);
if (rc != 0) { if (rc != 0) {
client->driver = NULL;
tpm_dev.client = NULL; tpm_dev.client = NULL;
rc = -ENODEV; rc = -ENODEV;
} }
......
...@@ -884,12 +884,19 @@ static int __init init_tis(void) ...@@ -884,12 +884,19 @@ static int __init init_tis(void)
rc = platform_driver_register(&tis_drv); rc = platform_driver_register(&tis_drv);
if (rc < 0) if (rc < 0)
return rc; return rc;
if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0))) pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
return PTR_ERR(pdev); if (IS_ERR(pdev)) {
if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) { rc = PTR_ERR(pdev);
goto err_dev;
}
rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
if (rc)
goto err_init;
return 0;
err_init:
platform_device_unregister(pdev); platform_device_unregister(pdev);
err_dev:
platform_driver_unregister(&tis_drv); platform_driver_unregister(&tis_drv);
}
return rc; return rc;
} }
......
...@@ -1392,7 +1392,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -1392,7 +1392,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @ctxlen contains the length of @ctx. * @ctxlen contains the length of @ctx.
* *
* @inode_getsecctx: * @inode_getsecctx:
* Returns a string containing all relevant security context information * On success, returns 0 and fills out @ctx and @ctxlen with the security
* context for the given @inode.
* *
* @inode we wish to get the security context of. * @inode we wish to get the security context of.
* @ctx is a pointer in which to place the allocated security context. * @ctx is a pointer in which to place the allocated security context.
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#ifndef __LINUX_TPM_H__ #ifndef __LINUX_TPM_H__
#define __LINUX_TPM_H__ #define __LINUX_TPM_H__
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
/* /*
* Chip num is this value or a valid tpm idx * Chip num is this value or a valid tpm idx
*/ */
......
...@@ -1936,6 +1936,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) ...@@ -1936,6 +1936,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE); inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
if (inode) { if (inode) {
#ifdef CONFIG_TMPFS_POSIX_ACL
error = generic_acl_init(inode, dir);
if (error) {
iput(inode);
return error;
}
#endif
error = security_inode_init_security(inode, dir, error = security_inode_init_security(inode, dir,
&dentry->d_name, &dentry->d_name,
shmem_initxattrs, NULL); shmem_initxattrs, NULL);
...@@ -1945,15 +1952,8 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) ...@@ -1945,15 +1952,8 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
return error; return error;
} }
} }
#ifdef CONFIG_TMPFS_POSIX_ACL
error = generic_acl_init(inode, dir);
if (error) {
iput(inode);
return error;
}
#else
error = 0; error = 0;
#endif
dir->i_size += BOGO_DIRENT_SIZE; dir->i_size += BOGO_DIRENT_SIZE;
dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
......
...@@ -88,7 +88,7 @@ static const char *const aa_audit_type[] = { ...@@ -88,7 +88,7 @@ static const char *const aa_audit_type[] = {
"HINT", "HINT",
"STATUS", "STATUS",
"ERROR", "ERROR",
"KILLED" "KILLED",
"AUTO" "AUTO"
}; };
......
...@@ -68,6 +68,23 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) ...@@ -68,6 +68,23 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
aa_get_profile(new->onexec); aa_get_profile(new->onexec);
} }
/**
* aa_get_task_profile - Get another task's profile
* @task: task to query (NOT NULL)
*
* Returns: counted reference to @task's profile
*/
struct aa_profile *aa_get_task_profile(struct task_struct *task)
{
struct aa_profile *p;
rcu_read_lock();
p = aa_get_profile(__aa_task_profile(task));
rcu_read_unlock();
return p;
}
/** /**
* aa_replace_current_profile - replace the current tasks profiles * aa_replace_current_profile - replace the current tasks profiles
* @profile: new profile (NOT NULL) * @profile: new profile (NOT NULL)
...@@ -76,7 +93,7 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) ...@@ -76,7 +93,7 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
*/ */
int aa_replace_current_profile(struct aa_profile *profile) int aa_replace_current_profile(struct aa_profile *profile)
{ {
struct aa_task_cxt *cxt = current_cred()->security; struct aa_task_cxt *cxt = current_cxt();
struct cred *new; struct cred *new;
BUG_ON(!profile); BUG_ON(!profile);
...@@ -87,17 +104,13 @@ int aa_replace_current_profile(struct aa_profile *profile) ...@@ -87,17 +104,13 @@ int aa_replace_current_profile(struct aa_profile *profile)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
cxt = new->security; cxt = cred_cxt(new);
if (unconfined(profile) || (cxt->profile->ns != profile->ns)) { if (unconfined(profile) || (cxt->profile->ns != profile->ns))
/* if switching to unconfined or a different profile namespace /* if switching to unconfined or a different profile namespace
* clear out context state * clear out context state
*/ */
aa_put_profile(cxt->previous); aa_clear_task_cxt_trans(cxt);
aa_put_profile(cxt->onexec);
cxt->previous = NULL;
cxt->onexec = NULL;
cxt->token = 0;
}
/* be careful switching cxt->profile, when racing replacement it /* be careful switching cxt->profile, when racing replacement it
* is possible that cxt->profile->replacedby is the reference keeping * is possible that cxt->profile->replacedby is the reference keeping
* @profile valid, so make sure to get its reference before dropping * @profile valid, so make sure to get its reference before dropping
...@@ -123,7 +136,7 @@ int aa_set_current_onexec(struct aa_profile *profile) ...@@ -123,7 +136,7 @@ int aa_set_current_onexec(struct aa_profile *profile)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
cxt = new->security; cxt = cred_cxt(new);
aa_get_profile(profile); aa_get_profile(profile);
aa_put_profile(cxt->onexec); aa_put_profile(cxt->onexec);
cxt->onexec = profile; cxt->onexec = profile;
...@@ -150,7 +163,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) ...@@ -150,7 +163,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
return -ENOMEM; return -ENOMEM;
BUG_ON(!profile); BUG_ON(!profile);
cxt = new->security; cxt = cred_cxt(new);
if (!cxt->previous) { if (!cxt->previous) {
/* transfer refcount */ /* transfer refcount */
cxt->previous = cxt->profile; cxt->previous = cxt->profile;
...@@ -187,7 +200,7 @@ int aa_restore_previous_profile(u64 token) ...@@ -187,7 +200,7 @@ int aa_restore_previous_profile(u64 token)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
cxt = new->security; cxt = cred_cxt(new);
if (cxt->token != token) { if (cxt->token != token) {
abort_creds(new); abort_creds(new);
return -EACCES; return -EACCES;
...@@ -205,11 +218,10 @@ int aa_restore_previous_profile(u64 token) ...@@ -205,11 +218,10 @@ int aa_restore_previous_profile(u64 token)
aa_get_profile(cxt->profile); aa_get_profile(cxt->profile);
aa_put_profile(cxt->previous); aa_put_profile(cxt->previous);
} }
/* clear exec && prev information when restoring to previous context */ /* ref has been transfered so avoid putting ref in clear_task_cxt */
cxt->previous = NULL; cxt->previous = NULL;
cxt->token = 0; /* clear exec && prev information when restoring to previous context */
aa_put_profile(cxt->onexec); aa_clear_task_cxt_trans(cxt);
cxt->onexec = NULL;
commit_creds(new); commit_creds(new);
return 0; return 0;
......
...@@ -62,17 +62,14 @@ static int may_change_ptraced_domain(struct task_struct *task, ...@@ -62,17 +62,14 @@ static int may_change_ptraced_domain(struct task_struct *task,
struct aa_profile *to_profile) struct aa_profile *to_profile)
{ {
struct task_struct *tracer; struct task_struct *tracer;
const struct cred *cred = NULL;
struct aa_profile *tracerp = NULL; struct aa_profile *tracerp = NULL;
int error = 0; int error = 0;
rcu_read_lock(); rcu_read_lock();
tracer = ptrace_parent(task); tracer = ptrace_parent(task);
if (tracer) { if (tracer)
/* released below */ /* released below */
cred = get_task_cred(tracer); tracerp = aa_get_task_profile(tracer);
tracerp = aa_cred_profile(cred);
}
/* not ptraced */ /* not ptraced */
if (!tracer || unconfined(tracerp)) if (!tracer || unconfined(tracerp))
...@@ -82,8 +79,7 @@ static int may_change_ptraced_domain(struct task_struct *task, ...@@ -82,8 +79,7 @@ static int may_change_ptraced_domain(struct task_struct *task,
out: out:
rcu_read_unlock(); rcu_read_unlock();
if (cred) aa_put_profile(tracerp);
put_cred(cred);
return error; return error;
} }
...@@ -360,7 +356,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -360,7 +356,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->cred_prepared) if (bprm->cred_prepared)
return 0; return 0;
cxt = bprm->cred->security; cxt = cred_cxt(bprm->cred);
BUG_ON(!cxt); BUG_ON(!cxt);
profile = aa_get_profile(aa_newest_version(cxt->profile)); profile = aa_get_profile(aa_newest_version(cxt->profile));
...@@ -443,6 +439,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -443,6 +439,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
} else { } else {
error = -ENOENT; error = -ENOENT;
info = "profile not found"; info = "profile not found";
/* remove MAY_EXEC to audit as failure */
perms.allow &= ~MAY_EXEC;
} }
} }
} else if (COMPLAIN_MODE(profile)) { } else if (COMPLAIN_MODE(profile)) {
...@@ -514,11 +512,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -514,11 +512,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
cxt->profile = new_profile; cxt->profile = new_profile;
/* clear out all temporary/transitional state from the context */ /* clear out all temporary/transitional state from the context */
aa_put_profile(cxt->previous); aa_clear_task_cxt_trans(cxt);
aa_put_profile(cxt->onexec);
cxt->previous = NULL;
cxt->onexec = NULL;
cxt->token = 0;
audit: audit:
error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
...@@ -557,7 +551,7 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm) ...@@ -557,7 +551,7 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)
void apparmor_bprm_committing_creds(struct linux_binprm *bprm) void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
{ {
struct aa_profile *profile = __aa_current_profile(); struct aa_profile *profile = __aa_current_profile();
struct aa_task_cxt *new_cxt = bprm->cred->security; struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred);
/* bail out if unconfined or not changing profile */ /* bail out if unconfined or not changing profile */
if ((new_cxt->profile == profile) || if ((new_cxt->profile == profile) ||
...@@ -634,7 +628,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) ...@@ -634,7 +628,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
/* released below */ /* released below */
cred = get_current_cred(); cred = get_current_cred();
cxt = cred->security; cxt = cred_cxt(cred);
profile = aa_cred_profile(cred); profile = aa_cred_profile(cred);
previous_profile = cxt->previous; previous_profile = cxt->previous;
...@@ -750,7 +744,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, ...@@ -750,7 +744,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
bool permtest) bool permtest)
{ {
const struct cred *cred; const struct cred *cred;
struct aa_task_cxt *cxt;
struct aa_profile *profile, *target = NULL; struct aa_profile *profile, *target = NULL;
struct aa_namespace *ns = NULL; struct aa_namespace *ns = NULL;
struct file_perms perms = {}; struct file_perms perms = {};
...@@ -770,7 +763,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, ...@@ -770,7 +763,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
} }
cred = get_current_cred(); cred = get_current_cred();
cxt = cred->security;
profile = aa_cred_profile(cred); profile = aa_cred_profile(cred);
/* /*
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef __APPARMOR_H #ifndef __APPARMOR_H
#define __APPARMOR_H #define __APPARMOR_H
#include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
#include "match.h" #include "match.h"
...@@ -64,9 +65,18 @@ extern int apparmor_initialized __initdata; ...@@ -64,9 +65,18 @@ extern int apparmor_initialized __initdata;
/* fn's in lib */ /* fn's in lib */
char *aa_split_fqname(char *args, char **ns_name); char *aa_split_fqname(char *args, char **ns_name);
void aa_info_message(const char *str); void aa_info_message(const char *str);
void *kvmalloc(size_t size); void *__aa_kvmalloc(size_t size, gfp_t flags);
void kvfree(void *buffer); void kvfree(void *buffer);
static inline void *kvmalloc(size_t size)
{
return __aa_kvmalloc(size, 0);
}
static inline void *kvzalloc(size_t size)
{
return __aa_kvmalloc(size, __GFP_ZERO);
}
/** /**
* aa_strneq - compare null terminated @str to a non null terminated substring * aa_strneq - compare null terminated @str to a non null terminated substring
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#include "policy.h" #include "policy.h"
#define cred_cxt(X) (X)->security
#define current_cxt() cred_cxt(current_cred())
/* struct aa_file_cxt - the AppArmor context the file was opened in /* struct aa_file_cxt - the AppArmor context the file was opened in
* @perms: the permission the file was opened with * @perms: the permission the file was opened with
* *
...@@ -80,23 +83,8 @@ int aa_replace_current_profile(struct aa_profile *profile); ...@@ -80,23 +83,8 @@ int aa_replace_current_profile(struct aa_profile *profile);
int aa_set_current_onexec(struct aa_profile *profile); int aa_set_current_onexec(struct aa_profile *profile);
int aa_set_current_hat(struct aa_profile *profile, u64 token); int aa_set_current_hat(struct aa_profile *profile, u64 token);
int aa_restore_previous_profile(u64 cookie); int aa_restore_previous_profile(u64 cookie);
struct aa_profile *aa_get_task_profile(struct task_struct *task);
/**
* __aa_task_is_confined - determine if @task has any confinement
* @task: task to check confinement of (NOT NULL)
*
* If @task != current needs to be called in RCU safe critical section
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
struct aa_task_cxt *cxt = __task_cred(task)->security;
BUG_ON(!cxt || !cxt->profile);
if (unconfined(aa_newest_version(cxt->profile)))
return 0;
return 1;
}
/** /**
* aa_cred_profile - obtain cred's profiles * aa_cred_profile - obtain cred's profiles
...@@ -108,11 +96,35 @@ static inline bool __aa_task_is_confined(struct task_struct *task) ...@@ -108,11 +96,35 @@ static inline bool __aa_task_is_confined(struct task_struct *task)
*/ */
static inline struct aa_profile *aa_cred_profile(const struct cred *cred) static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
{ {
struct aa_task_cxt *cxt = cred->security; struct aa_task_cxt *cxt = cred_cxt(cred);
BUG_ON(!cxt || !cxt->profile); BUG_ON(!cxt || !cxt->profile);
return aa_newest_version(cxt->profile); return aa_newest_version(cxt->profile);
} }
/**
* __aa_task_profile - retrieve another task's profile
* @task: task to query (NOT NULL)
*
* Returns: @task's profile without incrementing its ref count
*
* If @task != current needs to be called in RCU safe critical section
*/
static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
{
return aa_cred_profile(__task_cred(task));
}
/**
* __aa_task_is_confined - determine if @task has any confinement
* @task: task to check confinement of (NOT NULL)
*
* If @task != current needs to be called in RCU safe critical section
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
return !unconfined(__aa_task_profile(task));
}
/** /**
* __aa_current_profile - find the current tasks confining profile * __aa_current_profile - find the current tasks confining profile
* *
...@@ -136,7 +148,7 @@ static inline struct aa_profile *__aa_current_profile(void) ...@@ -136,7 +148,7 @@ static inline struct aa_profile *__aa_current_profile(void)
*/ */
static inline struct aa_profile *aa_current_profile(void) static inline struct aa_profile *aa_current_profile(void)
{ {
const struct aa_task_cxt *cxt = current_cred()->security; const struct aa_task_cxt *cxt = current_cxt();
struct aa_profile *profile; struct aa_profile *profile;
BUG_ON(!cxt || !cxt->profile); BUG_ON(!cxt || !cxt->profile);
...@@ -151,4 +163,17 @@ static inline struct aa_profile *aa_current_profile(void) ...@@ -151,4 +163,17 @@ static inline struct aa_profile *aa_current_profile(void)
return profile; return profile;
} }
/**
* aa_clear_task_cxt_trans - clear transition tracking info from the cxt
* @cxt: task context to clear (NOT NULL)
*/
static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt)
{
aa_put_profile(cxt->previous);
aa_put_profile(cxt->onexec);
cxt->previous = NULL;
cxt->onexec = NULL;
cxt->token = 0;
}
#endif /* __AA_CONTEXT_H */ #endif /* __AA_CONTEXT_H */
...@@ -186,11 +186,6 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules) ...@@ -186,11 +186,6 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
aa_free_domain_entries(&rules->trans); aa_free_domain_entries(&rules->trans);
} }
#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
/* from namei.c */
#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
/** /**
* aa_map_file_perms - map file flags to AppArmor permissions * aa_map_file_perms - map file flags to AppArmor permissions
* @file: open file to map flags to AppArmor permissions * @file: open file to map flags to AppArmor permissions
...@@ -199,8 +194,13 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules) ...@@ -199,8 +194,13 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
*/ */
static inline u32 aa_map_file_to_perms(struct file *file) static inline u32 aa_map_file_to_perms(struct file *file)
{ {
int flags = MAP_OPEN_FLAGS(file->f_flags); int flags = file->f_flags;
u32 perms = ACC_FMODE(file->f_mode); u32 perms = 0;
if (file->f_mode & FMODE_WRITE)
perms |= MAY_WRITE;
if (file->f_mode & FMODE_READ)
perms |= MAY_READ;
if ((flags & O_APPEND) && (perms & MAY_WRITE)) if ((flags & O_APPEND) && (perms & MAY_WRITE))
perms = (perms & ~MAY_WRITE) | MAY_APPEND; perms = (perms & ~MAY_WRITE) | MAY_APPEND;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file contains AppArmor policy dfa matching engine definitions. * This file contains AppArmor policy dfa matching engine definitions.
* *
* Copyright (C) 1998-2008 Novell/SUSE * Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd. * Copyright 2009-2012 Canonical Ltd.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -16,25 +16,30 @@ ...@@ -16,25 +16,30 @@
#define __AA_MATCH_H #define __AA_MATCH_H
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/workqueue.h>
#define DFA_NOMATCH 0 #define DFA_NOMATCH 0
#define DFA_START 1 #define DFA_START 1
#define DFA_VALID_PERM_MASK 0xffffffff
#define DFA_VALID_PERM2_MASK 0xffffffff
/** /**
* The format used for transition tables is based on the GNU flex table * The format used for transition tables is based on the GNU flex table
* file format (--tables-file option; see Table File Format in the flex * file format (--tables-file option; see Table File Format in the flex
* info pages and the flex sources for documentation). The magic number * info pages and the flex sources for documentation). The magic number
* used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because * used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because
* the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used * new tables have been defined and others YY_ID_CHK (check) and YY_ID_DEF
* slightly differently (see the apparmor-parser package). * (default) tables are used slightly differently (see the apparmor-parser
* package).
*
*
* The data in the packed dfa is stored in network byte order, and the tables
* are arranged for flexibility. We convert the table data to host native
* byte order.
*
* The dfa begins with a table set header, and is followed by the actual
* tables.
*/ */
#define YYTH_MAGIC 0x1B5E783D #define YYTH_MAGIC 0x1B5E783D
#define YYTH_DEF_RECURSE 0x1 /* DEF Table is recursive */
struct table_set_header { struct table_set_header {
u32 th_magic; /* YYTH_MAGIC */ u32 th_magic; /* YYTH_MAGIC */
...@@ -63,7 +68,7 @@ struct table_set_header { ...@@ -63,7 +68,7 @@ struct table_set_header {
#define YYTD_DATA32 4 #define YYTD_DATA32 4
#define YYTD_DATA64 8 #define YYTD_DATA64 8
/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the /* ACCEPT & ACCEPT2 tables gets 6 dedicated flags, YYTD_DATAX define the
* first flags * first flags
*/ */
#define ACCEPT1_FLAGS(X) ((X) & 0x3f) #define ACCEPT1_FLAGS(X) ((X) & 0x3f)
......
...@@ -32,13 +32,13 @@ ...@@ -32,13 +32,13 @@
extern const char *const profile_mode_names[]; extern const char *const profile_mode_names[];
#define APPARMOR_NAMES_MAX_INDEX 3 #define APPARMOR_NAMES_MAX_INDEX 3
#define COMPLAIN_MODE(_profile) \ #define PROFILE_MODE(_profile, _mode) \
((aa_g_profile_mode == APPARMOR_COMPLAIN) || \ ((aa_g_profile_mode == (_mode)) || \
((_profile)->mode == APPARMOR_COMPLAIN)) ((_profile)->mode == (_mode)))
#define KILL_MODE(_profile) \ #define COMPLAIN_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_COMPLAIN)
((aa_g_profile_mode == APPARMOR_KILL) || \
((_profile)->mode == APPARMOR_KILL)) #define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)
#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
...@@ -105,6 +105,7 @@ struct aa_ns_acct { ...@@ -105,6 +105,7 @@ struct aa_ns_acct {
* @acct: accounting for the namespace * @acct: accounting for the namespace
* @unconfined: special unconfined profile for the namespace * @unconfined: special unconfined profile for the namespace
* @sub_ns: list of namespaces under the current namespace. * @sub_ns: list of namespaces under the current namespace.
* @uniq_null: uniq value used for null learning profiles
* *
* An aa_namespace defines the set profiles that are searched to determine * An aa_namespace defines the set profiles that are searched to determine
* which profile to attach to a task. Profiles can not be shared between * which profile to attach to a task. Profiles can not be shared between
...@@ -127,6 +128,7 @@ struct aa_namespace { ...@@ -127,6 +128,7 @@ struct aa_namespace {
struct aa_ns_acct acct; struct aa_ns_acct acct;
struct aa_profile *unconfined; struct aa_profile *unconfined;
struct list_head sub_ns; struct list_head sub_ns;
atomic_t uniq_null;
}; };
/* struct aa_policydb - match engine for a policy /* struct aa_policydb - match engine for a policy
...@@ -148,7 +150,6 @@ struct aa_policydb { ...@@ -148,7 +150,6 @@ struct aa_policydb {
* @rename: optional profile name that this profile renamed * @rename: optional profile name that this profile renamed
* @xmatch: optional extended matching for unconfined executables names * @xmatch: optional extended matching for unconfined executables names
* @xmatch_len: xmatch prefix len, used to determine xmatch priority * @xmatch_len: xmatch prefix len, used to determine xmatch priority
* @sid: the unique security id number of this profile
* @audit: the auditing mode of the profile * @audit: the auditing mode of the profile
* @mode: the enforcement mode of the profile * @mode: the enforcement mode of the profile
* @flags: flags controlling profile behavior * @flags: flags controlling profile behavior
...@@ -184,7 +185,6 @@ struct aa_profile { ...@@ -184,7 +185,6 @@ struct aa_profile {
struct aa_dfa *xmatch; struct aa_dfa *xmatch;
int xmatch_len; int xmatch_len;
u32 sid;
enum audit_mode audit; enum audit_mode audit;
enum profile_mode mode; enum profile_mode mode;
u32 flags; u32 flags;
......
...@@ -21,6 +21,5 @@ ...@@ -21,6 +21,5 @@
int aa_getprocattr(struct aa_profile *profile, char **string); int aa_getprocattr(struct aa_profile *profile, char **string);
int aa_setprocattr_changehat(char *args, size_t size, int test); int aa_setprocattr_changehat(char *args, size_t size, int test);
int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test); int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
int aa_setprocattr_permipc(char *fqname);
#endif /* __AA_PROCATTR_H */ #endif /* __AA_PROCATTR_H */
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include <linux/types.h> #include <linux/types.h>
struct aa_profile; /* sid value that will not be allocated */
#define AA_SID_INVALID 0
#define AA_SID_ALLOC AA_SID_INVALID
u32 aa_alloc_sid(void); u32 aa_alloc_sid(void);
void aa_free_sid(u32 sid); void aa_free_sid(u32 sid);
......
...@@ -95,23 +95,18 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, ...@@ -95,23 +95,18 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
* - tracer profile has CAP_SYS_PTRACE * - tracer profile has CAP_SYS_PTRACE
*/ */
struct aa_profile *tracer_p; struct aa_profile *tracer_p = aa_get_task_profile(tracer);
/* cred released below */
const struct cred *cred = get_task_cred(tracer);
int error = 0; int error = 0;
tracer_p = aa_cred_profile(cred);
if (!unconfined(tracer_p)) { if (!unconfined(tracer_p)) {
/* lcred released below */ struct aa_profile *tracee_p = aa_get_task_profile(tracee);
const struct cred *lcred = get_task_cred(tracee);
struct aa_profile *tracee_p = aa_cred_profile(lcred);
error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
error = aa_audit_ptrace(tracer_p, tracee_p, error); error = aa_audit_ptrace(tracer_p, tracee_p, error);
put_cred(lcred); aa_put_profile(tracee_p);
} }
put_cred(cred); aa_put_profile(tracer_p);
return error; return error;
} }
...@@ -45,8 +45,10 @@ char *aa_split_fqname(char *fqname, char **ns_name) ...@@ -45,8 +45,10 @@ char *aa_split_fqname(char *fqname, char **ns_name)
*ns_name = skip_spaces(&name[1]); *ns_name = skip_spaces(&name[1]);
if (split) { if (split) {
/* overwrite ':' with \0 */ /* overwrite ':' with \0 */
*split = 0; *split++ = 0;
name = skip_spaces(split + 1); if (strncmp(split, "//", 2) == 0)
split += 2;
name = skip_spaces(split);
} else } else
/* a ns name without a following profile is allowed */ /* a ns name without a following profile is allowed */
name = NULL; name = NULL;
...@@ -75,15 +77,16 @@ void aa_info_message(const char *str) ...@@ -75,15 +77,16 @@ void aa_info_message(const char *str)
} }
/** /**
* kvmalloc - do allocation preferring kmalloc but falling back to vmalloc * __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
* @size: size of allocation * @size: how many bytes of memory are required
* @flags: the type of memory to allocate (see kmalloc).
* *
* Return: allocated buffer or NULL if failed * Return: allocated buffer or NULL if failed
* *
* It is possible that policy being loaded from the user is larger than * It is possible that policy being loaded from the user is larger than
* what can be allocated by kmalloc, in those cases fall back to vmalloc. * what can be allocated by kmalloc, in those cases fall back to vmalloc.
*/ */
void *kvmalloc(size_t size) void *__aa_kvmalloc(size_t size, gfp_t flags)
{ {
void *buffer = NULL; void *buffer = NULL;
...@@ -92,31 +95,21 @@ void *kvmalloc(size_t size) ...@@ -92,31 +95,21 @@ void *kvmalloc(size_t size)
/* do not attempt kmalloc if we need more than 16 pages at once */ /* do not attempt kmalloc if we need more than 16 pages at once */
if (size <= (16*PAGE_SIZE)) if (size <= (16*PAGE_SIZE))
buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN); buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN);
if (!buffer) { if (!buffer) {
/* see kvfree for why size must be at least work_struct size /* see kvfree for why size must be at least work_struct size
* when allocated via vmalloc * when allocated via vmalloc
*/ */
if (size < sizeof(struct work_struct)) if (size < sizeof(struct work_struct))
size = sizeof(struct work_struct); size = sizeof(struct work_struct);
if (flags & __GFP_ZERO)
buffer = vzalloc(size);
else
buffer = vmalloc(size); buffer = vmalloc(size);
} }
return buffer; return buffer;
} }
/**
* do_vfree - workqueue routine for freeing vmalloced memory
* @work: data to be freed
*
* The work_struct is overlaid to the data being freed, as at the point
* the work is scheduled the data is no longer valid, be its freeing
* needs to be delayed until safe.
*/
static void do_vfree(struct work_struct *work)
{
vfree(work);
}
/** /**
* kvfree - free an allocation do by kvmalloc * kvfree - free an allocation do by kvmalloc
* @buffer: buffer to free (MAYBE_NULL) * @buffer: buffer to free (MAYBE_NULL)
...@@ -125,13 +118,8 @@ static void do_vfree(struct work_struct *work) ...@@ -125,13 +118,8 @@ static void do_vfree(struct work_struct *work)
*/ */
void kvfree(void *buffer) void kvfree(void *buffer)
{ {
if (is_vmalloc_addr(buffer)) { if (is_vmalloc_addr(buffer))
/* Data is no longer valid so just use the allocated space vfree(buffer);
* as the work_struct else
*/
struct work_struct *work = (struct work_struct *) buffer;
INIT_WORK(work, do_vfree);
schedule_work(work);
} else
kfree(buffer); kfree(buffer);
} }
...@@ -48,8 +48,8 @@ int apparmor_initialized __initdata; ...@@ -48,8 +48,8 @@ int apparmor_initialized __initdata;
*/ */
static void apparmor_cred_free(struct cred *cred) static void apparmor_cred_free(struct cred *cred)
{ {
aa_free_task_context(cred->security); aa_free_task_context(cred_cxt(cred));
cred->security = NULL; cred_cxt(cred) = NULL;
} }
/* /*
...@@ -62,7 +62,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) ...@@ -62,7 +62,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
if (!cxt) if (!cxt)
return -ENOMEM; return -ENOMEM;
cred->security = cxt; cred_cxt(cred) = cxt;
return 0; return 0;
} }
...@@ -77,8 +77,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, ...@@ -77,8 +77,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
if (!cxt) if (!cxt)
return -ENOMEM; return -ENOMEM;
aa_dup_task_context(cxt, old->security); aa_dup_task_context(cxt, cred_cxt(old));
new->security = cxt; cred_cxt(new) = cxt;
return 0; return 0;
} }
...@@ -87,8 +87,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, ...@@ -87,8 +87,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
*/ */
static void apparmor_cred_transfer(struct cred *new, const struct cred *old) static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
{ {
const struct aa_task_cxt *old_cxt = old->security; const struct aa_task_cxt *old_cxt = cred_cxt(old);
struct aa_task_cxt *new_cxt = new->security; struct aa_task_cxt *new_cxt = cred_cxt(new);
aa_dup_task_context(new_cxt, old_cxt); aa_dup_task_context(new_cxt, old_cxt);
} }
...@@ -469,7 +469,6 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd) ...@@ -469,7 +469,6 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
static int common_mmap(int op, struct file *file, unsigned long prot, static int common_mmap(int op, struct file *file, unsigned long prot,
unsigned long flags) unsigned long flags)
{ {
struct dentry *dentry;
int mask = 0; int mask = 0;
if (!file || !file->f_security) if (!file || !file->f_security)
...@@ -486,7 +485,6 @@ static int common_mmap(int op, struct file *file, unsigned long prot, ...@@ -486,7 +485,6 @@ static int common_mmap(int op, struct file *file, unsigned long prot,
if (prot & PROT_EXEC) if (prot & PROT_EXEC)
mask |= AA_EXEC_MMAP; mask |= AA_EXEC_MMAP;
dentry = file->f_path.dentry;
return common_file_perm(op, file, mask); return common_file_perm(op, file, mask);
} }
...@@ -507,11 +505,9 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, ...@@ -507,11 +505,9 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value) char **value)
{ {
int error = -ENOENT; int error = -ENOENT;
struct aa_profile *profile;
/* released below */ /* released below */
const struct cred *cred = get_task_cred(task); const struct cred *cred = get_task_cred(task);
struct aa_task_cxt *cxt = cred->security; struct aa_task_cxt *cxt = cred_cxt(cred);
profile = aa_cred_profile(cred);
if (strcmp(name, "current") == 0) if (strcmp(name, "current") == 0)
error = aa_getprocattr(aa_newest_version(cxt->profile), error = aa_getprocattr(aa_newest_version(cxt->profile),
...@@ -533,6 +529,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, ...@@ -533,6 +529,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
static int apparmor_setprocattr(struct task_struct *task, char *name, static int apparmor_setprocattr(struct task_struct *task, char *name,
void *value, size_t size) void *value, size_t size)
{ {
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
char *command, *args = value; char *command, *args = value;
size_t arg_size; size_t arg_size;
int error; int error;
...@@ -576,30 +574,31 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, ...@@ -576,30 +574,31 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
} else if (strcmp(command, "permprofile") == 0) { } else if (strcmp(command, "permprofile") == 0) {
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
AA_DO_TEST); AA_DO_TEST);
} else if (strcmp(command, "permipc") == 0) { } else
error = aa_setprocattr_permipc(args); goto fail;
} else {
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = OP_SETPROCATTR;
aad.info = name;
aad.error = -EINVAL;
return aa_audit(AUDIT_APPARMOR_DENIED,
__aa_current_profile(), GFP_KERNEL,
&sa, NULL);
}
} else if (strcmp(name, "exec") == 0) { } else if (strcmp(name, "exec") == 0) {
if (strcmp(command, "exec") == 0)
error = aa_setprocattr_changeprofile(args, AA_ONEXEC, error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
!AA_DO_TEST); !AA_DO_TEST);
} else { else
goto fail;
} else
/* only support the "current" and "exec" process attributes */ /* only support the "current" and "exec" process attributes */
return -EINVAL; return -EINVAL;
}
if (!error) if (!error)
error = size; error = size;
return error; return error;
fail:
sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.profile = aa_current_profile();
aad.op = OP_SETPROCATTR;
aad.info = name;
aad.error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
return -EINVAL;
} }
static int apparmor_task_setrlimit(struct task_struct *task, static int apparmor_task_setrlimit(struct task_struct *task,
...@@ -886,7 +885,7 @@ static int __init set_init_cxt(void) ...@@ -886,7 +885,7 @@ static int __init set_init_cxt(void)
return -ENOMEM; return -ENOMEM;
cxt->profile = aa_get_profile(root_ns->unconfined); cxt->profile = aa_get_profile(root_ns->unconfined);
cred->security = cxt; cred_cxt(cred) = cxt;
return 0; return 0;
} }
...@@ -915,8 +914,11 @@ static int __init apparmor_init(void) ...@@ -915,8 +914,11 @@ static int __init apparmor_init(void)
error = register_security(&apparmor_ops); error = register_security(&apparmor_ops);
if (error) { if (error) {
struct cred *cred = (struct cred *)current->real_cred;
aa_free_task_context(cred_cxt(cred));
cred_cxt(cred) = NULL;
AA_ERROR("Unable to register AppArmor\n"); AA_ERROR("Unable to register AppArmor\n");
goto set_init_cxt_out; goto register_security_out;
} }
/* Report that AppArmor successfully initialized */ /* Report that AppArmor successfully initialized */
...@@ -930,9 +932,6 @@ static int __init apparmor_init(void) ...@@ -930,9 +932,6 @@ static int __init apparmor_init(void)
return error; return error;
set_init_cxt_out:
aa_free_task_context(current->real_cred->security);
register_security_out: register_security_out:
aa_free_root_ns(); aa_free_root_ns();
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file contains AppArmor dfa based regular expression matching engine * This file contains AppArmor dfa based regular expression matching engine
* *
* Copyright (C) 1998-2008 Novell/SUSE * Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd. * Copyright 2009-2012 Canonical Ltd.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "include/apparmor.h" #include "include/apparmor.h"
#include "include/match.h" #include "include/match.h"
#define base_idx(X) ((X) & 0xffffff)
/** /**
* unpack_table - unpack a dfa table (one of accept, default, base, next check) * unpack_table - unpack a dfa table (one of accept, default, base, next check)
* @blob: data to unpack (NOT NULL) * @blob: data to unpack (NOT NULL)
...@@ -30,7 +32,7 @@ ...@@ -30,7 +32,7 @@
* *
* Returns: pointer to table else NULL on failure * Returns: pointer to table else NULL on failure
* *
* NOTE: must be freed by kvfree (not kmalloc) * NOTE: must be freed by kvfree (not kfree)
*/ */
static struct table_header *unpack_table(char *blob, size_t bsize) static struct table_header *unpack_table(char *blob, size_t bsize)
{ {
...@@ -57,7 +59,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize) ...@@ -57,7 +59,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
if (bsize < tsize) if (bsize < tsize)
goto out; goto out;
table = kvmalloc(tsize); table = kvzalloc(tsize);
if (table) { if (table) {
*table = th; *table = th;
if (th.td_flags == YYTD_DATA8) if (th.td_flags == YYTD_DATA8)
...@@ -137,8 +139,7 @@ static int verify_dfa(struct aa_dfa *dfa, int flags) ...@@ -137,8 +139,7 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
for (i = 0; i < state_count; i++) { for (i = 0; i < state_count; i++) {
if (DEFAULT_TABLE(dfa)[i] >= state_count) if (DEFAULT_TABLE(dfa)[i] >= state_count)
goto out; goto out;
/* TODO: do check that DEF state recursion terminates */ if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
printk(KERN_ERR "AppArmor DFA next/check upper " printk(KERN_ERR "AppArmor DFA next/check upper "
"bounds error\n"); "bounds error\n");
goto out; goto out;
...@@ -314,7 +315,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, ...@@ -314,7 +315,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
u8 *equiv = EQUIV_TABLE(dfa); u8 *equiv = EQUIV_TABLE(dfa);
/* default is direct to next state */ /* default is direct to next state */
for (; len; len--) { for (; len; len--) {
pos = base[state] + equiv[(u8) *str++]; pos = base_idx(base[state]) + equiv[(u8) *str++];
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
...@@ -323,7 +324,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, ...@@ -323,7 +324,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
} else { } else {
/* default is direct to next state */ /* default is direct to next state */
for (; len; len--) { for (; len; len--) {
pos = base[state] + (u8) *str++; pos = base_idx(base[state]) + (u8) *str++;
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
...@@ -364,7 +365,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, ...@@ -364,7 +365,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
u8 *equiv = EQUIV_TABLE(dfa); u8 *equiv = EQUIV_TABLE(dfa);
/* default is direct to next state */ /* default is direct to next state */
while (*str) { while (*str) {
pos = base[state] + equiv[(u8) *str++]; pos = base_idx(base[state]) + equiv[(u8) *str++];
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
...@@ -373,7 +374,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, ...@@ -373,7 +374,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
} else { } else {
/* default is direct to next state */ /* default is direct to next state */
while (*str) { while (*str) {
pos = base[state] + (u8) *str++; pos = base_idx(base[state]) + (u8) *str++;
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
...@@ -409,14 +410,14 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, ...@@ -409,14 +410,14 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
u8 *equiv = EQUIV_TABLE(dfa); u8 *equiv = EQUIV_TABLE(dfa);
/* default is direct to next state */ /* default is direct to next state */
pos = base[state] + equiv[(u8) c]; pos = base_idx(base[state]) + equiv[(u8) c];
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
state = def[state]; state = def[state];
} else { } else {
/* default is direct to next state */ /* default is direct to next state */
pos = base[state] + (u8) c; pos = base_idx(base[state]) + (u8) c;
if (check[pos] == state) if (check[pos] == state)
state = next[pos]; state = next[pos];
else else
......
...@@ -174,7 +174,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, ...@@ -174,7 +174,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
if (info && error) { if (info && error) {
if (error == -ENOENT) if (error == -ENOENT)
*info = "Failed name lookup - deleted entry"; *info = "Failed name lookup - deleted entry";
else if (error == -ESTALE) else if (error == -EACCES)
*info = "Failed name lookup - disconnected path"; *info = "Failed name lookup - disconnected path";
else if (error == -ENAMETOOLONG) else if (error == -ENAMETOOLONG)
*info = "Failed name lookup - name too long"; *info = "Failed name lookup - name too long";
......
...@@ -87,7 +87,6 @@ ...@@ -87,7 +87,6 @@
#include "include/policy.h" #include "include/policy.h"
#include "include/policy_unpack.h" #include "include/policy_unpack.h"
#include "include/resource.h" #include "include/resource.h"
#include "include/sid.h"
/* root profile namespace */ /* root profile namespace */
...@@ -292,7 +291,6 @@ static struct aa_namespace *alloc_namespace(const char *prefix, ...@@ -292,7 +291,6 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
if (!ns->unconfined) if (!ns->unconfined)
goto fail_unconfined; goto fail_unconfined;
ns->unconfined->sid = aa_alloc_sid();
ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR | ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
PFLAG_IMMUTABLE; PFLAG_IMMUTABLE;
...@@ -303,6 +301,8 @@ static struct aa_namespace *alloc_namespace(const char *prefix, ...@@ -303,6 +301,8 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
*/ */
ns->unconfined->ns = aa_get_namespace(ns); ns->unconfined->ns = aa_get_namespace(ns);
atomic_set(&ns->uniq_null, 0);
return ns; return ns;
fail_unconfined: fail_unconfined:
...@@ -497,7 +497,6 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new) ...@@ -497,7 +497,6 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
/* released when @new is freed */ /* released when @new is freed */
new->parent = aa_get_profile(old->parent); new->parent = aa_get_profile(old->parent);
new->ns = aa_get_namespace(old->ns); new->ns = aa_get_namespace(old->ns);
new->sid = old->sid;
__list_add_profile(&policy->profiles, new); __list_add_profile(&policy->profiles, new);
/* inherit children */ /* inherit children */
list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) { list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
...@@ -635,83 +634,6 @@ void __init aa_free_root_ns(void) ...@@ -635,83 +634,6 @@ void __init aa_free_root_ns(void)
aa_put_namespace(ns); aa_put_namespace(ns);
} }
/**
* aa_alloc_profile - allocate, initialize and return a new profile
* @hname: name of the profile (NOT NULL)
*
* Returns: refcount profile or NULL on failure
*/
struct aa_profile *aa_alloc_profile(const char *hname)
{
struct aa_profile *profile;
/* freed by free_profile - usually through aa_put_profile */
profile = kzalloc(sizeof(*profile), GFP_KERNEL);
if (!profile)
return NULL;
if (!policy_init(&profile->base, NULL, hname)) {
kzfree(profile);
return NULL;
}
/* refcount released by caller */
return profile;
}
/**
* aa_new_null_profile - create a new null-X learning profile
* @parent: profile that caused this profile to be created (NOT NULL)
* @hat: true if the null- learning profile is a hat
*
* Create a null- complain mode profile used in learning mode. The name of
* the profile is unique and follows the format of parent//null-sid.
*
* null profiles are added to the profile list but the list does not
* hold a count on them so that they are automatically released when
* not in use.
*
* Returns: new refcounted profile else NULL on failure
*/
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
{
struct aa_profile *profile = NULL;
char *name;
u32 sid = aa_alloc_sid();
/* freed below */
name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
if (!name)
goto fail;
sprintf(name, "%s//null-%x", parent->base.hname, sid);
profile = aa_alloc_profile(name);
kfree(name);
if (!profile)
goto fail;
profile->sid = sid;
profile->mode = APPARMOR_COMPLAIN;
profile->flags = PFLAG_NULL;
if (hat)
profile->flags |= PFLAG_HAT;
/* released on free_profile */
profile->parent = aa_get_profile(parent);
profile->ns = aa_get_namespace(parent->ns);
write_lock(&profile->ns->lock);
__list_add_profile(&parent->base.profiles, profile);
write_unlock(&profile->ns->lock);
/* refcount released by caller */
return profile;
fail:
aa_free_sid(sid);
return NULL;
}
/** /**
* free_profile - free a profile * free_profile - free a profile
* @profile: the profile to free (MAYBE NULL) * @profile: the profile to free (MAYBE NULL)
...@@ -749,7 +671,6 @@ static void free_profile(struct aa_profile *profile) ...@@ -749,7 +671,6 @@ static void free_profile(struct aa_profile *profile)
aa_free_cap_rules(&profile->caps); aa_free_cap_rules(&profile->caps);
aa_free_rlimit_rules(&profile->rlimits); aa_free_rlimit_rules(&profile->rlimits);
aa_free_sid(profile->sid);
aa_put_dfa(profile->xmatch); aa_put_dfa(profile->xmatch);
aa_put_dfa(profile->policy.dfa); aa_put_dfa(profile->policy.dfa);
...@@ -790,6 +711,81 @@ void aa_free_profile_kref(struct kref *kref) ...@@ -790,6 +711,81 @@ void aa_free_profile_kref(struct kref *kref)
free_profile(p); free_profile(p);
} }
/**
* aa_alloc_profile - allocate, initialize and return a new profile
* @hname: name of the profile (NOT NULL)
*
* Returns: refcount profile or NULL on failure
*/
struct aa_profile *aa_alloc_profile(const char *hname)
{
struct aa_profile *profile;
/* freed by free_profile - usually through aa_put_profile */
profile = kzalloc(sizeof(*profile), GFP_KERNEL);
if (!profile)
return NULL;
if (!policy_init(&profile->base, NULL, hname)) {
kzfree(profile);
return NULL;
}
/* refcount released by caller */
return profile;
}
/**
* aa_new_null_profile - create a new null-X learning profile
* @parent: profile that caused this profile to be created (NOT NULL)
* @hat: true if the null- learning profile is a hat
*
* Create a null- complain mode profile used in learning mode. The name of
* the profile is unique and follows the format of parent//null-<uniq>.
*
* null profiles are added to the profile list but the list does not
* hold a count on them so that they are automatically released when
* not in use.
*
* Returns: new refcounted profile else NULL on failure
*/
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
{
struct aa_profile *profile = NULL;
char *name;
int uniq = atomic_inc_return(&parent->ns->uniq_null);
/* freed below */
name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
if (!name)
goto fail;
sprintf(name, "%s//null-%x", parent->base.hname, uniq);
profile = aa_alloc_profile(name);
kfree(name);
if (!profile)
goto fail;
profile->mode = APPARMOR_COMPLAIN;
profile->flags = PFLAG_NULL;
if (hat)
profile->flags |= PFLAG_HAT;
/* released on free_profile */
profile->parent = aa_get_profile(parent);
profile->ns = aa_get_namespace(parent->ns);
write_lock(&profile->ns->lock);
__list_add_profile(&parent->base.profiles, profile);
write_unlock(&profile->ns->lock);
/* refcount released by caller */
return profile;
fail:
return NULL;
}
/* TODO: profile accounting - setup in remove */ /* TODO: profile accounting - setup in remove */
/** /**
...@@ -972,7 +968,6 @@ static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy, ...@@ -972,7 +968,6 @@ static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
profile->parent = aa_get_profile((struct aa_profile *) policy); profile->parent = aa_get_profile((struct aa_profile *) policy);
__list_add_profile(&policy->profiles, profile); __list_add_profile(&policy->profiles, profile);
/* released on free_profile */ /* released on free_profile */
profile->sid = aa_alloc_sid();
profile->ns = aa_get_namespace(ns); profile->ns = aa_get_namespace(ns);
} }
...@@ -1110,14 +1105,8 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) ...@@ -1110,14 +1105,8 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
if (!error) { if (!error) {
if (rename_profile) if (rename_profile)
__replace_profile(rename_profile, new_profile); __replace_profile(rename_profile, new_profile);
if (old_profile) { if (old_profile)
/* when there are both rename and old profiles
* inherit old profiles sid
*/
if (rename_profile)
aa_free_sid(new_profile->sid);
__replace_profile(old_profile, new_profile); __replace_profile(old_profile, new_profile);
}
if (!(old_profile || rename_profile)) if (!(old_profile || rename_profile))
__add_new_profile(ns, policy, new_profile); __add_new_profile(ns, policy, new_profile);
} }
...@@ -1167,7 +1156,6 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) ...@@ -1167,7 +1156,6 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
if (fqname[0] == ':') { if (fqname[0] == ':') {
char *ns_name; char *ns_name;
name = aa_split_fqname(fqname, &ns_name); name = aa_split_fqname(fqname, &ns_name);
if (ns_name) {
/* released below */ /* released below */
ns = aa_find_namespace(root, ns_name); ns = aa_find_namespace(root, ns_name);
if (!ns) { if (!ns) {
...@@ -1175,7 +1163,6 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) ...@@ -1175,7 +1163,6 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
error = -ENOENT; error = -ENOENT;
goto fail; goto fail;
} }
}
} else } else
/* released below */ /* released below */
ns = aa_get_namespace(root); ns = aa_get_namespace(root);
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "include/match.h" #include "include/match.h"
#include "include/policy.h" #include "include/policy.h"
#include "include/policy_unpack.h" #include "include/policy_unpack.h"
#include "include/sid.h"
/* /*
* The AppArmor interface treats data as a type byte followed by the * The AppArmor interface treats data as a type byte followed by the
...@@ -290,6 +289,9 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name) ...@@ -290,6 +289,9 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
return res; return res;
} }
#define DFA_VALID_PERM_MASK 0xffffffff
#define DFA_VALID_PERM2_MASK 0xffffffff
/** /**
* verify_accept - verify the accept tables of a dfa * verify_accept - verify the accept tables of a dfa
* @dfa: dfa to verify accept tables of (NOT NULL) * @dfa: dfa to verify accept tables of (NOT NULL)
......
...@@ -163,9 +163,3 @@ int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test) ...@@ -163,9 +163,3 @@ int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
name = aa_split_fqname(fqname, &ns_name); name = aa_split_fqname(fqname, &ns_name);
return aa_change_profile(ns_name, name, onexec, test); return aa_change_profile(ns_name, name, onexec, test);
} }
int aa_setprocattr_permipc(char *fqname)
{
/* TODO: add ipc permission querying */
return -ENOTSUPP;
}
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/audit.h> #include <linux/audit.h>
#include "include/audit.h" #include "include/audit.h"
#include "include/context.h"
#include "include/resource.h" #include "include/resource.h"
#include "include/policy.h" #include "include/policy.h"
...@@ -90,17 +91,25 @@ int aa_map_resource(int resource) ...@@ -90,17 +91,25 @@ int aa_map_resource(int resource)
int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim) unsigned int resource, struct rlimit *new_rlim)
{ {
struct aa_profile *task_profile;
int error = 0; int error = 0;
rcu_read_lock();
task_profile = aa_get_profile(aa_cred_profile(__task_cred(task)));
rcu_read_unlock();
/* TODO: extend resource control to handle other (non current) /* TODO: extend resource control to handle other (non current)
* processes. AppArmor rules currently have the implicit assumption * profiles. AppArmor rules currently have the implicit assumption
* that the task is setting the resource of the current process * that the task is setting the resource of a task confined with
* the same profile.
*/ */
if ((task != current->group_leader) || if (profile != task_profile ||
(profile->rlimits.mask & (1 << resource) && (profile->rlimits.mask & (1 << resource) &&
new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
error = -EACCES; error = -EACCES;
aa_put_profile(task_profile);
return audit_resource(profile, resource, new_rlim->rlim_max, error); return audit_resource(profile, resource, new_rlim->rlim_max, error);
} }
......
...@@ -17,6 +17,21 @@ config INTEGRITY_SIGNATURE ...@@ -17,6 +17,21 @@ config INTEGRITY_SIGNATURE
This is useful for evm and module keyrings, when keys are This is useful for evm and module keyrings, when keys are
usually only added from initramfs. usually only added from initramfs.
config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
depends on INTEGRITY && AUDIT
default y
help
In addition to enabling integrity auditing support, this
option adds a kernel parameter 'integrity_audit', which
controls the level of integrity auditing messages.
0 - basic integrity auditing messages (default)
1 - additional integrity auditing messages
Additional informational integrity auditing messages would
be enabled by specifying 'integrity_audit=1' on the kernel
command line.
config INTEGRITY_ASYMMETRIC_KEYS config INTEGRITY_ASYMMETRIC_KEYS
boolean "Enable asymmetric keys support" boolean "Enable asymmetric keys support"
depends on INTEGRITY_SIGNATURE depends on INTEGRITY_SIGNATURE
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
obj-$(CONFIG_INTEGRITY) += integrity.o obj-$(CONFIG_INTEGRITY) += integrity.o
obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/audit.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/integrity.h> #include <linux/integrity.h>
#include <linux/evm.h> #include <linux/evm.h>
...@@ -24,6 +25,9 @@ ...@@ -24,6 +25,9 @@
int evm_initialized; int evm_initialized;
static char *integrity_status_msg[] = {
"pass", "fail", "no_label", "no_xattrs", "unknown"
};
char *evm_hmac = "hmac(sha1)"; char *evm_hmac = "hmac(sha1)";
char *evm_hash = "sha1"; char *evm_hash = "sha1";
int evm_hmac_version = CONFIG_EVM_HMAC_VERSION; int evm_hmac_version = CONFIG_EVM_HMAC_VERSION;
...@@ -262,9 +266,15 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, ...@@ -262,9 +266,15 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
if ((evm_status == INTEGRITY_PASS) || if ((evm_status == INTEGRITY_PASS) ||
(evm_status == INTEGRITY_NOXATTRS)) (evm_status == INTEGRITY_NOXATTRS))
return 0; return 0;
return -EPERM; goto out;
} }
evm_status = evm_verify_current_integrity(dentry); evm_status = evm_verify_current_integrity(dentry);
out:
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status],
-EPERM, 0);
return evm_status == INTEGRITY_PASS ? 0 : -EPERM; return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
} }
...@@ -357,6 +367,9 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -357,6 +367,9 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
if ((evm_status == INTEGRITY_PASS) || if ((evm_status == INTEGRITY_PASS) ||
(evm_status == INTEGRITY_NOXATTRS)) (evm_status == INTEGRITY_NOXATTRS))
return 0; return 0;
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status], -EPERM, 0);
return -EPERM; return -EPERM;
} }
......
...@@ -38,18 +38,6 @@ config IMA_MEASURE_PCR_IDX ...@@ -38,18 +38,6 @@ config IMA_MEASURE_PCR_IDX
that IMA uses to maintain the integrity aggregate of the that IMA uses to maintain the integrity aggregate of the
measurement list. If unsure, use the default 10. measurement list. If unsure, use the default 10.
config IMA_AUDIT
bool "Enables auditing support"
depends on IMA
depends on AUDIT
default y
help
This option adds a kernel parameter 'ima_audit', which
allows informational auditing messages to be enabled
at boot. If this option is selected, informational integrity
auditing messages can be enabled with 'ima_audit=1' on
the kernel command line.
config IMA_LSM_RULES config IMA_LSM_RULES
bool bool
depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK) depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK)
......
...@@ -7,5 +7,4 @@ obj-$(CONFIG_IMA) += ima.o ...@@ -7,5 +7,4 @@ obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_policy.o
ima-$(CONFIG_IMA_AUDIT) += ima_audit.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
...@@ -62,20 +62,6 @@ struct ima_queue_entry { ...@@ -62,20 +62,6 @@ struct ima_queue_entry {
}; };
extern struct list_head ima_measurements; /* list of all measurements */ extern struct list_head ima_measurements; /* list of all measurements */
#ifdef CONFIG_IMA_AUDIT
/* declarations */
void integrity_audit_msg(int audit_msgno, struct inode *inode,
const unsigned char *fname, const char *op,
const char *cause, int result, int info);
#else
static inline void integrity_audit_msg(int audit_msgno, struct inode *inode,
const unsigned char *fname,
const char *op, const char *cause,
int result, int info)
{
}
#endif
/* Internal IMA function definitions */ /* Internal IMA function definitions */
int ima_init(void); int ima_init(void);
void ima_cleanup(void); void ima_cleanup(void);
......
...@@ -113,5 +113,19 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig, ...@@ -113,5 +113,19 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig,
} }
#endif #endif
#ifdef CONFIG_INTEGRITY_AUDIT
/* declarations */
void integrity_audit_msg(int audit_msgno, struct inode *inode,
const unsigned char *fname, const char *op,
const char *cause, int result, int info);
#else
static inline void integrity_audit_msg(int audit_msgno, struct inode *inode,
const unsigned char *fname,
const char *op, const char *cause,
int result, int info)
{
}
#endif
/* set during initialization */ /* set during initialization */
extern int iint_initialized; extern int iint_initialized;
...@@ -13,20 +13,20 @@ ...@@ -13,20 +13,20 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/audit.h> #include <linux/audit.h>
#include "ima.h" #include "integrity.h"
static int ima_audit; static int integrity_audit_info;
/* ima_audit_setup - enable informational auditing messages */ /* ima_audit_setup - enable informational auditing messages */
static int __init ima_audit_setup(char *str) static int __init integrity_audit_setup(char *str)
{ {
unsigned long audit; unsigned long audit;
if (!strict_strtoul(str, 0, &audit)) if (!strict_strtoul(str, 0, &audit))
ima_audit = audit ? 1 : 0; integrity_audit_info = audit ? 1 : 0;
return 1; return 1;
} }
__setup("ima_audit=", ima_audit_setup); __setup("integrity_audit=", integrity_audit_setup);
void integrity_audit_msg(int audit_msgno, struct inode *inode, void integrity_audit_msg(int audit_msgno, struct inode *inode,
const unsigned char *fname, const char *op, const unsigned char *fname, const char *op,
...@@ -34,7 +34,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, ...@@ -34,7 +34,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
if (!ima_audit && audit_info == 1) /* Skip informational messages */ if (!integrity_audit_info && audit_info == 1) /* Skip info messages */
return; return;
ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
......
...@@ -28,6 +28,38 @@ ...@@ -28,6 +28,38 @@
#define SMK_LABELLEN 24 #define SMK_LABELLEN 24
#define SMK_LONGLABEL 256 #define SMK_LONGLABEL 256
/*
* This is the repository for labels seen so that it is
* not necessary to keep allocating tiny chuncks of memory
* and so that they can be shared.
*
* Labels are never modified in place. Anytime a label
* is imported (e.g. xattrset on a file) the list is checked
* for it and it is added if it doesn't exist. The address
* is passed out in either case. Entries are added, but
* never deleted.
*
* Since labels are hanging around anyway it doesn't
* hurt to maintain a secid for those awkward situations
* where kernel components that ought to use LSM independent
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
*/
struct smack_known {
struct list_head list;
char *smk_known;
u32 smk_secid;
struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
struct list_head smk_rules; /* access rules */
struct mutex smk_rules_lock; /* lock for rules */
};
/* /*
* Maximum number of bytes for the levels in a CIPSO IP option. * Maximum number of bytes for the levels in a CIPSO IP option.
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
...@@ -46,7 +78,7 @@ struct superblock_smack { ...@@ -46,7 +78,7 @@ struct superblock_smack {
}; };
struct socket_smack { struct socket_smack {
char *smk_out; /* outbound label */ struct smack_known *smk_out; /* outbound label */
char *smk_in; /* inbound label */ char *smk_in; /* inbound label */
char *smk_packet; /* TCP peer label */ char *smk_packet; /* TCP peer label */
}; };
...@@ -56,15 +88,15 @@ struct socket_smack { ...@@ -56,15 +88,15 @@ struct socket_smack {
*/ */
struct inode_smack { struct inode_smack {
char *smk_inode; /* label of the fso */ char *smk_inode; /* label of the fso */
char *smk_task; /* label of the task */ struct smack_known *smk_task; /* label of the task */
char *smk_mmap; /* label of the mmap domain */ struct smack_known *smk_mmap; /* label of the mmap domain */
struct mutex smk_lock; /* initialization lock */ struct mutex smk_lock; /* initialization lock */
int smk_flags; /* smack inode flags */ int smk_flags; /* smack inode flags */
}; };
struct task_smack { struct task_smack {
char *smk_task; /* label for access control */ struct smack_known *smk_task; /* label for access control */
char *smk_forked; /* label when forked */ struct smack_known *smk_forked; /* label when forked */
struct list_head smk_rules; /* per task access rules */ struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */ struct mutex smk_rules_lock; /* lock for the rules */
}; };
...@@ -78,7 +110,7 @@ struct task_smack { ...@@ -78,7 +110,7 @@ struct task_smack {
*/ */
struct smack_rule { struct smack_rule {
struct list_head list; struct list_head list;
char *smk_subject; struct smack_known *smk_subject;
char *smk_object; char *smk_object;
int smk_access; int smk_access;
}; };
...@@ -94,35 +126,14 @@ struct smk_netlbladdr { ...@@ -94,35 +126,14 @@ struct smk_netlbladdr {
}; };
/* /*
* This is the repository for labels seen so that it is * An entry in the table identifying ports.
* not necessary to keep allocating tiny chuncks of memory
* and so that they can be shared.
*
* Labels are never modified in place. Anytime a label
* is imported (e.g. xattrset on a file) the list is checked
* for it and it is added if it doesn't exist. The address
* is passed out in either case. Entries are added, but
* never deleted.
*
* Since labels are hanging around anyway it doesn't
* hurt to maintain a secid for those awkward situations
* where kernel components that ought to use LSM independent
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
*/ */
struct smack_known { struct smk_port_label {
struct list_head list; struct list_head list;
char *smk_known; struct sock *smk_sock; /* socket initialized on */
u32 smk_secid; unsigned short smk_port; /* the port number */
struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ char *smk_in; /* incoming label */
struct list_head smk_rules; /* access rules */ struct smack_known *smk_out; /* outgoing label */
struct mutex smk_rules_lock; /* lock for rules */
}; };
/* /*
...@@ -132,6 +143,7 @@ struct smack_known { ...@@ -132,6 +143,7 @@ struct smack_known {
#define SMK_FSFLOOR "smackfsfloor=" #define SMK_FSFLOOR "smackfsfloor="
#define SMK_FSHAT "smackfshat=" #define SMK_FSHAT "smackfshat="
#define SMK_FSROOT "smackfsroot=" #define SMK_FSROOT "smackfsroot="
#define SMK_FSTRANS "smackfstransmute="
#define SMACK_CIPSO_OPTION "-CIPSO" #define SMACK_CIPSO_OPTION "-CIPSO"
...@@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *); ...@@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *);
* These functions are in smack_access.c * These functions are in smack_access.c
*/ */
int smk_access_entry(char *, char *, struct list_head *); int smk_access_entry(char *, char *, struct list_head *);
int smk_access(char *, char *, int, struct smk_audit_info *); int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
int smk_curacc(char *, u32, struct smk_audit_info *); int smk_curacc(char *, u32, struct smk_audit_info *);
char *smack_from_secid(const u32); struct smack_known *smack_from_secid(const u32);
char *smk_parse_smack(const char *string, int len); char *smk_parse_smack(const char *string, int len);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
char *smk_import(const char *, int); char *smk_import(const char *, int);
...@@ -218,7 +230,7 @@ u32 smack_to_secid(const char *); ...@@ -218,7 +230,7 @@ u32 smack_to_secid(const char *);
*/ */
extern int smack_cipso_direct; extern int smack_cipso_direct;
extern int smack_cipso_mapped; extern int smack_cipso_mapped;
extern char *smack_net_ambient; extern struct smack_known *smack_net_ambient;
extern char *smack_onlycap; extern char *smack_onlycap;
extern const char *smack_cipso_option; extern const char *smack_cipso_option;
...@@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp) ...@@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp)
} }
/* /*
* Present a pointer to the smack label in an task blob. * Present a pointer to the smack label entry in an task blob.
*/ */
static inline char *smk_of_task(const struct task_smack *tsp) static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
{ {
return tsp->smk_task; return tsp->smk_task;
} }
/* /*
* Present a pointer to the forked smack label in an task blob. * Present a pointer to the forked smack label entry in an task blob.
*/ */
static inline char *smk_of_forked(const struct task_smack *tsp) static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
{ {
return tsp->smk_forked; return tsp->smk_forked;
} }
...@@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp) ...@@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp)
/* /*
* Present a pointer to the smack label in the current task blob. * Present a pointer to the smack label in the current task blob.
*/ */
static inline char *smk_of_current(void) static inline struct smack_known *smk_of_current(void)
{ {
return smk_of_task(current_security()); return smk_of_task(current_security());
} }
...@@ -283,9 +295,11 @@ static inline char *smk_of_current(void) ...@@ -283,9 +295,11 @@ static inline char *smk_of_current(void)
*/ */
static inline int smack_privileged(int cap) static inline int smack_privileged(int cap)
{ {
struct smack_known *skp = smk_of_current();
if (!capable(cap)) if (!capable(cap))
return 0; return 0;
if (smack_onlycap == NULL || smack_onlycap == smk_of_current()) if (smack_onlycap == NULL || smack_onlycap == skp->smk_known)
return 1; return 1;
return 0; return 0;
} }
......
...@@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label, ...@@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label,
list_for_each_entry_rcu(srp, rule_list, list) { list_for_each_entry_rcu(srp, rule_list, list) {
if (srp->smk_object == object_label && if (srp->smk_object == object_label &&
srp->smk_subject == subject_label) { srp->smk_subject->smk_known == subject_label) {
may = srp->smk_access; may = srp->smk_access;
break; break;
} }
...@@ -104,7 +104,7 @@ int smk_access_entry(char *subject_label, char *object_label, ...@@ -104,7 +104,7 @@ int smk_access_entry(char *subject_label, char *object_label,
/** /**
* smk_access - determine if a subject has a specific access to an object * smk_access - determine if a subject has a specific access to an object
* @subject_label: a pointer to the subject's Smack label * @subject_known: a pointer to the subject's Smack label entry
* @object_label: a pointer to the object's Smack label * @object_label: a pointer to the object's Smack label
* @request: the access requested, in "MAY" format * @request: the access requested, in "MAY" format
* @a : a pointer to the audit data * @a : a pointer to the audit data
...@@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label, ...@@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label,
* *
* Smack labels are shared on smack_list * Smack labels are shared on smack_list
*/ */
int smk_access(char *subject_label, char *object_label, int request, int smk_access(struct smack_known *subject_known, char *object_label,
struct smk_audit_info *a) int request, struct smk_audit_info *a)
{ {
struct smack_known *skp;
int may = MAY_NOT; int may = MAY_NOT;
int rc = 0; int rc = 0;
...@@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* *
* A star subject can't access any object. * A star subject can't access any object.
*/ */
if (subject_label == smack_known_star.smk_known) { if (subject_known == &smack_known_star) {
rc = -EACCES; rc = -EACCES;
goto out_audit; goto out_audit;
} }
...@@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An internet subject can access any object. * An internet subject can access any object.
*/ */
if (object_label == smack_known_web.smk_known || if (object_label == smack_known_web.smk_known ||
subject_label == smack_known_web.smk_known) subject_known == &smack_known_web)
goto out_audit; goto out_audit;
/* /*
* A star object can be accessed by any subject. * A star object can be accessed by any subject.
...@@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An object can be accessed in any way by a subject * An object can be accessed in any way by a subject
* with the same label. * with the same label.
*/ */
if (subject_label == object_label) if (subject_known->smk_known == object_label)
goto out_audit; goto out_audit;
/* /*
* A hat subject can read any object. * A hat subject can read any object.
...@@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request,
if ((request & MAY_ANYREAD) == request) { if ((request & MAY_ANYREAD) == request) {
if (object_label == smack_known_floor.smk_known) if (object_label == smack_known_floor.smk_known)
goto out_audit; goto out_audit;
if (subject_label == smack_known_hat.smk_known) if (subject_known == &smack_known_hat)
goto out_audit; goto out_audit;
} }
/* /*
...@@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request,
* good. A negative response from smk_access_entry() * good. A negative response from smk_access_entry()
* indicates there is no entry for this pair. * indicates there is no entry for this pair.
*/ */
skp = smk_find_entry(subject_label);
rcu_read_lock(); rcu_read_lock();
may = smk_access_entry(subject_label, object_label, &skp->smk_rules); may = smk_access_entry(subject_known->smk_known, object_label,
&subject_known->smk_rules);
rcu_read_unlock(); rcu_read_unlock();
if (may > 0 && (request & may) == request) if (may > 0 && (request & may) == request)
...@@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request,
out_audit: out_audit:
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
if (a) if (a)
smack_log(subject_label, object_label, request, rc, a); smack_log(subject_known->smk_known, object_label, request,
rc, a);
#endif #endif
return rc; return rc;
} }
...@@ -198,20 +198,21 @@ int smk_access(char *subject_label, char *object_label, int request, ...@@ -198,20 +198,21 @@ int smk_access(char *subject_label, char *object_label, int request,
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
{ {
struct task_smack *tsp = current_security(); struct task_smack *tsp = current_security();
char *sp = smk_of_task(tsp); struct smack_known *skp = smk_of_task(tsp);
int may; int may;
int rc; int rc;
/* /*
* Check the global rule list * Check the global rule list
*/ */
rc = smk_access(sp, obj_label, mode, NULL); rc = smk_access(skp, obj_label, mode, NULL);
if (rc == 0) { if (rc == 0) {
/* /*
* If there is an entry in the task's rule list * If there is an entry in the task's rule list
* it can further restrict access. * it can further restrict access.
*/ */
may = smk_access_entry(sp, obj_label, &tsp->smk_rules); may = smk_access_entry(skp->smk_known, obj_label,
&tsp->smk_rules);
if (may < 0) if (may < 0)
goto out_audit; goto out_audit;
if ((mode & may) == mode) if ((mode & may) == mode)
...@@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) ...@@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
out_audit: out_audit:
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
if (a) if (a)
smack_log(sp, obj_label, mode, rc, a); smack_log(skp->smk_known, obj_label, mode, rc, a);
#endif #endif
return rc; return rc;
} }
...@@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, ...@@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
sap->flags |= NETLBL_SECATTR_MLS_CAT; sap->flags |= NETLBL_SECATTR_MLS_CAT;
sap->attr.mls.lvl = level; sap->attr.mls.lvl = level;
sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (!sap->attr.mls.cat)
return -ENOMEM;
sap->attr.mls.cat->startbit = 0; sap->attr.mls.cat->startbit = 0;
for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
...@@ -513,10 +516,10 @@ char *smk_import(const char *string, int len) ...@@ -513,10 +516,10 @@ char *smk_import(const char *string, int len)
* smack_from_secid - find the Smack label associated with a secid * smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label * @secid: an integer that might be associated with a Smack label
* *
* Returns a pointer to the appropriate Smack label if there is one, * Returns a pointer to the appropriate Smack label entry if there is one,
* otherwise a pointer to the invalid Smack label. * otherwise a pointer to the invalid Smack label.
*/ */
char *smack_from_secid(const u32 secid) struct smack_known *smack_from_secid(const u32 secid)
{ {
struct smack_known *skp; struct smack_known *skp;
...@@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid) ...@@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid)
list_for_each_entry_rcu(skp, &smack_known_list, list) { list_for_each_entry_rcu(skp, &smack_known_list, list) {
if (skp->smk_secid == secid) { if (skp->smk_secid == secid) {
rcu_read_unlock(); rcu_read_unlock();
return skp->smk_known; return skp;
} }
} }
...@@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid) ...@@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid)
* of a secid that is not on the list. * of a secid that is not on the list.
*/ */
rcu_read_unlock(); rcu_read_unlock();
return smack_known_invalid.smk_known; return &smack_known_invalid;
} }
/** /**
......
...@@ -27,10 +27,13 @@ ...@@ -27,10 +27,13 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/dccp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/pipe_fs_i.h> #include <linux/pipe_fs_i.h>
#include <net/cipso_ipv4.h> #include <net/cipso_ipv4.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/dcache.h> #include <linux/dcache.h>
...@@ -45,6 +48,12 @@ ...@@ -45,6 +48,12 @@
#define TRANS_TRUE "TRUE" #define TRANS_TRUE "TRUE"
#define TRANS_TRUE_SIZE 4 #define TRANS_TRUE_SIZE 4
#define SMK_CONNECTING 0
#define SMK_RECEIVING 1
#define SMK_SENDING 2
LIST_HEAD(smk_ipv6_port_list);
/** /**
* smk_fetch - Fetch the smack label from a file. * smk_fetch - Fetch the smack label from a file.
* @ip: a pointer to the inode * @ip: a pointer to the inode
...@@ -53,11 +62,12 @@ ...@@ -53,11 +62,12 @@
* Returns a pointer to the master list entry for the Smack label * Returns a pointer to the master list entry for the Smack label
* or NULL if there was no label to fetch. * or NULL if there was no label to fetch.
*/ */
static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct dentry *dp)
{ {
int rc; int rc;
char *buffer; char *buffer;
char *result = NULL; struct smack_known *skp = NULL;
if (ip->i_op->getxattr == NULL) if (ip->i_op->getxattr == NULL)
return NULL; return NULL;
...@@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) ...@@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
if (rc > 0) if (rc > 0)
result = smk_import(buffer, rc); skp = smk_import_entry(buffer, rc);
kfree(buffer); kfree(buffer);
return result; return skp;
} }
/** /**
...@@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack) ...@@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack)
* *
* Returns the new blob or NULL if there's no memory available * Returns the new blob or NULL if there's no memory available
*/ */
static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp) static struct task_smack *new_task_smack(struct smack_known *task,
struct smack_known *forked, gfp_t gfp)
{ {
struct task_smack *tsp; struct task_smack *tsp;
...@@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) ...@@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{ {
int rc; int rc;
struct smk_audit_info ad; struct smk_audit_info ad;
char *tsp; struct smack_known *skp;
rc = cap_ptrace_access_check(ctp, mode); rc = cap_ptrace_access_check(ctp, mode);
if (rc != 0) if (rc != 0)
return rc; return rc;
tsp = smk_of_task(task_security(ctp)); skp = smk_of_task(task_security(ctp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ctp); smk_ad_setfield_u_tsk(&ad, ctp);
rc = smk_curacc(tsp, MAY_READWRITE, &ad); rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
return rc; return rc;
} }
...@@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp) ...@@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
{ {
int rc; int rc;
struct smk_audit_info ad; struct smk_audit_info ad;
char *tsp; struct smack_known *skp;
rc = cap_ptrace_traceme(ptp); rc = cap_ptrace_traceme(ptp);
if (rc != 0) if (rc != 0)
return rc; return rc;
tsp = smk_of_task(task_security(ptp)); skp = smk_of_task(task_security(ptp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ptp); smk_ad_setfield_u_tsk(&ad, ptp);
rc = smk_curacc(tsp, MAY_READWRITE, &ad); rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
return rc; return rc;
} }
...@@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) ...@@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
static int smack_syslog(int typefrom_file) static int smack_syslog(int typefrom_file)
{ {
int rc = 0; int rc = 0;
char *sp = smk_of_current(); struct smack_known *skp = smk_of_current();
if (smack_privileged(CAP_MAC_OVERRIDE)) if (smack_privileged(CAP_MAC_OVERRIDE))
return 0; return 0;
if (sp != smack_known_floor.smk_known) if (skp != &smack_known_floor)
rc = -EACCES; rc = -EACCES;
return rc; return rc;
...@@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb) ...@@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb)
sbsp->smk_default = smack_known_floor.smk_known; sbsp->smk_default = smack_known_floor.smk_known;
sbsp->smk_floor = smack_known_floor.smk_known; sbsp->smk_floor = smack_known_floor.smk_known;
sbsp->smk_hat = smack_known_hat.smk_known; sbsp->smk_hat = smack_known_hat.smk_known;
sbsp->smk_initialized = 0; /*
* smk_initialized will be zero from kzalloc.
*/
sb->s_security = sbsp; sb->s_security = sbsp;
return 0; return 0;
...@@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts) ...@@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
dp = smackopts; dp = smackopts;
else if (strstr(cp, SMK_FSROOT) == cp) else if (strstr(cp, SMK_FSROOT) == cp)
dp = smackopts; dp = smackopts;
else if (strstr(cp, SMK_FSTRANS) == cp)
dp = smackopts;
else else
dp = otheropts; dp = otheropts;
...@@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) ...@@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
char *op; char *op;
char *commap; char *commap;
char *nsp; char *nsp;
int transmute = 0;
if (sp->smk_initialized != 0) if (sp->smk_initialized)
return 0; return 0;
sp->smk_initialized = 1; sp->smk_initialized = 1;
...@@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) ...@@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
nsp = smk_import(op, 0); nsp = smk_import(op, 0);
if (nsp != NULL) if (nsp != NULL)
sp->smk_root = nsp; sp->smk_root = nsp;
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
nsp = smk_import(op, 0);
if (nsp != NULL) {
sp->smk_root = nsp;
transmute = 1;
}
} }
} }
...@@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) ...@@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
* Initialize the root inode. * Initialize the root inode.
*/ */
isp = inode->i_security; isp = inode->i_security;
if (isp == NULL) if (inode->i_security == NULL) {
inode->i_security = new_inode_smack(sp->smk_root); inode->i_security = new_inode_smack(sp->smk_root);
else isp = inode->i_security;
} else
isp->smk_inode = sp->smk_root; isp->smk_inode = sp->smk_root;
if (transmute)
isp->smk_flags |= SMK_INODE_TRANSMUTE;
return 0; return 0;
} }
...@@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm) ...@@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm)
*/ */
static int smack_inode_alloc_security(struct inode *inode) static int smack_inode_alloc_security(struct inode *inode)
{ {
inode->i_security = new_inode_smack(smk_of_current()); struct smack_known *skp = smk_of_current();
inode->i_security = new_inode_smack(skp->smk_known);
if (inode->i_security == NULL) if (inode->i_security == NULL)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
...@@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name, const struct qstr *qstr, char **name,
void **value, size_t *len) void **value, size_t *len)
{ {
struct smack_known *skp;
struct inode_smack *issp = inode->i_security; struct inode_smack *issp = inode->i_security;
char *csp = smk_of_current(); struct smack_known *skp = smk_of_current();
char *isp = smk_of_inode(inode); char *isp = smk_of_inode(inode);
char *dsp = smk_of_inode(dir); char *dsp = smk_of_inode(dir);
int may; int may;
...@@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
} }
if (value) { if (value) {
skp = smk_find_entry(csp);
rcu_read_lock(); rcu_read_lock();
may = smk_access_entry(csp, dsp, &skp->smk_rules); may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
rcu_read_unlock(); rcu_read_unlock();
/* /*
...@@ -862,29 +888,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -862,29 +888,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
char *nsp; struct smack_known *skp;
struct inode_smack *isp = dentry->d_inode->i_security; struct inode_smack *isp = dentry->d_inode->i_security;
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
return;
}
skp = smk_import_entry(value, size);
if (strcmp(name, XATTR_NAME_SMACK) == 0) { if (strcmp(name, XATTR_NAME_SMACK) == 0) {
nsp = smk_import(value, size); if (skp != NULL)
if (nsp != NULL) isp->smk_inode = skp->smk_known;
isp->smk_inode = nsp;
else else
isp->smk_inode = smack_known_invalid.smk_known; isp->smk_inode = smack_known_invalid.smk_known;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
nsp = smk_import(value, size); if (skp != NULL)
if (nsp != NULL) isp->smk_task = skp;
isp->smk_task = nsp;
else else
isp->smk_task = smack_known_invalid.smk_known; isp->smk_task = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
nsp = smk_import(value, size); if (skp != NULL)
if (nsp != NULL) isp->smk_mmap = skp;
isp->smk_mmap = nsp;
else else
isp->smk_mmap = smack_known_invalid.smk_known; isp->smk_mmap = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) }
isp->smk_flags |= SMK_INODE_TRANSMUTE;
return; return;
} }
...@@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode, ...@@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
if (strcmp(name, XATTR_SMACK_IPIN) == 0) if (strcmp(name, XATTR_SMACK_IPIN) == 0)
isp = ssp->smk_in; isp = ssp->smk_in;
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
isp = ssp->smk_out; isp = ssp->smk_out->smk_known;
else else
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask) ...@@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask)
*/ */
static int smack_file_alloc_security(struct file *file) static int smack_file_alloc_security(struct file *file)
{ {
file->f_security = smk_of_current(); struct smack_known *skp = smk_of_current();
file->f_security = skp->smk_known;
return 0; return 0;
} }
...@@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file, ...@@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file,
unsigned long flags) unsigned long flags)
{ {
struct smack_known *skp; struct smack_known *skp;
struct smack_known *mkp;
struct smack_rule *srp; struct smack_rule *srp;
struct task_smack *tsp; struct task_smack *tsp;
char *sp;
char *msmack;
char *osmack; char *osmack;
struct inode_smack *isp; struct inode_smack *isp;
int may; int may;
...@@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file, ...@@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file,
isp = file_inode(file)->i_security; isp = file_inode(file)->i_security;
if (isp->smk_mmap == NULL) if (isp->smk_mmap == NULL)
return 0; return 0;
msmack = isp->smk_mmap; mkp = isp->smk_mmap;
tsp = current_security(); tsp = current_security();
sp = smk_of_current(); skp = smk_of_current();
skp = smk_find_entry(sp);
rc = 0; rc = 0;
rcu_read_lock(); rcu_read_lock();
...@@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file, ...@@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file,
/* /*
* Matching labels always allows access. * Matching labels always allows access.
*/ */
if (msmack == osmack) if (mkp->smk_known == osmack)
continue; continue;
/* /*
* If there is a matching local rule take * If there is a matching local rule take
* that into account as well. * that into account as well.
*/ */
may = smk_access_entry(srp->smk_subject, osmack, may = smk_access_entry(srp->smk_subject->smk_known, osmack,
&tsp->smk_rules); &tsp->smk_rules);
if (may == -ENOENT) if (may == -ENOENT)
may = srp->smk_access; may = srp->smk_access;
...@@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file, ...@@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file,
* If there isn't one a SMACK64MMAP subject * If there isn't one a SMACK64MMAP subject
* can't have as much access as current. * can't have as much access as current.
*/ */
skp = smk_find_entry(msmack); mmay = smk_access_entry(mkp->smk_known, osmack,
mmay = smk_access_entry(msmack, osmack, &skp->smk_rules); &mkp->smk_rules);
if (mmay == -ENOENT) { if (mmay == -ENOENT) {
rc = -EACCES; rc = -EACCES;
break; break;
...@@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file, ...@@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file,
* If there is a local entry it modifies the * If there is a local entry it modifies the
* potential access, too. * potential access, too.
*/ */
tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules); tmay = smk_access_entry(mkp->smk_known, osmack,
&tsp->smk_rules);
if (tmay != -ENOENT) if (tmay != -ENOENT)
mmay &= tmay; mmay &= tmay;
...@@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file, ...@@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file,
*/ */
static int smack_file_set_fowner(struct file *file) static int smack_file_set_fowner(struct file *file)
{ {
file->f_security = smk_of_current(); struct smack_known *skp = smk_of_current();
file->f_security = skp->smk_known;
return 0; return 0;
} }
...@@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file) ...@@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file)
static int smack_file_send_sigiotask(struct task_struct *tsk, static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum) struct fown_struct *fown, int signum)
{ {
struct smack_known *skp;
struct smack_known *tkp = smk_of_task(tsk->cred->security);
struct file *file; struct file *file;
int rc; int rc;
char *tsp = smk_of_task(tsk->cred->security);
struct smk_audit_info ad; struct smk_audit_info ad;
/* /*
...@@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, ...@@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
file = container_of(fown, struct file, f_owner); file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */ /* we don't log here as rc can be overriden */
rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); skp = smk_find_entry(file->f_security);
rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
rc = 0; rc = 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, tsk); smk_ad_setfield_u_tsk(&ad, tsk);
smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
return rc; return rc;
} }
...@@ -1469,12 +1502,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) ...@@ -1469,12 +1502,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
static int smack_kernel_act_as(struct cred *new, u32 secid) static int smack_kernel_act_as(struct cred *new, u32 secid)
{ {
struct task_smack *new_tsp = new->security; struct task_smack *new_tsp = new->security;
char *smack = smack_from_secid(secid); struct smack_known *skp = smack_from_secid(secid);
if (smack == NULL) if (skp == NULL)
return -EINVAL; return -EINVAL;
new_tsp->smk_task = smack; new_tsp->smk_task = skp;
return 0; return 0;
} }
...@@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new, ...@@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new,
struct inode_smack *isp = inode->i_security; struct inode_smack *isp = inode->i_security;
struct task_smack *tsp = new->security; struct task_smack *tsp = new->security;
tsp->smk_forked = isp->smk_inode; tsp->smk_forked = smk_find_entry(isp->smk_inode);
tsp->smk_task = isp->smk_inode; tsp->smk_task = tsp->smk_forked;
return 0; return 0;
} }
...@@ -1509,10 +1542,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access, ...@@ -1509,10 +1542,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const char *caller) const char *caller)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
struct smack_known *skp = smk_of_task(task_security(p));
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p); smk_ad_setfield_u_tsk(&ad, p);
return smk_curacc(smk_of_task(task_security(p)), access, &ad); return smk_curacc(skp->smk_known, access, &ad);
} }
/** /**
...@@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p) ...@@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p)
*/ */
static void smack_task_getsecid(struct task_struct *p, u32 *secid) static void smack_task_getsecid(struct task_struct *p, u32 *secid)
{ {
*secid = smack_to_secid(smk_of_task(task_security(p))); struct smack_known *skp = smk_of_task(task_security(p));
*secid = skp->smk_secid;
} }
/** /**
...@@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, ...@@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid) int sig, u32 secid)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
struct smack_known *skp;
struct smack_known *tkp = smk_of_task(task_security(p));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p); smk_ad_setfield_u_tsk(&ad, p);
...@@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, ...@@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver. * can write the receiver.
*/ */
if (secid == 0) if (secid == 0)
return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE, return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
&ad);
/* /*
* If the secid isn't 0 we're dealing with some USB IO * If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing * specific behavior. This is not clean. For one thing
* we can't take privilege into account. * we can't take privilege into account.
*/ */
return smk_access(smack_from_secid(secid), skp = smack_from_secid(secid);
smk_of_task(task_security(p)), MAY_WRITE, &ad); return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
} }
/** /**
...@@ -1710,7 +1747,9 @@ static int smack_task_wait(struct task_struct *p) ...@@ -1710,7 +1747,9 @@ static int smack_task_wait(struct task_struct *p)
static void smack_task_to_inode(struct task_struct *p, struct inode *inode) static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{ {
struct inode_smack *isp = inode->i_security; struct inode_smack *isp = inode->i_security;
isp->smk_inode = smk_of_task(task_security(p)); struct smack_known *skp = smk_of_task(task_security(p));
isp->smk_inode = skp->smk_known;
} }
/* /*
...@@ -1729,15 +1768,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) ...@@ -1729,15 +1768,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
*/ */
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{ {
char *csp = smk_of_current(); struct smack_known *skp = smk_of_current();
struct socket_smack *ssp; struct socket_smack *ssp;
ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
if (ssp == NULL) if (ssp == NULL)
return -ENOMEM; return -ENOMEM;
ssp->smk_in = csp; ssp->smk_in = skp->smk_known;
ssp->smk_out = csp; ssp->smk_out = skp;
ssp->smk_packet = NULL; ssp->smk_packet = NULL;
sk->sk_security = ssp; sk->sk_security = ssp;
...@@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled) ...@@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
labeled == SMACK_UNLABELED_SOCKET) labeled == SMACK_UNLABELED_SOCKET)
netlbl_sock_delattr(sk); netlbl_sock_delattr(sk);
else { else {
skp = smk_find_entry(ssp->smk_out); skp = ssp->smk_out;
rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);
} }
...@@ -1847,6 +1886,7 @@ static int smack_netlabel(struct sock *sk, int labeled) ...@@ -1847,6 +1886,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
*/ */
static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
{ {
struct smack_known *skp;
int rc; int rc;
int sk_lbl; int sk_lbl;
char *hostsp; char *hostsp;
...@@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ...@@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
#endif #endif
sk_lbl = SMACK_UNLABELED_SOCKET; sk_lbl = SMACK_UNLABELED_SOCKET;
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); skp = ssp->smk_out;
rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
} else { } else {
sk_lbl = SMACK_CIPSO_SOCKET; sk_lbl = SMACK_CIPSO_SOCKET;
rc = 0; rc = 0;
...@@ -1877,6 +1918,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ...@@ -1877,6 +1918,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
return smack_netlabel(sk, sk_lbl); return smack_netlabel(sk, sk_lbl);
} }
/**
* smk_ipv6_port_label - Smack port access table management
* @sock: socket
* @address: address
*
* Create or update the port list entry
*/
static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
{
struct sock *sk = sock->sk;
struct sockaddr_in6 *addr6;
struct socket_smack *ssp = sock->sk->sk_security;
struct smk_port_label *spp;
unsigned short port = 0;
if (address == NULL) {
/*
* This operation is changing the Smack information
* on the bound socket. Take the changes to the port
* as well.
*/
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
if (sk != spp->smk_sock)
continue;
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;
return;
}
/*
* A NULL address is only used for updating existing
* bound entries. If there isn't one, it's OK.
*/
return;
}
addr6 = (struct sockaddr_in6 *)address;
port = ntohs(addr6->sin6_port);
/*
* This is a special case that is safely ignored.
*/
if (port == 0)
return;
/*
* Look for an existing port list entry.
* This is an indication that a port is getting reused.
*/
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
if (spp->smk_port != port)
continue;
spp->smk_port = port;
spp->smk_sock = sk;
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;
return;
}
/*
* A new port entry is required.
*/
spp = kzalloc(sizeof(*spp), GFP_KERNEL);
if (spp == NULL)
return;
spp->smk_port = port;
spp->smk_sock = sk;
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;
list_add(&spp->list, &smk_ipv6_port_list);
return;
}
/**
* smk_ipv6_port_check - check Smack port access
* @sock: socket
* @address: address
*
* Create or update the port list entry
*/
static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
int act)
{
__be16 *bep;
__be32 *be32p;
struct sockaddr_in6 *addr6;
struct smk_port_label *spp;
struct socket_smack *ssp = sk->sk_security;
struct smack_known *skp;
unsigned short port = 0;
char *object;
struct smk_audit_info ad;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
if (act == SMK_RECEIVING) {
skp = smack_net_ambient;
object = ssp->smk_in;
} else {
skp = ssp->smk_out;
object = smack_net_ambient->smk_known;
}
/*
* Get the IP address and port from the address.
*/
addr6 = (struct sockaddr_in6 *)address;
port = ntohs(addr6->sin6_port);
bep = (__be16 *)(&addr6->sin6_addr);
be32p = (__be32 *)(&addr6->sin6_addr);
/*
* It's remote, so port lookup does no good.
*/
if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1)
goto auditout;
/*
* It's local so the send check has to have passed.
*/
if (act == SMK_RECEIVING) {
skp = &smack_known_web;
goto auditout;
}
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
if (spp->smk_port != port)
continue;
object = spp->smk_in;
if (act == SMK_CONNECTING)
ssp->smk_packet = spp->smk_out->smk_known;
break;
}
auditout:
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = sk->sk_family;
ad.a.u.net->dport = port;
if (act == SMK_RECEIVING)
ad.a.u.net->v6info.saddr = addr6->sin6_addr;
else
ad.a.u.net->v6info.daddr = addr6->sin6_addr;
#endif
return smk_access(skp, object, MAY_WRITE, &ad);
}
/** /**
* smack_inode_setsecurity - set smack xattrs * smack_inode_setsecurity - set smack xattrs
* @inode: the object * @inode: the object
...@@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ...@@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
static int smack_inode_setsecurity(struct inode *inode, const char *name, static int smack_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
char *sp; struct smack_known *skp;
struct inode_smack *nsp = inode->i_security; struct inode_smack *nsp = inode->i_security;
struct socket_smack *ssp; struct socket_smack *ssp;
struct socket *sock; struct socket *sock;
...@@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ...@@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
if (value == NULL || size > SMK_LONGLABEL || size == 0) if (value == NULL || size > SMK_LONGLABEL || size == 0)
return -EACCES; return -EACCES;
sp = smk_import(value, size); skp = smk_import_entry(value, size);
if (sp == NULL) if (skp == NULL)
return -EINVAL; return -EINVAL;
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
nsp->smk_inode = sp; nsp->smk_inode = skp->smk_known;
nsp->smk_flags |= SMK_INODE_INSTANT; nsp->smk_flags |= SMK_INODE_INSTANT;
return 0; return 0;
} }
...@@ -1923,10 +2113,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ...@@ -1923,10 +2113,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
ssp = sock->sk->sk_security; ssp = sock->sk->sk_security;
if (strcmp(name, XATTR_SMACK_IPIN) == 0) if (strcmp(name, XATTR_SMACK_IPIN) == 0)
ssp->smk_in = sp; ssp->smk_in = skp->smk_known;
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
ssp->smk_out = sp; ssp->smk_out = skp;
if (sock->sk->sk_family != PF_UNIX) { if (sock->sk->sk_family == PF_INET) {
rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
if (rc != 0) if (rc != 0)
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1936,6 +2126,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ...@@ -1936,6 +2126,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
} else } else
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (sock->sk->sk_family == PF_INET6)
smk_ipv6_port_label(sock, NULL);
return 0; return 0;
} }
...@@ -1962,6 +2155,25 @@ static int smack_socket_post_create(struct socket *sock, int family, ...@@ -1962,6 +2155,25 @@ static int smack_socket_post_create(struct socket *sock, int family,
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
} }
/**
* smack_socket_bind - record port binding information.
* @sock: the socket
* @address: the port address
* @addrlen: size of the address
*
* Records the label bound to a port.
*
* Returns 0
*/
static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
int addrlen)
{
if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
smk_ipv6_port_label(sock, address);
return 0;
}
/** /**
* smack_socket_connect - connect access check * smack_socket_connect - connect access check
* @sock: the socket * @sock: the socket
...@@ -1975,12 +2187,24 @@ static int smack_socket_post_create(struct socket *sock, int family, ...@@ -1975,12 +2187,24 @@ static int smack_socket_post_create(struct socket *sock, int family,
static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
int addrlen) int addrlen)
{ {
if (sock->sk == NULL || sock->sk->sk_family != PF_INET) int rc = 0;
if (sock->sk == NULL)
return 0; return 0;
switch (sock->sk->sk_family) {
case PF_INET:
if (addrlen < sizeof(struct sockaddr_in)) if (addrlen < sizeof(struct sockaddr_in))
return -EINVAL; return -EINVAL;
rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); break;
case PF_INET6:
if (addrlen < sizeof(struct sockaddr_in6))
return -EINVAL;
rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING);
break;
}
return rc;
} }
/** /**
...@@ -2011,7 +2235,9 @@ static int smack_flags_to_may(int flags) ...@@ -2011,7 +2235,9 @@ static int smack_flags_to_may(int flags)
*/ */
static int smack_msg_msg_alloc_security(struct msg_msg *msg) static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{ {
msg->security = smk_of_current(); struct smack_known *skp = smk_of_current();
msg->security = skp->smk_known;
return 0; return 0;
} }
...@@ -2046,8 +2272,9 @@ static char *smack_of_shm(struct shmid_kernel *shp) ...@@ -2046,8 +2272,9 @@ static char *smack_of_shm(struct shmid_kernel *shp)
static int smack_shm_alloc_security(struct shmid_kernel *shp) static int smack_shm_alloc_security(struct shmid_kernel *shp)
{ {
struct kern_ipc_perm *isp = &shp->shm_perm; struct kern_ipc_perm *isp = &shp->shm_perm;
struct smack_known *skp = smk_of_current();
isp->security = smk_of_current(); isp->security = skp->smk_known;
return 0; return 0;
} }
...@@ -2169,8 +2396,9 @@ static char *smack_of_sem(struct sem_array *sma) ...@@ -2169,8 +2396,9 @@ static char *smack_of_sem(struct sem_array *sma)
static int smack_sem_alloc_security(struct sem_array *sma) static int smack_sem_alloc_security(struct sem_array *sma)
{ {
struct kern_ipc_perm *isp = &sma->sem_perm; struct kern_ipc_perm *isp = &sma->sem_perm;
struct smack_known *skp = smk_of_current();
isp->security = smk_of_current(); isp->security = skp->smk_known;
return 0; return 0;
} }
...@@ -2287,8 +2515,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, ...@@ -2287,8 +2515,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
static int smack_msg_queue_alloc_security(struct msg_queue *msq) static int smack_msg_queue_alloc_security(struct msg_queue *msq)
{ {
struct kern_ipc_perm *kisp = &msq->q_perm; struct kern_ipc_perm *kisp = &msq->q_perm;
struct smack_known *skp = smk_of_current();
kisp->security = smk_of_current(); kisp->security = skp->smk_known;
return 0; return 0;
} }
...@@ -2460,8 +2689,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -2460,8 +2689,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
struct super_block *sbp; struct super_block *sbp;
struct superblock_smack *sbsp; struct superblock_smack *sbsp;
struct inode_smack *isp; struct inode_smack *isp;
char *csp = smk_of_current(); struct smack_known *skp;
char *fetched; struct smack_known *ckp = smk_of_current();
char *final; char *final;
char trattr[TRANS_TRUE_SIZE]; char trattr[TRANS_TRUE_SIZE];
int transflag = 0; int transflag = 0;
...@@ -2528,7 +2757,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -2528,7 +2757,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Programs that change smack have to treat the * Programs that change smack have to treat the
* pty with respect. * pty with respect.
*/ */
final = csp; final = ckp->smk_known;
break; break;
case SOCKFS_MAGIC: case SOCKFS_MAGIC:
/* /*
...@@ -2583,9 +2812,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -2583,9 +2812,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Get the dentry for xattr. * Get the dentry for xattr.
*/ */
dp = dget(opt_dentry); dp = dget(opt_dentry);
fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
if (fetched != NULL) if (skp != NULL)
final = fetched; final = skp->smk_known;
/* /*
* Transmuting directory * Transmuting directory
...@@ -2625,7 +2854,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -2625,7 +2854,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
} }
if (final == NULL) if (final == NULL)
isp->smk_inode = csp; isp->smk_inode = ckp->smk_known;
else else
isp->smk_inode = final; isp->smk_inode = final;
...@@ -2648,13 +2877,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -2648,13 +2877,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/ */
static int smack_getprocattr(struct task_struct *p, char *name, char **value) static int smack_getprocattr(struct task_struct *p, char *name, char **value)
{ {
struct smack_known *skp = smk_of_task(task_security(p));
char *cp; char *cp;
int slen; int slen;
if (strcmp(name, "current") != 0) if (strcmp(name, "current") != 0)
return -EINVAL; return -EINVAL;
cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL); cp = kstrdup(skp->smk_known, GFP_KERNEL);
if (cp == NULL) if (cp == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -2680,7 +2910,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, ...@@ -2680,7 +2910,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
{ {
struct task_smack *tsp; struct task_smack *tsp;
struct cred *new; struct cred *new;
char *newsmack; struct smack_known *skp;
/* /*
* Changing another process' Smack value is too dangerous * Changing another process' Smack value is too dangerous
...@@ -2698,14 +2928,14 @@ static int smack_setprocattr(struct task_struct *p, char *name, ...@@ -2698,14 +2928,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (strcmp(name, "current") != 0) if (strcmp(name, "current") != 0)
return -EINVAL; return -EINVAL;
newsmack = smk_import(value, size); skp = smk_import_entry(value, size);
if (newsmack == NULL) if (skp == NULL)
return -EINVAL; return -EINVAL;
/* /*
* No process is ever allowed the web ("@") label. * No process is ever allowed the web ("@") label.
*/ */
if (newsmack == smack_known_web.smk_known) if (skp == &smack_known_web)
return -EPERM; return -EPERM;
new = prepare_creds(); new = prepare_creds();
...@@ -2713,7 +2943,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, ...@@ -2713,7 +2943,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
return -ENOMEM; return -ENOMEM;
tsp = new->security; tsp = new->security;
tsp->smk_task = newsmack; tsp->smk_task = skp;
commit_creds(new); commit_creds(new);
return size; return size;
...@@ -2731,6 +2961,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, ...@@ -2731,6 +2961,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
static int smack_unix_stream_connect(struct sock *sock, static int smack_unix_stream_connect(struct sock *sock,
struct sock *other, struct sock *newsk) struct sock *other, struct sock *newsk)
{ {
struct smack_known *skp;
struct socket_smack *ssp = sock->sk_security; struct socket_smack *ssp = sock->sk_security;
struct socket_smack *osp = other->sk_security; struct socket_smack *osp = other->sk_security;
struct socket_smack *nsp = newsk->sk_security; struct socket_smack *nsp = newsk->sk_security;
...@@ -2744,15 +2975,17 @@ static int smack_unix_stream_connect(struct sock *sock, ...@@ -2744,15 +2975,17 @@ static int smack_unix_stream_connect(struct sock *sock,
smk_ad_setfield_u_net_sk(&ad, other); smk_ad_setfield_u_net_sk(&ad, other);
#endif #endif
if (!smack_privileged(CAP_MAC_OVERRIDE)) if (!smack_privileged(CAP_MAC_OVERRIDE)) {
rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); skp = ssp->smk_out;
rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
}
/* /*
* Cross reference the peer labels for SO_PEERSEC. * Cross reference the peer labels for SO_PEERSEC.
*/ */
if (rc == 0) { if (rc == 0) {
nsp->smk_packet = ssp->smk_out; nsp->smk_packet = ssp->smk_out->smk_known;
ssp->smk_packet = osp->smk_out; ssp->smk_packet = osp->smk_out->smk_known;
} }
return rc; return rc;
...@@ -2770,8 +3003,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) ...@@ -2770,8 +3003,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
{ {
struct socket_smack *ssp = sock->sk->sk_security; struct socket_smack *ssp = sock->sk->sk_security;
struct socket_smack *osp = other->sk->sk_security; struct socket_smack *osp = other->sk->sk_security;
struct smack_known *skp;
struct smk_audit_info ad; struct smk_audit_info ad;
int rc = 0;
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
struct lsm_network_audit net; struct lsm_network_audit net;
...@@ -2780,10 +3013,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) ...@@ -2780,10 +3013,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
smk_ad_setfield_u_net_sk(&ad, other->sk); smk_ad_setfield_u_net_sk(&ad, other->sk);
#endif #endif
if (!smack_privileged(CAP_MAC_OVERRIDE)) if (smack_privileged(CAP_MAC_OVERRIDE))
rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); return 0;
return rc; skp = ssp->smk_out;
return smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
} }
/** /**
...@@ -2792,22 +3026,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) ...@@ -2792,22 +3026,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
* @msg: the message * @msg: the message
* @size: the size of the message * @size: the size of the message
* *
* Return 0 if the current subject can write to the destination * Return 0 if the current subject can write to the destination host.
* host. This is only a question if the destination is a single * For IPv4 this is only a question if the destination is a single label host.
* label host. * For IPv6 this is a check against the label of the port.
*/ */
static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size) int size)
{ {
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
struct sockaddr *sap = (struct sockaddr *) msg->msg_name;
int rc = 0;
/* /*
* Perfectly reasonable for this to be NULL * Perfectly reasonable for this to be NULL
*/ */
if (sip == NULL || sip->sin_family != AF_INET) if (sip == NULL)
return 0; return 0;
return smack_netlabel_send(sock->sk, sip); switch (sip->sin_family) {
case AF_INET:
rc = smack_netlabel_send(sock->sk, sip);
break;
case AF_INET6:
rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
break;
}
return rc;
} }
/** /**
...@@ -2815,13 +3059,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -2815,13 +3059,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
* @sap: netlabel secattr * @sap: netlabel secattr
* @ssp: socket security information * @ssp: socket security information
* *
* Returns a pointer to a Smack label found on the label list. * Returns a pointer to a Smack label entry found on the label list.
*/ */
static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
struct socket_smack *ssp) struct socket_smack *ssp)
{ {
struct smack_known *kp; struct smack_known *skp;
char *sp;
int found = 0; int found = 0;
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
...@@ -2836,11 +3079,11 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, ...@@ -2836,11 +3079,11 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
* ambient value. * ambient value.
*/ */
rcu_read_lock(); rcu_read_lock();
list_for_each_entry(kp, &smack_known_list, list) { list_for_each_entry(skp, &smack_known_list, list) {
if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl)
continue; continue;
if (memcmp(sap->attr.mls.cat, if (memcmp(sap->attr.mls.cat,
kp->smk_netlabel.attr.mls.cat, skp->smk_netlabel.attr.mls.cat,
SMK_CIPSOLEN) != 0) SMK_CIPSOLEN) != 0)
continue; continue;
found = 1; found = 1;
...@@ -2849,17 +3092,17 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, ...@@ -2849,17 +3092,17 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
rcu_read_unlock(); rcu_read_unlock();
if (found) if (found)
return kp->smk_known; return skp;
if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
return smack_known_web.smk_known; return &smack_known_web;
return smack_known_star.smk_known; return &smack_known_star;
} }
if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
/* /*
* Looks like a fallback, which gives us a secid. * Looks like a fallback, which gives us a secid.
*/ */
sp = smack_from_secid(sap->attr.secid); skp = smack_from_secid(sap->attr.secid);
/* /*
* This has got to be a bug because it is * This has got to be a bug because it is
* impossible to specify a fallback without * impossible to specify a fallback without
...@@ -2867,8 +3110,8 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, ...@@ -2867,8 +3110,8 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
* it has a secid, and the only way to get a * it has a secid, and the only way to get a
* secid is from a fallback. * secid is from a fallback.
*/ */
BUG_ON(sp == NULL); BUG_ON(skp == NULL);
return sp; return skp;
} }
/* /*
* Without guidance regarding the smack value * Without guidance regarding the smack value
...@@ -2878,6 +3121,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, ...@@ -2878,6 +3121,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
return smack_net_ambient; return smack_net_ambient;
} }
static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap)
{
struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
u8 nexthdr;
int offset;
int proto = -EINVAL;
struct ipv6hdr _ipv6h;
struct ipv6hdr *ip6;
__be16 frag_off;
struct tcphdr _tcph, *th;
struct udphdr _udph, *uh;
struct dccp_hdr _dccph, *dh;
sip->sin6_port = 0;
offset = skb_network_offset(skb);
ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
if (ip6 == NULL)
return -EINVAL;
sip->sin6_addr = ip6->saddr;
nexthdr = ip6->nexthdr;
offset += sizeof(_ipv6h);
offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
if (offset < 0)
return -EINVAL;
proto = nexthdr;
switch (proto) {
case IPPROTO_TCP:
th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
if (th != NULL)
sip->sin6_port = th->source;
break;
case IPPROTO_UDP:
uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
if (uh != NULL)
sip->sin6_port = uh->source;
break;
case IPPROTO_DCCP:
dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
if (dh != NULL)
sip->sin6_port = dh->dccph_sport;
break;
}
return proto;
}
/** /**
* smack_socket_sock_rcv_skb - Smack packet delivery access check * smack_socket_sock_rcv_skb - Smack packet delivery access check
* @sk: socket * @sk: socket
...@@ -2889,15 +3180,15 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -2889,15 +3180,15 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ {
struct netlbl_lsm_secattr secattr; struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = sk->sk_security; struct socket_smack *ssp = sk->sk_security;
char *csp; struct smack_known *skp;
int rc; struct sockaddr sadd;
int rc = 0;
struct smk_audit_info ad; struct smk_audit_info ad;
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
struct lsm_network_audit net; struct lsm_network_audit net;
#endif #endif
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) switch (sk->sk_family) {
return 0; case PF_INET:
/* /*
* Translate what netlabel gave us. * Translate what netlabel gave us.
*/ */
...@@ -2905,9 +3196,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -2905,9 +3196,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
if (rc == 0) if (rc == 0)
csp = smack_from_secattr(&secattr, ssp); skp = smack_from_secattr(&secattr, ssp);
else else
csp = smack_net_ambient; skp = smack_net_ambient;
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
...@@ -2923,9 +3214,18 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -2923,9 +3214,18 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* This is the simplist possible security model * This is the simplist possible security model
* for networking. * for networking.
*/ */
rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad); rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
if (rc != 0) if (rc != 0)
netlbl_skbuff_err(skb, rc, 0); netlbl_skbuff_err(skb, rc, 0);
break;
case PF_INET6:
rc = smk_skb_to_addr_ipv6(skb, &sadd);
if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
else
rc = 0;
break;
}
return rc; return rc;
} }
...@@ -2979,7 +3279,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, ...@@ -2979,7 +3279,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
{ {
struct netlbl_lsm_secattr secattr; struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = NULL; struct socket_smack *ssp = NULL;
char *sp; struct smack_known *skp;
int family = PF_UNSPEC; int family = PF_UNSPEC;
u32 s = 0; /* 0 is the invalid secid */ u32 s = 0; /* 0 is the invalid secid */
int rc; int rc;
...@@ -2995,7 +3295,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, ...@@ -2995,7 +3295,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
if (family == PF_UNIX) { if (family == PF_UNIX) {
ssp = sock->sk->sk_security; ssp = sock->sk->sk_security;
s = smack_to_secid(ssp->smk_out); s = ssp->smk_out->smk_secid;
} else if (family == PF_INET || family == PF_INET6) { } else if (family == PF_INET || family == PF_INET6) {
/* /*
* Translate what netlabel gave us. * Translate what netlabel gave us.
...@@ -3005,8 +3305,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, ...@@ -3005,8 +3305,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0) { if (rc == 0) {
sp = smack_from_secattr(&secattr, ssp); skp = smack_from_secattr(&secattr, ssp);
s = smack_to_secid(sp); s = skp->smk_secid;
} }
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
} }
...@@ -3027,13 +3327,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, ...@@ -3027,13 +3327,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
static void smack_sock_graft(struct sock *sk, struct socket *parent) static void smack_sock_graft(struct sock *sk, struct socket *parent)
{ {
struct socket_smack *ssp; struct socket_smack *ssp;
struct smack_known *skp = smk_of_current();
if (sk == NULL || if (sk == NULL ||
(sk->sk_family != PF_INET && sk->sk_family != PF_INET6)) (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
return; return;
ssp = sk->sk_security; ssp = sk->sk_security;
ssp->smk_in = ssp->smk_out = smk_of_current(); ssp->smk_in = skp->smk_known;
ssp->smk_out = skp;
/* cssp->smk_packet is already set in smack_inet_csk_clone() */ /* cssp->smk_packet is already set in smack_inet_csk_clone() */
} }
...@@ -3055,7 +3357,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -3055,7 +3357,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct netlbl_lsm_secattr secattr; struct netlbl_lsm_secattr secattr;
struct sockaddr_in addr; struct sockaddr_in addr;
struct iphdr *hdr; struct iphdr *hdr;
char *sp;
char *hsp; char *hsp;
int rc; int rc;
struct smk_audit_info ad; struct smk_audit_info ad;
...@@ -3063,16 +3364,24 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -3063,16 +3364,24 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct lsm_network_audit net; struct lsm_network_audit net;
#endif #endif
/* handle mapped IPv4 packets arriving via IPv6 sockets */ if (family == PF_INET6) {
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) /*
* Handle mapped IPv4 packets arriving
* via IPv6 sockets. Don't set up netlabel
* processing on IPv6.
*/
if (skb->protocol == htons(ETH_P_IP))
family = PF_INET; family = PF_INET;
else
return 0;
}
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0) if (rc == 0)
sp = smack_from_secattr(&secattr, ssp); skp = smack_from_secattr(&secattr, ssp);
else else
sp = smack_known_huh.smk_known; skp = &smack_known_huh;
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
...@@ -3085,7 +3394,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -3085,7 +3394,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Receiving a packet requires that the other end be able to write * Receiving a packet requires that the other end be able to write
* here. Read access is not required. * here. Read access is not required.
*/ */
rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad); rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
if (rc != 0) if (rc != 0)
return rc; return rc;
...@@ -3093,7 +3402,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -3093,7 +3402,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Save the peer's label in the request_sock so we can later setup * Save the peer's label in the request_sock so we can later setup
* smk_packet in the child socket so that SO_PEERCRED can report it. * smk_packet in the child socket so that SO_PEERCRED can report it.
*/ */
req->peer_secid = smack_to_secid(sp); req->peer_secid = skp->smk_secid;
/* /*
* We need to decide if we want to label the incoming connection here * We need to decide if we want to label the incoming connection here
...@@ -3106,10 +3415,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -3106,10 +3415,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
hsp = smack_host_label(&addr); hsp = smack_host_label(&addr);
rcu_read_unlock(); rcu_read_unlock();
if (hsp == NULL) { if (hsp == NULL)
skp = smk_find_entry(sp);
rc = netlbl_req_setattr(req, &skp->smk_netlabel); rc = netlbl_req_setattr(req, &skp->smk_netlabel);
} else else
netlbl_req_delattr(req); netlbl_req_delattr(req);
return rc; return rc;
...@@ -3126,10 +3434,12 @@ static void smack_inet_csk_clone(struct sock *sk, ...@@ -3126,10 +3434,12 @@ static void smack_inet_csk_clone(struct sock *sk,
const struct request_sock *req) const struct request_sock *req)
{ {
struct socket_smack *ssp = sk->sk_security; struct socket_smack *ssp = sk->sk_security;
struct smack_known *skp;
if (req->peer_secid != 0) if (req->peer_secid != 0) {
ssp->smk_packet = smack_from_secid(req->peer_secid); skp = smack_from_secid(req->peer_secid);
else ssp->smk_packet = skp->smk_known;
} else
ssp->smk_packet = NULL; ssp->smk_packet = NULL;
} }
...@@ -3155,7 +3465,9 @@ static void smack_inet_csk_clone(struct sock *sk, ...@@ -3155,7 +3465,9 @@ static void smack_inet_csk_clone(struct sock *sk,
static int smack_key_alloc(struct key *key, const struct cred *cred, static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags) unsigned long flags)
{ {
key->security = smk_of_task(cred->security); struct smack_known *skp = smk_of_task(cred->security);
key->security = skp->smk_known;
return 0; return 0;
} }
...@@ -3184,7 +3496,7 @@ static int smack_key_permission(key_ref_t key_ref, ...@@ -3184,7 +3496,7 @@ static int smack_key_permission(key_ref_t key_ref,
{ {
struct key *keyp; struct key *keyp;
struct smk_audit_info ad; struct smk_audit_info ad;
char *tsp = smk_of_task(cred->security); struct smack_known *tkp = smk_of_task(cred->security);
keyp = key_ref_to_ptr(key_ref); keyp = key_ref_to_ptr(key_ref);
if (keyp == NULL) if (keyp == NULL)
...@@ -3198,15 +3510,14 @@ static int smack_key_permission(key_ref_t key_ref, ...@@ -3198,15 +3510,14 @@ static int smack_key_permission(key_ref_t key_ref,
/* /*
* This should not occur * This should not occur
*/ */
if (tsp == NULL) if (tkp == NULL)
return -EACCES; return -EACCES;
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
ad.a.u.key_struct.key = keyp->serial; ad.a.u.key_struct.key = keyp->serial;
ad.a.u.key_struct.key_desc = keyp->description; ad.a.u.key_struct.key_desc = keyp->description;
#endif #endif
return smk_access(tsp, keyp->security, return smk_access(tkp, keyp->security, MAY_READWRITE, &ad);
MAY_READWRITE, &ad);
} }
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
...@@ -3288,7 +3599,7 @@ static int smack_audit_rule_known(struct audit_krule *krule) ...@@ -3288,7 +3599,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)
static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
struct audit_context *actx) struct audit_context *actx)
{ {
char *smack; struct smack_known *skp;
char *rule = vrule; char *rule = vrule;
if (!rule) { if (!rule) {
...@@ -3300,7 +3611,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, ...@@ -3300,7 +3611,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return 0; return 0;
smack = smack_from_secid(secid); skp = smack_from_secid(secid);
/* /*
* No need to do string comparisons. If a match occurs, * No need to do string comparisons. If a match occurs,
...@@ -3308,9 +3619,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, ...@@ -3308,9 +3619,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
* label. * label.
*/ */
if (op == Audit_equal) if (op == Audit_equal)
return (rule == smack); return (rule == skp->smk_known);
if (op == Audit_not_equal) if (op == Audit_not_equal)
return (rule != smack); return (rule != skp->smk_known);
return 0; return 0;
} }
...@@ -3338,11 +3649,11 @@ static void smack_audit_rule_free(void *vrule) ...@@ -3338,11 +3649,11 @@ static void smack_audit_rule_free(void *vrule)
*/ */
static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
char *sp = smack_from_secid(secid); struct smack_known *skp = smack_from_secid(secid);
if (secdata) if (secdata)
*secdata = sp; *secdata = skp->smk_known;
*seclen = strlen(sp); *seclen = strlen(skp->smk_known);
return 0; return 0;
} }
...@@ -3498,6 +3809,7 @@ struct security_operations smack_ops = { ...@@ -3498,6 +3809,7 @@ struct security_operations smack_ops = {
.unix_may_send = smack_unix_may_send, .unix_may_send = smack_unix_may_send,
.socket_post_create = smack_socket_post_create, .socket_post_create = smack_socket_post_create,
.socket_bind = smack_socket_bind,
.socket_connect = smack_socket_connect, .socket_connect = smack_socket_connect,
.socket_sendmsg = smack_socket_sendmsg, .socket_sendmsg = smack_socket_sendmsg,
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb, .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
...@@ -3577,8 +3889,8 @@ static __init int smack_init(void) ...@@ -3577,8 +3889,8 @@ static __init int smack_init(void)
if (!security_module_enable(&smack_ops)) if (!security_module_enable(&smack_ops))
return 0; return 0;
tsp = new_task_smack(smack_known_floor.smk_known, tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
smack_known_floor.smk_known, GFP_KERNEL); GFP_KERNEL);
if (tsp == NULL) if (tsp == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -66,7 +66,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock); ...@@ -66,7 +66,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
* If it isn't somehow marked, use this. * If it isn't somehow marked, use this.
* It can be reset via smackfs/ambient * It can be reset via smackfs/ambient
*/ */
char *smack_net_ambient; struct smack_known *smack_net_ambient;
/* /*
* This is the level in a CIPSO header that indicates a * This is the level in a CIPSO header that indicates a
...@@ -112,7 +112,7 @@ struct smack_master_list { ...@@ -112,7 +112,7 @@ struct smack_master_list {
LIST_HEAD(smack_rule_list); LIST_HEAD(smack_rule_list);
struct smack_parsed_rule { struct smack_parsed_rule {
char *smk_subject; struct smack_known *smk_subject;
char *smk_object; char *smk_object;
int smk_access1; int smk_access1;
int smk_access2; int smk_access2;
...@@ -163,9 +163,11 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp) ...@@ -163,9 +163,11 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp)
*/ */
static void smk_netlabel_audit_set(struct netlbl_audit *nap) static void smk_netlabel_audit_set(struct netlbl_audit *nap)
{ {
struct smack_known *skp = smk_of_current();
nap->loginuid = audit_get_loginuid(current); nap->loginuid = audit_get_loginuid(current);
nap->sessionid = audit_get_sessionid(current); nap->sessionid = audit_get_sessionid(current);
nap->secid = smack_to_secid(smk_of_current()); nap->secid = skp->smk_secid;
} }
/* /*
...@@ -306,7 +308,7 @@ static int smk_fill_rule(const char *subject, const char *object, ...@@ -306,7 +308,7 @@ static int smk_fill_rule(const char *subject, const char *object,
struct smack_known *skp; struct smack_known *skp;
if (import) { if (import) {
rule->smk_subject = smk_import(subject, len); rule->smk_subject = smk_import_entry(subject, len);
if (rule->smk_subject == NULL) if (rule->smk_subject == NULL)
return -1; return -1;
...@@ -321,7 +323,7 @@ static int smk_fill_rule(const char *subject, const char *object, ...@@ -321,7 +323,7 @@ static int smk_fill_rule(const char *subject, const char *object,
kfree(cp); kfree(cp);
if (skp == NULL) if (skp == NULL)
return -1; return -1;
rule->smk_subject = skp->smk_known; rule->smk_subject = skp;
cp = smk_parse_smack(object, len); cp = smk_parse_smack(object, len);
if (cp == NULL) if (cp == NULL)
...@@ -445,7 +447,6 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, ...@@ -445,7 +447,6 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
struct list_head *rule_list, struct list_head *rule_list,
struct mutex *rule_lock, int format) struct mutex *rule_lock, int format)
{ {
struct smack_known *skp;
struct smack_parsed_rule *rule; struct smack_parsed_rule *rule;
char *data; char *data;
int datalen; int datalen;
...@@ -505,12 +506,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, ...@@ -505,12 +506,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
goto out_free_rule; goto out_free_rule;
} }
if (rule_list == NULL) { if (rule_list == NULL) {
load = 1; load = 1;
skp = smk_find_entry(rule->smk_subject); rule_list = &rule->smk_subject->smk_rules;
rule_list = &skp->smk_rules; rule_lock = &rule->smk_subject->smk_rules_lock;
rule_lock = &skp->smk_rules_lock;
} }
rc = smk_set_access(rule, rule_list, rule_lock, load); rc = smk_set_access(rule, rule_list, rule_lock, load);
...@@ -579,13 +578,14 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) ...@@ -579,13 +578,14 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
* because you should expect to be able to write * because you should expect to be able to write
* anything you read back. * anything you read back.
*/ */
if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max) if (strlen(srp->smk_subject->smk_known) >= max ||
strlen(srp->smk_object) >= max)
return; return;
if (srp->smk_access == 0) if (srp->smk_access == 0)
return; return;
seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object); seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object);
seq_putc(s, ' '); seq_putc(s, ' ');
...@@ -738,9 +738,9 @@ static void smk_unlbl_ambient(char *oldambient) ...@@ -738,9 +738,9 @@ static void smk_unlbl_ambient(char *oldambient)
__func__, __LINE__, rc); __func__, __LINE__, rc);
} }
if (smack_net_ambient == NULL) if (smack_net_ambient == NULL)
smack_net_ambient = smack_known_floor.smk_known; smack_net_ambient = &smack_known_floor;
rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, rc = netlbl_cfg_unlbl_map_add(smack_net_ambient->smk_known, PF_INET,
NULL, NULL, &nai); NULL, NULL, &nai);
if (rc != 0) if (rc != 0)
printk(KERN_WARNING "%s:%d add rc = %d\n", printk(KERN_WARNING "%s:%d add rc = %d\n",
...@@ -881,7 +881,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, ...@@ -881,7 +881,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
if (format == SMK_FIXED24_FMT) if (format == SMK_FIXED24_FMT)
rule += SMK_LABELLEN; rule += SMK_LABELLEN;
else else
rule += strlen(skp->smk_known); rule += strlen(skp->smk_known) + 1;
ret = sscanf(rule, "%d", &maplevel); ret = sscanf(rule, "%d", &maplevel);
if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
...@@ -1535,11 +1535,12 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, ...@@ -1535,11 +1535,12 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
*/ */
mutex_lock(&smack_ambient_lock); mutex_lock(&smack_ambient_lock);
asize = strlen(smack_net_ambient) + 1; asize = strlen(smack_net_ambient->smk_known) + 1;
if (cn >= asize) if (cn >= asize)
rc = simple_read_from_buffer(buf, cn, ppos, rc = simple_read_from_buffer(buf, cn, ppos,
smack_net_ambient, asize); smack_net_ambient->smk_known,
asize);
else else
rc = -EINVAL; rc = -EINVAL;
...@@ -1560,8 +1561,8 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, ...@@ -1560,8 +1561,8 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
static ssize_t smk_write_ambient(struct file *file, const char __user *buf, static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct smack_known *skp;
char *oldambient; char *oldambient;
char *smack = NULL;
char *data; char *data;
int rc = count; int rc = count;
...@@ -1577,16 +1578,16 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, ...@@ -1577,16 +1578,16 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
goto out; goto out;
} }
smack = smk_import(data, count); skp = smk_import_entry(data, count);
if (smack == NULL) { if (skp == NULL) {
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
mutex_lock(&smack_ambient_lock); mutex_lock(&smack_ambient_lock);
oldambient = smack_net_ambient; oldambient = smack_net_ambient->smk_known;
smack_net_ambient = smack; smack_net_ambient = skp;
smk_unlbl_ambient(oldambient); smk_unlbl_ambient(oldambient);
mutex_unlock(&smack_ambient_lock); mutex_unlock(&smack_ambient_lock);
...@@ -1645,7 +1646,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, ...@@ -1645,7 +1646,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char *data; char *data;
char *sp = smk_of_task(current->cred->security); struct smack_known *skp = smk_of_task(current->cred->security);
int rc = count; int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN)) if (!smack_privileged(CAP_MAC_ADMIN))
...@@ -1656,7 +1657,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, ...@@ -1656,7 +1657,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
* explicitly for clarity. The smk_access() implementation * explicitly for clarity. The smk_access() implementation
* would use smk_access(smack_onlycap, MAY_WRITE) * would use smk_access(smack_onlycap, MAY_WRITE)
*/ */
if (smack_onlycap != NULL && smack_onlycap != sp) if (smack_onlycap != NULL && smack_onlycap != skp->smk_known)
return -EPERM; return -EPERM;
data = kzalloc(count, GFP_KERNEL); data = kzalloc(count, GFP_KERNEL);
...@@ -1866,8 +1867,8 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, ...@@ -1866,8 +1867,8 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
if (res) if (res)
return -EINVAL; return -EINVAL;
res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1, res = smk_access(rule.smk_subject, rule.smk_object,
NULL); rule.smk_access1, NULL);
data[0] = res == 0 ? '1' : '0'; data[0] = res == 0 ? '1' : '0';
data[1] = '\0'; data[1] = '\0';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment