Commit 539c99fd authored by James Morris's avatar James Morris

Merge branch 'next' into for-linus

parents ba2e1c5f 4d09ec0f
......@@ -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
time, and possibly to sleep whilst doing so, then the caller should get a
reference on them using:
......@@ -426,17 +423,16 @@ credentials, hiding the RCU magic from the caller:
uid_t task_uid(task) Task's real 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,
then:
If the caller is holding the RCU read lock at the time anyway, then:
__task_cred(task)->uid
__task_cred(task)->euid
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()
called, the result stored in a temporary pointer and then the credential
aspects called from that before dropping the lock. This prevents the
potentially expensive RCU magic from being invoked multiple times.
need to be accessed, RCU read lock should be used, __task_cred() called, the
result stored in a temporary pointer and then the credential aspects called
from that before dropping the lock. This prevents the potentially expensive
RCU magic from being invoked multiple times.
Should some other single aspect of another task's credentials need to be
accessed, then this can be used:
......
......@@ -99,6 +99,7 @@ parameter is applicable:
SWSUSP Software suspend (hibernation) is enabled.
SUSPEND System suspend states are enabled.
FTRACE Function tracing enabled.
TPM TPM drivers are enabled.
TS Appropriate touchscreen support is enabled.
UMS USB Mass Storage support is enabled.
USB USB support is enabled.
......@@ -2610,6 +2611,15 @@ and is between 256 and 4096 characters. It is defined in the file
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]
[FTRACE] will set tracing buffer size.
......
......@@ -17,14 +17,16 @@ menuconfig TCG_TPM
obtained at: <http://sourceforge.net/projects/trousers>. To
compile this driver as a module, choose M here; the module
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.
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
config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface"
depends on PNP
---help---
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
......
......@@ -1068,6 +1068,27 @@ void tpm_remove_hardware(struct device *dev)
}
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
* so that it can be restored.
......@@ -1075,17 +1096,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware);
int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
u8 savestate[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 10, /* blob length (in bytes) */
0, 0, 0, 152 /* TPM_ORD_SaveState */
};
struct tpm_cmd_t cmd;
int rc;
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
if (chip == NULL)
return -ENODEV;
tpm_transmit(chip, savestate, sizeof(savestate));
return 0;
/* for buggy tpm, flush pcrs with extend to selected dummy */
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);
......
......@@ -598,7 +598,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
tpm_remove_hardware(chip->dev);
return rc;
}
#ifdef CONFIG_PNP
static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id)
{
......@@ -663,7 +663,7 @@ static struct pnp_driver tis_pnp_driver = {
module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
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)
{
return tpm_pm_suspend(&dev->dev, msg);
......@@ -690,21 +690,21 @@ MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
static int __init init_tis(void)
{
int rc;
#ifdef CONFIG_PNP
if (!force)
return pnp_register_driver(&tis_pnp_driver);
#endif
if (force) {
rc = platform_driver_register(&tis_drv);
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);
}
rc = platform_driver_register(&tis_drv);
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 pnp_register_driver(&tis_pnp_driver);
return rc;
}
static void __exit cleanup_tis(void)
......@@ -728,12 +728,14 @@ static void __exit cleanup_tis(void)
list_del(&i->list);
}
spin_unlock(&tis_lock);
if (force) {
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
} else
#ifdef CONFIG_PNP
if (!force) {
pnp_unregister_driver(&tis_pnp_driver);
return;
}
#endif
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
}
module_init(init_tis);
......
......@@ -1205,8 +1205,6 @@ void generic_delete_inode(struct inode *inode)
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
security_inode_delete(inode);
if (op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode;
/* Filesystems implementing their own
......
......@@ -628,7 +628,6 @@ void mntput_no_expire(struct vfsmount *mnt)
mnt->mnt_pinned = 0;
spin_unlock(&vfsmount_lock);
acct_auto_close_mnt(mnt);
security_sb_umount_close(mnt);
goto repeat;
}
}
......@@ -1117,8 +1116,6 @@ static int do_umount(struct vfsmount *mnt, int flags)
retval = 0;
}
spin_unlock(&vfsmount_lock);
if (retval)
security_sb_umount_busy(mnt);
up_write(&namespace_sem);
release_mounts(&umount_list);
return retval;
......@@ -1435,17 +1432,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
if (cant_mount(path->dentry))
goto out_unlock;
err = security_sb_check_sb(mnt, path);
if (err)
goto out_unlock;
err = -ENOENT;
if (!d_unlinked(path->dentry))
err = attach_recursive_mnt(mnt, path, NULL);
out_unlock:
mutex_unlock(&path->dentry->d_inode->i_mutex);
if (!err)
security_sb_post_addmount(mnt, path);
return err;
}
......@@ -1581,8 +1571,6 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
}
up_write(&sb->s_umount);
if (!err) {
security_sb_post_remount(path->mnt, flags, data);
spin_lock(&vfsmount_lock);
touch_mnt_namespace(path->mnt->mnt_ns);
spin_unlock(&vfsmount_lock);
......@@ -2277,7 +2265,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
touch_mnt_namespace(current->nsproxy->mnt_ns);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&root, &new);
security_sb_post_pivotroot(&root, &new);
error = 0;
path_put(&root_parent);
path_put(&parent_path);
......
......@@ -33,7 +33,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_IPC 4
#define LSM_AUDIT_DATA_TASK 5
#define LSM_AUDIT_DATA_KEY 6
#define LSM_AUDIT_NO_AUDIT 7
#define LSM_AUDIT_DATA_NONE 7
#define LSM_AUDIT_DATA_KMOD 8
struct task_struct *tsk;
union {
......
This diff is collapsed.
......@@ -216,7 +216,6 @@ static int acct_on(char *name)
{
struct file *file;
struct vfsmount *mnt;
int error;
struct pid_namespace *ns;
struct bsd_acct_struct *acct = NULL;
......@@ -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);
if (ns->bacct == NULL) {
ns->bacct = acct;
......@@ -281,7 +273,7 @@ static int acct_on(char *name)
*/
SYSCALL_DEFINE1(acct, const char __user *, name)
{
int error;
int error = 0;
if (!capable(CAP_SYS_PACCT))
return -EPERM;
......@@ -299,13 +291,11 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
if (acct == NULL)
return 0;
error = security_acct(NULL);
if (!error) {
spin_lock(&acct_lock);
acct_file_reopen(acct, NULL, NULL);
spin_unlock(&acct_lock);
}
spin_lock(&acct_lock);
acct_file_reopen(acct, NULL, NULL);
spin_unlock(&acct_lock);
}
return error;
}
......
......@@ -523,8 +523,6 @@ int commit_creds(struct cred *new)
#endif
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 */
/* dumpability changes */
......
......@@ -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 retval;
retval = security_task_setgroups(group_info);
if (retval)
return retval;
put_group_info(new->group_info);
groups_sort(group_info);
get_group_info(group_info);
......
......@@ -492,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
return -ENOMEM;
old = current_cred();
retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
if (retval)
goto error;
retval = -EPERM;
if (rgid != (gid_t) -1) {
if (old->gid == rgid ||
......@@ -543,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
return -ENOMEM;
old = current_cred();
retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
if (retval)
goto error;
retval = -EPERM;
if (capable(CAP_SETGID))
new->gid = new->egid = new->sgid = new->fsgid = gid;
......@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
return -ENOMEM;
old = current_cred();
retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
if (retval)
goto error;
retval = -EPERM;
if (ruid != (uid_t) -1) {
new->uid = ruid;
......@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
return -ENOMEM;
old = current_cred();
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
if (retval)
goto error;
retval = -EPERM;
if (capable(CAP_SETUID)) {
new->suid = new->uid = uid;
......@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
if (!new)
return -ENOMEM;
retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
if (retval)
goto error;
old = current_cred();
retval = -EPERM;
......@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
return -ENOMEM;
old = current_cred();
retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
if (retval)
goto error;
retval = -EPERM;
if (!capable(CAP_SETGID)) {
if (rgid != (gid_t) -1 && rgid != old->gid &&
......@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
old = current_cred();
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 ||
uid == old->suid || uid == old->fsuid ||
capable(CAP_SETUID)) {
......@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
}
}
error:
abort_creds(new);
return old_fsuid;
......@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
old = current_cred();
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 ||
gid == old->sgid || gid == old->fsgid ||
capable(CAP_SETGID)) {
......@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
}
}
error:
abort_creds(new);
return old_fsgid;
......
......@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
fprintf(fout, "\n");
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);
for (j = 0; j < max(1, 40 - strlen(s)); j++)
fprintf(fout, " ");
......
......@@ -12,11 +12,6 @@
#include <linux/security.h>
static int cap_acct(struct file *file)
{
return 0;
}
static int cap_sysctl(ctl_table *table, int op)
{
return 0;
......@@ -80,42 +75,16 @@ static int cap_sb_mount(char *dev_name, struct path *path, char *type,
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)
{
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)
{
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,
struct security_mnt_opts *opts)
{
......@@ -221,10 +190,6 @@ static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
return 0;
}
static void cap_inode_delete(struct inode *ino)
{
}
static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
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)
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)
{
}
......@@ -426,16 +387,6 @@ static int cap_kernel_module_request(char *kmod_name)
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)
{
return 0;
......@@ -456,11 +407,6 @@ static void cap_task_getsecid(struct task_struct *p, u32 *secid)
*secid = 0;
}
static int cap_task_setgroups(struct group_info *group_info)
{
return 0;
}
static int cap_task_getioprio(struct task_struct *p)
{
return 0;
......@@ -875,13 +821,6 @@ static int cap_key_getsecurity(struct key *key, char **_buffer)
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 */
#ifdef CONFIG_AUDIT
......@@ -915,13 +854,12 @@ static void cap_audit_rule_free(void *lsmrule)
} \
} 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_traceme);
set_to_cap_if_null(ops, capget);
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, quotactl);
set_to_cap_if_null(ops, quota_on);
......@@ -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_statfs);
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_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_post_pivotroot);
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_parse_opts_str);
......@@ -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_setattr);
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_post_setxattr);
set_to_cap_if_null(ops, inode_getxattr);
......@@ -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_free);
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, kernel_act_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, task_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_getpgid);
set_to_cap_if_null(ops, task_getsid);
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_setioprio);
set_to_cap_if_null(ops, task_getioprio);
......@@ -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_permission);
set_to_cap_if_null(ops, key_getsecurity);
set_to_cap_if_null(ops, key_session_to_parent);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
set_to_cap_if_null(ops, audit_rule_init);
......
......@@ -570,7 +570,7 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
}
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
......@@ -596,7 +596,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
}
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
......@@ -931,7 +931,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
* @addr: address attempting to be mapped
* @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
* capability security module. Returns 0 if this mapping should be allowed
* -EPERM if not.
......
......@@ -470,7 +470,7 @@ struct cgroup_subsys devices_subsys = {
.name = "devices",
.can_attach = devcgroup_can_attach,
.create = devcgroup_create,
.destroy = devcgroup_destroy,
.destroy = devcgroup_destroy,
.populate = devcgroup_populate,
.subsys_id = devices_subsys_id,
};
......
......@@ -2,15 +2,14 @@
#
config IMA
bool "Integrity Measurement Architecture(IMA)"
depends on ACPI
depends on SECURITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_MD5
select CRYPTO_SHA1
select TCG_TPM
select TCG_TIS
select TCG_TPM if !S390
select TCG_TIS if TCG_TPM
help
The Trusted Computing Group(TCG) runtime Integrity
Measurement Architecture(IMA) maintains a list of hash
......
......@@ -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);
void ima_init_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);
/* LSM based policy rules require audit */
......
......@@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
return;
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,
audit_get_loginuid(current),
audit_get_sessionid(current));
......
......@@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc)
desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
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));
rc = PTR_ERR(desc->tfm);
return rc;
......@@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
return;
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 = {
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
char *data;
int rc;
char *data = NULL;
ssize_t result;
if (datalen >= PAGE_SIZE)
return -ENOMEM;
if (*ppos != 0) {
/* No partial writes. */
return -EINVAL;
}
datalen = PAGE_SIZE - 1;
/* No partial writes. */
result = -EINVAL;
if (*ppos != 0)
goto out;
result = -ENOMEM;
data = kmalloc(datalen + 1, GFP_KERNEL);
if (!data)
return -ENOMEM;
goto out;
if (copy_from_user(data, buf, datalen)) {
kfree(data);
return -EFAULT;
}
*(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);
return datalen;
return result;
}
static struct dentry *ima_dir;
......
......@@ -80,17 +80,17 @@ void iint_free(struct kref *kref)
iint->version = 0;
iint->flags = 0UL;
if (iint->readcount != 0) {
printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__,
printk(KERN_INFO "%s: readcount: %ld\n", __func__,
iint->readcount);
iint->readcount = 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 = 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 = 0;
}
......
......@@ -83,7 +83,7 @@ int __init ima_init(void)
ima_used_chip = 1;
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_init_policy();
......
......@@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
(iint->writecount < 0)) &&
!ima_limit_imbalance(file)) {
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);
dump_stack();
}
......
......@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
{
int result;
if (entry->lsm[lsm_rule].rule)
return -EINVAL;
entry->lsm[lsm_rule].type = audit_type;
result = security_filter_rule_init(entry->lsm[lsm_rule].type,
Audit_equal, args,
......@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
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)
{
struct audit_buffer *ab;
......@@ -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);
entry->action = -1;
while ((p = strsep(&rule, " \n")) != NULL) {
entry->uid = -1;
entry->action = UNKNOWN;
while ((p = strsep(&rule, " \t")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token;
unsigned long lnum;
if (result < 0)
break;
if (!*p)
if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
continue;
token = match_token(p, policy_tokens, args);
switch (token) {
case Opt_measure:
audit_log_format(ab, "%s ", "measure");
ima_log_string(ab, "action", "measure");
if (entry->action != UNKNOWN)
result = -EINVAL;
entry->action = MEASURE;
break;
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;
break;
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)
entry->func = FILE_CHECK;
/* PATH_CHECK is for backwards compat */
......@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
entry->flags |= IMA_FUNC;
break;
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)
entry->mask = MAY_EXEC;
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)
entry->flags |= IMA_MASK;
break;
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,
&entry->fsmagic);
if (!result)
entry->flags |= IMA_FSMAGIC;
break;
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);
if (!result) {
entry->uid = (uid_t) lnum;
......@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
}
break;
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,
LSM_OBJ_USER,
AUDIT_OBJ_USER);
break;
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,
LSM_OBJ_ROLE,
AUDIT_OBJ_ROLE);
break;
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,
LSM_OBJ_TYPE,
AUDIT_OBJ_TYPE);
break;
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,
LSM_SUBJ_USER,
AUDIT_SUBJ_USER);
break;
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,
LSM_SUBJ_ROLE,
AUDIT_SUBJ_ROLE);
break;
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,
LSM_SUBJ_TYPE,
AUDIT_SUBJ_TYPE);
break;
case Opt_err:
audit_log_format(ab, "UNKNOWN=%s ", p);
ima_log_string(ab, "UNKNOWN", p);
result = -EINVAL;
break;
}
}
if (entry->action == UNKNOWN)
if (!result && (entry->action == UNKNOWN))
result = -EINVAL;
audit_log_format(ab, "res=%d", !result ? 0 : 1);
audit_log_format(ab, "res=%d", !!result);
audit_log_end(ab);
return result;
}
......@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
* @rule - ima measurement policy rule
*
* 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";
char *p;
struct ima_measure_rule_entry *entry;
int result = 0;
ssize_t result, len;
int audit_info = 0;
/* Prevent installed policy from changing */
......@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule)
INIT_LIST_HEAD(&entry->list);
result = ima_parse_rule(rule, entry);
if (!result) {
mutex_lock(&ima_measure_mutex);
list_add_tail(&entry->list, &measure_policy_rules);
mutex_unlock(&ima_measure_mutex);
} else {
p = strsep(&rule, "\n");
len = strlen(p) + 1;
if (*p == '#') {
kfree(entry);
return len;
}
result = ima_parse_rule(p, entry);
if (result) {
kfree(entry);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
NULL, op, "invalid policy", result,
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 */
......
......@@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
qe = kmalloc(sizeof(*qe), GFP_KERNEL);
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;
}
qe->entry = entry;
......@@ -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);
if (result != 0)
pr_err("Error Communicating to TPM chip\n");
pr_err("IMA: Error Communicating to TPM chip\n");
return result;
}
......
......@@ -87,7 +87,16 @@ extern wait_queue_head_t request_key_conswq;
extern struct key_type *key_type_lookup(const char *type);
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,
const struct key_type *type,
......
......@@ -355,7 +355,7 @@ EXPORT_SYMBOL(key_alloc);
*/
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;
key_check(key);
......@@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
struct key *authkey)
struct key *authkey,
struct keyring_list **_prealloc)
{
int ret, awaken;
......@@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key,
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
__key_link(keyring, key, _prealloc);
/* disable the authorisation key */
if (authkey)
......@@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring,
struct key *authkey)
{
struct keyring_list *prealloc;
int ret;
if (keyring)
down_write(&keyring->sem);
if (keyring) {
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)
up_write(&keyring->sem);
__key_link_end(keyring, key->type, prealloc);
return ret;
......@@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key,
struct key *keyring,
struct key *authkey)
{
struct keyring_list *prealloc;
struct timespec now;
int ret, awaken;
int ret, awaken, link_ret = 0;
key_check(key);
key_check(keyring);
......@@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key,
ret = -EBUSY;
if (keyring)
down_write(&keyring->sem);
link_ret = __key_link_begin(keyring, key->type,
key->description, &prealloc);
mutex_lock(&key_construction_mutex);
......@@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key,
ret = 0;
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
if (keyring && link_ret == 0)
__key_link(keyring, key, &prealloc);
/* disable the authorisation key */
if (authkey)
......@@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key,
mutex_unlock(&key_construction_mutex);
if (keyring)
up_write(&keyring->sem);
__key_link_end(keyring, key->type, prealloc);
/* wake up anyone waiting for a key to be constructed */
if (awaken)
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret;
return ret == 0 ? link_ret : ret;
} /* end key_negate_and_link() */
......@@ -749,6 +758,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_perm_t perm,
unsigned long flags)
{
struct keyring_list *prealloc;
const struct cred *cred = current_cred();
struct key_type *ktype;
struct key *keyring, *key = NULL;
......@@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
if (keyring->type != &key_type_keyring)
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
* to modify the keyring */
......@@ -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 */
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
&prealloc);
if (ret < 0) {
key_put(key);
key_ref = ERR_PTR(ret);
......@@ -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));
error_3:
up_write(&keyring->sem);
__key_link_end(keyring, ktype, prealloc);
error_2:
key_type_put(ktype);
error:
......@@ -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 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_ref = __key_update(key_ref, payload, plen);
......
......@@ -212,15 +212,15 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
ret = key->serial;
key_put(key);
error5:
error5:
key_type_put(ktype);
error4:
error4:
key_ref_put(dest_ref);
error3:
error3:
kfree(callout_info);
error2:
error2:
kfree(description);
error:
error:
return ret;
} /* end sys_request_key() */
......@@ -246,7 +246,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
error:
error:
return ret;
} /* end keyctl_get_keyring_ID() */
......@@ -275,7 +275,7 @@ long keyctl_join_session_keyring(const char __user *_name)
ret = join_session_keyring(name);
kfree(name);
error:
error:
return ret;
} /* end keyctl_join_session_keyring() */
......@@ -322,9 +322,9 @@ long keyctl_update_key(key_serial_t id,
ret = key_update(key_ref, payload, plen);
key_ref_put(key_ref);
error2:
error2:
kfree(payload);
error:
error:
return ret;
} /* end keyctl_update_key() */
......@@ -356,7 +356,7 @@ long keyctl_revoke_key(key_serial_t id)
ret = 0;
key_ref_put(key_ref);
error:
error:
return ret;
} /* end keyctl_revoke_key() */
......@@ -381,7 +381,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
ret = keyring_clear(key_ref_to_ptr(keyring_ref));
key_ref_put(keyring_ref);
error:
error:
return ret;
} /* end keyctl_keyring_clear() */
......@@ -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));
key_ref_put(key_ref);
error2:
error2:
key_ref_put(keyring_ref);
error:
error:
return ret;
} /* end keyctl_keyring_link() */
......@@ -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));
key_ref_put(key_ref);
error2:
error2:
key_ref_put(keyring_ref);
error:
error:
return ret;
} /* end keyctl_keyring_unlink() */
......@@ -529,9 +529,9 @@ long keyctl_describe_key(key_serial_t keyid,
}
kfree(tmpbuf);
error2:
error2:
key_ref_put(key_ref);
error:
error:
return ret;
} /* end keyctl_describe_key() */
......@@ -616,17 +616,17 @@ long keyctl_keyring_search(key_serial_t ringid,
ret = key_ref_to_ptr(key_ref)->serial;
error6:
error6:
key_ref_put(key_ref);
error5:
error5:
key_type_put(ktype);
error4:
error4:
key_ref_put(dest_ref);
error3:
error3:
key_ref_put(keyring_ref);
error2:
error2:
kfree(description);
error:
error:
return ret;
} /* end keyctl_keyring_search() */
......@@ -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 */
can_read_key:
can_read_key:
ret = key_validate(key);
if (ret == 0) {
ret = -EOPNOTSUPP;
......@@ -686,9 +686,9 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
}
}
error2:
error2:
key_put(key);
error:
error:
return ret;
} /* end keyctl_read_key() */
......@@ -1282,26 +1282,19 @@ long keyctl_session_to_parent(void)
/* the parent must have the same effective ownership and mustn't be
* SUID/SGID */
if (pcred-> uid != mycred->euid ||
if (pcred->uid != mycred->euid ||
pcred->euid != mycred->euid ||
pcred->suid != mycred->euid ||
pcred-> gid != mycred->egid ||
pcred->gid != mycred->egid ||
pcred->egid != mycred->egid ||
pcred->sgid != mycred->egid)
goto not_permitted;
/* 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)
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
* that */
oldcred = parent->replacement_session_keyring;
......
This diff is collapsed.
......@@ -109,7 +109,7 @@ int key_validate(struct key *key)
}
}
error:
error:
return ret;
} /* end key_validate() */
......
......@@ -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)
{
(*_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)
......
......@@ -508,7 +508,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ret = install_thread_keyring();
if (ret < 0) {
key = ERR_PTR(ret);
key_ref = ERR_PTR(ret);
goto error;
}
goto reget_creds;
......@@ -526,7 +526,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ret = install_process_keyring();
if (ret < 0) {
key = ERR_PTR(ret);
key_ref = ERR_PTR(ret);
goto error;
}
goto reget_creds;
......@@ -585,7 +585,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
case KEY_SPEC_GROUP_KEYRING:
/* group keyrings are not yet supported */
key = ERR_PTR(-EINVAL);
key_ref = ERR_PTR(-EINVAL);
goto error;
case KEY_SPEC_REQKEY_AUTH_KEY:
......
......@@ -299,12 +299,15 @@ static int construct_alloc_key(struct key_type *type,
struct key_user *user,
struct key **_key)
{
struct keyring_list *prealloc;
const struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref;
int ret;
kenter("%s,%s,,,", type->name, description);
*_key = NULL;
mutex_lock(&user->cons_lock);
key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
......@@ -314,8 +317,12 @@ static int construct_alloc_key(struct key_type *type,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
if (dest_keyring)
down_write(&dest_keyring->sem);
if (dest_keyring) {
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
* 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,
goto key_already_present;
if (dest_keyring)
__key_link(dest_keyring, key);
__key_link(dest_keyring, key, &prealloc);
mutex_unlock(&key_construction_mutex);
if (dest_keyring)
up_write(&dest_keyring->sem);
__key_link_end(dest_keyring, type, prealloc);
mutex_unlock(&user->cons_lock);
*_key = key;
kleave(" = 0 [%d]", key_serial(key));
return 0;
/* the key is now present - we tell the caller that we found it by
* returning -EINPROGRESS */
key_already_present:
key_put(key);
mutex_unlock(&key_construction_mutex);
key = key_ref_to_ptr(key_ref);
if (dest_keyring) {
__key_link(dest_keyring, key_ref_to_ptr(key_ref));
up_write(&dest_keyring->sem);
ret = __key_link_check_live_key(dest_keyring, key);
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);
key_put(key);
*_key = key = key_ref_to_ptr(key_ref);
*_key = key;
kleave(" = -EINPROGRESS [%d]", key_serial(key));
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:
mutex_unlock(&user->cons_lock);
*_key = NULL;
kleave(" = %ld", PTR_ERR(key));
return PTR_ERR(key);
}
......@@ -390,6 +415,10 @@ static struct key *construct_key_and_link(struct key_type *type,
kdebug("cons failed");
goto construction_failed;
}
} else if (ret == -EINPROGRESS) {
ret = 0;
} else {
key = ERR_PTR(ret);
}
key_put(dest_keyring);
......@@ -422,6 +451,7 @@ struct key *request_key_and_link(struct key_type *type,
const struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref;
int ret;
kenter("%s,%s,%p,%zu,%p,%p,%lx",
type->name, description, callout_info, callout_len, aux,
......@@ -435,8 +465,13 @@ struct key *request_key_and_link(struct key_type *type,
key = key_ref_to_ptr(key_ref);
if (dest_keyring) {
construct_get_dest_keyring(&dest_keyring);
key_link(dest_keyring, key);
ret = key_link(dest_keyring, key);
key_put(dest_keyring);
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
goto error;
}
}
} else if (PTR_ERR(key_ref) != -EAGAIN) {
key = ERR_CAST(key_ref);
......
......@@ -221,7 +221,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
}
switch (a->type) {
case LSM_AUDIT_NO_AUDIT:
case LSM_AUDIT_DATA_NONE:
return;
case LSM_AUDIT_DATA_IPC:
audit_log_format(ab, " key=%d ", a->u.ipc_id);
......
......@@ -23,14 +23,14 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY;
/* 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 default_security_ops = {
.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 */
if (!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,
* 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)) {
printk(KERN_DEBUG "%s could not verify "
......@@ -190,11 +190,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
return ret;
}
int security_acct(struct file *file)
{
return security_ops->acct(file);
}
int security_sysctl(struct ctl_table *table, int op)
{
return security_ops->sysctl(table, op);
......@@ -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);
}
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)
{
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)
{
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,
struct security_mnt_opts *opts)
{
......@@ -580,13 +545,6 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *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,
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)
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)
{
security_ops->cred_transfer(new, old);
......@@ -774,22 +727,12 @@ int security_kernel_module_request(char *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 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)
{
return security_ops->task_setpgid(p, pgid);
......@@ -811,11 +754,6 @@ void security_task_getsecid(struct task_struct *p, u32 *secid)
}
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)
{
return security_ops->task_setnice(p, nice);
......@@ -1319,13 +1257,6 @@ int security_key_getsecurity(struct key *key, char **_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 */
#ifdef CONFIG_AUDIT
......
......@@ -499,8 +499,7 @@ void avc_audit(u32 ssid, u32 tsid,
return;
if (!a) {
a = &stack_data;
memset(a, 0, sizeof(*a));
a->type = LSM_AUDIT_NO_AUDIT;
COMMON_AUDIT_DATA_INIT(a, NONE);
}
a->selinux_audit_data.tclass = tclass;
a->selinux_audit_data.requested = requested;
......
......@@ -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)
{
struct sk_security_struct *ssec;
struct sk_security_struct *sksec;
ssec = kzalloc(sizeof(*ssec), priority);
if (!ssec)
sksec = kzalloc(sizeof(*sksec), priority);
if (!sksec)
return -ENOMEM;
ssec->peer_sid = SECINITSID_UNLABELED;
ssec->sid = SECINITSID_UNLABELED;
sk->sk_security = ssec;
sksec->peer_sid = SECINITSID_UNLABELED;
sksec->sid = SECINITSID_UNLABELED;
sk->sk_security = sksec;
selinux_netlbl_sk_security_reset(ssec);
selinux_netlbl_sk_security_reset(sksec);
return 0;
}
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;
selinux_netlbl_sk_security_free(ssec);
kfree(ssec);
selinux_netlbl_sk_security_free(sksec);
kfree(sksec);
}
/* The security server must be initialized before
......@@ -323,7 +323,7 @@ extern int ss_initialized;
/* 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 transition SIDs",
"uses task SIDs",
......@@ -2999,13 +2999,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
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)
{
const struct cred *cred = current_cred();
int rc = 0;
#ifndef CONFIG_PPC32
if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
if (default_noexec &&
(prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
/*
* We are making executable an anonymous mapping or a
* 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
if (rc)
goto error;
}
#endif
if (file) {
/* read access is always possible with a mapping */
......@@ -3076,8 +3077,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (selinux_checkreqprot)
prot = reqprot;
#ifndef CONFIG_PPC32
if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
int rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
......@@ -3099,7 +3100,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (rc)
return rc;
}
#endif
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,
struct socket *other,
struct sock *newsk)
{
struct sk_security_struct *ssec;
struct sk_security_struct *sksec;
struct inode_security_struct *isec;
struct inode_security_struct *other_isec;
struct common_audit_data ad;
......@@ -4021,13 +4021,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
return err;
/* connecting socket */
ssec = sock->sk->sk_security;
ssec->peer_sid = other_isec->sid;
sksec = sock->sk->sk_security;
sksec->peer_sid = other_isec->sid;
/* server child socket */
ssec = newsk->sk_security;
ssec->peer_sid = isec->sid;
err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
sksec = newsk->sk_security;
sksec->peer_sid = isec->sid;
err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
return err;
}
......@@ -4190,7 +4190,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
int err = 0;
char *scontext;
u32 scontext_len;
struct sk_security_struct *ssec;
struct sk_security_struct *sksec;
struct inode_security_struct *isec;
u32 peer_sid = SECSID_NULL;
......@@ -4198,8 +4198,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
isec->sclass == SECCLASS_TCP_SOCKET) {
ssec = sock->sk->sk_security;
peer_sid = ssec->peer_sid;
sksec = sock->sk->sk_security;
peer_sid = sksec->peer_sid;
}
if (peer_sid == SECSID_NULL) {
err = -ENOPROTOOPT;
......@@ -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)
{
struct sk_security_struct *ssec = sk->sk_security;
struct sk_security_struct *newssec = newsk->sk_security;
struct sk_security_struct *sksec = sk->sk_security;
struct sk_security_struct *newsksec = newsk->sk_security;
newssec->sid = ssec->sid;
newssec->peer_sid = ssec->peer_sid;
newssec->sclass = ssec->sclass;
newsksec->sid = sksec->sid;
newsksec->peer_sid = sksec->peer_sid;
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)
......@@ -5662,6 +5662,8 @@ static __init int selinux_init(void)
/* Set the security state for the initial task. */
cred_init_security();
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL);
......
/* This file is automatically generated. Do not edit. */
static char *initial_sid_to_string[] =
static const char *initial_sid_to_string[] =
{
"null",
"kernel",
......
......@@ -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_sk_security_free(struct sk_security_struct *ssec);
void selinux_netlbl_sk_security_reset(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 *sksec);
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
......@@ -79,13 +79,13 @@ static inline void selinux_netlbl_err(struct sk_buff *skb,
}
static inline void selinux_netlbl_sk_security_free(
struct sk_security_struct *ssec)
struct sk_security_struct *sksec)
{
return;
}
static inline void selinux_netlbl_sk_security_reset(
struct sk_security_struct *ssec)
struct sk_security_struct *sksec)
{
return;
}
......
......@@ -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
* @sssec: the sk_security_struct
* @sksec: the sk_security_struct
*
* Description:
* 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)
netlbl_secattr_free(ssec->nlbl_secattr);
if (sksec->nlbl_secattr != NULL)
netlbl_secattr_free(sksec->nlbl_secattr);
}
/**
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
* @ssec: the sk_security_struct
* @sksec: the sk_security_struct
* @family: the socket family
*
* Description:
......@@ -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.
*
*/
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 @@
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/selinux_netlink.h>
......
......@@ -11,7 +11,6 @@
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
......
......@@ -503,11 +503,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
return length;
length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL);
scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon)
return length;
tcon = kzalloc(size+1, GFP_KERNEL);
tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon)
goto out;
......@@ -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)
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)
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)
goto out2;
......@@ -550,11 +550,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
return length;
length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL);
scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon)
return length;
tcon = kzalloc(size+1, GFP_KERNEL);
tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon)
goto out;
......@@ -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)
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)
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)
goto out2;
......@@ -609,11 +609,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
return length;
length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL);
scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon)
return length;
tcon = kzalloc(size+1, GFP_KERNEL);
tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon)
goto out;
......@@ -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)
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)
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)
goto out2;
......@@ -666,11 +666,11 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
return length;
length = -ENOMEM;
con = kzalloc(size+1, GFP_KERNEL);
con = kzalloc(size + 1, GFP_KERNEL);
if (!con)
return length;
user = kzalloc(size+1, GFP_KERNEL);
user = kzalloc(size + 1, GFP_KERNEL);
if (!user)
goto out;
......@@ -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)
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)
goto out2;
......@@ -727,11 +727,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
return length;
length = -ENOMEM;
scon = kzalloc(size+1, GFP_KERNEL);
scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon)
return length;
tcon = kzalloc(size+1, GFP_KERNEL);
tcon = kzalloc(size + 1, GFP_KERNEL);
if (!tcon)
goto out;
......@@ -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)
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)
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)
goto out2;
......@@ -1401,7 +1401,7 @@ static int sel_make_perm_files(char *objclass, int classvalue,
}
inode->i_fop = &sel_perm_ops;
/* 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);
}
......@@ -1489,7 +1489,7 @@ static int sel_make_classes(void)
goto out;
/* +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++) {
struct dentry *class_name_dir;
......@@ -1506,7 +1506,7 @@ static int sel_make_classes(void)
goto out1;
/* 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);
if (rc)
goto out1;
......
......@@ -255,7 +255,7 @@ int mls_context_to_sid(struct policydb *pol,
if (!pol->mls_enabled) {
if (def_sid != SECSID_NULL && oldc)
*scontext += strlen(*scontext)+1;
*scontext += strlen(*scontext) + 1;
return 0;
}
......
......@@ -40,7 +40,7 @@
#define _DEBUG_HASHES
#ifdef DEBUG_HASHES
static char *symtab_name[SYM_NUM] = {
static const char *symtab_name[SYM_NUM] = {
"common prefixes",
"classes",
"roles",
......@@ -156,12 +156,11 @@ static int roles_init(struct policydb *p)
rc = -EINVAL;
goto out_free_role;
}
key = kmalloc(strlen(OBJECT_R)+1, GFP_KERNEL);
key = kstrdup(OBJECT_R, GFP_KERNEL);
if (!key) {
rc = -ENOMEM;
goto out_free_role;
}
strcpy(key, OBJECT_R);
rc = hashtab_insert(p->p_roles.table, key, role);
if (rc)
goto out_free_key;
......@@ -2195,7 +2194,7 @@ int policydb_read(struct policydb *p, void *fp)
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)
goto bad;
......
......@@ -274,15 +274,15 @@ static int constraint_expr_eval(struct context *scontext,
case CEXPR_AND:
BUG_ON(sp < 1);
sp--;
s[sp] &= s[sp+1];
s[sp] &= s[sp + 1];
break;
case CEXPR_OR:
BUG_ON(sp < 1);
sp--;
s[sp] |= s[sp+1];
s[sp] |= s[sp + 1];
break;
case CEXPR_ATTR:
if (sp == (CEXPR_MAXDEPTH-1))
if (sp == (CEXPR_MAXDEPTH - 1))
return 0;
switch (e->attr) {
case CEXPR_USER:
......@@ -1216,7 +1216,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
*sid = SECSID_NULL;
/* 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)
return -ENOMEM;
memcpy(scontext2, scontext, scontext_len);
......@@ -1760,22 +1760,28 @@ int security_load_policy(void *data, size_t len)
if (!ss_initialized) {
avtab_cache_init();
if (policydb_read(&policydb, fp)) {
rc = policydb_read(&policydb, fp);
if (rc) {
avtab_cache_destroy();
return -EINVAL;
return rc;
}
if (selinux_set_mapping(&policydb, secclass_map,
&current_mapping,
&current_mapping_size)) {
rc = selinux_set_mapping(&policydb, secclass_map,
&current_mapping,
&current_mapping_size);
if (rc) {
policydb_destroy(&policydb);
avtab_cache_destroy();
return -EINVAL;
return rc;
}
if (policydb_load_isids(&policydb, &sidtab)) {
rc = policydb_load_isids(&policydb, &sidtab);
if (rc) {
policydb_destroy(&policydb);
avtab_cache_destroy();
return -EINVAL;
return rc;
}
security_load_policycaps();
ss_initialized = 1;
seqno = ++latest_granting;
......@@ -1791,8 +1797,9 @@ int security_load_policy(void *data, size_t len)
sidtab_hash_eval(&sidtab, "sids");
#endif
if (policydb_read(&newpolicydb, fp))
return -EINVAL;
rc = policydb_read(&newpolicydb, fp);
if (rc)
return rc;
/* If switching between different policy types, log MLS status */
if (policydb.mls_enabled && !newpolicydb.mls_enabled)
......@@ -1807,8 +1814,8 @@ int security_load_policy(void *data, size_t len)
return rc;
}
if (selinux_set_mapping(&newpolicydb, secclass_map,
&map, &map_size))
rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
if (rc)
goto err;
rc = security_preserve_bools(&newpolicydb);
......@@ -1819,10 +1826,10 @@ int security_load_policy(void *data, size_t len)
/* Clone the SID table. */
sidtab_shutdown(&sidtab);
if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
rc = -ENOMEM;
rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
if (rc)
goto err;
}
/*
* Convert the internal representations of contexts
......@@ -2101,9 +2108,9 @@ int security_get_user_sids(u32 fromsid,
ebitmap_for_each_positive_bit(&user->roles, rnode, 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) {
usercon.type = j+1;
usercon.type = j + 1;
if (mls_setup_user_range(fromcon, user, &usercon))
continue;
......
......@@ -19,7 +19,6 @@
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/stat.h>
#include <linux/ext2_fs.h>
#include <linux/kd.h>
#include <asm/ioctls.h>
#include <linux/ip.h>
......@@ -1118,15 +1117,6 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
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
* @new: the new credentials
......@@ -3121,7 +3111,6 @@ struct security_operations smack_ops = {
.cred_alloc_blank = smack_cred_alloc_blank,
.cred_free = smack_cred_free,
.cred_prepare = smack_cred_prepare,
.cred_commit = smack_cred_commit,
.cred_transfer = smack_cred_transfer,
.kernel_act_as = smack_kernel_act_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,
static int tomoyo_write_control(struct file *file, const char __user *buffer,
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.
*
......@@ -171,6 +214,33 @@ static void tomoyo_normalize_line(unsigned char *buffer)
*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.
* @filename: The pathname to check.
......@@ -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
int profile)
{
static DEFINE_MUTEX(lock);
struct tomoyo_profile *ptr = NULL;
int i;
if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
mutex_lock(&lock);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return NULL;
ptr = tomoyo_profile_ptr[profile];
if (ptr)
goto ok;
ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
if (!tomoyo_memory_ok(ptr)) {
kfree(ptr);
ptr = NULL;
......@@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
mb(); /* Avoid out-of-order execution. */
tomoyo_profile_ptr[profile] = ptr;
ok:
mutex_unlock(&lock);
mutex_unlock(&tomoyo_policy_lock);
return ptr;
}
......@@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list);
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
{
struct tomoyo_policy_manager_entry *entry = NULL;
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;
bool is_domain = false;
if (tomoyo_is_domain_def(manager)) {
if (!tomoyo_is_correct_domain(manager))
return -EINVAL;
is_domain = true;
e.is_domain = true;
} else {
if (!tomoyo_is_correct_path(manager, 1, -1, -1))
return -EINVAL;
}
saved_manager = tomoyo_get_name(manager);
if (!saved_manager)
e.manager = tomoyo_get_name(manager);
if (!e.manager)
return -ENOMEM;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
if (ptr->manager != saved_manager)
if (ptr->manager != e.manager)
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->manager = saved_manager;
saved_manager = NULL;
entry->is_domain = is_domain;
list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_policy_manager_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list,
&tomoyo_policy_manager_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
tomoyo_put_name(saved_manager);
kfree(entry);
out:
tomoyo_put_name(e.manager);
return error;
}
......@@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname)
name.name = domainname;
tomoyo_fill_path_info(&name);
mutex_lock(&tomoyo_policy_lock);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return 0;
/* Is there an active domain? */
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
/* Never delete tomoyo_kernel_domain */
......@@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
{
int pos;
u8 bit;
const char *atmark = "";
const char *filename;
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++) {
const char *msg;
if (!(perm & (1 << bit)))
continue;
/* Print "read/write" instead of "read" and "write". */
if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
&& (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
continue;
msg = tomoyo_path2keyword(bit);
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg,
atmark, filename))
if (!tomoyo_io_printf(head, "allow_%s ",
tomoyo_path2keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_io_printf(head, "\n"))
goto out;
}
head->read_bit = 0;
......@@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
struct tomoyo_path2_acl *ptr)
{
int pos;
const char *atmark1 = "";
const char *atmark2 = "";
const char *filename1;
const char *filename2;
const u8 perm = ptr->perm;
u8 bit;
filename1 = ptr->filename1->name;
filename2 = ptr->filename2->name;
for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
const char *msg;
if (!(perm & (1 << bit)))
continue;
msg = tomoyo_path22keyword(bit);
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg,
atmark1, filename1, atmark2, filename2))
if (!tomoyo_io_printf(head, "allow_%s ",
tomoyo_path22keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name1) ||
!tomoyo_print_name_union(head, &ptr->name2) ||
!tomoyo_io_printf(head, "\n"))
goto out;
}
head->read_bit = 0;
......@@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
return tomoyo_write_pattern_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
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;
}
......@@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
head->read_var2 = NULL;
head->read_step = 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;
break;
default:
......@@ -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)
{
struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL);
struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
if (!head)
return -ENOMEM;
......@@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
} else {
if (!head->readbuf_size)
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) {
kfree(head);
return -ENOMEM;
......@@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
head->write = NULL;
} else if (head->write) {
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) {
kfree(head->read_buf);
kfree(head);
......
......@@ -54,6 +54,7 @@ struct linux_binprm;
#define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain "
#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_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_USE_PROFILE "use_profile "
#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read"
......@@ -204,6 +205,27 @@ struct tomoyo_path_info_with_data {
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
*
......@@ -274,7 +296,7 @@ struct tomoyo_domain_info {
*
* (1) "head" which is a "struct tomoyo_acl_info".
* (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",
* "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
......@@ -287,8 +309,7 @@ struct tomoyo_path_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
u8 perm_high;
u16 perm;
/* Pointer to single pathname. */
const struct tomoyo_path_info *filename;
struct tomoyo_name_union name;
};
/*
......@@ -298,8 +319,8 @@ struct tomoyo_path_acl {
*
* (1) "head" which is a "struct tomoyo_acl_info".
* (2) "perm" which is a bitmask of permitted operations.
* (3) "filename1" is the source/old pathname.
* (4) "filename2" is the destination/new pathname.
* (3) "name1" is the source/old pathname.
* (4) "name2" is the destination/new pathname.
*
* Directives held by this structure are "allow_rename", "allow_link" and
* "allow_pivot_root".
......@@ -307,10 +328,8 @@ struct tomoyo_path_acl {
struct tomoyo_path2_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */
u8 perm;
/* Pointer to single pathname. */
const struct tomoyo_path_info *filename1;
/* Pointer to single pathname. */
const struct tomoyo_path_info *filename2;
struct tomoyo_name_union name1;
struct tomoyo_name_union name2;
};
/*
......@@ -514,6 +533,9 @@ struct tomoyo_policy_manager_entry {
/********** 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. */
bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
/* Transactional sprintf() for policy dump. */
......@@ -526,6 +548,12 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
const s8 pattern_type, const s8 end_type);
/* Check whether the token can be a domainname. */
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. */
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern);
......@@ -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);
/* Read "file_pattern" entry in exception policy. */
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. */
bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
/* Read "deny_rewrite" entry in exception policy. */
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? */
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
/* Convert double path operation to operation name. */
......@@ -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);
/* Create "file_pattern" entry in exception policy. */
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. */
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
/* Find or create a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname,
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. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
const u8 index);
......@@ -616,6 +654,7 @@ char *tomoyo_realpath_from_path(struct path *path);
/* Check memory quota. */
bool tomoyo_memory_ok(void *ptr);
void *tomoyo_commit_ok(void *data, const unsigned int size);
/*
* Keep the given name on the RAM.
......@@ -641,6 +680,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
int tomoyo_check_rewrite_permission(struct file *filp);
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. */
void tomoyo_run_gc(void);
......@@ -654,6 +696,7 @@ extern struct srcu_struct tomoyo_ss;
/* The list for "struct tomoyo_domain_info". */
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_keeper_list;
extern struct list_head tomoyo_alias_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_policy_manager_list;
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
extern struct mutex tomoyo_name_list_lock;
/* Lock for protecting policy. */
extern struct mutex tomoyo_policy_lock;
......@@ -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)
{
return current_cred()->security;
......@@ -736,6 +784,59 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
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.
* @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,
const bool is_not,
const bool is_delete)
{
struct tomoyo_domain_initializer_entry *entry = NULL;
struct tomoyo_domain_initializer_entry *ptr;
const struct tomoyo_path_info *saved_program = NULL;
const struct tomoyo_path_info *saved_domainname = NULL;
struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */
if (domainname) {
if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true;
e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL;
saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
e.domainname = tomoyo_get_name(domainname);
if (!e.domainname)
goto out;
}
saved_program = tomoyo_get_name(program);
if (!saved_program)
e.program = tomoyo_get_name(program);
if (!e.program)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
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) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->domainname = saved_domainname;
saved_domainname = NULL;
entry->program = saved_program;
saved_program = NULL;
entry->is_not = is_not;
entry->is_last_name = is_last_name;
list_add_tail_rcu(&entry->list,
&tomoyo_domain_initializer_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_domain_initializer_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list,
&tomoyo_domain_initializer_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_domainname);
tomoyo_put_name(saved_program);
kfree(entry);
tomoyo_put_name(e.domainname);
tomoyo_put_name(e.program);
return error;
}
......@@ -350,56 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
const bool is_not,
const bool is_delete)
{
struct tomoyo_domain_keeper_entry *entry = NULL;
struct tomoyo_domain_keeper_entry *ptr;
const struct tomoyo_path_info *saved_domainname = NULL;
const struct tomoyo_path_info *saved_program = NULL;
struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true;
e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL;
if (program) {
if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL;
saved_program = tomoyo_get_name(program);
if (!saved_program)
e.program = tomoyo_get_name(program);
if (!e.program)
goto out;
}
saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
e.domainname = tomoyo_get_name(domainname);
if (!e.domainname)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
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) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->domainname = saved_domainname;
saved_domainname = NULL;
entry->program = saved_program;
saved_program = NULL;
entry->is_not = is_not;
entry->is_last_name = is_last_name;
list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_domain_keeper_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list,
&tomoyo_domain_keeper_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_domainname);
tomoyo_put_name(saved_program);
kfree(entry);
tomoyo_put_name(e.domainname);
tomoyo_put_name(e.program);
return error;
}
......@@ -551,44 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name,
const char *aliased_name,
const bool is_delete)
{
struct tomoyo_alias_entry *entry = NULL;
struct tomoyo_alias_entry *ptr;
const struct tomoyo_path_info *saved_original_name;
const struct tomoyo_path_info *saved_aliased_name;
struct tomoyo_alias_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
!tomoyo_is_correct_path(aliased_name, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */
saved_original_name = tomoyo_get_name(original_name);
saved_aliased_name = tomoyo_get_name(aliased_name);
if (!saved_original_name || !saved_aliased_name)
e.original_name = tomoyo_get_name(original_name);
e.aliased_name = tomoyo_get_name(aliased_name);
if (!e.original_name || !e.aliased_name)
goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
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) {
if (ptr->original_name != saved_original_name ||
ptr->aliased_name != saved_aliased_name)
if (!tomoyo_is_same_alias_entry(ptr, &e))
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->original_name = saved_original_name;
saved_original_name = NULL;
entry->aliased_name = saved_aliased_name;
saved_aliased_name = NULL;
list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_alias_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_original_name);
tomoyo_put_name(saved_aliased_name);
kfree(entry);
tomoyo_put_name(e.original_name);
tomoyo_put_name(e.aliased_name);
return error;
}
......@@ -656,7 +631,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
const u8 profile)
{
struct tomoyo_domain_info *entry;
struct tomoyo_domain_info *domain;
struct tomoyo_domain_info *domain = NULL;
const struct tomoyo_path_info *saved_domainname;
bool found = false;
......@@ -665,8 +640,9 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
return NULL;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
entry = kzalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
if (domain->is_deleted ||
tomoyo_pathcmp(saved_domainname, domain->domainname))
......@@ -685,6 +661,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
found = true;
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_domainname);
kfree(entry);
return found ? domain : NULL;
......@@ -705,7 +682,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* This function assumes that the size of buffer returned by
* 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 *domain = NULL;
const char *old_domain_name = old_domain->domainname->name;
......
This diff is collapsed.
......@@ -12,6 +12,8 @@
#include <linux/slab.h>
enum tomoyo_gc_id {
TOMOYO_ID_PATH_GROUP,
TOMOYO_ID_PATH_GROUP_MEMBER,
TOMOYO_ID_DOMAIN_INITIALIZER,
TOMOYO_ID_DOMAIN_KEEPER,
TOMOYO_ID_ALIAS,
......@@ -91,15 +93,15 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
{
struct tomoyo_path_acl *entry
= container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename);
tomoyo_put_name_union(&entry->name);
}
break;
case TOMOYO_TYPE_PATH2_ACL:
{
struct tomoyo_path2_acl *entry
= container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename1);
tomoyo_put_name(entry->filename2);
tomoyo_put_name_union(&entry->name1);
tomoyo_put_name_union(&entry->name2);
}
break;
default:
......@@ -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)
{
mutex_lock(&tomoyo_policy_lock);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return;
{
struct tomoyo_globally_readable_file_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
......@@ -275,8 +289,6 @@ static void tomoyo_collect_entry(void)
break;
}
}
mutex_unlock(&tomoyo_policy_lock);
mutex_lock(&tomoyo_name_list_lock);
{
int i;
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
......@@ -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)
......@@ -335,6 +370,12 @@ static void tomoyo_kfree_entry(void)
if (!tomoyo_del_domain(p->element))
continue;
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:
printk(KERN_WARNING "Unknown type\n");
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,
*/
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)
<= TOMOYO_MAX_PATHNAME_LEN - 1);
......@@ -222,6 +222,25 @@ bool tomoyo_memory_ok(void *ptr)
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.
*
......@@ -240,8 +259,6 @@ void tomoyo_memory_free(void *ptr)
* "const struct tomoyo_path_info *".
*/
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.
......@@ -263,14 +280,15 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
len = strlen(name) + 1;
hash = full_name_hash((const unsigned char *) name, len - 1);
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) {
if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
continue;
atomic_inc(&ptr->users);
goto out;
}
ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
allocated_len = ptr ? ksize(ptr) : 0;
if (!ptr || (tomoyo_quota_for_policy &&
atomic_read(&tomoyo_policy_memory_size) + allocated_len
......@@ -290,7 +308,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
tomoyo_fill_path_info(&ptr->entry);
list_add_tail(&ptr->list, head);
out:
mutex_unlock(&tomoyo_name_list_lock);
mutex_unlock(&tomoyo_policy_lock);
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