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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (61 commits)
  KEYS: Return more accurate error codes
  LSM: Add __init to fixup function.
  TOMOYO: Add pathname grouping support.
  ima: remove ACPI dependency
  TPM: ACPI/PNP dependency removal
  security/selinux/ss: Use kstrdup
  TOMOYO: Use stack memory for pending entry.
  Revert "ima: remove ACPI dependency"
  Revert "TPM: ACPI/PNP dependency removal"
  KEYS: Do preallocation for __key_link()
  TOMOYO: Use mutex_lock_interruptible.
  KEYS: Better handling of errors from construct_alloc_key()
  KEYS: keyring_serialise_link_sem is only needed for keyring->keyring links
  TOMOYO: Use GFP_NOFS rather than GFP_KERNEL.
  ima: remove ACPI dependency
  TPM: ACPI/PNP dependency removal
  selinux: generalize disabling of execmem for plt-in-heap archs
  LSM Audit: rename LSM_AUDIT_NO_AUDIT to LSM_AUDIT_DATA_NONE
  CRED: Holding a spinlock does not imply the holding of RCU read lock
  SMACK: Don't #include Ext2 headers
  ...
This commit is contained in:
Linus Torvalds 2010-05-20 08:55:50 -07:00
commit 96b5b7f4f2
57 changed files with 1248 additions and 1063 deletions

View file

@ -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:

View file

@ -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.
@ -2616,6 +2617,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.

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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 {

View file

@ -267,49 +267,16 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @orig the original mount data copied from userspace.
* @copy copied data which will be passed to the security module.
* Returns 0 if the copy was successful.
* @sb_check_sb:
* Check permission before the device with superblock @mnt->sb is mounted
* on the mount point named by @nd.
* @mnt contains the vfsmount for device being mounted.
* @path contains the path for the mount point.
* Return 0 if permission is granted.
* @sb_umount:
* Check permission before the @mnt file system is unmounted.
* @mnt contains the mounted file system.
* @flags contains the unmount flags, e.g. MNT_FORCE.
* Return 0 if permission is granted.
* @sb_umount_close:
* Close any files in the @mnt mounted filesystem that are held open by
* the security module. This hook is called during an umount operation
* prior to checking whether the filesystem is still busy.
* @mnt contains the mounted filesystem.
* @sb_umount_busy:
* Handle a failed umount of the @mnt mounted filesystem, e.g. re-opening
* any files that were closed by umount_close. This hook is called during
* an umount operation if the umount fails after a call to the
* umount_close hook.
* @mnt contains the mounted filesystem.
* @sb_post_remount:
* Update the security module's state when a filesystem is remounted.
* This hook is only called if the remount was successful.
* @mnt contains the mounted file system.
* @flags contains the new filesystem flags.
* @data contains the filesystem-specific data.
* @sb_post_addmount:
* Update the security module's state when a filesystem is mounted.
* This hook is called any time a mount is successfully grafetd to
* the tree.
* @mnt contains the mounted filesystem.
* @mountpoint contains the path for the mount point.
* @sb_pivotroot:
* Check permission before pivoting the root filesystem.
* @old_path contains the path for the new location of the current root (put_old).
* @new_path contains the path for the new root (new_root).
* Return 0 if permission is granted.
* @sb_post_pivotroot:
* Update module state after a successful pivot.
* @old_path contains the path for the old root.
* @new_path contains the path for the new root.
* @sb_set_mnt_opts:
* Set the security relevant mount options used for a superblock
* @sb the superblock to set security mount options for
@ -511,12 +478,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @mnt is the vfsmount where the dentry was looked up
* @dentry contains the dentry structure for the file.
* Return 0 if permission is granted.
* @inode_delete:
* @inode contains the inode structure for deleted inode.
* This hook is called when a deleted inode is released (i.e. an inode
* with no hard links has its use count drop to zero). A security module
* can use this hook to release any persistent label associated with the
* inode.
* @inode_setxattr:
* Check permission before setting the extended attributes
* @value identified by @name for @dentry.
@ -691,10 +652,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @old points to the original credentials.
* @gfp indicates the atomicity of any memory allocations.
* Prepare a new set of credentials by copying the data from the old set.
* @cred_commit:
* @new points to the new credentials.
* @old points to the original credentials.
* Install a new set of credentials.
* @cred_transfer:
* @new points to the new credentials.
* @old points to the original credentials.
@ -717,18 +674,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* userspace to load a kernel module with the given name.
* @kmod_name name of the module requested by the kernel
* Return 0 if successful.
* @task_setuid:
* Check permission before setting one or more of the user identity
* attributes of the current process. The @flags parameter indicates
* which of the set*uid system calls invoked this hook and how to
* interpret the @id0, @id1, and @id2 parameters. See the LSM_SETID
* definitions at the beginning of this file for the @flags values and
* their meanings.
* @id0 contains a uid.
* @id1 contains a uid.
* @id2 contains a uid.
* @flags contains one of the LSM_SETID_* values.
* Return 0 if permission is granted.
* @task_fix_setuid:
* Update the module's state after setting one or more of the user
* identity attributes of the current process. The @flags parameter
@ -738,18 +683,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @old is the set of credentials that are being replaces
* @flags contains one of the LSM_SETID_* values.
* Return 0 on success.
* @task_setgid:
* Check permission before setting one or more of the group identity
* attributes of the current process. The @flags parameter indicates
* which of the set*gid system calls invoked this hook and how to
* interpret the @id0, @id1, and @id2 parameters. See the LSM_SETID
* definitions at the beginning of this file for the @flags values and
* their meanings.
* @id0 contains a gid.
* @id1 contains a gid.
* @id2 contains a gid.
* @flags contains one of the LSM_SETID_* values.
* Return 0 if permission is granted.
* @task_setpgid:
* Check permission before setting the process group identifier of the
* process @p to @pgid.
@ -771,11 +704,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @p contains the task_struct for the process and place is into @secid.
* In case of failure, @secid will be set to zero.
*
* @task_setgroups:
* Check permission before setting the supplementary group set of the
* current process.
* @group_info contains the new group information.
* Return 0 if permission is granted.
* @task_setnice:
* Check permission before setting the nice value of @p to @nice.
* @p contains the task_struct of process.
@ -1139,13 +1067,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return the length of the string (including terminating NUL) or -ve if
* an error.
* May also return 0 (and a NULL buffer pointer) if there is no label.
* @key_session_to_parent:
* Forcibly assign the session keyring from a process to its parent
* process.
* @cred: Pointer to process's credentials
* @parent_cred: Pointer to parent process's credentials
* @keyring: Proposed new session keyring
* Return 0 if permission is granted, -ve error otherwise.
*
* Security hooks affecting all System V IPC operations.
*
@ -1333,13 +1254,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @cap contains the capability <include/linux/capability.h>.
* @audit: Whether to write an audit message or not
* Return 0 if the capability is granted for @tsk.
* @acct:
* Check permission before enabling or disabling process accounting. If
* accounting is being enabled, then @file refers to the open file used to
* store accounting records. If accounting is being disabled, then @file
* is NULL.
* @file contains the file structure for the accounting file (may be NULL).
* Return 0 if permission is granted.
* @sysctl:
* Check permission before accessing the @table sysctl variable in the
* manner specified by @op.
@ -1462,7 +1376,6 @@ struct security_operations {
const kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, const struct cred *cred,
int cap, int audit);
int (*acct) (struct file *file);
int (*sysctl) (struct ctl_table *table, int op);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
int (*quota_on) (struct dentry *dentry);
@ -1484,18 +1397,9 @@ struct security_operations {
int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct path *path,
char *type, unsigned long flags, void *data);
int (*sb_check_sb) (struct vfsmount *mnt, struct path *path);
int (*sb_umount) (struct vfsmount *mnt, int flags);
void (*sb_umount_close) (struct vfsmount *mnt);
void (*sb_umount_busy) (struct vfsmount *mnt);
void (*sb_post_remount) (struct vfsmount *mnt,
unsigned long flags, void *data);
void (*sb_post_addmount) (struct vfsmount *mnt,
struct path *mountpoint);
int (*sb_pivotroot) (struct path *old_path,
struct path *new_path);
void (*sb_post_pivotroot) (struct path *old_path,
struct path *new_path);
int (*sb_set_mnt_opts) (struct super_block *sb,
struct security_mnt_opts *opts);
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
@ -1544,7 +1448,6 @@ struct security_operations {
int (*inode_permission) (struct inode *inode, int mask);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
int (*inode_setxattr) (struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
void (*inode_post_setxattr) (struct dentry *dentry, const char *name,
@ -1585,20 +1488,16 @@ struct security_operations {
void (*cred_free) (struct cred *cred);
int (*cred_prepare)(struct cred *new, const struct cred *old,
gfp_t gfp);
void (*cred_commit)(struct cred *new, const struct cred *old);
void (*cred_transfer)(struct cred *new, const struct cred *old);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_module_request)(char *kmod_name);
int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
int (*task_fix_setuid) (struct cred *new, const struct cred *old,
int flags);
int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);
int (*task_setpgid) (struct task_struct *p, pid_t pgid);
int (*task_getpgid) (struct task_struct *p);
int (*task_getsid) (struct task_struct *p);
void (*task_getsecid) (struct task_struct *p, u32 *secid);
int (*task_setgroups) (struct group_info *group_info);
int (*task_setnice) (struct task_struct *p, int nice);
int (*task_setioprio) (struct task_struct *p, int ioprio);
int (*task_getioprio) (struct task_struct *p);
@ -1728,9 +1627,6 @@ struct security_operations {
const struct cred *cred,
key_perm_t perm);
int (*key_getsecurity)(struct key *key, char **_buffer);
int (*key_session_to_parent)(const struct cred *cred,
const struct cred *parent_cred,
struct key *key);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
@ -1761,7 +1657,6 @@ int security_capset(struct cred *new, const struct cred *old,
int security_capable(int cap);
int security_real_capable(struct task_struct *tsk, int cap);
int security_real_capable_noaudit(struct task_struct *tsk, int cap);
int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry);
@ -1783,14 +1678,8 @@ int security_sb_show_options(struct seq_file *m, struct super_block *sb);
int security_sb_statfs(struct dentry *dentry);
int security_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data);
int security_sb_check_sb(struct vfsmount *mnt, struct path *path);
int security_sb_umount(struct vfsmount *mnt, int flags);
void security_sb_umount_close(struct vfsmount *mnt);
void security_sb_umount_busy(struct vfsmount *mnt);
void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data);
void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint);
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
void security_sb_post_pivotroot(struct path *old_path, struct path *new_path);
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
@ -1816,7 +1705,6 @@ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_permission(struct inode *inode, int mask);
int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
int security_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
@ -1850,20 +1738,16 @@ int security_task_create(unsigned long clone_flags);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_commit_creds(struct cred *new, const struct cred *old);
void security_transfer_creds(struct cred *new, const struct cred *old);
int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_module_request(char *kmod_name);
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags);
int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags);
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
int security_task_getsid(struct task_struct *p);
void security_task_getsecid(struct task_struct *p, u32 *secid);
int security_task_setgroups(struct group_info *group_info);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
@ -1990,11 +1874,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
return ret;
}
static inline int security_acct(struct file *file)
{
return 0;
}
static inline int security_sysctl(struct ctl_table *table, int op)
{
return 0;
@ -2099,41 +1978,17 @@ static inline int security_sb_mount(char *dev_name, struct path *path,
return 0;
}
static inline int security_sb_check_sb(struct vfsmount *mnt,
struct path *path)
{
return 0;
}
static inline int security_sb_umount(struct vfsmount *mnt, int flags)
{
return 0;
}
static inline void security_sb_umount_close(struct vfsmount *mnt)
{ }
static inline void security_sb_umount_busy(struct vfsmount *mnt)
{ }
static inline void security_sb_post_remount(struct vfsmount *mnt,
unsigned long flags, void *data)
{ }
static inline void security_sb_post_addmount(struct vfsmount *mnt,
struct path *mountpoint)
{ }
static inline int security_sb_pivotroot(struct path *old_path,
struct path *new_path)
{
return 0;
}
static inline void security_sb_post_pivotroot(struct path *old_path,
struct path *new_path)
{ }
static inline int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
@ -2249,9 +2104,6 @@ static inline int security_inode_getattr(struct vfsmount *mnt,
return 0;
}
static inline void security_inode_delete(struct inode *inode)
{ }
static inline int security_inode_setxattr(struct dentry *dentry,
const char *name, const void *value, size_t size, int flags)
{
@ -2398,11 +2250,6 @@ static inline int security_prepare_creds(struct cred *new,
return 0;
}
static inline void security_commit_creds(struct cred *new,
const struct cred *old)
{
}
static inline void security_transfer_creds(struct cred *new,
const struct cred *old)
{
@ -2424,12 +2271,6 @@ static inline int security_kernel_module_request(char *kmod_name)
return 0;
}
static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
int flags)
{
return 0;
}
static inline int security_task_fix_setuid(struct cred *new,
const struct cred *old,
int flags)
@ -2437,12 +2278,6 @@ static inline int security_task_fix_setuid(struct cred *new,
return cap_task_fix_setuid(new, old, flags);
}
static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2,
int flags)
{
return 0;
}
static inline int security_task_setpgid(struct task_struct *p, pid_t pgid)
{
return 0;
@ -2463,11 +2298,6 @@ static inline void security_task_getsecid(struct task_struct *p, u32 *secid)
*secid = 0;
}
static inline int security_task_setgroups(struct group_info *group_info)
{
return 0;
}
static inline int security_task_setnice(struct task_struct *p, int nice)
{
return cap_task_setnice(p, nice);
@ -3064,9 +2894,6 @@ void security_key_free(struct key *key);
int security_key_permission(key_ref_t key_ref,
const struct cred *cred, key_perm_t perm);
int security_key_getsecurity(struct key *key, char **_buffer);
int security_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key);
#else
@ -3094,13 +2921,6 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
return 0;
}
static inline int security_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key)
{
return 0;
}
#endif
#endif /* CONFIG_KEYS */

View file

@ -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;
}

View file

@ -522,8 +522,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 */

View file

@ -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);

View file

@ -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;

View file

@ -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, " ");

View file

@ -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);

View file

@ -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.

View file

@ -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,
};

View file

@ -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

View file

@ -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 */

View file

@ -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));

View file

@ -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");
}
/*

View file

@ -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;

View file

@ -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;
}

View file

@ -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();

View file

@ -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();
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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;

View file

@ -17,7 +17,7 @@
#include <linux/seq_file.h>
#include <linux/err.h>
#include <keys/keyring-type.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include "internal.h"
#define rcu_dereference_locked_keyring(keyring) \
@ -44,7 +44,7 @@ static inline unsigned keyring_hash(const char *desc)
unsigned bucket = 0;
for (; *desc; desc++)
bucket += (unsigned char) *desc;
bucket += (unsigned char)*desc;
return bucket & (KEYRING_NAME_HASH_SIZE - 1);
}
@ -175,12 +175,10 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
{
struct keyring_list *klist;
if (keyring->description) {
if (keyring->description)
seq_puts(m, keyring->description);
}
else {
else
seq_puts(m, "[anon]");
}
rcu_read_lock();
klist = rcu_dereference(keyring->payload.subscriptions);
@ -241,7 +239,7 @@ static long keyring_read(const struct key *keyring,
ret = qty;
}
error:
error:
return ret;
} /* end keyring_read() */
@ -310,7 +308,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
key_check(keyring);
/* top keyring must have search permission to begin the search */
err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
if (err < 0) {
key_ref = ERR_PTR(err);
goto error;
@ -512,7 +510,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
rcu_read_unlock();
return ERR_PTR(-ENOKEY);
found:
found:
atomic_inc(&key->usage);
rcu_read_unlock();
return make_key_ref(key, possessed);
@ -602,7 +600,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
sp = 0;
/* start processing a new keyring */
descend:
descend:
if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
goto not_this_keyring;
@ -611,7 +609,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
goto not_this_keyring;
kix = 0;
ascend:
ascend:
/* iterate through the remaining keys in this keyring */
for (; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix];
@ -637,7 +635,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
/* the keyring we're looking at was disqualified or didn't contain a
* matching key */
not_this_keyring:
not_this_keyring:
if (sp > 0) {
/* resume the checking of a keyring higher up in the tree */
sp--;
@ -648,34 +646,20 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
ret = 0; /* no cycles detected */
error:
error:
rcu_read_unlock();
return ret;
too_deep:
too_deep:
ret = -ELOOP;
goto error;
cycle_detected:
cycle_detected:
ret = -EDEADLK;
goto error;
} /* end keyring_detect_cycle() */
/*****************************************************************************/
/*
* dispose of a keyring list after the RCU grace period
*/
static void keyring_link_rcu_disposal(struct rcu_head *rcu)
{
struct keyring_list *klist =
container_of(rcu, struct keyring_list, rcu);
kfree(klist);
} /* end keyring_link_rcu_disposal() */
/*****************************************************************************/
/*
* dispose of a keyring list after the RCU grace period, freeing the unlinked
* key
@ -685,55 +669,51 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
struct keyring_list *klist =
container_of(rcu, struct keyring_list, rcu);
key_put(klist->keys[klist->delkey]);
if (klist->delkey != USHORT_MAX)
key_put(klist->keys[klist->delkey]);
kfree(klist);
}
} /* end keyring_unlink_rcu_disposal() */
/*****************************************************************************/
/*
* link a key into to a keyring
* - must be called with the keyring's semaphore write-locked
* - discard already extant link to matching key if there is one
* preallocate memory so that a key can be linked into to a keyring
*/
int __key_link(struct key *keyring, struct key *key)
int __key_link_begin(struct key *keyring, const struct key_type *type,
const char *description,
struct keyring_list **_prealloc)
__acquires(&keyring->sem)
{
struct keyring_list *klist, *nklist;
unsigned max;
size_t size;
int loop, ret;
kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
if (keyring->type != &key_type_keyring)
return -ENOTDIR;
down_write(&keyring->sem);
ret = -EKEYREVOKED;
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
goto error;
goto error_krsem;
ret = -ENOTDIR;
if (keyring->type != &key_type_keyring)
goto error;
/* serialise link/link calls to prevent parallel calls causing a cycle
* when linking two keyring in opposite orders */
if (type == &key_type_keyring)
down_write(&keyring_serialise_link_sem);
/* serialise link/link calls to prevent parallel calls causing a
* cycle when applied to two keyring in opposite orders */
down_write(&keyring_serialise_link_sem);
/* check that we aren't going to create a cycle adding one keyring to
* another */
if (key->type == &key_type_keyring) {
ret = keyring_detect_cycle(keyring, key);
if (ret < 0)
goto error2;
}
klist = rcu_dereference_locked_keyring(keyring);
/* see if there's a matching key we can displace */
klist = rcu_dereference_locked_keyring(keyring);
if (klist && klist->nkeys > 0) {
struct key_type *type = key->type;
for (loop = klist->nkeys - 1; loop >= 0; loop--) {
if (klist->keys[loop]->type == type &&
strcmp(klist->keys[loop]->description,
key->description) == 0
description) == 0
) {
/* found a match - replace with new key */
/* found a match - we'll replace this one with
* the new key */
size = sizeof(struct key *) * klist->maxkeys;
size += sizeof(*klist);
BUG_ON(size > PAGE_SIZE);
@ -741,22 +721,10 @@ int __key_link(struct key *keyring, struct key *key)
ret = -ENOMEM;
nklist = kmemdup(klist, size, GFP_KERNEL);
if (!nklist)
goto error2;
/* replace matched key */
atomic_inc(&key->usage);
nklist->keys[loop] = key;
rcu_assign_pointer(
keyring->payload.subscriptions,
nklist);
/* dispose of the old keyring list and the
* displaced key */
klist->delkey = loop;
call_rcu(&klist->rcu,
keyring_unlink_rcu_disposal);
goto error_sem;
/* note replacement slot */
klist->delkey = nklist->delkey = loop;
goto done;
}
}
@ -766,88 +734,167 @@ int __key_link(struct key *keyring, struct key *key)
ret = key_payload_reserve(keyring,
keyring->datalen + KEYQUOTA_LINK_BYTES);
if (ret < 0)
goto error2;
goto error_sem;
if (klist && klist->nkeys < klist->maxkeys) {
/* there's sufficient slack space to add directly */
atomic_inc(&key->usage);
klist->keys[klist->nkeys] = key;
smp_wmb();
klist->nkeys++;
smp_wmb();
}
else {
/* there's sufficient slack space to append directly */
nklist = NULL;
} else {
/* grow the key list */
max = 4;
if (klist)
max += klist->maxkeys;
ret = -ENFILE;
if (max > 65535)
goto error3;
if (max > USHORT_MAX - 1)
goto error_quota;
size = sizeof(*klist) + sizeof(struct key *) * max;
if (size > PAGE_SIZE)
goto error3;
goto error_quota;
ret = -ENOMEM;
nklist = kmalloc(size, GFP_KERNEL);
if (!nklist)
goto error3;
nklist->maxkeys = max;
nklist->nkeys = 0;
goto error_quota;
nklist->maxkeys = max;
if (klist) {
nklist->nkeys = klist->nkeys;
memcpy(nklist->keys,
klist->keys,
memcpy(nklist->keys, klist->keys,
sizeof(struct key *) * klist->nkeys);
nklist->delkey = klist->nkeys;
nklist->nkeys = klist->nkeys + 1;
klist->delkey = USHORT_MAX;
} else {
nklist->nkeys = 1;
nklist->delkey = 0;
}
/* add the key into the new space */
atomic_inc(&key->usage);
nklist->keys[nklist->nkeys++] = key;
rcu_assign_pointer(keyring->payload.subscriptions, nklist);
/* dispose of the old keyring list */
if (klist)
call_rcu(&klist->rcu, keyring_link_rcu_disposal);
nklist->keys[nklist->delkey] = NULL;
}
done:
ret = 0;
error2:
up_write(&keyring_serialise_link_sem);
error:
return ret;
*_prealloc = nklist;
kleave(" = 0");
return 0;
error3:
error_quota:
/* undo the quota changes */
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
goto error2;
error_sem:
if (type == &key_type_keyring)
up_write(&keyring_serialise_link_sem);
error_krsem:
up_write(&keyring->sem);
kleave(" = %d", ret);
return ret;
}
} /* end __key_link() */
/*
* check already instantiated keys aren't going to be a problem
* - the caller must have called __key_link_begin()
* - don't need to call this for keys that were created since __key_link_begin()
* was called
*/
int __key_link_check_live_key(struct key *keyring, struct key *key)
{
if (key->type == &key_type_keyring)
/* check that we aren't going to create a cycle by linking one
* keyring to another */
return keyring_detect_cycle(keyring, key);
return 0;
}
/*
* link a key into to a keyring
* - must be called with __key_link_begin() having being called
* - discard already extant link to matching key if there is one
*/
void __key_link(struct key *keyring, struct key *key,
struct keyring_list **_prealloc)
{
struct keyring_list *klist, *nklist;
nklist = *_prealloc;
*_prealloc = NULL;
kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
klist = rcu_dereference_protected(keyring->payload.subscriptions,
rwsem_is_locked(&keyring->sem));
atomic_inc(&key->usage);
/* there's a matching key we can displace or an empty slot in a newly
* allocated list we can fill */
if (nklist) {
kdebug("replace %hu/%hu/%hu",
nklist->delkey, nklist->nkeys, nklist->maxkeys);
nklist->keys[nklist->delkey] = key;
rcu_assign_pointer(keyring->payload.subscriptions, nklist);
/* dispose of the old keyring list and, if there was one, the
* displaced key */
if (klist) {
kdebug("dispose %hu/%hu/%hu",
klist->delkey, klist->nkeys, klist->maxkeys);
call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
}
} else {
/* there's sufficient slack space to append directly */
klist->keys[klist->nkeys] = key;
smp_wmb();
klist->nkeys++;
}
}
/*
* finish linking a key into to a keyring
* - must be called with __key_link_begin() having being called
*/
void __key_link_end(struct key *keyring, struct key_type *type,
struct keyring_list *prealloc)
__releases(&keyring->sem)
{
BUG_ON(type == NULL);
BUG_ON(type->name == NULL);
kenter("%d,%s,%p", keyring->serial, type->name, prealloc);
if (type == &key_type_keyring)
up_write(&keyring_serialise_link_sem);
if (prealloc) {
kfree(prealloc);
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
}
up_write(&keyring->sem);
}
/*****************************************************************************/
/*
* link a key to a keyring
*/
int key_link(struct key *keyring, struct key *key)
{
struct keyring_list *prealloc;
int ret;
key_check(keyring);
key_check(key);
down_write(&keyring->sem);
ret = __key_link(keyring, key);
up_write(&keyring->sem);
ret = __key_link_begin(keyring, key->type, key->description, &prealloc);
if (ret == 0) {
ret = __key_link_check_live_key(keyring, key);
if (ret == 0)
__key_link(keyring, key, &prealloc);
__key_link_end(keyring, key->type, prealloc);
}
return ret;
} /* end key_link() */
}
EXPORT_SYMBOL(key_link);

View file

@ -109,7 +109,7 @@ int key_validate(struct key *key)
}
}
error:
error:
return ret;
} /* end key_validate() */

View file

@ -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)

View file

@ -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:

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -1,5 +1,5 @@
/* This file is automatically generated. Do not edit. */
static char *initial_sid_to_string[] =
static const char *initial_sid_to_string[] =
{
"null",
"kernel",

View file

@ -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;
}

View file

@ -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;
}
/**

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -1 +1 @@
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

View file

@ -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);

View file

@ -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.

View file

@ -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;

View file

@ -45,6 +45,37 @@ static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
};
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
if (!ptr)
return;
if (ptr->is_group)
tomoyo_put_path_group(ptr->group);
else
tomoyo_put_name(ptr->filename);
}
bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr)
{
if (ptr->is_group)
return tomoyo_path_matches_group(name, ptr->group, 1);
return tomoyo_path_matches_pattern(name, ptr->filename);
}
static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
*name,
const struct tomoyo_name_union
*ptr, const bool may_use_pattern)
{
if (ptr->is_group)
return tomoyo_path_matches_group(name, ptr->group,
may_use_pattern);
if (may_use_pattern || !ptr->filename->is_patterned)
return tomoyo_path_matches_pattern(name, ptr->filename);
return false;
}
/**
* tomoyo_path2keyword - Get the name of single path operation.
*
@ -100,7 +131,7 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
{
int error;
struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
GFP_KERNEL);
GFP_NOFS);
if (!buf)
return NULL;
@ -164,36 +195,36 @@ LIST_HEAD(tomoyo_globally_readable_list);
static int tomoyo_update_globally_readable_entry(const char *filename,
const bool is_delete)
{
struct tomoyo_globally_readable_file_entry *entry = NULL;
struct tomoyo_globally_readable_file_entry *ptr;
const struct tomoyo_path_info *saved_filename;
struct tomoyo_globally_readable_file_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(filename, 1, 0, -1))
return -EINVAL;
saved_filename = tomoyo_get_name(filename);
if (!saved_filename)
e.filename = tomoyo_get_name(filename);
if (!e.filename)
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_globally_readable_list, list) {
if (ptr->filename != saved_filename)
if (ptr->filename != e.filename)
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->filename = saved_filename;
saved_filename = NULL;
list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_globally_readable_file_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list,
&tomoyo_globally_readable_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
tomoyo_put_name(saved_filename);
kfree(entry);
out:
tomoyo_put_name(e.filename);
return error;
}
@ -311,37 +342,34 @@ LIST_HEAD(tomoyo_pattern_list);
static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete)
{
struct tomoyo_pattern_entry *entry = NULL;
struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
int error = is_delete ? -ENOENT : -ENOMEM;
saved_pattern = tomoyo_get_name(pattern);
if (!saved_pattern)
if (!e.pattern)
return error;
if (!saved_pattern->is_patterned)
if (!e.pattern->is_patterned)
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_pattern_list, list) {
if (saved_pattern != ptr->pattern)
if (e.pattern != ptr->pattern)
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->pattern = saved_pattern;
saved_pattern = NULL;
list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_pattern_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
kfree(entry);
tomoyo_put_name(saved_pattern);
tomoyo_put_name(e.pattern);
return error;
}
@ -464,36 +492,36 @@ LIST_HEAD(tomoyo_no_rewrite_list);
static int tomoyo_update_no_rewrite_entry(const char *pattern,
const bool is_delete)
{
struct tomoyo_no_rewrite_entry *entry = NULL;
struct tomoyo_no_rewrite_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
struct tomoyo_no_rewrite_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
return -EINVAL;
saved_pattern = tomoyo_get_name(pattern);
if (!saved_pattern)
e.pattern = tomoyo_get_name(pattern);
if (!e.pattern)
return error;
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_no_rewrite_list, list) {
if (ptr->pattern != saved_pattern)
if (ptr->pattern != e.pattern)
continue;
ptr->is_deleted = is_delete;
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->pattern = saved_pattern;
saved_pattern = NULL;
list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_no_rewrite_entry *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->list,
&tomoyo_no_rewrite_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
tomoyo_put_name(saved_pattern);
kfree(entry);
out:
tomoyo_put_name(e.pattern);
return error;
}
@ -640,13 +668,9 @@ static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
if (!(acl->perm_high & (perm >> 16)))
continue;
}
if (may_use_pattern || !acl->filename->is_patterned) {
if (!tomoyo_path_matches_pattern(filename,
acl->filename))
continue;
} else {
if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
may_use_pattern))
continue;
}
error = 0;
break;
}
@ -805,70 +829,64 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info *const domain,
const bool is_delete)
{
static const u32 rw_mask =
static const u32 tomoyo_rw_mask =
(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
const struct tomoyo_path_info *saved_filename;
struct tomoyo_acl_info *ptr;
struct tomoyo_path_acl *entry = NULL;
int error = is_delete ? -ENOENT : -ENOMEM;
const u32 perm = 1 << type;
struct tomoyo_acl_info *ptr;
struct tomoyo_path_acl e = {
.head.type = TOMOYO_TYPE_PATH_ACL,
.perm_high = perm >> 16,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM;
if (type == TOMOYO_TYPE_READ_WRITE)
e.perm |= tomoyo_rw_mask;
if (!domain)
return -EINVAL;
if (!tomoyo_is_correct_path(filename, 0, 0, 0))
if (!tomoyo_parse_name_union(filename, &e.name))
return -EINVAL;
saved_filename = tomoyo_get_name(filename);
if (!saved_filename)
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, &domain->acl_info_list, list) {
struct tomoyo_path_acl *acl =
container_of(ptr, struct tomoyo_path_acl, head);
if (ptr->type != TOMOYO_TYPE_PATH_ACL)
continue;
if (acl->filename != saved_filename)
if (!tomoyo_is_same_path_acl(acl, &e))
continue;
if (is_delete) {
if (perm <= 0xFFFF)
acl->perm &= ~perm;
else
acl->perm_high &= ~(perm >> 16);
if ((acl->perm & rw_mask) != rw_mask)
if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
acl->perm &= ~rw_mask;
acl->perm &= ~tomoyo_rw_mask;
} else {
if (perm <= 0xFFFF)
acl->perm |= perm;
else
acl->perm_high |= (perm >> 16);
if ((acl->perm & rw_mask) == rw_mask)
if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
acl->perm |= rw_mask;
acl->perm |= tomoyo_rw_mask;
}
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->head.type = TOMOYO_TYPE_PATH_ACL;
if (perm <= 0xFFFF)
entry->perm = perm;
else
entry->perm_high = (perm >> 16);
if (perm == (1 << TOMOYO_TYPE_READ_WRITE))
entry->perm |= rw_mask;
entry->filename = saved_filename;
saved_filename = NULL;
list_add_tail_rcu(&entry->head.list, &domain->acl_info_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_path_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->head.list,
&domain->acl_info_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
kfree(entry);
tomoyo_put_name(saved_filename);
out:
tomoyo_put_name_union(&e.name);
return error;
}
@ -890,32 +908,25 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
struct tomoyo_domain_info *const domain,
const bool is_delete)
{
const struct tomoyo_path_info *saved_filename1;
const struct tomoyo_path_info *saved_filename2;
struct tomoyo_acl_info *ptr;
struct tomoyo_path2_acl *entry = NULL;
int error = is_delete ? -ENOENT : -ENOMEM;
const u8 perm = 1 << type;
struct tomoyo_path2_acl e = {
.head.type = TOMOYO_TYPE_PATH2_ACL,
.perm = perm
};
struct tomoyo_acl_info *ptr;
int error = is_delete ? -ENOENT : -ENOMEM;
if (!domain)
return -EINVAL;
if (!tomoyo_is_correct_path(filename1, 0, 0, 0) ||
!tomoyo_is_correct_path(filename2, 0, 0, 0))
return -EINVAL;
saved_filename1 = tomoyo_get_name(filename1);
saved_filename2 = tomoyo_get_name(filename2);
if (!saved_filename1 || !saved_filename2)
if (!tomoyo_parse_name_union(filename1, &e.name1) ||
!tomoyo_parse_name_union(filename2, &e.name2))
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, &domain->acl_info_list, list) {
struct tomoyo_path2_acl *acl =
container_of(ptr, struct tomoyo_path2_acl, head);
if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
continue;
if (acl->filename1 != saved_filename1 ||
acl->filename2 != saved_filename2)
if (!tomoyo_is_same_path2_acl(acl, &e))
continue;
if (is_delete)
acl->perm &= ~perm;
@ -924,22 +935,19 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
error = 0;
break;
}
if (!is_delete && error && tomoyo_memory_ok(entry)) {
entry->head.type = TOMOYO_TYPE_PATH2_ACL;
entry->perm = perm;
entry->filename1 = saved_filename1;
saved_filename1 = NULL;
entry->filename2 = saved_filename2;
saved_filename2 = NULL;
list_add_tail_rcu(&entry->head.list, &domain->acl_info_list);
entry = NULL;
error = 0;
if (!is_delete && error) {
struct tomoyo_path2_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
list_add_tail_rcu(&entry->head.list,
&domain->acl_info_list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
out:
tomoyo_put_name(saved_filename1);
tomoyo_put_name(saved_filename2);
kfree(entry);
tomoyo_put_name_union(&e.name1);
tomoyo_put_name_union(&e.name2);
return error;
}
@ -992,9 +1000,9 @@ static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
acl = container_of(ptr, struct tomoyo_path2_acl, head);
if (!(acl->perm & perm))
continue;
if (!tomoyo_path_matches_pattern(filename1, acl->filename1))
if (!tomoyo_compare_name_union(filename1, &acl->name1))
continue;
if (!tomoyo_path_matches_pattern(filename2, acl->filename2))
if (!tomoyo_compare_name_union(filename2, &acl->name2))
continue;
error = 0;
break;

View file

@ -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;

View file

@ -0,0 +1,172 @@
/*
* 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;
}

View file

@ -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;
}