Commit 96b5b7f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (61 commits)
  KEYS: Return more accurate error codes
  LSM: Add __init to fixup function.
  TOMOYO: Add pathname grouping support.
  ima: remove ACPI dependency
  TPM: ACPI/PNP dependency removal
  security/selinux/ss: Use kstrdup
  TOMOYO: Use stack memory for pending entry.
  Revert "ima: remove ACPI dependency"
  Revert "TPM: ACPI/PNP dependency removal"
  KEYS: Do preallocation for __key_link()
  TOMOYO: Use mutex_lock_interruptible.
  KEYS: Better handling of errors from construct_alloc_key()
  KEYS: keyring_serialise_link_sem is only needed for keyring->keyring links
  TOMOYO: Use GFP_NOFS rather than GFP_KERNEL.
  ima: remove ACPI dependency
  TPM: ACPI/PNP dependency removal
  selinux: generalize disabling of execmem for plt-in-heap archs
  LSM Audit: rename LSM_AUDIT_NO_AUDIT to LSM_AUDIT_DATA_NONE
  CRED: Holding a spinlock does not imply the holding of RCU read lock
  SMACK: Don't #include Ext2 headers
  ...
parents f72caf7e 539c99fd
...@@ -408,9 +408,6 @@ This should be used inside the RCU read lock, as in the following example: ...@@ -408,9 +408,6 @@ This should be used inside the RCU read lock, as in the following example:
... ...
} }
A function need not get RCU read lock to use __task_cred() if it is holding a
spinlock at the time as this implicitly holds the RCU read lock.
Should it be necessary to hold another task's credentials for a long period of Should it be necessary to hold another task's credentials for a long period of
time, and possibly to sleep whilst doing so, then the caller should get a time, and possibly to sleep whilst doing so, then the caller should get a
reference on them using: reference on them using:
...@@ -426,17 +423,16 @@ credentials, hiding the RCU magic from the caller: ...@@ -426,17 +423,16 @@ credentials, hiding the RCU magic from the caller:
uid_t task_uid(task) Task's real UID uid_t task_uid(task) Task's real UID
uid_t task_euid(task) Task's effective UID uid_t task_euid(task) Task's effective UID
If the caller is holding a spinlock or the RCU read lock at the time anyway, If the caller is holding the RCU read lock at the time anyway, then:
then:
__task_cred(task)->uid __task_cred(task)->uid
__task_cred(task)->euid __task_cred(task)->euid
should be used instead. Similarly, if multiple aspects of a task's credentials should be used instead. Similarly, if multiple aspects of a task's credentials
need to be accessed, RCU read lock or a spinlock should be used, __task_cred() need to be accessed, RCU read lock should be used, __task_cred() called, the
called, the result stored in a temporary pointer and then the credential result stored in a temporary pointer and then the credential aspects called
aspects called from that before dropping the lock. This prevents the from that before dropping the lock. This prevents the potentially expensive
potentially expensive RCU magic from being invoked multiple times. RCU magic from being invoked multiple times.
Should some other single aspect of another task's credentials need to be Should some other single aspect of another task's credentials need to be
accessed, then this can be used: accessed, then this can be used:
......
...@@ -99,6 +99,7 @@ parameter is applicable: ...@@ -99,6 +99,7 @@ parameter is applicable:
SWSUSP Software suspend (hibernation) is enabled. SWSUSP Software suspend (hibernation) is enabled.
SUSPEND System suspend states are enabled. SUSPEND System suspend states are enabled.
FTRACE Function tracing enabled. FTRACE Function tracing enabled.
TPM TPM drivers are enabled.
TS Appropriate touchscreen support is enabled. TS Appropriate touchscreen support is enabled.
UMS USB Mass Storage support is enabled. UMS USB Mass Storage support is enabled.
USB USB support is enabled. USB USB support is enabled.
...@@ -2616,6 +2617,15 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -2616,6 +2617,15 @@ and is between 256 and 4096 characters. It is defined in the file
tp720= [HW,PS2] tp720= [HW,PS2]
tpm_suspend_pcr=[HW,TPM]
Format: integer pcr id
Specify that at suspend time, the tpm driver
should extend the specified pcr with zeros,
as a workaround for some chips which fail to
flush the last written pcr on TPM_SaveState.
This will guarantee that all the other pcrs
are saved.
trace_buf_size=nn[KMG] trace_buf_size=nn[KMG]
[FTRACE] will set tracing buffer size. [FTRACE] will set tracing buffer size.
......
...@@ -17,14 +17,16 @@ menuconfig TCG_TPM ...@@ -17,14 +17,16 @@ menuconfig TCG_TPM
obtained at: <http://sourceforge.net/projects/trousers>. To obtained at: <http://sourceforge.net/projects/trousers>. To
compile this driver as a module, choose M here; the module compile this driver as a module, choose M here; the module
will be called tpm. If unsure, say N. will be called tpm. If unsure, say N.
Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI Notes:
1) For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI
and CONFIG_PNPACPI. and CONFIG_PNPACPI.
2) Without ACPI enabled, the BIOS event log won't be accessible,
which is required to validate the PCR 0-7 values.
if TCG_TPM if TCG_TPM
config TCG_TIS config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface" tristate "TPM Interface Specification 1.2 Interface"
depends on PNP
---help--- ---help---
If you have a TPM security chip that is compliant with the If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification say Yes and it will be accessible TCG TIS 1.2 TPM specification say Yes and it will be accessible
......
...@@ -1068,6 +1068,27 @@ void tpm_remove_hardware(struct device *dev) ...@@ -1068,6 +1068,27 @@ void tpm_remove_hardware(struct device *dev)
} }
EXPORT_SYMBOL_GPL(tpm_remove_hardware); EXPORT_SYMBOL_GPL(tpm_remove_hardware);
#define TPM_ORD_SAVESTATE cpu_to_be32(152)
#define SAVESTATE_RESULT_SIZE 10
static struct tpm_input_header savestate_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(10),
.ordinal = TPM_ORD_SAVESTATE
};
/* Bug workaround - some TPM's don't flush the most
* recently changed pcr on suspend, so force the flush
* with an extend to the selected _unused_ non-volatile pcr.
*/
static int tpm_suspend_pcr;
static int __init tpm_suspend_setup(char *str)
{
get_option(&str, &tpm_suspend_pcr);
return 1;
}
__setup("tpm_suspend_pcr=", tpm_suspend_setup);
/* /*
* We are about to suspend. Save the TPM state * We are about to suspend. Save the TPM state
* so that it can be restored. * so that it can be restored.
...@@ -1075,17 +1096,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware); ...@@ -1075,17 +1096,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware);
int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
u8 savestate[] = { struct tpm_cmd_t cmd;
0, 193, /* TPM_TAG_RQU_COMMAND */ int rc;
0, 0, 0, 10, /* blob length (in bytes) */
0, 0, 0, 152 /* TPM_ORD_SaveState */ u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
};
if (chip == NULL) if (chip == NULL)
return -ENODEV; return -ENODEV;
tpm_transmit(chip, savestate, sizeof(savestate)); /* for buggy tpm, flush pcrs with extend to selected dummy */
return 0; if (tpm_suspend_pcr) {
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
TPM_DIGEST_SIZE);
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"extending dummy pcr before suspend");
}
/* now do the actual savestate */
cmd.header.in = savestate_header;
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
"sending savestate before suspend");
return rc;
} }
EXPORT_SYMBOL_GPL(tpm_pm_suspend); EXPORT_SYMBOL_GPL(tpm_pm_suspend);
......
...@@ -598,7 +598,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, ...@@ -598,7 +598,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
tpm_remove_hardware(chip->dev); tpm_remove_hardware(chip->dev);
return rc; return rc;
} }
#ifdef CONFIG_PNP
static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id) const struct pnp_device_id *pnp_id)
{ {
...@@ -663,7 +663,7 @@ static struct pnp_driver tis_pnp_driver = { ...@@ -663,7 +663,7 @@ static struct pnp_driver tis_pnp_driver = {
module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
#endif
static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg) static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
{ {
return tpm_pm_suspend(&dev->dev, msg); return tpm_pm_suspend(&dev->dev, msg);
...@@ -690,21 +690,21 @@ MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); ...@@ -690,21 +690,21 @@ MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
static int __init init_tis(void) static int __init init_tis(void)
{ {
int rc; int rc;
#ifdef CONFIG_PNP
if (!force)
return pnp_register_driver(&tis_pnp_driver);
#endif
if (force) { rc = platform_driver_register(&tis_drv);
rc = platform_driver_register(&tis_drv); if (rc < 0)
if (rc < 0)
return rc;
if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
return PTR_ERR(pdev);
if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
}
return rc; return rc;
if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
return PTR_ERR(pdev);
if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
} }
return rc;
return pnp_register_driver(&tis_pnp_driver);
} }
static void __exit cleanup_tis(void) static void __exit cleanup_tis(void)
...@@ -728,12 +728,14 @@ static void __exit cleanup_tis(void) ...@@ -728,12 +728,14 @@ static void __exit cleanup_tis(void)
list_del(&i->list); list_del(&i->list);
} }
spin_unlock(&tis_lock); spin_unlock(&tis_lock);
#ifdef CONFIG_PNP
if (force) { if (!force) {
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
} else
pnp_unregister_driver(&tis_pnp_driver); pnp_unregister_driver(&tis_pnp_driver);
return;
}
#endif
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
} }
module_init(init_tis); module_init(init_tis);
......
...@@ -1205,8 +1205,6 @@ void generic_delete_inode(struct inode *inode) ...@@ -1205,8 +1205,6 @@ void generic_delete_inode(struct inode *inode)
inodes_stat.nr_inodes--; inodes_stat.nr_inodes--;
spin_unlock(&inode_lock); spin_unlock(&inode_lock);
security_inode_delete(inode);
if (op->delete_inode) { if (op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode; void (*delete)(struct inode *) = op->delete_inode;
/* Filesystems implementing their own /* Filesystems implementing their own
......
...@@ -628,7 +628,6 @@ void mntput_no_expire(struct vfsmount *mnt) ...@@ -628,7 +628,6 @@ void mntput_no_expire(struct vfsmount *mnt)
mnt->mnt_pinned = 0; mnt->mnt_pinned = 0;
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
acct_auto_close_mnt(mnt); acct_auto_close_mnt(mnt);
security_sb_umount_close(mnt);
goto repeat; goto repeat;
} }
} }
...@@ -1117,8 +1116,6 @@ static int do_umount(struct vfsmount *mnt, int flags) ...@@ -1117,8 +1116,6 @@ static int do_umount(struct vfsmount *mnt, int flags)
retval = 0; retval = 0;
} }
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
if (retval)
security_sb_umount_busy(mnt);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);
return retval; return retval;
...@@ -1435,17 +1432,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) ...@@ -1435,17 +1432,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
if (cant_mount(path->dentry)) if (cant_mount(path->dentry))
goto out_unlock; goto out_unlock;
err = security_sb_check_sb(mnt, path);
if (err)
goto out_unlock;
err = -ENOENT;
if (!d_unlinked(path->dentry)) if (!d_unlinked(path->dentry))
err = attach_recursive_mnt(mnt, path, NULL); err = attach_recursive_mnt(mnt, path, NULL);
out_unlock: out_unlock:
mutex_unlock(&path->dentry->d_inode->i_mutex); mutex_unlock(&path->dentry->d_inode->i_mutex);
if (!err)
security_sb_post_addmount(mnt, path);
return err; return err;
} }
...@@ -1581,8 +1571,6 @@ static int do_remount(struct path *path, int flags, int mnt_flags, ...@@ -1581,8 +1571,6 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
} }
up_write(&sb->s_umount); up_write(&sb->s_umount);
if (!err) { if (!err) {
security_sb_post_remount(path->mnt, flags, data);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
touch_mnt_namespace(path->mnt->mnt_ns); touch_mnt_namespace(path->mnt->mnt_ns);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
...@@ -2277,7 +2265,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, ...@@ -2277,7 +2265,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
touch_mnt_namespace(current->nsproxy->mnt_ns); touch_mnt_namespace(current->nsproxy->mnt_ns);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
chroot_fs_refs(&root, &new); chroot_fs_refs(&root, &new);
security_sb_post_pivotroot(&root, &new);
error = 0; error = 0;
path_put(&root_parent); path_put(&root_parent);
path_put(&parent_path); path_put(&parent_path);
......
...@@ -33,7 +33,7 @@ struct common_audit_data { ...@@ -33,7 +33,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_IPC 4 #define LSM_AUDIT_DATA_IPC 4
#define LSM_AUDIT_DATA_TASK 5 #define LSM_AUDIT_DATA_TASK 5
#define LSM_AUDIT_DATA_KEY 6 #define LSM_AUDIT_DATA_KEY 6
#define LSM_AUDIT_NO_AUDIT 7 #define LSM_AUDIT_DATA_NONE 7
#define LSM_AUDIT_DATA_KMOD 8 #define LSM_AUDIT_DATA_KMOD 8
struct task_struct *tsk; struct task_struct *tsk;
union { union {
......
This diff is collapsed.
...@@ -216,7 +216,6 @@ static int acct_on(char *name) ...@@ -216,7 +216,6 @@ static int acct_on(char *name)
{ {
struct file *file; struct file *file;
struct vfsmount *mnt; struct vfsmount *mnt;
int error;
struct pid_namespace *ns; struct pid_namespace *ns;
struct bsd_acct_struct *acct = NULL; struct bsd_acct_struct *acct = NULL;
...@@ -244,13 +243,6 @@ static int acct_on(char *name) ...@@ -244,13 +243,6 @@ static int acct_on(char *name)
} }
} }
error = security_acct(file);
if (error) {
kfree(acct);
filp_close(file, NULL);
return error;
}
spin_lock(&acct_lock); spin_lock(&acct_lock);
if (ns->bacct == NULL) { if (ns->bacct == NULL) {
ns->bacct = acct; ns->bacct = acct;
...@@ -281,7 +273,7 @@ static int acct_on(char *name) ...@@ -281,7 +273,7 @@ static int acct_on(char *name)
*/ */
SYSCALL_DEFINE1(acct, const char __user *, name) SYSCALL_DEFINE1(acct, const char __user *, name)
{ {
int error; int error = 0;
if (!capable(CAP_SYS_PACCT)) if (!capable(CAP_SYS_PACCT))
return -EPERM; return -EPERM;
...@@ -299,13 +291,11 @@ SYSCALL_DEFINE1(acct, const char __user *, name) ...@@ -299,13 +291,11 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
if (acct == NULL) if (acct == NULL)
return 0; return 0;
error = security_acct(NULL); spin_lock(&acct_lock);
if (!error) { acct_file_reopen(acct, NULL, NULL);
spin_lock(&acct_lock); spin_unlock(&acct_lock);
acct_file_reopen(acct, NULL, NULL);
spin_unlock(&acct_lock);
}
} }
return error; return error;
} }
......
...@@ -522,8 +522,6 @@ int commit_creds(struct cred *new) ...@@ -522,8 +522,6 @@ int commit_creds(struct cred *new)
#endif #endif
BUG_ON(atomic_read(&new->usage) < 1); BUG_ON(atomic_read(&new->usage) < 1);
security_commit_creds(new, old);
get_cred(new); /* we will require a ref for the subj creds too */ get_cred(new); /* we will require a ref for the subj creds too */
/* dumpability changes */ /* dumpability changes */
......
...@@ -164,12 +164,6 @@ int groups_search(const struct group_info *group_info, gid_t grp) ...@@ -164,12 +164,6 @@ int groups_search(const struct group_info *group_info, gid_t grp)
*/ */
int set_groups(struct cred *new, struct group_info *group_info) int set_groups(struct cred *new, struct group_info *group_info)
{ {
int retval;
retval = security_task_setgroups(group_info);
if (retval)
return retval;
put_group_info(new->group_info); put_group_info(new->group_info);
groups_sort(group_info); groups_sort(group_info);
get_group_info(group_info); get_group_info(group_info);
......
...@@ -492,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) ...@@ -492,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
return -ENOMEM; return -ENOMEM;
old = current_cred(); old = current_cred();
retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
if (retval)
goto error;
retval = -EPERM; retval = -EPERM;
if (rgid != (gid_t) -1) { if (rgid != (gid_t) -1) {
if (old->gid == rgid || if (old->gid == rgid ||
...@@ -543,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) ...@@ -543,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
return -ENOMEM; return -ENOMEM;
old = current_cred(); old = current_cred();
retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
if (retval)
goto error;
retval = -EPERM; retval = -EPERM;
if (capable(CAP_SETGID)) if (capable(CAP_SETGID))
new->gid = new->egid = new->sgid = new->fsgid = gid; new->gid = new->egid = new->sgid = new->fsgid = gid;
...@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) ...@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
return -ENOMEM; return -ENOMEM;
old = current_cred(); old = current_cred();
retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
if (retval)
goto error;
retval = -EPERM; retval = -EPERM;
if (ruid != (uid_t) -1) { if (ruid != (uid_t) -1) {
new->uid = ruid; new->uid = ruid;
...@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) ...@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
return -ENOMEM; return -ENOMEM;
old = current_cred(); old = current_cred();
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
if (retval)
goto error;
retval = -EPERM; retval = -EPERM;
if (capable(CAP_SETUID)) { if (capable(CAP_SETUID)) {
new->suid = new->uid = uid; new->suid = new->uid = uid;
...@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) ...@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
if (retval)
goto error;
old = current_cred(); old = current_cred();
retval = -EPERM; retval = -EPERM;
...@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) ...@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
return -ENOMEM; return -ENOMEM;
old = current_cred(); old = current_cred();
retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
if (retval)
goto error;
retval = -EPERM; retval = -EPERM;
if (!capable(CAP_SETGID)) { if (!capable(CAP_SETGID)) {
if (rgid != (gid_t) -1 && rgid != old->gid && if (rgid != (gid_t) -1 && rgid != old->gid &&
...@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) ...@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
old = current_cred(); old = current_cred();
old_fsuid = old->fsuid; old_fsuid = old->fsuid;
if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
goto error;
if (uid == old->uid || uid == old->euid || if (uid == old->uid || uid == old->euid ||
uid == old->suid || uid == old->fsuid || uid == old->suid || uid == old->fsuid ||
capable(CAP_SETUID)) { capable(CAP_SETUID)) {
...@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) ...@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
} }
} }
error:
abort_creds(new); abort_creds(new);
return old_fsuid; return old_fsuid;
...@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) ...@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
old = current_cred(); old = current_cred();
old_fsgid = old->fsgid; old_fsgid = old->fsgid;
if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
goto error;
if (gid == old->gid || gid == old->egid || if (gid == old->gid || gid == old->egid ||
gid == old->sgid || gid == old->fsgid || gid == old->sgid || gid == old->fsgid ||
capable(CAP_SETGID)) { capable(CAP_SETGID)) {
...@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) ...@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
} }
} }
error:
abort_creds(new); abort_creds(new);
return old_fsgid; return old_fsgid;
......
...@@ -81,7 +81,7 @@ int main(int argc, char *argv[]) ...@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
fprintf(fout, "\n"); fprintf(fout, "\n");
for (i = 1; i < isids_len; i++) { for (i = 1; i < isids_len; i++) {
char *s = initial_sid_to_string[i]; const char *s = initial_sid_to_string[i];
fprintf(fout, "#define SECINITSID_%s", s); fprintf(fout, "#define SECINITSID_%s", s);
for (j = 0; j < max(1, 40 - strlen(s)); j++) for (j = 0; j < max(1, 40 - strlen(s)); j++)
fprintf(fout, " "); fprintf(fout, " ");
......
...@@ -12,11 +12,6 @@ ...@@ -12,11 +12,6 @@
#include <linux/security.h> #include <linux/security.h>
static int cap_acct(struct file *file)
{
return 0;
}
static int cap_sysctl(ctl_table *table, int op) static int cap_sysctl(ctl_table *table, int op)
{ {
return 0; return 0;
...@@ -80,42 +75,16 @@ static int cap_sb_mount(char *dev_name, struct path *path, char *type, ...@@ -80,42 +75,16 @@ static int cap_sb_mount(char *dev_name, struct path *path, char *type,
return 0; return 0;
} }
static int cap_sb_check_sb(struct vfsmount *mnt, struct path *path)
{
return 0;
}
static int cap_sb_umount(struct vfsmount *mnt, int flags) static int cap_sb_umount(struct vfsmount *mnt, int flags)
{ {
return 0; return 0;
} }
static void cap_sb_umount_close(struct vfsmount *mnt)
{
}
static void cap_sb_umount_busy(struct vfsmount *mnt)
{
}
static void cap_sb_post_remount(struct vfsmount *mnt, unsigned long flags,
void *data)
{
}
static void cap_sb_post_addmount(struct vfsmount *mnt, struct path *path)
{
}
static int cap_sb_pivotroot(struct path *old_path, struct path *new_path) static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
{ {
return 0; return 0;
} }
static void cap_sb_post_pivotroot(struct path *old_path, struct path *new_path)
{
}
static int cap_sb_set_mnt_opts(struct super_block *sb, static int cap_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts) struct security_mnt_opts *opts)
{ {
...@@ -221,10 +190,6 @@ static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) ...@@ -221,10 +190,6 @@ static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
return 0; return 0;
} }
static void cap_inode_delete(struct inode *ino)
{
}
static void cap_inode_post_setxattr(struct dentry *dentry, const char *name, static void cap_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)
{ {
...@@ -403,10 +368,6 @@ static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) ...@@ -403,10 +368,6 @@ static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp)
return 0; return 0;
} }
static void cap_cred_commit(struct cred *new, const struct cred *old)
{
}
static void cap_cred_transfer(struct cred *new, const struct cred *old) static void cap_cred_transfer(struct cred *new, const struct cred *old)
{ {
} }
...@@ -426,16 +387,6 @@ static int cap_kernel_module_request(char *kmod_name) ...@@ -426,16 +387,6 @@ static int cap_kernel_module_request(char *kmod_name)
return 0; return 0;
} }
static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
return 0;
}
static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
{
return 0;
}
static int cap_task_setpgid(struct task_struct *p, pid_t pgid) static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
{ {
return 0; return 0;
...@@ -456,11 +407,6 @@ static void cap_task_getsecid(struct task_struct *p, u32 *secid) ...@@ -456,11 +407,6 @@ static void cap_task_getsecid(struct task_struct *p, u32 *secid)
*secid = 0; *secid = 0;
} }
static int cap_task_setgroups(struct group_info *group_info)
{
return 0;
}
static int cap_task_getioprio(struct task_struct *p) static int cap_task_getioprio(struct task_struct *p)
{ {
return 0; return 0;
...@@ -875,13 +821,6 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) ...@@ -875,13 +821,6 @@ static int cap_key_getsecurity(struct key *key, char **_buffer)
return 0; return 0;
} }
static int cap_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key)
{
return 0;
}
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
...@@ -915,13 +854,12 @@ static void cap_audit_rule_free(void *lsmrule) ...@@ -915,13 +854,12 @@ static void cap_audit_rule_free(void *lsmrule)
} \ } \
} while (0) } while (0)
void security_fixup_ops(struct security_operations *ops) void __init security_fixup_ops(struct security_operations *ops)
{ {
set_to_cap_if_null(ops, ptrace_access_check); set_to_cap_if_null(ops, ptrace_access_check);
set_to_cap_if_null(ops, ptrace_traceme); set_to_cap_if_null(ops, ptrace_traceme);
set_to_cap_if_null(ops, capget); set_to_cap_if_null(ops, capget);
set_to_cap_if_null(ops, capset); set_to_cap_if_null(ops, capset);
set_to_cap_if_null(ops, acct);
set_to_cap_if_null(ops, capable); set_to_cap_if_null(ops, capable);
set_to_cap_if_null(ops, quotactl); set_to_cap_if_null(ops, quotactl);
set_to_cap_if_null(ops, quota_on); set_to_cap_if_null(ops, quota_on);
...@@ -941,14 +879,8 @@ void security_fixup_ops(struct security_operations *ops) ...@@ -941,14 +879,8 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, sb_show_options); set_to_cap_if_null(ops, sb_show_options);
set_to_cap_if_null(ops, sb_statfs); set_to_cap_if_null(ops, sb_statfs);
set_to_cap_if_null(ops, sb_mount); set_to_cap_if_null(ops, sb_mount);
set_to_cap_if_null(ops, sb_check_sb);
set_to_cap_if_null(ops, sb_umount); set_to_cap_if_null(ops, sb_umount);
set_to_cap_if_null(ops, sb_umount_close);
set_to_cap_if_null(ops, sb_umount_busy);
set_to_cap_if_null(ops, sb_post_remount);
set_to_cap_if_null(ops, sb_post_addmount);
set_to_cap_if_null(ops, sb_pivotroot); set_to_cap_if_null(ops, sb_pivotroot);
set_to_cap_if_null(ops, sb_post_pivotroot);
set_to_cap_if_null(ops, sb_set_mnt_opts); set_to_cap_if_null(ops, sb_set_mnt_opts);
set_to_cap_if_null(ops, sb_clone_mnt_opts); set_to_cap_if_null(ops, sb_clone_mnt_opts);
set_to_cap_if_null(ops, sb_parse_opts_str); set_to_cap_if_null(ops, sb_parse_opts_str);
...@@ -968,7 +900,6 @@ void security_fixup_ops(struct security_operations *ops) ...@@ -968,7 +900,6 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, inode_permission); set_to_cap_if_null(ops, inode_permission);
set_to_cap_if_null(ops, inode_setattr); set_to_cap_if_null(ops, inode_setattr);
set_to_cap_if_null(ops, inode_getattr); set_to_cap_if_null(ops, inode_getattr);
set_to_cap_if_null(ops, inode_delete);
set_to_cap_if_null(ops, inode_setxattr); set_to_cap_if_null(ops, inode_setxattr);
set_to_cap_if_null(ops, inode_post_setxattr); set_to_cap_if_null(ops, inode_post_setxattr);
set_to_cap_if_null(ops, inode_getxattr); set_to_cap_if_null(ops, inode_getxattr);
...@@ -1009,19 +940,15 @@ void security_fixup_ops(struct security_operations *ops) ...@@ -1009,19 +940,15 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, cred_alloc_blank); set_to_cap_if_null(ops, cred_alloc_blank);
set_to_cap_if_null(ops, cred_free); set_to_cap_if_null(ops, cred_free);
set_to_cap_if_null(ops, cred_prepare); set_to_cap_if_null(ops, cred_prepare);
set_to_cap_if_null(ops, cred_commit);
set_to_cap_if_null(ops, cred_transfer); set_to_cap_if_null(ops, cred_transfer);
set_to_cap_if_null(ops, kernel_act_as); set_to_cap_if_null(ops, kernel_act_as);
set_to_cap_if_null(ops, kernel_create_files_as); set_to_cap_if_null(ops, kernel_create_files_as);
set_to_cap_if_null(ops, kernel_module_request); set_to_cap_if_null(ops, kernel_module_request);
set_to_cap_if_null(ops, task_setuid);
set_to_cap_if_null(ops, task_fix_setuid); set_to_cap_if_null(ops, task_fix_setuid);
set_to_cap_if_null(ops, task_setgid);
set_to_cap_if_null(ops, task_setpgid); set_to_cap_if_null(ops, task_setpgid);
set_to_cap_if_null(ops, task_getpgid); set_to_cap_if_null(ops, task_getpgid);
set_to_cap_if_null(ops, task_getsid); set_to_cap_if_null(ops, task_getsid);
set_to_cap_if_null(ops, task_getsecid); set_to_cap_if_null(ops, task_getsecid);
set_to_cap_if_null(ops, task_setgroups);
set_to_cap_if_null(ops, task_setnice); set_to_cap_if_null(ops, task_setnice);
set_to_cap_if_null(ops, task_setioprio); set_to_cap_if_null(ops, task_setioprio);
set_to_cap_if_null(ops, task_getioprio); set_to_cap_if_null(ops, task_getioprio);
...@@ -1113,7 +1040,6 @@ void security_fixup_ops(struct security_operations *ops) ...@@ -1113,7 +1040,6 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, key_free); set_to_cap_if_null(ops, key_free);
set_to_cap_if_null(ops, key_permission); set_to_cap_if_null(ops, key_permission);
set_to_cap_if_null(ops, key_getsecurity); set_to_cap_if_null(ops, key_getsecurity);
set_to_cap_if_null(ops, key_session_to_parent);
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
set_to_cap_if_null(ops, audit_rule_init); set_to_cap_if_null(ops, audit_rule_init);
......
...@@ -570,7 +570,7 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -570,7 +570,7 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
} }
if (!strncmp(name, XATTR_SECURITY_PREFIX, if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) && sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN)) !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
...@@ -596,7 +596,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) ...@@ -596,7 +596,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
} }
if (!strncmp(name, XATTR_SECURITY_PREFIX, if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) && sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN)) !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
...@@ -931,7 +931,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) ...@@ -931,7 +931,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
* @addr: address attempting to be mapped * @addr: address attempting to be mapped
* @addr_only: unused * @addr_only: unused
* *
* If the process is attempting to map memory below mmap_min_addr they need * If the process is attempting to map memory below dac_mmap_min_addr they need
* CAP_SYS_RAWIO. The other parameters to this function are unused by the * CAP_SYS_RAWIO. The other parameters to this function are unused by the
* capability security module. Returns 0 if this mapping should be allowed * capability security module. Returns 0 if this mapping should be allowed
* -EPERM if not. * -EPERM if not.
......
...@@ -470,7 +470,7 @@ struct cgroup_subsys devices_subsys = { ...@@ -470,7 +470,7 @@ struct cgroup_subsys devices_subsys = {
.name = "devices", .name = "devices",
.can_attach = devcgroup_can_attach, .can_attach = devcgroup_can_attach,
.create = devcgroup_create, .create = devcgroup_create,
.destroy = devcgroup_destroy, .destroy = devcgroup_destroy,
.populate = devcgroup_populate, .populate = devcgroup_populate,
.subsys_id = devices_subsys_id, .subsys_id = devices_subsys_id,
}; };
......
...@@ -2,15 +2,14 @@ ...@@ -2,15 +2,14 @@
# #
config IMA config IMA
bool "Integrity Measurement Architecture(IMA)" bool "Integrity Measurement Architecture(IMA)"
depends on ACPI
depends on SECURITY depends on SECURITY
select SECURITYFS select SECURITYFS
select CRYPTO select CRYPTO
select CRYPTO_HMAC select CRYPTO_HMAC
select CRYPTO_MD5 select CRYPTO_MD5
select CRYPTO_SHA1 select CRYPTO_SHA1
select TCG_TPM select TCG_TPM if !S390
select TCG_TIS select TCG_TIS if TCG_TPM
help help
The Trusted Computing Group(TCG) runtime Integrity The Trusted Computing Group(TCG) runtime Integrity
Measurement Architecture(IMA) maintains a list of hash Measurement Architecture(IMA) maintains a list of hash
......
...@@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; ...@@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
void ima_init_policy(void); void ima_init_policy(void);
void ima_update_policy(void); void ima_update_policy(void);
int ima_parse_add_rule(char *); ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void); void ima_delete_rules(void);
/* LSM based policy rules require audit */ /* LSM based policy rules require audit */
......
...@@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, ...@@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
return; return;
ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
current->pid, current_cred()->uid, current->pid, current_cred()->uid,
audit_get_loginuid(current), audit_get_loginuid(current),
audit_get_sessionid(current)); audit_get_sessionid(current));
......
...@@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc) ...@@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc)
desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(desc->tfm)) { if (IS_ERR(desc->tfm)) {
pr_info("failed to load %s transform: %ld\n", pr_info("IMA: failed to load %s transform: %ld\n",
ima_hash, PTR_ERR(desc->tfm)); ima_hash, PTR_ERR(desc->tfm));
rc = PTR_ERR(desc->tfm); rc = PTR_ERR(desc->tfm);
return rc; return rc;
...@@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr) ...@@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
return; return;
if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
pr_err("Error Communicating to TPM chip\n"); pr_err("IMA: Error Communicating to TPM chip\n");
} }
/* /*
......
...@@ -244,32 +244,34 @@ static const struct file_operations ima_ascii_measurements_ops = { ...@@ -244,32 +244,34 @@ static const struct file_operations ima_ascii_measurements_ops = {
static ssize_t ima_write_policy(struct file *file, const char __user *buf, static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos) size_t datalen, loff_t *ppos)
{ {
char *data; char *data = NULL;
int rc; ssize_t result;
if (datalen >= PAGE_SIZE) if (datalen >= PAGE_SIZE)
return -ENOMEM; datalen = PAGE_SIZE - 1;
if (*ppos != 0) {
/* No partial writes. */ /* No partial writes. */
return -EINVAL; result = -EINVAL;
} if (*ppos != 0)
goto out;
result = -ENOMEM;
data = kmalloc(datalen + 1, GFP_KERNEL); data = kmalloc(datalen + 1, GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; goto out;
if (copy_from_user(data, buf, datalen)) {
kfree(data);
return -EFAULT;
}
*(data + datalen) = '\0'; *(data + datalen) = '\0';
rc = ima_parse_add_rule(data);
if (rc < 0) {
datalen = -EINVAL;
valid_policy = 0;
}
result = -EFAULT;
if (copy_from_user(data, buf, datalen))
goto out;
result = ima_parse_add_rule(data);
out:
if (result < 0)
valid_policy = 0;
kfree(data); kfree(data);
return datalen; return result;
} }
static struct dentry *ima_dir; static struct dentry *ima_dir;
......
...@@ -80,17 +80,17 @@ void iint_free(struct kref *kref) ...@@ -80,17 +80,17 @@ void iint_free(struct kref *kref)
iint->version = 0; iint->version = 0;
iint->flags = 0UL; iint->flags = 0UL;
if (iint->readcount != 0) { if (iint->readcount != 0) {
printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__, printk(KERN_INFO "%s: readcount: %ld\n", __func__,
iint->readcount); iint->readcount);
iint->readcount = 0; iint->readcount = 0;
} }
if (iint->writecount != 0) { if (iint->writecount != 0) {
printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__, printk(KERN_INFO "%s: writecount: %ld\n", __func__,
iint->writecount); iint->writecount);
iint->writecount = 0; iint->writecount = 0;
} }
if (iint->opencount != 0) { if (iint->opencount != 0) {
printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__, printk(KERN_INFO "%s: opencount: %ld\n", __func__,
iint->opencount); iint->opencount);
iint->opencount = 0; iint->opencount = 0;
} }
......
...@@ -83,7 +83,7 @@ int __init ima_init(void) ...@@ -83,7 +83,7 @@ int __init ima_init(void)
ima_used_chip = 1; ima_used_chip = 1;
if (!ima_used_chip) if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n"); pr_info("IMA: No TPM chip found, activating TPM-bypass!\n");
ima_add_boot_aggregate(); /* boot aggregate must be first entry */ ima_add_boot_aggregate(); /* boot aggregate must be first entry */
ima_init_policy(); ima_init_policy();
......
...@@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, ...@@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
(iint->writecount < 0)) && (iint->writecount < 0)) &&
!ima_limit_imbalance(file)) { !ima_limit_imbalance(file)) {
printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
__FUNCTION__, iint->readcount, iint->writecount, __func__, iint->readcount, iint->writecount,
iint->opencount); iint->opencount);
dump_stack(); dump_stack();
} }
......
...@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, ...@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
{ {
int result; int result;
if (entry->lsm[lsm_rule].rule)
return -EINVAL;
entry->lsm[lsm_rule].type = audit_type; entry->lsm[lsm_rule].type = audit_type;
result = security_filter_rule_init(entry->lsm[lsm_rule].type, result = security_filter_rule_init(entry->lsm[lsm_rule].type,
Audit_equal, args, Audit_equal, args,
...@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, ...@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
return result; return result;
} }
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
{
audit_log_format(ab, "%s=", key);
audit_log_untrustedstring(ab, value);
audit_log_format(ab, " ");
}
static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
...@@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ...@@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
entry->action = -1; entry->uid = -1;
while ((p = strsep(&rule, " \n")) != NULL) { entry->action = UNKNOWN;
while ((p = strsep(&rule, " \t")) != NULL) {
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
int token; int token;
unsigned long lnum; unsigned long lnum;
if (result < 0) if (result < 0)
break; break;
if (!*p) if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
continue; continue;
token = match_token(p, policy_tokens, args); token = match_token(p, policy_tokens, args);
switch (token) { switch (token) {
case Opt_measure: case Opt_measure:
audit_log_format(ab, "%s ", "measure"); ima_log_string(ab, "action", "measure");
if (entry->action != UNKNOWN)
result = -EINVAL;
entry->action = MEASURE; entry->action = MEASURE;
break; break;
case Opt_dont_measure: case Opt_dont_measure:
audit_log_format(ab, "%s ", "dont_measure"); ima_log_string(ab, "action", "dont_measure");
if (entry->action != UNKNOWN)
result = -EINVAL;
entry->action = DONT_MEASURE; entry->action = DONT_MEASURE;
break; break;
case Opt_func: case Opt_func:
audit_log_format(ab, "func=%s ", args[0].from); ima_log_string(ab, "func", args[0].from);
if (entry->func)
result = -EINVAL;
if (strcmp(args[0].from, "FILE_CHECK") == 0) if (strcmp(args[0].from, "FILE_CHECK") == 0)
entry->func = FILE_CHECK; entry->func = FILE_CHECK;
/* PATH_CHECK is for backwards compat */ /* PATH_CHECK is for backwards compat */
...@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ...@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
entry->flags |= IMA_FUNC; entry->flags |= IMA_FUNC;
break; break;
case Opt_mask: case Opt_mask:
audit_log_format(ab, "mask=%s ", args[0].from); ima_log_string(ab, "mask", args[0].from);
if (entry->mask)
result = -EINVAL;
if ((strcmp(args[0].from, "MAY_EXEC")) == 0) if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
entry->mask = MAY_EXEC; entry->mask = MAY_EXEC;
else if (strcmp(args[0].from, "MAY_WRITE") == 0) else if (strcmp(args[0].from, "MAY_WRITE") == 0)
...@@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ...@@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
entry->flags |= IMA_MASK; entry->flags |= IMA_MASK;
break; break;
case Opt_fsmagic: case Opt_fsmagic:
audit_log_format(ab, "fsmagic=%s ", args[0].from); ima_log_string(ab, "fsmagic", args[0].from);
if (entry->fsmagic) {
result = -EINVAL;
break;
}
result = strict_strtoul(args[0].from, 16, result = strict_strtoul(args[0].from, 16,
&entry->fsmagic); &entry->fsmagic);
if (!result) if (!result)
entry->flags |= IMA_FSMAGIC; entry->flags |= IMA_FSMAGIC;
break; break;
case Opt_uid: case Opt_uid:
audit_log_format(ab, "uid=%s ", args[0].from); ima_log_string(ab, "uid", args[0].from);
if (entry->uid != -1) {
result = -EINVAL;
break;
}
result = strict_strtoul(args[0].from, 10, &lnum); result = strict_strtoul(args[0].from, 10, &lnum);
if (!result) { if (!result) {
entry->uid = (uid_t) lnum; entry->uid = (uid_t) lnum;
...@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ...@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
} }
break; break;
case Opt_obj_user: case Opt_obj_user:
audit_log_format(ab, "obj_user=%s ", args[0].from); ima_log_string(ab, "obj_user", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_USER, LSM_OBJ_USER,
AUDIT_OBJ_USER); AUDIT_OBJ_USER);
break; break;
case Opt_obj_role: case Opt_obj_role:
audit_log_format(ab, "obj_role=%s ", args[0].from); ima_log_string(ab, "obj_role", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_ROLE, LSM_OBJ_ROLE,
AUDIT_OBJ_ROLE); AUDIT_OBJ_ROLE);
break; break;
case Opt_obj_type: case Opt_obj_type:
audit_log_format(ab, "obj_type=%s ", args[0].from); ima_log_string(ab, "obj_type", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_OBJ_TYPE, LSM_OBJ_TYPE,
AUDIT_OBJ_TYPE); AUDIT_OBJ_TYPE);
break; break;
case Opt_subj_user: case Opt_subj_user:
audit_log_format(ab, "subj_user=%s ", args[0].from); ima_log_string(ab, "subj_user", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_USER, LSM_SUBJ_USER,
AUDIT_SUBJ_USER); AUDIT_SUBJ_USER);
break; break;
case Opt_subj_role: case Opt_subj_role:
audit_log_format(ab, "subj_role=%s ", args[0].from); ima_log_string(ab, "subj_role", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_ROLE, LSM_SUBJ_ROLE,
AUDIT_SUBJ_ROLE); AUDIT_SUBJ_ROLE);
break; break;
case Opt_subj_type: case Opt_subj_type:
audit_log_format(ab, "subj_type=%s ", args[0].from); ima_log_string(ab, "subj_type", args[0].from);
result = ima_lsm_rule_init(entry, args[0].from, result = ima_lsm_rule_init(entry, args[0].from,
LSM_SUBJ_TYPE, LSM_SUBJ_TYPE,
AUDIT_SUBJ_TYPE); AUDIT_SUBJ_TYPE);
break; break;
case Opt_err: case Opt_err:
audit_log_format(ab, "UNKNOWN=%s ", p); ima_log_string(ab, "UNKNOWN", p);
result = -EINVAL;
break; break;
} }
} }
if (entry->action == UNKNOWN) if (!result && (entry->action == UNKNOWN))
result = -EINVAL; result = -EINVAL;
audit_log_format(ab, "res=%d", !result ? 0 : 1); audit_log_format(ab, "res=%d", !!result);
audit_log_end(ab); audit_log_end(ab);
return result; return result;
} }
...@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ...@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
* @rule - ima measurement policy rule * @rule - ima measurement policy rule
* *
* Uses a mutex to protect the policy list from multiple concurrent writers. * Uses a mutex to protect the policy list from multiple concurrent writers.
* Returns 0 on success, an error code on failure. * Returns the length of the rule parsed, an error code on failure
*/ */
int ima_parse_add_rule(char *rule) ssize_t ima_parse_add_rule(char *rule)
{ {
const char *op = "update_policy"; const char *op = "update_policy";
char *p;
struct ima_measure_rule_entry *entry; struct ima_measure_rule_entry *entry;
int result = 0; ssize_t result, len;
int audit_info = 0; int audit_info = 0;
/* Prevent installed policy from changing */ /* Prevent installed policy from changing */
...@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule) ...@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule)
INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->list);
result = ima_parse_rule(rule, entry); p = strsep(&rule, "\n");
if (!result) { len = strlen(p) + 1;
mutex_lock(&ima_measure_mutex);
list_add_tail(&entry->list, &measure_policy_rules); if (*p == '#') {
mutex_unlock(&ima_measure_mutex); kfree(entry);
} else { return len;
}
result = ima_parse_rule(p, entry);
if (result) {
kfree(entry); kfree(entry);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
NULL, op, "invalid policy", result, NULL, op, "invalid policy", result,
audit_info); audit_info);
return result;
} }
return result;
mutex_lock(&ima_measure_mutex);
list_add_tail(&entry->list, &measure_policy_rules);
mutex_unlock(&ima_measure_mutex);
return len;
} }
/* ima_delete_rules called to cleanup invalid policy */ /* ima_delete_rules called to cleanup invalid policy */
......
...@@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) ...@@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
qe = kmalloc(sizeof(*qe), GFP_KERNEL); qe = kmalloc(sizeof(*qe), GFP_KERNEL);
if (qe == NULL) { if (qe == NULL) {
pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n");
return -ENOMEM; return -ENOMEM;
} }
qe->entry = entry; qe->entry = entry;
...@@ -94,7 +94,7 @@ static int ima_pcr_extend(const u8 *hash) ...@@ -94,7 +94,7 @@ static int ima_pcr_extend(const u8 *hash)
result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
if (result != 0) if (result != 0)
pr_err("Error Communicating to TPM chip\n"); pr_err("IMA: Error Communicating to TPM chip\n");
return result; return result;
} }
......
...@@ -87,7 +87,16 @@ extern wait_queue_head_t request_key_conswq; ...@@ -87,7 +87,16 @@ extern wait_queue_head_t request_key_conswq;
extern struct key_type *key_type_lookup(const char *type); extern struct key_type *key_type_lookup(const char *type);
extern void key_type_put(struct key_type *ktype); extern void key_type_put(struct key_type *ktype);
extern int __key_link(struct key *keyring, struct key *key); extern int __key_link_begin(struct key *keyring,
const struct key_type *type,
const char *description,
struct keyring_list **_prealloc);
extern int __key_link_check_live_key(struct key *keyring, struct key *key);
extern void __key_link(struct key *keyring, struct key *key,
struct keyring_list **_prealloc);
extern void __key_link_end(struct key *keyring,
struct key_type *type,
struct keyring_list *prealloc);
extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *type, const struct key_type *type,
......
...@@ -355,7 +355,7 @@ EXPORT_SYMBOL(key_alloc); ...@@ -355,7 +355,7 @@ EXPORT_SYMBOL(key_alloc);
*/ */
int key_payload_reserve(struct key *key, size_t datalen) int key_payload_reserve(struct key *key, size_t datalen)
{ {
int delta = (int) datalen - key->datalen; int delta = (int)datalen - key->datalen;
int ret = 0; int ret = 0;
key_check(key); key_check(key);
...@@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key, ...@@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key,
const void *data, const void *data,
size_t datalen, size_t datalen,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey,
struct keyring_list **_prealloc)
{ {
int ret, awaken; int ret, awaken;
...@@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key, ...@@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key,
/* and link it into the destination keyring */ /* and link it into the destination keyring */
if (keyring) if (keyring)
ret = __key_link(keyring, key); __key_link(keyring, key, _prealloc);
/* disable the authorisation key */ /* disable the authorisation key */
if (authkey) if (authkey)
...@@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key, ...@@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct keyring_list *prealloc;
int ret; int ret;
if (keyring) if (keyring) {
down_write(&keyring->sem); ret = __key_link_begin(keyring, key->type, key->description,
&prealloc);
if (ret < 0)
return ret;
}
ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey); ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
&prealloc);
if (keyring) if (keyring)
up_write(&keyring->sem); __key_link_end(keyring, key->type, prealloc);
return ret; return ret;
...@@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key, ...@@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct keyring_list *prealloc;
struct timespec now; struct timespec now;
int ret, awaken; int ret, awaken, link_ret = 0;
key_check(key); key_check(key);
key_check(keyring); key_check(keyring);
...@@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key, ...@@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key,
ret = -EBUSY; ret = -EBUSY;
if (keyring) if (keyring)
down_write(&keyring->sem); link_ret = __key_link_begin(keyring, key->type,
key->description, &prealloc);
mutex_lock(&key_construction_mutex); mutex_lock(&key_construction_mutex);
...@@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key, ...@@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key,
ret = 0; ret = 0;
/* and link it into the destination keyring */ /* and link it into the destination keyring */
if (keyring) if (keyring && link_ret == 0)
ret = __key_link(keyring, key); __key_link(keyring, key, &prealloc);
/* disable the authorisation key */ /* disable the authorisation key */
if (authkey) if (authkey)
...@@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key, ...@@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key,
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
if (keyring) if (keyring)
up_write(&keyring->sem); __key_link_end(keyring, key->type, prealloc);
/* wake up anyone waiting for a key to be constructed */ /* wake up anyone waiting for a key to be constructed */
if (awaken) if (awaken)
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret; return ret == 0 ? link_ret : ret;
} /* end key_negate_and_link() */ } /* end key_negate_and_link() */
...@@ -749,6 +758,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -749,6 +758,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_perm_t perm, key_perm_t perm,
unsigned long flags) unsigned long flags)
{ {
struct keyring_list *prealloc;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key_type *ktype; struct key_type *ktype;
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
...@@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
if (keyring->type != &key_type_keyring) if (keyring->type != &key_type_keyring)
goto error_2; goto error_2;
down_write(&keyring->sem); ret = __key_link_begin(keyring, ktype, description, &prealloc);
if (ret < 0)
goto error_2;
/* if we're going to allocate a new key, we're going to have /* if we're going to allocate a new key, we're going to have
* to modify the keyring */ * to modify the keyring */
...@@ -817,7 +829,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -817,7 +829,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
} }
/* instantiate it and link it into the target keyring */ /* instantiate it and link it into the target keyring */
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
&prealloc);
if (ret < 0) { if (ret < 0) {
key_put(key); key_put(key);
key_ref = ERR_PTR(ret); key_ref = ERR_PTR(ret);
...@@ -827,7 +840,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -827,7 +840,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
error_3: error_3:
up_write(&keyring->sem); __key_link_end(keyring, ktype, prealloc);
error_2: error_2:
key_type_put(ktype); key_type_put(ktype);
error: error:
...@@ -837,7 +850,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -837,7 +850,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* we found a matching key, so we're going to try to update it /* we found a matching key, so we're going to try to update it
* - we can drop the locks first as we have the key pinned * - we can drop the locks first as we have the key pinned
*/ */
up_write(&keyring->sem); __key_link_end(keyring, ktype, prealloc);
key_type_put(ktype); key_type_put(ktype);
key_ref = __key_update(key_ref, payload, plen); key_ref = __key_update(key_ref, payload, plen);
......
...@@ -212,15 +212,15 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, ...@@ -212,15 +212,15 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
ret = key->serial; ret = key->serial;
key_put(key); key_put(key);
error5: error5:
key_type_put(ktype); key_type_put(ktype);
error4: error4:
key_ref_put(dest_ref); key_ref_put(dest_ref);
error3: error3:
kfree(callout_info); kfree(callout_info);
error2: error2:
kfree(description); kfree(description);
error: error:
return ret; return ret;
} /* end sys_request_key() */ } /* end sys_request_key() */
...@@ -246,7 +246,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) ...@@ -246,7 +246,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
ret = key_ref_to_ptr(key_ref)->serial; ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref); key_ref_put(key_ref);
error: error:
return ret; return ret;
} /* end keyctl_get_keyring_ID() */ } /* end keyctl_get_keyring_ID() */
...@@ -275,7 +275,7 @@ long keyctl_join_session_keyring(const char __user *_name) ...@@ -275,7 +275,7 @@ long keyctl_join_session_keyring(const char __user *_name)
ret = join_session_keyring(name); ret = join_session_keyring(name);
kfree(name); kfree(name);
error: error:
return ret; return ret;
} /* end keyctl_join_session_keyring() */ } /* end keyctl_join_session_keyring() */
...@@ -322,9 +322,9 @@ long keyctl_update_key(key_serial_t id, ...@@ -322,9 +322,9 @@ long keyctl_update_key(key_serial_t id,
ret = key_update(key_ref, payload, plen); ret = key_update(key_ref, payload, plen);
key_ref_put(key_ref); key_ref_put(key_ref);
error2: error2:
kfree(payload); kfree(payload);
error: error:
return ret; return ret;
} /* end keyctl_update_key() */ } /* end keyctl_update_key() */
...@@ -356,7 +356,7 @@ long keyctl_revoke_key(key_serial_t id) ...@@ -356,7 +356,7 @@ long keyctl_revoke_key(key_serial_t id)
ret = 0; ret = 0;
key_ref_put(key_ref); key_ref_put(key_ref);
error: error:
return ret; return ret;
} /* end keyctl_revoke_key() */ } /* end keyctl_revoke_key() */
...@@ -381,7 +381,7 @@ long keyctl_keyring_clear(key_serial_t ringid) ...@@ -381,7 +381,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
ret = keyring_clear(key_ref_to_ptr(keyring_ref)); ret = keyring_clear(key_ref_to_ptr(keyring_ref));
key_ref_put(keyring_ref); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
} /* end keyctl_keyring_clear() */ } /* end keyctl_keyring_clear() */
...@@ -413,9 +413,9 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) ...@@ -413,9 +413,9 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
key_ref_put(key_ref); key_ref_put(key_ref);
error2: error2:
key_ref_put(keyring_ref); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
} /* end keyctl_keyring_link() */ } /* end keyctl_keyring_link() */
...@@ -447,9 +447,9 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) ...@@ -447,9 +447,9 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
key_ref_put(key_ref); key_ref_put(key_ref);
error2: error2:
key_ref_put(keyring_ref); key_ref_put(keyring_ref);
error: error:
return ret; return ret;
} /* end keyctl_keyring_unlink() */ } /* end keyctl_keyring_unlink() */
...@@ -529,9 +529,9 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -529,9 +529,9 @@ long keyctl_describe_key(key_serial_t keyid,
} }
kfree(tmpbuf); kfree(tmpbuf);
error2: error2:
key_ref_put(key_ref); key_ref_put(key_ref);
error: error:
return ret; return ret;
} /* end keyctl_describe_key() */ } /* end keyctl_describe_key() */
...@@ -616,17 +616,17 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -616,17 +616,17 @@ long keyctl_keyring_search(key_serial_t ringid,
ret = key_ref_to_ptr(key_ref)->serial; ret = key_ref_to_ptr(key_ref)->serial;
error6: error6:
key_ref_put(key_ref); key_ref_put(key_ref);
error5: error5:
key_type_put(ktype); key_type_put(ktype);
error4: error4:
key_ref_put(dest_ref); key_ref_put(dest_ref);
error3: error3:
key_ref_put(keyring_ref); key_ref_put(keyring_ref);
error2: error2:
kfree(description); kfree(description);
error: error:
return ret; return ret;
} /* end keyctl_keyring_search() */ } /* end keyctl_keyring_search() */
...@@ -673,7 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) ...@@ -673,7 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
} }
/* the key is probably readable - now try to read it */ /* the key is probably readable - now try to read it */
can_read_key: can_read_key:
ret = key_validate(key); ret = key_validate(key);
if (ret == 0) { if (ret == 0) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
...@@ -686,9 +686,9 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) ...@@ -686,9 +686,9 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
} }
} }
error2: error2:
key_put(key); key_put(key);
error: error:
return ret; return ret;
} /* end keyctl_read_key() */ } /* end keyctl_read_key() */
...@@ -1282,26 +1282,19 @@ long keyctl_session_to_parent(void) ...@@ -1282,26 +1282,19 @@ long keyctl_session_to_parent(void)
/* the parent must have the same effective ownership and mustn't be /* the parent must have the same effective ownership and mustn't be
* SUID/SGID */ * SUID/SGID */
if (pcred-> uid != mycred->euid || if (pcred->uid != mycred->euid ||
pcred->euid != mycred->euid || pcred->euid != mycred->euid ||
pcred->suid != mycred->euid || pcred->suid != mycred->euid ||
pcred-> gid != mycred->egid || pcred->gid != mycred->egid ||
pcred->egid != mycred->egid || pcred->egid != mycred->egid ||
pcred->sgid != mycred->egid) pcred->sgid != mycred->egid)
goto not_permitted; goto not_permitted;
/* the keyrings must have the same UID */ /* the keyrings must have the same UID */
if (pcred ->tgcred->session_keyring->uid != mycred->euid || if (pcred->tgcred->session_keyring->uid != mycred->euid ||
mycred->tgcred->session_keyring->uid != mycred->euid) mycred->tgcred->session_keyring->uid != mycred->euid)
goto not_permitted; goto not_permitted;
/* the LSM must permit the replacement of the parent's keyring with the
* keyring from this process */
ret = security_key_session_to_parent(mycred, pcred,
key_ref_to_ptr(keyring_r));
if (ret < 0)
goto not_permitted;
/* if there's an already pending keyring replacement, then we replace /* if there's an already pending keyring replacement, then we replace
* that */ * that */
oldcred = parent->replacement_session_keyring; oldcred = parent->replacement_session_keyring;
......
This diff is collapsed.
...@@ -109,7 +109,7 @@ int key_validate(struct key *key) ...@@ -109,7 +109,7 @@ int key_validate(struct key *key)
} }
} }
error: error:
return ret; return ret;
} /* end key_validate() */ } /* end key_validate() */
......
...@@ -306,7 +306,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) ...@@ -306,7 +306,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
{ {
(*_pos)++; (*_pos)++;
return key_user_next((struct rb_node *) v); return key_user_next((struct rb_node *)v);
} }
static void proc_key_users_stop(struct seq_file *p, void *v) static void proc_key_users_stop(struct seq_file *p, void *v)
......
...@@ -508,7 +508,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -508,7 +508,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ret = install_thread_keyring(); ret = install_thread_keyring();
if (ret < 0) { if (ret < 0) {
key = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error; goto error;
} }
goto reget_creds; goto reget_creds;
...@@ -526,7 +526,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -526,7 +526,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ret = install_process_keyring(); ret = install_process_keyring();
if (ret < 0) { if (ret < 0) {
key = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error; goto error;
} }
goto reget_creds; goto reget_creds;
...@@ -585,7 +585,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -585,7 +585,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
case KEY_SPEC_GROUP_KEYRING: case KEY_SPEC_GROUP_KEYRING:
/* group keyrings are not yet supported */ /* group keyrings are not yet supported */
key = ERR_PTR(-EINVAL); key_ref = ERR_PTR(-EINVAL);
goto error; goto error;
case KEY_SPEC_REQKEY_AUTH_KEY: case KEY_SPEC_REQKEY_AUTH_KEY:
......
...@@ -299,12 +299,15 @@ static int construct_alloc_key(struct key_type *type, ...@@ -299,12 +299,15 @@ static int construct_alloc_key(struct key_type *type,
struct key_user *user, struct key_user *user,
struct key **_key) struct key **_key)
{ {
struct keyring_list *prealloc;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
int ret;
kenter("%s,%s,,,", type->name, description); kenter("%s,%s,,,", type->name, description);
*_key = NULL;
mutex_lock(&user->cons_lock); mutex_lock(&user->cons_lock);
key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
...@@ -314,8 +317,12 @@ static int construct_alloc_key(struct key_type *type, ...@@ -314,8 +317,12 @@ static int construct_alloc_key(struct key_type *type,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
if (dest_keyring) if (dest_keyring) {
down_write(&dest_keyring->sem); ret = __key_link_begin(dest_keyring, type, description,
&prealloc);
if (ret < 0)
goto link_prealloc_failed;
}
/* attach the key to the destination keyring under lock, but we do need /* attach the key to the destination keyring under lock, but we do need
* to do another check just in case someone beat us to it whilst we * to do another check just in case someone beat us to it whilst we
...@@ -327,31 +334,49 @@ static int construct_alloc_key(struct key_type *type, ...@@ -327,31 +334,49 @@ static int construct_alloc_key(struct key_type *type,
goto key_already_present; goto key_already_present;
if (dest_keyring) if (dest_keyring)
__key_link(dest_keyring, key); __key_link(dest_keyring, key, &prealloc);
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
if (dest_keyring) if (dest_keyring)
up_write(&dest_keyring->sem); __key_link_end(dest_keyring, type, prealloc);
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
*_key = key; *_key = key;
kleave(" = 0 [%d]", key_serial(key)); kleave(" = 0 [%d]", key_serial(key));
return 0; return 0;
/* the key is now present - we tell the caller that we found it by
* returning -EINPROGRESS */
key_already_present: key_already_present:
key_put(key);
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
key = key_ref_to_ptr(key_ref);
if (dest_keyring) { if (dest_keyring) {
__key_link(dest_keyring, key_ref_to_ptr(key_ref)); ret = __key_link_check_live_key(dest_keyring, key);
up_write(&dest_keyring->sem); if (ret == 0)
__key_link(dest_keyring, key, &prealloc);
__key_link_end(dest_keyring, type, prealloc);
if (ret < 0)
goto link_check_failed;
} }
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
key_put(key); *_key = key;
*_key = key = key_ref_to_ptr(key_ref);
kleave(" = -EINPROGRESS [%d]", key_serial(key)); kleave(" = -EINPROGRESS [%d]", key_serial(key));
return -EINPROGRESS; return -EINPROGRESS;
link_check_failed:
mutex_unlock(&user->cons_lock);
key_put(key);
kleave(" = %d [linkcheck]", ret);
return ret;
link_prealloc_failed:
up_write(&dest_keyring->sem);
mutex_unlock(&user->cons_lock);
kleave(" = %d [prelink]", ret);
return ret;
alloc_failed: alloc_failed:
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
*_key = NULL;
kleave(" = %ld", PTR_ERR(key)); kleave(" = %ld", PTR_ERR(key));
return PTR_ERR(key); return PTR_ERR(key);
} }
...@@ -390,6 +415,10 @@ static struct key *construct_key_and_link(struct key_type *type, ...@@ -390,6 +415,10 @@ static struct key *construct_key_and_link(struct key_type *type,
kdebug("cons failed"); kdebug("cons failed");
goto construction_failed; goto construction_failed;
} }
} else if (ret == -EINPROGRESS) {
ret = 0;
} else {
key = ERR_PTR(ret);
} }
key_put(dest_keyring); key_put(dest_keyring);
...@@ -422,6 +451,7 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -422,6 +451,7 @@ struct key *request_key_and_link(struct key_type *type,
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
int ret;
kenter("%s,%s,%p,%zu,%p,%p,%lx", kenter("%s,%s,%p,%zu,%p,%p,%lx",
type->name, description, callout_info, callout_len, aux, type->name, description, callout_info, callout_len, aux,
...@@ -435,8 +465,13 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -435,8 +465,13 @@ struct key *request_key_and_link(struct key_type *type,
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
if (dest_keyring) { if (dest_keyring) {
construct_get_dest_keyring(&dest_keyring); construct_get_dest_keyring(&dest_keyring);
key_link(dest_keyring, key); ret = key_link(dest_keyring, key);
key_put(dest_keyring); key_put(dest_keyring);
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
goto error;
}
} }
} else if (PTR_ERR(key_ref) != -EAGAIN) { } else if (PTR_ERR(key_ref) != -EAGAIN) {
key = ERR_CAST(key_ref); key = ERR_CAST(key_ref);
......
...@@ -221,7 +221,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, ...@@ -221,7 +221,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
} }
switch (a->type) { switch (a->type) {
case LSM_AUDIT_NO_AUDIT: case LSM_AUDIT_DATA_NONE:
return; return;
case LSM_AUDIT_DATA_IPC: case LSM_AUDIT_DATA_IPC:
audit_log_format(ab, " key=%d ", a->u.ipc_id); audit_log_format(ab, " key=%d ", a->u.ipc_id);
......
...@@ -23,14 +23,14 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = ...@@ -23,14 +23,14 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY; CONFIG_DEFAULT_SECURITY;
/* things that live in capability.c */ /* things that live in capability.c */
extern void security_fixup_ops(struct security_operations *ops); extern void __init security_fixup_ops(struct security_operations *ops);
static struct security_operations *security_ops; static struct security_operations *security_ops;
static struct security_operations default_security_ops = { static struct security_operations default_security_ops = {
.name = "default", .name = "default",
}; };
static inline int verify(struct security_operations *ops) static inline int __init verify(struct security_operations *ops)
{ {
/* verify the security_operations structure exists */ /* verify the security_operations structure exists */
if (!ops) if (!ops)
...@@ -117,7 +117,7 @@ int __init security_module_enable(struct security_operations *ops) ...@@ -117,7 +117,7 @@ int __init security_module_enable(struct security_operations *ops)
* If there is already a security module registered with the kernel, * If there is already a security module registered with the kernel,
* an error will be returned. Otherwise %0 is returned on success. * an error will be returned. Otherwise %0 is returned on success.
*/ */
int register_security(struct security_operations *ops) int __init register_security(struct security_operations *ops)
{ {
if (verify(ops)) { if (verify(ops)) {
printk(KERN_DEBUG "%s could not verify " printk(KERN_DEBUG "%s could not verify "
...@@ -190,11 +190,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap) ...@@ -190,11 +190,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
return ret; return ret;
} }
int security_acct(struct file *file)
{
return security_ops->acct(file);
}
int security_sysctl(struct ctl_table *table, int op) int security_sysctl(struct ctl_table *table, int op)
{ {
return security_ops->sysctl(table, op); return security_ops->sysctl(table, op);
...@@ -306,46 +301,16 @@ int security_sb_mount(char *dev_name, struct path *path, ...@@ -306,46 +301,16 @@ int security_sb_mount(char *dev_name, struct path *path,
return security_ops->sb_mount(dev_name, path, type, flags, data); return security_ops->sb_mount(dev_name, path, type, flags, data);
} }
int security_sb_check_sb(struct vfsmount *mnt, struct path *path)
{
return security_ops->sb_check_sb(mnt, path);
}
int security_sb_umount(struct vfsmount *mnt, int flags) int security_sb_umount(struct vfsmount *mnt, int flags)
{ {
return security_ops->sb_umount(mnt, flags); return security_ops->sb_umount(mnt, flags);
} }
void security_sb_umount_close(struct vfsmount *mnt)
{
security_ops->sb_umount_close(mnt);
}
void security_sb_umount_busy(struct vfsmount *mnt)
{
security_ops->sb_umount_busy(mnt);
}
void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data)
{
security_ops->sb_post_remount(mnt, flags, data);
}
void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint)
{
security_ops->sb_post_addmount(mnt, mountpoint);
}
int security_sb_pivotroot(struct path *old_path, struct path *new_path) int security_sb_pivotroot(struct path *old_path, struct path *new_path)
{ {
return security_ops->sb_pivotroot(old_path, new_path); return security_ops->sb_pivotroot(old_path, new_path);
} }
void security_sb_post_pivotroot(struct path *old_path, struct path *new_path)
{
security_ops->sb_post_pivotroot(old_path, new_path);
}
int security_sb_set_mnt_opts(struct super_block *sb, int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts) struct security_mnt_opts *opts)
{ {
...@@ -580,13 +545,6 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) ...@@ -580,13 +545,6 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
return security_ops->inode_getattr(mnt, dentry); return security_ops->inode_getattr(mnt, dentry);
} }
void security_inode_delete(struct inode *inode)
{
if (unlikely(IS_PRIVATE(inode)))
return;
security_ops->inode_delete(inode);
}
int security_inode_setxattr(struct dentry *dentry, const char *name, int security_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
...@@ -749,11 +707,6 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) ...@@ -749,11 +707,6 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
return security_ops->cred_prepare(new, old, gfp); return security_ops->cred_prepare(new, old, gfp);
} }
void security_commit_creds(struct cred *new, const struct cred *old)
{
security_ops->cred_commit(new, old);
}
void security_transfer_creds(struct cred *new, const struct cred *old) void security_transfer_creds(struct cred *new, const struct cred *old)
{ {
security_ops->cred_transfer(new, old); security_ops->cred_transfer(new, old);
...@@ -774,22 +727,12 @@ int security_kernel_module_request(char *kmod_name) ...@@ -774,22 +727,12 @@ int security_kernel_module_request(char *kmod_name)
return security_ops->kernel_module_request(kmod_name); return security_ops->kernel_module_request(kmod_name);
} }
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
return security_ops->task_setuid(id0, id1, id2, flags);
}
int security_task_fix_setuid(struct cred *new, const struct cred *old, int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags) int flags)
{ {
return security_ops->task_fix_setuid(new, old, flags); return security_ops->task_fix_setuid(new, old, flags);
} }
int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
{
return security_ops->task_setgid(id0, id1, id2, flags);
}
int security_task_setpgid(struct task_struct *p, pid_t pgid) int security_task_setpgid(struct task_struct *p, pid_t pgid)
{ {
return security_ops->task_setpgid(p, pgid); return security_ops->task_setpgid(p, pgid);
...@@ -811,11 +754,6 @@ void security_task_getsecid(struct task_struct *p, u32 *secid) ...@@ -811,11 +754,6 @@ void security_task_getsecid(struct task_struct *p, u32 *secid)
} }
EXPORT_SYMBOL(security_task_getsecid); EXPORT_SYMBOL(security_task_getsecid);
int security_task_setgroups(struct group_info *group_info)
{
return security_ops->task_setgroups(group_info);
}
int security_task_setnice(struct task_struct *p, int nice) int security_task_setnice(struct task_struct *p, int nice)
{ {
return security_ops->task_setnice(p, nice); return security_ops->task_setnice(p, nice);
...@@ -1319,13 +1257,6 @@ int security_key_getsecurity(struct key *key, char **_buffer) ...@@ -1319,13 +1257,6 @@ int security_key_getsecurity(struct key *key, char **_buffer)
return security_ops->key_getsecurity(key, _buffer); return security_ops->key_getsecurity(key, _buffer);
} }
int security_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key)
{
return security_ops->key_session_to_parent(cred, parent_cred, key);
}
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
......
...@@ -499,8 +499,7 @@ void avc_audit(u32 ssid, u32 tsid, ...@@ -499,8 +499,7 @@ void avc_audit(u32 ssid, u32 tsid,
return; return;
if (!a) { if (!a) {
a = &stack_data; a = &stack_data;
memset(a, 0, sizeof(*a)); COMMON_AUDIT_DATA_INIT(a, NONE);
a->type = LSM_AUDIT_NO_AUDIT;
} }
a->selinux_audit_data.tclass = tclass; a->selinux_audit_data.tclass = tclass;
a->selinux_audit_data.requested = requested; a->selinux_audit_data.requested = requested;
......
...@@ -293,28 +293,28 @@ static void superblock_free_security(struct super_block *sb) ...@@ -293,28 +293,28 @@ static void superblock_free_security(struct super_block *sb)
static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{ {
struct sk_security_struct *ssec; struct sk_security_struct *sksec;
ssec = kzalloc(sizeof(*ssec), priority); sksec = kzalloc(sizeof(*sksec), priority);
if (!ssec) if (!sksec)
return -ENOMEM; return -ENOMEM;
ssec->peer_sid = SECINITSID_UNLABELED; sksec->peer_sid = SECINITSID_UNLABELED;
ssec->sid = SECINITSID_UNLABELED; sksec->sid = SECINITSID_UNLABELED;
sk->sk_security = ssec; sk->sk_security = sksec;
selinux_netlbl_sk_security_reset(ssec); selinux_netlbl_sk_security_reset(sksec);
return 0; return 0;
} }
static void sk_free_security(struct sock *sk) static void sk_free_security(struct sock *sk)
{ {
struct sk_security_struct *ssec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
sk->sk_security = NULL; sk->sk_security = NULL;
selinux_netlbl_sk_security_free(ssec); selinux_netlbl_sk_security_free(sksec);
kfree(ssec); kfree(sksec);
} }
/* The security server must be initialized before /* The security server must be initialized before
...@@ -323,7 +323,7 @@ extern int ss_initialized; ...@@ -323,7 +323,7 @@ extern int ss_initialized;
/* The file system's label must be initialized prior to use. */ /* The file system's label must be initialized prior to use. */
static char *labeling_behaviors[6] = { static const char *labeling_behaviors[6] = {
"uses xattr", "uses xattr",
"uses transition SIDs", "uses transition SIDs",
"uses task SIDs", "uses task SIDs",
...@@ -2999,13 +2999,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, ...@@ -2999,13 +2999,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
return file_has_perm(cred, file, av); return file_has_perm(cred, file, av);
} }
static int default_noexec;
static int file_map_prot_check(struct file *file, unsigned long prot, int shared) static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
int rc = 0; int rc = 0;
#ifndef CONFIG_PPC32 if (default_noexec &&
if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
/* /*
* We are making executable an anonymous mapping or a * We are making executable an anonymous mapping or a
* private file mapping that will also be writable. * private file mapping that will also be writable.
...@@ -3015,7 +3017,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared ...@@ -3015,7 +3017,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
if (rc) if (rc)
goto error; goto error;
} }
#endif
if (file) { if (file) {
/* read access is always possible with a mapping */ /* read access is always possible with a mapping */
...@@ -3076,8 +3077,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, ...@@ -3076,8 +3077,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (selinux_checkreqprot) if (selinux_checkreqprot)
prot = reqprot; prot = reqprot;
#ifndef CONFIG_PPC32 if (default_noexec &&
if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
int rc = 0; int rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk && if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) { vma->vm_end <= vma->vm_mm->brk) {
...@@ -3099,7 +3100,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, ...@@ -3099,7 +3100,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (rc) if (rc)
return rc; return rc;
} }
#endif
return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
} }
...@@ -4002,7 +4002,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, ...@@ -4002,7 +4002,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
struct socket *other, struct socket *other,
struct sock *newsk) struct sock *newsk)
{ {
struct sk_security_struct *ssec; struct sk_security_struct *sksec;
struct inode_security_struct *isec; struct inode_security_struct *isec;
struct inode_security_struct *other_isec; struct inode_security_struct *other_isec;
struct common_audit_data ad; struct common_audit_data ad;
...@@ -4021,13 +4021,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, ...@@ -4021,13 +4021,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
return err; return err;
/* connecting socket */ /* connecting socket */
ssec = sock->sk->sk_security; sksec = sock->sk->sk_security;
ssec->peer_sid = other_isec->sid; sksec->peer_sid = other_isec->sid;
/* server child socket */ /* server child socket */
ssec = newsk->sk_security; sksec = newsk->sk_security;
ssec->peer_sid = isec->sid; sksec->peer_sid = isec->sid;
err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
return err; return err;
} }
...@@ -4190,7 +4190,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op ...@@ -4190,7 +4190,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
int err = 0; int err = 0;
char *scontext; char *scontext;
u32 scontext_len; u32 scontext_len;
struct sk_security_struct *ssec; struct sk_security_struct *sksec;
struct inode_security_struct *isec; struct inode_security_struct *isec;
u32 peer_sid = SECSID_NULL; u32 peer_sid = SECSID_NULL;
...@@ -4198,8 +4198,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op ...@@ -4198,8 +4198,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
isec->sclass == SECCLASS_TCP_SOCKET) { isec->sclass == SECCLASS_TCP_SOCKET) {
ssec = sock->sk->sk_security; sksec = sock->sk->sk_security;
peer_sid = ssec->peer_sid; peer_sid = sksec->peer_sid;
} }
if (peer_sid == SECSID_NULL) { if (peer_sid == SECSID_NULL) {
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
...@@ -4266,14 +4266,14 @@ static void selinux_sk_free_security(struct sock *sk) ...@@ -4266,14 +4266,14 @@ static void selinux_sk_free_security(struct sock *sk)
static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
{ {
struct sk_security_struct *ssec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
struct sk_security_struct *newssec = newsk->sk_security; struct sk_security_struct *newsksec = newsk->sk_security;
newssec->sid = ssec->sid; newsksec->sid = sksec->sid;
newssec->peer_sid = ssec->peer_sid; newsksec->peer_sid = sksec->peer_sid;
newssec->sclass = ssec->sclass; newsksec->sclass = sksec->sclass;
selinux_netlbl_sk_security_reset(newssec); selinux_netlbl_sk_security_reset(newsksec);
} }
static void selinux_sk_getsecid(struct sock *sk, u32 *secid) static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
...@@ -5662,6 +5662,8 @@ static __init int selinux_init(void) ...@@ -5662,6 +5662,8 @@ static __init int selinux_init(void)
/* Set the security state for the initial task. */ /* Set the security state for the initial task. */
cred_init_security(); cred_init_security();
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
sel_inode_cache = kmem_cache_create("selinux_inode_security", sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct), sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
......
/* This file is automatically generated. Do not edit. */ /* This file is automatically generated. Do not edit. */
static char *initial_sid_to_string[] = static const char *initial_sid_to_string[] =
{ {
"null", "null",
"kernel", "kernel",
......
...@@ -42,8 +42,8 @@ void selinux_netlbl_cache_invalidate(void); ...@@ -42,8 +42,8 @@ void selinux_netlbl_cache_invalidate(void);
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec);
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec); void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec);
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family, u16 family,
...@@ -79,13 +79,13 @@ static inline void selinux_netlbl_err(struct sk_buff *skb, ...@@ -79,13 +79,13 @@ static inline void selinux_netlbl_err(struct sk_buff *skb,
} }
static inline void selinux_netlbl_sk_security_free( static inline void selinux_netlbl_sk_security_free(
struct sk_security_struct *ssec) struct sk_security_struct *sksec)
{ {
return; return;
} }
static inline void selinux_netlbl_sk_security_reset( static inline void selinux_netlbl_sk_security_reset(
struct sk_security_struct *ssec) struct sk_security_struct *sksec)
{ {
return; return;
} }
......
...@@ -132,21 +132,21 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) ...@@ -132,21 +132,21 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
/** /**
* selinux_netlbl_sk_security_free - Free the NetLabel fields * selinux_netlbl_sk_security_free - Free the NetLabel fields
* @sssec: the sk_security_struct * @sksec: the sk_security_struct
* *
* Description: * Description:
* Free all of the memory in the NetLabel fields of a sk_security_struct. * Free all of the memory in the NetLabel fields of a sk_security_struct.
* *
*/ */
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
{ {
if (ssec->nlbl_secattr != NULL) if (sksec->nlbl_secattr != NULL)
netlbl_secattr_free(ssec->nlbl_secattr); netlbl_secattr_free(sksec->nlbl_secattr);
} }
/** /**
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
* @ssec: the sk_security_struct * @sksec: the sk_security_struct
* @family: the socket family * @family: the socket family
* *
* Description: * Description:
...@@ -154,9 +154,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) ...@@ -154,9 +154,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
* The caller is responsibile for all the NetLabel sk_security_struct locking. * The caller is responsibile for all the NetLabel sk_security_struct locking.
* *
*/ */
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec) void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
{ {
ssec->nlbl_state = NLBL_UNSET; sksec->nlbl_state = NLBL_UNSET;
} }
/** /**
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/selinux_netlink.h> #include <linux/selinux_netlink.h>
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/if.h> #include <linux/if.h>
......
...@@ -503,11 +503,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -503,11 +503,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
return length; return length;
length = -ENOMEM; length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL); scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon) if (!scon)
return length; return length;
tcon = kzalloc(size+1, GFP_KERNEL); tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon) if (!tcon)
goto out; goto out;
...@@ -515,10 +515,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -515,10 +515,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2; goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length < 0) if (length < 0)
goto out2; goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
if (length < 0) if (length < 0)
goto out2; goto out2;
...@@ -550,11 +550,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -550,11 +550,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
return length; return length;
length = -ENOMEM; length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL); scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon) if (!scon)
return length; return length;
tcon = kzalloc(size+1, GFP_KERNEL); tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon) if (!tcon)
goto out; goto out;
...@@ -562,10 +562,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -562,10 +562,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2; goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length < 0) if (length < 0)
goto out2; goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
if (length < 0) if (length < 0)
goto out2; goto out2;
...@@ -609,11 +609,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) ...@@ -609,11 +609,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
return length; return length;
length = -ENOMEM; length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL); scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon) if (!scon)
return length; return length;
tcon = kzalloc(size+1, GFP_KERNEL); tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon) if (!tcon)
goto out; goto out;
...@@ -621,10 +621,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) ...@@ -621,10 +621,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2; goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length < 0) if (length < 0)
goto out2; goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
if (length < 0) if (length < 0)
goto out2; goto out2;
...@@ -666,11 +666,11 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) ...@@ -666,11 +666,11 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
return length; return length;
length = -ENOMEM; length = -ENOMEM;
con = kzalloc(size+1, GFP_KERNEL); con = kzalloc(size + 1, GFP_KERNEL);
if (!con) if (!con)
return length; return length;
user = kzalloc(size+1, GFP_KERNEL); user = kzalloc(size + 1, GFP_KERNEL);
if (!user) if (!user)
goto out; goto out;
...@@ -678,7 +678,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) ...@@ -678,7 +678,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2) if (sscanf(buf, "%s %s", con, user) != 2)
goto out2; goto out2;
length = security_context_to_sid(con, strlen(con)+1, &sid); length = security_context_to_sid(con, strlen(con) + 1, &sid);
if (length < 0) if (length < 0)
goto out2; goto out2;
...@@ -727,11 +727,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) ...@@ -727,11 +727,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
return length; return length;
length = -ENOMEM; length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL); scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon) if (!scon)
return length; return length;
tcon = kzalloc(size+1, GFP_KERNEL); tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon) if (!tcon)
goto out; goto out;
...@@ -739,10 +739,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) ...@@ -739,10 +739,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2; goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length < 0) if (length < 0)
goto out2; goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
if (length < 0) if (length < 0)
goto out2; goto out2;
...@@ -1401,7 +1401,7 @@ static int sel_make_perm_files(char *objclass, int classvalue, ...@@ -1401,7 +1401,7 @@ static int sel_make_perm_files(char *objclass, int classvalue,
} }
inode->i_fop = &sel_perm_ops; inode->i_fop = &sel_perm_ops;
/* i+1 since perm values are 1-indexed */ /* i+1 since perm values are 1-indexed */
inode->i_ino = sel_perm_to_ino(classvalue, i+1); inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
d_add(dentry, inode); d_add(dentry, inode);
} }
...@@ -1489,7 +1489,7 @@ static int sel_make_classes(void) ...@@ -1489,7 +1489,7 @@ static int sel_make_classes(void)
goto out; goto out;
/* +2 since classes are 1-indexed */ /* +2 since classes are 1-indexed */
last_class_ino = sel_class_to_ino(nclasses+2); last_class_ino = sel_class_to_ino(nclasses + 2);
for (i = 0; i < nclasses; i++) { for (i = 0; i < nclasses; i++) {
struct dentry *class_name_dir; struct dentry *class_name_dir;
...@@ -1506,7 +1506,7 @@ static int sel_make_classes(void) ...@@ -1506,7 +1506,7 @@ static int sel_make_classes(void)
goto out1; goto out1;
/* i+1 since class values are 1-indexed */ /* i+1 since class values are 1-indexed */
rc = sel_make_class_dir_entries(classes[i], i+1, rc = sel_make_class_dir_entries(classes[i], i + 1,
class_name_dir); class_name_dir);
if (rc) if (rc)
goto out1; goto out1;
......
...@@ -255,7 +255,7 @@ int mls_context_to_sid(struct policydb *pol, ...@@ -255,7 +255,7 @@ int mls_context_to_sid(struct policydb *pol,
if (!pol->mls_enabled) { if (!pol->mls_enabled) {
if (def_sid != SECSID_NULL && oldc) if (def_sid != SECSID_NULL && oldc)
*scontext += strlen(*scontext)+1; *scontext += strlen(*scontext) + 1;
return 0; return 0;
} }
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define _DEBUG_HASHES #define _DEBUG_HASHES
#ifdef DEBUG_HASHES #ifdef DEBUG_HASHES
static char *symtab_name[SYM_NUM] = { static const char *symtab_name[SYM_NUM] = {
"common prefixes", "common prefixes",
"classes", "classes",
"roles", "roles",
...@@ -156,12 +156,11 @@ static int roles_init(struct policydb *p) ...@@ -156,12 +156,11 @@ static int roles_init(struct policydb *p)
rc = -EINVAL; rc = -EINVAL;
goto out_free_role; goto out_free_role;
} }
key = kmalloc(strlen(OBJECT_R)+1, GFP_KERNEL); key = kstrdup(OBJECT_R, GFP_KERNEL);
if (!key) { if (!key) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_free_role; goto out_free_role;
} }
strcpy(key, OBJECT_R);
rc = hashtab_insert(p->p_roles.table, key, role); rc = hashtab_insert(p->p_roles.table, key, role);
if (rc) if (rc)
goto out_free_key; goto out_free_key;
...@@ -2195,7 +2194,7 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -2195,7 +2194,7 @@ int policydb_read(struct policydb *p, void *fp)
rangetr_hash_eval(p->range_tr); rangetr_hash_eval(p->range_tr);
} }
p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
if (!p->type_attr_map) if (!p->type_attr_map)
goto bad; goto bad;
......
...@@ -274,15 +274,15 @@ static int constraint_expr_eval(struct context *scontext, ...@@ -274,15 +274,15 @@ static int constraint_expr_eval(struct context *scontext,
case CEXPR_AND: case CEXPR_AND:
BUG_ON(sp < 1); BUG_ON(sp < 1);
sp--; sp--;
s[sp] &= s[sp+1]; s[sp] &= s[sp + 1];
break; break;
case CEXPR_OR: case CEXPR_OR:
BUG_ON(sp < 1); BUG_ON(sp < 1);
sp--; sp--;
s[sp] |= s[sp+1]; s[sp] |= s[sp + 1];
break; break;
case CEXPR_ATTR: case CEXPR_ATTR:
if (sp == (CEXPR_MAXDEPTH-1)) if (sp == (CEXPR_MAXDEPTH - 1))
return 0; return 0;
switch (e->attr) { switch (e->attr) {
case CEXPR_USER: case CEXPR_USER:
...@@ -1216,7 +1216,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, ...@@ -1216,7 +1216,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
*sid = SECSID_NULL; *sid = SECSID_NULL;
/* Copy the string so that we can modify the copy as we parse it. */ /* Copy the string so that we can modify the copy as we parse it. */
scontext2 = kmalloc(scontext_len+1, gfp_flags); scontext2 = kmalloc(scontext_len + 1, gfp_flags);
if (!scontext2) if (!scontext2)
return -ENOMEM; return -ENOMEM;
memcpy(scontext2, scontext, scontext_len); memcpy(scontext2, scontext, scontext_len);
...@@ -1760,22 +1760,28 @@ int security_load_policy(void *data, size_t len) ...@@ -1760,22 +1760,28 @@ int security_load_policy(void *data, size_t len)
if (!ss_initialized) { if (!ss_initialized) {
avtab_cache_init(); avtab_cache_init();
if (policydb_read(&policydb, fp)) { rc = policydb_read(&policydb, fp);
if (rc) {
avtab_cache_destroy(); avtab_cache_destroy();
return -EINVAL; return rc;
} }
if (selinux_set_mapping(&policydb, secclass_map,
&current_mapping, rc = selinux_set_mapping(&policydb, secclass_map,
&current_mapping_size)) { &current_mapping,
&current_mapping_size);
if (rc) {
policydb_destroy(&policydb); policydb_destroy(&policydb);
avtab_cache_destroy(); avtab_cache_destroy();
return -EINVAL; return rc;
} }
if (policydb_load_isids(&policydb, &sidtab)) {
rc = policydb_load_isids(&policydb, &sidtab);
if (rc) {
policydb_destroy(&policydb); policydb_destroy(&policydb);
avtab_cache_destroy(); avtab_cache_destroy();
return -EINVAL; return rc;
} }
security_load_policycaps(); security_load_policycaps();
ss_initialized = 1; ss_initialized = 1;
seqno = ++latest_granting; seqno = ++latest_granting;
...@@ -1791,8 +1797,9 @@ int security_load_policy(void *data, size_t len) ...@@ -1791,8 +1797,9 @@ int security_load_policy(void *data, size_t len)
sidtab_hash_eval(&sidtab, "sids"); sidtab_hash_eval(&sidtab, "sids");
#endif #endif
if (policydb_read(&newpolicydb, fp)) rc = policydb_read(&newpolicydb, fp);
return -EINVAL; if (rc)
return rc;
/* If switching between different policy types, log MLS status */ /* If switching between different policy types, log MLS status */
if (policydb.mls_enabled && !newpolicydb.mls_enabled) if (policydb.mls_enabled && !newpolicydb.mls_enabled)
...@@ -1807,8 +1814,8 @@ int security_load_policy(void *data, size_t len) ...@@ -1807,8 +1814,8 @@ int security_load_policy(void *data, size_t len)
return rc; return rc;
} }
if (selinux_set_mapping(&newpolicydb, secclass_map, rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
&map, &map_size)) if (rc)
goto err; goto err;
rc = security_preserve_bools(&newpolicydb); rc = security_preserve_bools(&newpolicydb);
...@@ -1819,10 +1826,10 @@ int security_load_policy(void *data, size_t len) ...@@ -1819,10 +1826,10 @@ int security_load_policy(void *data, size_t len)
/* Clone the SID table. */ /* Clone the SID table. */
sidtab_shutdown(&sidtab); sidtab_shutdown(&sidtab);
if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
rc = -ENOMEM; rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
if (rc)
goto err; goto err;
}
/* /*
* Convert the internal representations of contexts * Convert the internal representations of contexts
...@@ -2101,9 +2108,9 @@ int security_get_user_sids(u32 fromsid, ...@@ -2101,9 +2108,9 @@ int security_get_user_sids(u32 fromsid,
ebitmap_for_each_positive_bit(&user->roles, rnode, i) { ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i]; role = policydb.role_val_to_struct[i];
usercon.role = i+1; usercon.role = i + 1;
ebitmap_for_each_positive_bit(&role->types, tnode, j) { ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1; usercon.type = j + 1;
if (mls_setup_user_range(fromcon, user, &usercon)) if (mls_setup_user_range(fromcon, user, &usercon))
continue; continue;
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/ext2_fs.h>
#include <linux/kd.h> #include <linux/kd.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -1118,15 +1117,6 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, ...@@ -1118,15 +1117,6 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
return 0; return 0;
} }
/**
* smack_cred_commit - commit new credentials
* @new: the new credentials
* @old: the original credentials
*/
static void smack_cred_commit(struct cred *new, const struct cred *old)
{
}
/** /**
* smack_cred_transfer - Transfer the old credentials to the new credentials * smack_cred_transfer - Transfer the old credentials to the new credentials
* @new: the new credentials * @new: the new credentials
...@@ -3121,7 +3111,6 @@ struct security_operations smack_ops = { ...@@ -3121,7 +3111,6 @@ struct security_operations smack_ops = {
.cred_alloc_blank = smack_cred_alloc_blank, .cred_alloc_blank = smack_cred_alloc_blank,
.cred_free = smack_cred_free, .cred_free = smack_cred_free,
.cred_prepare = smack_cred_prepare, .cred_prepare = smack_cred_prepare,
.cred_commit = smack_cred_commit,
.cred_transfer = smack_cred_transfer, .cred_transfer = smack_cred_transfer,
.kernel_act_as = smack_kernel_act_as, .kernel_act_as = smack_kernel_act_as,
.kernel_create_files_as = smack_kernel_create_files_as, .kernel_create_files_as = smack_kernel_create_files_as,
......
obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
...@@ -75,6 +75,49 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, ...@@ -75,6 +75,49 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
static int tomoyo_write_control(struct file *file, const char __user *buffer, static int tomoyo_write_control(struct file *file, const char __user *buffer,
const int buffer_len); const int buffer_len);
/**
* tomoyo_parse_name_union - Parse a tomoyo_name_union.
*
* @filename: Name or name group.
* @ptr: Pointer to "struct tomoyo_name_union".
*
* Returns true on success, false otherwise.
*/
bool tomoyo_parse_name_union(const char *filename,
struct tomoyo_name_union *ptr)
{
if (!tomoyo_is_correct_path(filename, 0, 0, 0))
return false;
if (filename[0] == '@') {
ptr->group = tomoyo_get_path_group(filename + 1);
ptr->is_group = true;
return ptr->group != NULL;
}
ptr->filename = tomoyo_get_name(filename);
ptr->is_group = false;
return ptr->filename != NULL;
}
/**
* tomoyo_print_name_union - Print a tomoyo_name_union.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_name_union".
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
const struct tomoyo_name_union *ptr)
{
int pos = head->read_avail;
if (pos && head->read_buf[pos - 1] == ' ')
head->read_avail--;
if (ptr->is_group)
return tomoyo_io_printf(head, " @%s",
ptr->group->group_name->name);
return tomoyo_io_printf(head, " %s", ptr->filename->name);
}
/** /**
* tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
* *
...@@ -171,6 +214,33 @@ static void tomoyo_normalize_line(unsigned char *buffer) ...@@ -171,6 +214,33 @@ static void tomoyo_normalize_line(unsigned char *buffer)
*dp = '\0'; *dp = '\0';
} }
/**
* tomoyo_tokenize - Tokenize string.
*
* @buffer: The line to tokenize.
* @w: Pointer to "char *".
* @size: Sizeof @w .
*
* Returns true on success, false otherwise.
*/
bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
{
int count = size / sizeof(char *);
int i;
for (i = 0; i < count; i++)
w[i] = "";
for (i = 0; i < count; i++) {
char *cp = strchr(buffer, ' ');
if (cp)
*cp = '\0';
w[i] = buffer;
if (!cp)
break;
buffer = cp + 1;
}
return i < count || !*buffer;
}
/** /**
* tomoyo_is_correct_path - Validate a pathname. * tomoyo_is_correct_path - Validate a pathname.
* @filename: The pathname to check. * @filename: The pathname to check.
...@@ -874,17 +944,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) ...@@ -874,17 +944,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
int profile) int profile)
{ {
static DEFINE_MUTEX(lock);
struct tomoyo_profile *ptr = NULL; struct tomoyo_profile *ptr = NULL;
int i; int i;
if (profile >= TOMOYO_MAX_PROFILES) if (profile >= TOMOYO_MAX_PROFILES)
return NULL; return NULL;
mutex_lock(&lock); if (mutex_lock_interruptible(&tomoyo_policy_lock))
return NULL;
ptr = tomoyo_profile_ptr[profile]; ptr = tomoyo_profile_ptr[profile];
if (ptr) if (ptr)
goto ok; goto ok;
ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
if (!tomoyo_memory_ok(ptr)) { if (!tomoyo_memory_ok(ptr)) {
kfree(ptr); kfree(ptr);
ptr = NULL; ptr = NULL;
...@@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned ...@@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
mb(); /* Avoid out-of-order execution. */ mb(); /* Avoid out-of-order execution. */
tomoyo_profile_ptr[profile] = ptr; tomoyo_profile_ptr[profile] = ptr;
ok: ok:
mutex_unlock(&lock); mutex_unlock(&tomoyo_policy_lock);
return ptr; return ptr;
} }
...@@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list); ...@@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list);
static int tomoyo_update_manager_entry(const char *manager, static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_policy_manager_entry *entry = NULL;
struct tomoyo_policy_manager_entry *ptr; struct tomoyo_policy_manager_entry *ptr;
const struct tomoyo_path_info *saved_manager; struct tomoyo_policy_manager_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_domain = false;
if (tomoyo_is_domain_def(manager)) { if (tomoyo_is_domain_def(manager)) {
if (!tomoyo_is_correct_domain(manager)) if (!tomoyo_is_correct_domain(manager))
return -EINVAL; return -EINVAL;
is_domain = true; e.is_domain = true;
} else { } else {
if (!tomoyo_is_correct_path(manager, 1, -1, -1)) if (!tomoyo_is_correct_path(manager, 1, -1, -1))
return -EINVAL; return -EINVAL;
} }
saved_manager = tomoyo_get_name(manager); e.manager = tomoyo_get_name(manager);
if (!saved_manager) if (!e.manager)
return -ENOMEM; return -ENOMEM;
if (!is_delete) if (mutex_lock_interruptible(&tomoyo_policy_lock))
entry = kmalloc(sizeof(*entry), GFP_KERNEL); goto out;
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
if (ptr->manager != saved_manager) if (ptr->manager != e.manager)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->manager = saved_manager; struct tomoyo_policy_manager_entry *entry =
saved_manager = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->is_domain = is_domain; if (entry) {
list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); list_add_tail_rcu(&entry->list,
entry = NULL; &tomoyo_policy_manager_list);
error = 0; error = 0;
}
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
tomoyo_put_name(saved_manager); out:
kfree(entry); tomoyo_put_name(e.manager);
return error; return error;
} }
...@@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname) ...@@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname)
name.name = domainname; name.name = domainname;
tomoyo_fill_path_info(&name); tomoyo_fill_path_info(&name);
mutex_lock(&tomoyo_policy_lock); if (mutex_lock_interruptible(&tomoyo_policy_lock))
return 0;
/* Is there an active domain? */ /* Is there an active domain? */
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
/* Never delete tomoyo_kernel_domain */ /* Never delete tomoyo_kernel_domain */
...@@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, ...@@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
{ {
int pos; int pos;
u8 bit; u8 bit;
const char *atmark = "";
const char *filename;
const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
filename = ptr->filename->name;
for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
const char *msg;
if (!(perm & (1 << bit))) if (!(perm & (1 << bit)))
continue; continue;
/* Print "read/write" instead of "read" and "write". */ /* Print "read/write" instead of "read" and "write". */
if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
&& (perm & (1 << TOMOYO_TYPE_READ_WRITE))) && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
continue; continue;
msg = tomoyo_path2keyword(bit);
pos = head->read_avail; pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, if (!tomoyo_io_printf(head, "allow_%s ",
atmark, filename)) tomoyo_path2keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_io_printf(head, "\n"))
goto out; goto out;
} }
head->read_bit = 0; head->read_bit = 0;
...@@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, ...@@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
struct tomoyo_path2_acl *ptr) struct tomoyo_path2_acl *ptr)
{ {
int pos; int pos;
const char *atmark1 = "";
const char *atmark2 = "";
const char *filename1;
const char *filename2;
const u8 perm = ptr->perm; const u8 perm = ptr->perm;
u8 bit; u8 bit;
filename1 = ptr->filename1->name;
filename2 = ptr->filename2->name;
for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
const char *msg;
if (!(perm & (1 << bit))) if (!(perm & (1 << bit)))
continue; continue;
msg = tomoyo_path22keyword(bit);
pos = head->read_avail; pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, if (!tomoyo_io_printf(head, "allow_%s ",
atmark1, filename1, atmark2, filename2)) tomoyo_path22keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name1) ||
!tomoyo_print_name_union(head, &ptr->name2) ||
!tomoyo_io_printf(head, "\n"))
goto out; goto out;
} }
head->read_bit = 0; head->read_bit = 0;
...@@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) ...@@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
return tomoyo_write_pattern_policy(data, is_delete); return tomoyo_write_pattern_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
return tomoyo_write_no_rewrite_policy(data, is_delete); return tomoyo_write_no_rewrite_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
return tomoyo_write_path_group_policy(data, is_delete);
return -EINVAL; return -EINVAL;
} }
...@@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) ...@@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
head->read_var2 = NULL; head->read_var2 = NULL;
head->read_step = 9; head->read_step = 9;
case 9: case 9:
if (!tomoyo_read_path_group_policy(head))
break;
head->read_var1 = NULL;
head->read_var2 = NULL;
head->read_step = 10;
case 10:
head->read_eof = true; head->read_eof = true;
break; break;
default: default:
...@@ -1886,7 +1955,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) ...@@ -1886,7 +1955,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
*/ */
static int tomoyo_open_control(const u8 type, struct file *file) static int tomoyo_open_control(const u8 type, struct file *file)
{ {
struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
if (!head) if (!head)
return -ENOMEM; return -ENOMEM;
...@@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) ...@@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
} else { } else {
if (!head->readbuf_size) if (!head->readbuf_size)
head->readbuf_size = 4096 * 2; head->readbuf_size = 4096 * 2;
head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
if (!head->read_buf) { if (!head->read_buf) {
kfree(head); kfree(head);
return -ENOMEM; return -ENOMEM;
...@@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) ...@@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
head->write = NULL; head->write = NULL;
} else if (head->write) { } else if (head->write) {
head->writebuf_size = 4096 * 2; head->writebuf_size = 4096 * 2;
head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
if (!head->write_buf) { if (!head->write_buf) {
kfree(head->read_buf); kfree(head->read_buf);
kfree(head); kfree(head);
......
...@@ -54,6 +54,7 @@ struct linux_binprm; ...@@ -54,6 +54,7 @@ struct linux_binprm;
#define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain "
#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain "
#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain "
#define TOMOYO_KEYWORD_PATH_GROUP "path_group "
#define TOMOYO_KEYWORD_SELECT "select " #define TOMOYO_KEYWORD_SELECT "select "
#define TOMOYO_KEYWORD_USE_PROFILE "use_profile " #define TOMOYO_KEYWORD_USE_PROFILE "use_profile "
#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read"
...@@ -204,6 +205,27 @@ struct tomoyo_path_info_with_data { ...@@ -204,6 +205,27 @@ struct tomoyo_path_info_with_data {
char barrier2[16]; /* Safeguard for overrun. */ char barrier2[16]; /* Safeguard for overrun. */
}; };
struct tomoyo_name_union {
const struct tomoyo_path_info *filename;
struct tomoyo_path_group *group;
u8 is_group;
};
/* Structure for "path_group" directive. */
struct tomoyo_path_group {
struct list_head list;
const struct tomoyo_path_info *group_name;
struct list_head member_list;
atomic_t users;
};
/* Structure for "path_group" directive. */
struct tomoyo_path_group_member {
struct list_head list;
bool is_deleted;
const struct tomoyo_path_info *member_name;
};
/* /*
* tomoyo_acl_info is a structure which is used for holding * tomoyo_acl_info is a structure which is used for holding
* *
...@@ -274,7 +296,7 @@ struct tomoyo_domain_info { ...@@ -274,7 +296,7 @@ struct tomoyo_domain_info {
* *
* (1) "head" which is a "struct tomoyo_acl_info". * (1) "head" which is a "struct tomoyo_acl_info".
* (2) "perm" which is a bitmask of permitted operations. * (2) "perm" which is a bitmask of permitted operations.
* (3) "filename" is the pathname. * (3) "name" is the pathname.
* *
* Directives held by this structure are "allow_read/write", "allow_execute", * Directives held by this structure are "allow_read/write", "allow_execute",
* "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
...@@ -287,8 +309,7 @@ struct tomoyo_path_acl { ...@@ -287,8 +309,7 @@ struct tomoyo_path_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
u8 perm_high; u8 perm_high;
u16 perm; u16 perm;
/* Pointer to single pathname. */ struct tomoyo_name_union name;
const struct tomoyo_path_info *filename;
}; };
/* /*
...@@ -298,8 +319,8 @@ struct tomoyo_path_acl { ...@@ -298,8 +319,8 @@ struct tomoyo_path_acl {
* *
* (1) "head" which is a "struct tomoyo_acl_info". * (1) "head" which is a "struct tomoyo_acl_info".
* (2) "perm" which is a bitmask of permitted operations. * (2) "perm" which is a bitmask of permitted operations.
* (3) "filename1" is the source/old pathname. * (3) "name1" is the source/old pathname.
* (4) "filename2" is the destination/new pathname. * (4) "name2" is the destination/new pathname.
* *
* Directives held by this structure are "allow_rename", "allow_link" and * Directives held by this structure are "allow_rename", "allow_link" and
* "allow_pivot_root". * "allow_pivot_root".
...@@ -307,10 +328,8 @@ struct tomoyo_path_acl { ...@@ -307,10 +328,8 @@ struct tomoyo_path_acl {
struct tomoyo_path2_acl { struct tomoyo_path2_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */
u8 perm; u8 perm;
/* Pointer to single pathname. */ struct tomoyo_name_union name1;
const struct tomoyo_path_info *filename1; struct tomoyo_name_union name2;
/* Pointer to single pathname. */
const struct tomoyo_path_info *filename2;
}; };
/* /*
...@@ -514,6 +533,9 @@ struct tomoyo_policy_manager_entry { ...@@ -514,6 +533,9 @@ struct tomoyo_policy_manager_entry {
/********** Function prototypes. **********/ /********** Function prototypes. **********/
/* Check whether the given name matches the given name_union. */
bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr);
/* Check whether the domain has too many ACL entries to hold. */ /* Check whether the domain has too many ACL entries to hold. */
bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
/* Transactional sprintf() for policy dump. */ /* Transactional sprintf() for policy dump. */
...@@ -526,6 +548,12 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, ...@@ -526,6 +548,12 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
const s8 pattern_type, const s8 end_type); const s8 pattern_type, const s8 end_type);
/* Check whether the token can be a domainname. */ /* Check whether the token can be a domainname. */
bool tomoyo_is_domain_def(const unsigned char *buffer); bool tomoyo_is_domain_def(const unsigned char *buffer);
bool tomoyo_parse_name_union(const char *filename,
struct tomoyo_name_union *ptr);
/* Check whether the given filename matches the given path_group. */
bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
const struct tomoyo_path_group *group,
const bool may_use_pattern);
/* Check whether the given filename matches the given pattern. */ /* Check whether the given filename matches the given pattern. */
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern); const struct tomoyo_path_info *pattern);
...@@ -540,10 +568,14 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head); ...@@ -540,10 +568,14 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head);
bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
/* Read "file_pattern" entry in exception policy. */ /* Read "file_pattern" entry in exception policy. */
bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
/* Read "path_group" entry in exception policy. */
bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head);
/* Read "allow_read" entry in exception policy. */ /* Read "allow_read" entry in exception policy. */
bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
/* Read "deny_rewrite" entry in exception policy. */ /* Read "deny_rewrite" entry in exception policy. */
bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head);
/* Tokenize a line. */
bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
/* Write domain policy violation warning message to console? */ /* Write domain policy violation warning message to console? */
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
/* Convert double path operation to operation name. */ /* Convert double path operation to operation name. */
...@@ -580,12 +612,18 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); ...@@ -580,12 +612,18 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
/* Create "file_pattern" entry in exception policy. */ /* Create "file_pattern" entry in exception policy. */
int tomoyo_write_pattern_policy(char *data, const bool is_delete); int tomoyo_write_pattern_policy(char *data, const bool is_delete);
/* Create "path_group" entry in exception policy. */
int tomoyo_write_path_group_policy(char *data, const bool is_delete);
/* Find a domain by the given name. */ /* Find a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
/* Find or create a domain by the given name. */ /* Find or create a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname, domainname,
const u8 profile); const u8 profile);
/* Allocate memory for "struct tomoyo_path_group". */
struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
/* Check mode for specified functionality. */ /* Check mode for specified functionality. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
const u8 index); const u8 index);
...@@ -616,6 +654,7 @@ char *tomoyo_realpath_from_path(struct path *path); ...@@ -616,6 +654,7 @@ char *tomoyo_realpath_from_path(struct path *path);
/* Check memory quota. */ /* Check memory quota. */
bool tomoyo_memory_ok(void *ptr); bool tomoyo_memory_ok(void *ptr);
void *tomoyo_commit_ok(void *data, const unsigned int size);
/* /*
* Keep the given name on the RAM. * Keep the given name on the RAM.
...@@ -641,6 +680,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, ...@@ -641,6 +680,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
int tomoyo_check_rewrite_permission(struct file *filp); int tomoyo_check_rewrite_permission(struct file *filp);
int tomoyo_find_next_domain(struct linux_binprm *bprm); int tomoyo_find_next_domain(struct linux_binprm *bprm);
/* Drop refcount on tomoyo_name_union. */
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
/* Run garbage collector. */ /* Run garbage collector. */
void tomoyo_run_gc(void); void tomoyo_run_gc(void);
...@@ -654,6 +696,7 @@ extern struct srcu_struct tomoyo_ss; ...@@ -654,6 +696,7 @@ extern struct srcu_struct tomoyo_ss;
/* The list for "struct tomoyo_domain_info". */ /* The list for "struct tomoyo_domain_info". */
extern struct list_head tomoyo_domain_list; extern struct list_head tomoyo_domain_list;
extern struct list_head tomoyo_path_group_list;
extern struct list_head tomoyo_domain_initializer_list; extern struct list_head tomoyo_domain_initializer_list;
extern struct list_head tomoyo_domain_keeper_list; extern struct list_head tomoyo_domain_keeper_list;
extern struct list_head tomoyo_alias_list; extern struct list_head tomoyo_alias_list;
...@@ -662,7 +705,6 @@ extern struct list_head tomoyo_pattern_list; ...@@ -662,7 +705,6 @@ extern struct list_head tomoyo_pattern_list;
extern struct list_head tomoyo_no_rewrite_list; extern struct list_head tomoyo_no_rewrite_list;
extern struct list_head tomoyo_policy_manager_list; extern struct list_head tomoyo_policy_manager_list;
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
extern struct mutex tomoyo_name_list_lock;
/* Lock for protecting policy. */ /* Lock for protecting policy. */
extern struct mutex tomoyo_policy_lock; extern struct mutex tomoyo_policy_lock;
...@@ -725,6 +767,12 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name) ...@@ -725,6 +767,12 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
} }
} }
static inline void tomoyo_put_path_group(struct tomoyo_path_group *group)
{
if (group)
atomic_dec(&group->users);
}
static inline struct tomoyo_domain_info *tomoyo_domain(void) static inline struct tomoyo_domain_info *tomoyo_domain(void)
{ {
return current_cred()->security; return current_cred()->security;
...@@ -736,6 +784,59 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct ...@@ -736,6 +784,59 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
return task_cred_xxx(task, security); return task_cred_xxx(task, security);
} }
static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1,
const struct tomoyo_acl_info *p2)
{
return p1->type == p2->type;
}
static inline bool tomoyo_is_same_name_union
(const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2)
{
return p1->filename == p2->filename && p1->group == p2->group &&
p1->is_group == p2->is_group;
}
static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
const struct tomoyo_path_acl *p2)
{
return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
tomoyo_is_same_name_union(&p1->name, &p2->name);
}
static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
const struct tomoyo_path2_acl *p2)
{
return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
tomoyo_is_same_name_union(&p1->name1, &p2->name1) &&
tomoyo_is_same_name_union(&p1->name2, &p2->name2);
}
static inline bool tomoyo_is_same_domain_initializer_entry
(const struct tomoyo_domain_initializer_entry *p1,
const struct tomoyo_domain_initializer_entry *p2)
{
return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
}
static inline bool tomoyo_is_same_domain_keeper_entry
(const struct tomoyo_domain_keeper_entry *p1,
const struct tomoyo_domain_keeper_entry *p2)
{
return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
}
static inline bool tomoyo_is_same_alias_entry
(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
{
return p1->original_name == p2->original_name &&
p1->aliased_name == p2->aliased_name;
}
/** /**
* list_for_each_cookie - iterate over a list with cookie. * list_for_each_cookie - iterate over a list with cookie.
* @pos: the &struct list_head to use as a loop cursor. * @pos: the &struct list_head to use as a loop cursor.
......
...@@ -130,57 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, ...@@ -130,57 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
const bool is_not, const bool is_not,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_domain_initializer_entry *entry = NULL;
struct tomoyo_domain_initializer_entry *ptr; struct tomoyo_domain_initializer_entry *ptr;
const struct tomoyo_path_info *saved_program = NULL; struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
const struct tomoyo_path_info *saved_domainname = NULL;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_correct_path(program, 1, -1, -1)) if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */ return -EINVAL; /* No patterns allowed. */
if (domainname) { if (domainname) {
if (!tomoyo_is_domain_def(domainname) && if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1)) tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true; e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname)) else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL; return -EINVAL;
saved_domainname = tomoyo_get_name(domainname); e.domainname = tomoyo_get_name(domainname);
if (!saved_domainname) if (!e.domainname)
goto out; goto out;
} }
saved_program = tomoyo_get_name(program); e.program = tomoyo_get_name(program);
if (!saved_program) if (!e.program)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_not != is_not || if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->domainname = saved_domainname; struct tomoyo_domain_initializer_entry *entry =
saved_domainname = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->program = saved_program; if (entry) {
saved_program = NULL; list_add_tail_rcu(&entry->list,
entry->is_not = is_not; &tomoyo_domain_initializer_list);
entry->is_last_name = is_last_name; error = 0;
list_add_tail_rcu(&entry->list, }
&tomoyo_domain_initializer_list);
entry = NULL;
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(e.domainname);
tomoyo_put_name(saved_program); tomoyo_put_name(e.program);
kfree(entry);
return error; return error;
} }
...@@ -350,56 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, ...@@ -350,56 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
const bool is_not, const bool is_not,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_domain_keeper_entry *entry = NULL;
struct tomoyo_domain_keeper_entry *ptr; struct tomoyo_domain_keeper_entry *ptr;
const struct tomoyo_path_info *saved_domainname = NULL; struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
const struct tomoyo_path_info *saved_program = NULL;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_domain_def(domainname) && if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1)) tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true; e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname)) else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL; return -EINVAL;
if (program) { if (program) {
if (!tomoyo_is_correct_path(program, 1, -1, -1)) if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL; return -EINVAL;
saved_program = tomoyo_get_name(program); e.program = tomoyo_get_name(program);
if (!saved_program) if (!e.program)
goto out; goto out;
} }
saved_domainname = tomoyo_get_name(domainname); e.domainname = tomoyo_get_name(domainname);
if (!saved_domainname) if (!e.domainname)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_not != is_not || if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->domainname = saved_domainname; struct tomoyo_domain_keeper_entry *entry =
saved_domainname = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->program = saved_program; if (entry) {
saved_program = NULL; list_add_tail_rcu(&entry->list,
entry->is_not = is_not; &tomoyo_domain_keeper_list);
entry->is_last_name = is_last_name; error = 0;
list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); }
entry = NULL;
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(e.domainname);
tomoyo_put_name(saved_program); tomoyo_put_name(e.program);
kfree(entry);
return error; return error;
} }
...@@ -551,44 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name, ...@@ -551,44 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name,
const char *aliased_name, const char *aliased_name,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_alias_entry *entry = NULL;
struct tomoyo_alias_entry *ptr; struct tomoyo_alias_entry *ptr;
const struct tomoyo_path_info *saved_original_name; struct tomoyo_alias_entry e = { };
const struct tomoyo_path_info *saved_aliased_name;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
!tomoyo_is_correct_path(aliased_name, 1, -1, -1)) !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */ return -EINVAL; /* No patterns allowed. */
saved_original_name = tomoyo_get_name(original_name); e.original_name = tomoyo_get_name(original_name);
saved_aliased_name = tomoyo_get_name(aliased_name); e.aliased_name = tomoyo_get_name(aliased_name);
if (!saved_original_name || !saved_aliased_name) if (!e.original_name || !e.aliased_name)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (ptr->original_name != saved_original_name || if (!tomoyo_is_same_alias_entry(ptr, &e))
ptr->aliased_name != saved_aliased_name)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->original_name = saved_original_name; struct tomoyo_alias_entry *entry =
saved_original_name = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->aliased_name = saved_aliased_name; if (entry) {
saved_aliased_name = NULL; list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
list_add_tail_rcu(&entry->list, &tomoyo_alias_list); error = 0;
entry = NULL; }
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_original_name); tomoyo_put_name(e.original_name);
tomoyo_put_name(saved_aliased_name); tomoyo_put_name(e.aliased_name);
kfree(entry);
return error; return error;
} }
...@@ -656,7 +631,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * ...@@ -656,7 +631,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
const u8 profile) const u8 profile)
{ {
struct tomoyo_domain_info *entry; struct tomoyo_domain_info *entry;
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain = NULL;
const struct tomoyo_path_info *saved_domainname; const struct tomoyo_path_info *saved_domainname;
bool found = false; bool found = false;
...@@ -665,8 +640,9 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * ...@@ -665,8 +640,9 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
saved_domainname = tomoyo_get_name(domainname); saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname) if (!saved_domainname)
return NULL; return NULL;
entry = kzalloc(sizeof(*entry), GFP_KERNEL); entry = kzalloc(sizeof(*entry), GFP_NOFS);
mutex_lock(&tomoyo_policy_lock); if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
if (domain->is_deleted || if (domain->is_deleted ||
tomoyo_pathcmp(saved_domainname, domain->domainname)) tomoyo_pathcmp(saved_domainname, domain->domainname))
...@@ -685,6 +661,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * ...@@ -685,6 +661,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
found = true; found = true;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(saved_domainname);
kfree(entry); kfree(entry);
return found ? domain : NULL; return found ? domain : NULL;
...@@ -705,7 +682,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -705,7 +682,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* This function assumes that the size of buffer returned by * This function assumes that the size of buffer returned by
* tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
*/ */
struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL; struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name; const char *old_domain_name = old_domain->domainname->name;
......
This diff is collapsed.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/slab.h> #include <linux/slab.h>
enum tomoyo_gc_id { enum tomoyo_gc_id {
TOMOYO_ID_PATH_GROUP,
TOMOYO_ID_PATH_GROUP_MEMBER,
TOMOYO_ID_DOMAIN_INITIALIZER, TOMOYO_ID_DOMAIN_INITIALIZER,
TOMOYO_ID_DOMAIN_KEEPER, TOMOYO_ID_DOMAIN_KEEPER,
TOMOYO_ID_ALIAS, TOMOYO_ID_ALIAS,
...@@ -91,15 +93,15 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl) ...@@ -91,15 +93,15 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
{ {
struct tomoyo_path_acl *entry struct tomoyo_path_acl *entry
= container_of(acl, typeof(*entry), head); = container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename); tomoyo_put_name_union(&entry->name);
} }
break; break;
case TOMOYO_TYPE_PATH2_ACL: case TOMOYO_TYPE_PATH2_ACL:
{ {
struct tomoyo_path2_acl *entry struct tomoyo_path2_acl *entry
= container_of(acl, typeof(*entry), head); = container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename1); tomoyo_put_name_union(&entry->name1);
tomoyo_put_name(entry->filename2); tomoyo_put_name_union(&entry->name2);
} }
break; break;
default: default:
...@@ -149,9 +151,21 @@ static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) ...@@ -149,9 +151,21 @@ static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
{ {
} }
static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
*member)
{
tomoyo_put_name(member->member_name);
}
static void tomoyo_del_path_group(struct tomoyo_path_group *group)
{
tomoyo_put_name(group->group_name);
}
static void tomoyo_collect_entry(void) static void tomoyo_collect_entry(void)
{ {
mutex_lock(&tomoyo_policy_lock); if (mutex_lock_interruptible(&tomoyo_policy_lock))
return;
{ {
struct tomoyo_globally_readable_file_entry *ptr; struct tomoyo_globally_readable_file_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
...@@ -275,8 +289,6 @@ static void tomoyo_collect_entry(void) ...@@ -275,8 +289,6 @@ static void tomoyo_collect_entry(void)
break; break;
} }
} }
mutex_unlock(&tomoyo_policy_lock);
mutex_lock(&tomoyo_name_list_lock);
{ {
int i; int i;
for (i = 0; i < TOMOYO_MAX_HASH; i++) { for (i = 0; i < TOMOYO_MAX_HASH; i++) {
...@@ -294,7 +306,30 @@ static void tomoyo_collect_entry(void) ...@@ -294,7 +306,30 @@ static void tomoyo_collect_entry(void)
} }
} }
} }
mutex_unlock(&tomoyo_name_list_lock); {
struct tomoyo_path_group *group;
list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
struct tomoyo_path_group_member *member;
list_for_each_entry_rcu(member, &group->member_list,
list) {
if (!member->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
member))
list_del_rcu(&member->list);
else
break;
}
if (!list_empty(&group->member_list) ||
atomic_read(&group->users))
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
list_del_rcu(&group->list);
else
break;
}
}
mutex_unlock(&tomoyo_policy_lock);
} }
static void tomoyo_kfree_entry(void) static void tomoyo_kfree_entry(void)
...@@ -335,6 +370,12 @@ static void tomoyo_kfree_entry(void) ...@@ -335,6 +370,12 @@ static void tomoyo_kfree_entry(void)
if (!tomoyo_del_domain(p->element)) if (!tomoyo_del_domain(p->element))
continue; continue;
break; break;
case TOMOYO_ID_PATH_GROUP_MEMBER:
tomoyo_del_path_group_member(p->element);
break;
case TOMOYO_ID_PATH_GROUP:
tomoyo_del_path_group(p->element);
break;
default: default:
printk(KERN_WARNING "Unknown type\n"); printk(KERN_WARNING "Unknown type\n");
break; break;
......
/*
* security/tomoyo/path_group.c
*
* Copyright (C) 2005-2009 NTT DATA CORPORATION
*/
#include <linux/slab.h>
#include "common.h"
/* The list for "struct ccs_path_group". */
LIST_HEAD(tomoyo_path_group_list);
/**
* tomoyo_get_path_group - Allocate memory for "struct tomoyo_path_group".
*
* @group_name: The name of pathname group.
*
* Returns pointer to "struct tomoyo_path_group" on success, NULL otherwise.
*/
struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name)
{
struct tomoyo_path_group *entry = NULL;
struct tomoyo_path_group *group = NULL;
const struct tomoyo_path_info *saved_group_name;
int error = -ENOMEM;
if (!tomoyo_is_correct_path(group_name, 0, 0, 0) ||
!group_name[0])
return NULL;
saved_group_name = tomoyo_get_name(group_name);
if (!saved_group_name)
return NULL;
entry = kzalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
if (saved_group_name != group->group_name)
continue;
atomic_inc(&group->users);
error = 0;
break;
}
if (error && tomoyo_memory_ok(entry)) {
INIT_LIST_HEAD(&entry->member_list);
entry->group_name = saved_group_name;
saved_group_name = NULL;
atomic_set(&entry->users, 1);
list_add_tail_rcu(&entry->list, &tomoyo_path_group_list);
group = entry;
entry = NULL;
error = 0;
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_group_name);
kfree(entry);
return !error ? group : NULL;
}
/**
* tomoyo_write_path_group_policy - Write "struct tomoyo_path_group" list.
*
* @data: String to parse.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, nagative value otherwise.
*/
int tomoyo_write_path_group_policy(char *data, const bool is_delete)
{
struct tomoyo_path_group *group;
struct tomoyo_path_group_member *member;
struct tomoyo_path_group_member e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
char *w[2];
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
return -EINVAL;
group = tomoyo_get_path_group(w[0]);
if (!group)
return -ENOMEM;
e.member_name = tomoyo_get_name(w[1]);
if (!e.member_name)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(member, &group->member_list, list) {
if (member->member_name != e.member_name)
continue;
member->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error) {
struct tomoyo_path_group_member *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list, &group->member_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(e.member_name);
tomoyo_put_path_group(group);
return error;
}
/**
* tomoyo_read_path_group_policy - Read "struct tomoyo_path_group" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/
bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head)
{
struct list_head *gpos;
struct list_head *mpos;
list_for_each_cookie(gpos, head->read_var1, &tomoyo_path_group_list) {
struct tomoyo_path_group *group;
group = list_entry(gpos, struct tomoyo_path_group, list);
list_for_each_cookie(mpos, head->read_var2,
&group->member_list) {
struct tomoyo_path_group_member *member;
member = list_entry(mpos,
struct tomoyo_path_group_member,
list);
if (member->is_deleted)
continue;
if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_PATH_GROUP
"%s %s\n",
group->group_name->name,
member->member_name->name))
return false;
}
}
return true;
}
/**
* tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
*
* @pathname: The name of pathname.
* @group: Pointer to "struct tomoyo_path_group".
* @may_use_pattern: True if wild card is permitted.
*
* Returns true if @pathname matches pathnames in @group, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/
bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
const struct tomoyo_path_group *group,
const bool may_use_pattern)
{
struct tomoyo_path_group_member *member;
bool matched = false;
list_for_each_entry_rcu(member, &group->member_list, list) {
if (member->is_deleted)
continue;
if (!member->member_name->is_patterned) {
if (tomoyo_pathcmp(pathname, member->member_name))
continue;
} else if (may_use_pattern) {
if (!tomoyo_path_matches_pattern(pathname,
member->member_name))
continue;
} else
continue;
matched = true;
break;
}
return matched;
}
...@@ -139,7 +139,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, ...@@ -139,7 +139,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname,
*/ */
char *tomoyo_realpath_from_path(struct path *path) char *tomoyo_realpath_from_path(struct path *path)
{ {
char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
<= TOMOYO_MAX_PATHNAME_LEN - 1); <= TOMOYO_MAX_PATHNAME_LEN - 1);
...@@ -222,6 +222,25 @@ bool tomoyo_memory_ok(void *ptr) ...@@ -222,6 +222,25 @@ bool tomoyo_memory_ok(void *ptr)
return false; return false;
} }
/**
* tomoyo_commit_ok - Check memory quota.
*
* @data: Data to copy from.
* @size: Size in byte.
*
* Returns pointer to allocated memory on success, NULL otherwise.
*/
void *tomoyo_commit_ok(void *data, const unsigned int size)
{
void *ptr = kzalloc(size, GFP_NOFS);
if (tomoyo_memory_ok(ptr)) {
memmove(ptr, data, size);
memset(data, 0, size);
return ptr;
}
return NULL;
}
/** /**
* tomoyo_memory_free - Free memory for elements. * tomoyo_memory_free - Free memory for elements.
* *
...@@ -240,8 +259,6 @@ void tomoyo_memory_free(void *ptr) ...@@ -240,8 +259,6 @@ void tomoyo_memory_free(void *ptr)
* "const struct tomoyo_path_info *". * "const struct tomoyo_path_info *".
*/ */
struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
/* Lock for protecting tomoyo_name_list . */
DEFINE_MUTEX(tomoyo_name_list_lock);
/** /**
* tomoyo_get_name - Allocate permanent memory for string data. * tomoyo_get_name - Allocate permanent memory for string data.
...@@ -263,14 +280,15 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) ...@@ -263,14 +280,15 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
len = strlen(name) + 1; len = strlen(name) + 1;
hash = full_name_hash((const unsigned char *) name, len - 1); hash = full_name_hash((const unsigned char *) name, len - 1);
head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
mutex_lock(&tomoyo_name_list_lock); if (mutex_lock_interruptible(&tomoyo_policy_lock))
return NULL;
list_for_each_entry(ptr, head, list) { list_for_each_entry(ptr, head, list) {
if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
continue; continue;
atomic_inc(&ptr->users); atomic_inc(&ptr->users);
goto out; goto out;
} }
ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
allocated_len = ptr ? ksize(ptr) : 0; allocated_len = ptr ? ksize(ptr) : 0;
if (!ptr || (tomoyo_quota_for_policy && if (!ptr || (tomoyo_quota_for_policy &&
atomic_read(&tomoyo_policy_memory_size) + allocated_len atomic_read(&tomoyo_policy_memory_size) + allocated_len
...@@ -290,7 +308,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) ...@@ -290,7 +308,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
tomoyo_fill_path_info(&ptr->entry); tomoyo_fill_path_info(&ptr->entry);
list_add_tail(&ptr->list, head); list_add_tail(&ptr->list, head);
out: out:
mutex_unlock(&tomoyo_name_list_lock); mutex_unlock(&tomoyo_policy_lock);
return ptr ? &ptr->entry : NULL; return ptr ? &ptr->entry : NULL;
} }
......
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