diff options
Diffstat (limited to 'security')
34 files changed, 376 insertions, 235 deletions
diff --git a/security/Makefile b/security/Makefile index a5918e0..05f1c93 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,14 +16,14 @@ obj-$(CONFIG_MMU) += min_addr.o # Object file lists obj-$(CONFIG_SECURITY) += security.o capability.o obj-$(CONFIG_SECURITYFS) += inode.o -obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o -obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o +obj-$(CONFIG_SECURITY_SELINUX) += selinux/ +obj-$(CONFIG_SECURITY_SMACK) += smack/ obj-$(CONFIG_AUDIT) += lsm_audit.o -obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o -obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o -obj-$(CONFIG_SECURITY_YAMA) += yama/built-in.o +obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ +obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ +obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity -obj-$(CONFIG_INTEGRITY) += integrity/built-in.o +obj-$(CONFIG_INTEGRITY) += integrity/ diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 8fb1488..97130f8 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -66,7 +66,6 @@ extern int apparmor_initialized __initdata; char *aa_split_fqname(char *args, char **ns_name); void aa_info_message(const char *str); void *__aa_kvmalloc(size_t size, gfp_t flags); -void kvfree(void *buffer); static inline void *kvmalloc(size_t size) { diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 6968992..c1827e0 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -104,17 +104,3 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) } return buffer; } - -/** - * kvfree - free an allocation do by kvmalloc - * @buffer: buffer to free (MAYBE_NULL) - * - * Free a buffer allocated by kvmalloc - */ -void kvfree(void *buffer) -{ - if (is_vmalloc_addr(buffer)) - vfree(buffer); - else - kfree(buffer); -} diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 4257b7e..9981000 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -751,7 +751,7 @@ module_param_named(enabled, apparmor_enabled, bool, S_IRUGO); static int __init apparmor_enabled_setup(char *str) { unsigned long enabled; - int error = strict_strtoul(str, 0, &enabled); + int error = kstrtoul(str, 0, &enabled); if (!error) apparmor_enabled = enabled ? 1 : 0; return 1; diff --git a/security/capability.c b/security/capability.c index 21e2b9c..ad0d4de 100644 --- a/security/capability.c +++ b/security/capability.c @@ -116,7 +116,7 @@ static int cap_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, void **ctx, u32 *ctxlen) { - return 0; + return -EOPNOTSUPP; } static int cap_inode_alloc_security(struct inode *inode) diff --git a/security/device_cgroup.c b/security/device_cgroup.c index d3b6d2c..9134dbf 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -58,11 +58,9 @@ static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) { - return css_to_devcgroup(task_css(task, devices_subsys_id)); + return css_to_devcgroup(task_css(task, devices_cgrp_id)); } -struct cgroup_subsys devices_subsys; - /* * called under devcgroup_mutex */ @@ -308,57 +306,138 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) } /** - * may_access - verifies if a new exception is part of what is allowed - * by a dev cgroup based on the default policy + - * exceptions. This is used to make sure a child cgroup - * won't have more privileges than its parent or to - * verify if a certain access is allowed. - * @dev_cgroup: dev cgroup to be tested against - * @refex: new exception - * @behavior: behavior of the exception + * match_exception - iterates the exception list trying to find a complete match + * @exceptions: list of exceptions + * @type: device type (DEV_BLOCK or DEV_CHAR) + * @major: device file major number, ~0 to match all + * @minor: device file minor number, ~0 to match all + * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) + * + * It is considered a complete match if an exception is found that will + * contain the entire range of provided parameters. + * + * Return: true in case it matches an exception completely */ -static bool may_access(struct dev_cgroup *dev_cgroup, - struct dev_exception_item *refex, - enum devcg_behavior behavior) +static bool match_exception(struct list_head *exceptions, short type, + u32 major, u32 minor, short access) { struct dev_exception_item *ex; - bool match = false; - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&devcgroup_mutex), - "device_cgroup::may_access() called without proper synchronization"); + list_for_each_entry_rcu(ex, exceptions, list) { + if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) + continue; + if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) + continue; + if (ex->major != ~0 && ex->major != major) + continue; + if (ex->minor != ~0 && ex->minor != minor) + continue; + /* provided access cannot have more than the exception rule */ + if (access & (~ex->access)) + continue; + return true; + } + return false; +} - list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) { - if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) +/** + * match_exception_partial - iterates the exception list trying to find a partial match + * @exceptions: list of exceptions + * @type: device type (DEV_BLOCK or DEV_CHAR) + * @major: device file major number, ~0 to match all + * @minor: device file minor number, ~0 to match all + * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) + * + * It is considered a partial match if an exception's range is found to + * contain *any* of the devices specified by provided parameters. This is + * used to make sure no extra access is being granted that is forbidden by + * any of the exception list. + * + * Return: true in case the provided range mat matches an exception completely + */ +static bool match_exception_partial(struct list_head *exceptions, short type, + u32 major, u32 minor, short access) +{ + struct dev_exception_item *ex; + + list_for_each_entry_rcu(ex, exceptions, list) { + if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) continue; - if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) + if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) continue; - if (ex->major != ~0 && ex->major != refex->major) + /* + * We must be sure that both the exception and the provided + * range aren't masking all devices + */ + if (ex->major != ~0 && major != ~0 && ex->major != major) continue; - if (ex->minor != ~0 && ex->minor != refex->minor) + if (ex->minor != ~0 && minor != ~0 && ex->minor != minor) continue; - if (refex->access & (~ex->access)) + /* + * In order to make sure the provided range isn't matching + * an exception, all its access bits shouldn't match the + * exception's access bits + */ + if (!(access & ex->access)) continue; - match = true; - break; + return true; } + return false; +} + +/** + * verify_new_ex - verifies if a new exception is allowed by parent cgroup's permissions + * @dev_cgroup: dev cgroup to be tested against + * @refex: new exception + * @behavior: behavior of the exception's dev_cgroup + * + * This is used to make sure a child cgroup won't have more privileges + * than its parent + */ +static bool verify_new_ex(struct dev_cgroup *dev_cgroup, + struct dev_exception_item *refex, + enum devcg_behavior behavior) +{ + bool match = false; + + rcu_lockdep_assert(rcu_read_lock_held() || + lockdep_is_held(&devcgroup_mutex), + "device_cgroup:verify_new_ex called without proper synchronization"); if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) { if (behavior == DEVCG_DEFAULT_ALLOW) { - /* the exception will deny access to certain devices */ + /* + * new exception in the child doesn't matter, only + * adding extra restrictions + */ return true; } else { - /* the exception will allow access to certain devices */ + /* + * new exception in the child will add more devices + * that can be acessed, so it can't match any of + * parent's exceptions, even slightly + */ + match = match_exception_partial(&dev_cgroup->exceptions, + refex->type, + refex->major, + refex->minor, + refex->access); + if (match) - /* - * a new exception allowing access shouldn't - * match an parent's exception - */ return false; return true; } } else { - /* only behavior == DEVCG_DEFAULT_DENY allowed here */ + /* + * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore + * the new exception will add access to more devices and must + * be contained completely in an parent's exception to be + * allowed + */ + match = match_exception(&dev_cgroup->exceptions, refex->type, + refex->major, refex->minor, + refex->access); + if (match) /* parent has an exception that matches the proposed */ return true; @@ -380,7 +459,38 @@ static int parent_has_perm(struct dev_cgroup *childcg, if (!parent) return 1; - return may_access(parent, ex, childcg->behavior); + return verify_new_ex(parent, ex, childcg->behavior); +} + +/** + * parent_allows_removal - verify if it's ok to remove an exception + * @childcg: child cgroup from where the exception will be removed + * @ex: exception being removed + * + * When removing an exception in cgroups with default ALLOW policy, it must + * be checked if removing it will give the child cgroup more access than the + * parent. + * + * Return: true if it's ok to remove exception, false otherwise + */ +static bool parent_allows_removal(struct dev_cgroup *childcg, + struct dev_exception_item *ex) +{ + struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css)); + + if (!parent) + return true; + + /* It's always allowed to remove access to devices */ + if (childcg->behavior == DEVCG_DEFAULT_DENY) + return true; + + /* + * Make sure you're not removing part or a whole exception existing in + * the parent cgroup + */ + return !match_exception_partial(&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); } /** @@ -498,7 +608,7 @@ static inline bool has_children(struct dev_cgroup *devcgroup) * parent cgroup has the access you're asking for. */ static int devcgroup_update_access(struct dev_cgroup *devcgroup, - int filetype, const char *buffer) + int filetype, char *buffer) { const char *b; char temp[12]; /* 11 + 1 characters needed for a u32 */ @@ -618,17 +728,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, switch (filetype) { case DEVCG_ALLOW: - if (!parent_has_perm(devcgroup, &ex)) - return -EPERM; /* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { + /* Check if the parent allows removing it first */ + if (!parent_allows_removal(devcgroup, &ex)) + return -EPERM; dev_exception_rm(devcgroup, &ex); - return 0; + break; } + + if (!parent_has_perm(devcgroup, &ex)) + return -EPERM; rc = dev_exception_add(devcgroup, &ex); break; case DEVCG_DENY: @@ -654,7 +768,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, } static int devcgroup_access_write(struct cgroup_subsys_state *css, - struct cftype *cft, const char *buffer) + struct cftype *cft, char *buffer) { int retval; @@ -684,13 +798,11 @@ static struct cftype dev_cgroup_files[] = { { } /* terminate */ }; -struct cgroup_subsys devices_subsys = { - .name = "devices", +struct cgroup_subsys devices_cgrp_subsys = { .css_alloc = devcgroup_css_alloc, .css_free = devcgroup_css_free, .css_online = devcgroup_online, .css_offline = devcgroup_offline, - .subsys_id = devices_subsys_id, .base_cftypes = dev_cgroup_files, }; @@ -708,18 +820,18 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor, short access) { struct dev_cgroup *dev_cgroup; - struct dev_exception_item ex; - int rc; - - memset(&ex, 0, sizeof(ex)); - ex.type = type; - ex.major = major; - ex.minor = minor; - ex.access = access; + bool rc; rcu_read_lock(); dev_cgroup = task_devcgroup(current); - rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior); + if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) + /* Can't match any of the exceptions, even partially */ + rc = !match_exception_partial(&dev_cgroup->exceptions, + type, major, minor, access); + else + /* Need to match completely one exception to be allowed */ + rc = match_exception(&dev_cgroup->exceptions, type, major, + minor, access); rcu_read_unlock(); if (!rc) diff --git a/security/integrity/Makefile b/security/integrity/Makefile index 0f9cffb..0793f48 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -10,6 +10,6 @@ obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o integrity-y := iint.o subdir-$(CONFIG_IMA) += ima -obj-$(CONFIG_IMA) += ima/built-in.o +obj-$(CONFIG_IMA) += ima/ subdir-$(CONFIG_EVM) += evm -obj-$(CONFIG_EVM) += evm/built-in.o +obj-$(CONFIG_EVM) += evm/ diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index fea9749..d35b491 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,10 +1,10 @@ config EVM boolean "EVM support" - depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n) + depends on SECURITY + select KEYS + select ENCRYPTED_KEYS select CRYPTO_HMAC - select CRYPTO_MD5 select CRYPTO_SHA1 - select ENCRYPTED_KEYS default n help EVM protects a file's security extended attributes against diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 30bd1ec..37c88dd 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -32,19 +32,19 @@ extern struct crypto_shash *hash_tfm; /* List of EVM protected security xattrs */ extern char *evm_config_xattrnames[]; -extern int evm_init_key(void); -extern int evm_update_evmxattr(struct dentry *dentry, - const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len); -extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); -extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr, - char *hmac_val); -extern int evm_init_secfs(void); +int evm_init_key(void); +int evm_update_evmxattr(struct dentry *dentry, + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len); +int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, char *digest); +int evm_init_hmac(struct inode *inode, const struct xattr *xattr, + char *hmac_val); +int evm_init_secfs(void); #endif diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 3bab89e..6b540f1 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -13,6 +13,8 @@ * Using root's kernel master key (kmk), calculate the HMAC */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/crypto.h> #include <linux/xattr.h> @@ -103,13 +105,13 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, umode_t mode; } hmac_misc; - memset(&hmac_misc, 0, sizeof hmac_misc); + memset(&hmac_misc, 0, sizeof(hmac_misc)); hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); hmac_misc.mode = inode->i_mode; - crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); + crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); if (evm_hmac_version > 1) crypto_shash_update(desc, inode->i_sb->s_uuid, sizeof(inode->i_sb->s_uuid)); @@ -137,7 +139,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, int error; int size; - if (!inode->i_op || !inode->i_op->getxattr) + if (!inode->i_op->getxattr) return -EOPNOTSUPP; desc = init_desc(type); if (IS_ERR(desc)) @@ -221,7 +223,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, desc = init_desc(EVM_XATTR_HMAC); if (IS_ERR(desc)) { - printk(KERN_INFO "init_desc failed\n"); + pr_info("init_desc failed\n"); return PTR_ERR(desc); } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 336b3dd..6e0bd93 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -14,6 +14,8 @@ * evm_inode_removexattr, and evm_verifyxattr */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/crypto.h> #include <linux/audit.h> @@ -62,7 +64,7 @@ static int evm_find_protected_xattrs(struct dentry *dentry) int error; int count = 0; - if (!inode->i_op || !inode->i_op->getxattr) + if (!inode->i_op->getxattr) return -EOPNOTSUPP; for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { @@ -432,7 +434,7 @@ static int __init init_evm(void) error = evm_init_secfs(); if (error < 0) { - printk(KERN_INFO "EVM: Error registering secfs\n"); + pr_info("Error registering secfs\n"); goto err; } @@ -449,7 +451,7 @@ static int __init evm_display_config(void) char **xattrname; for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) - printk(KERN_INFO "EVM: %s\n", *xattrname); + pr_info("%s\n", *xattrname); return 0; } diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 30f670a..cf12a04 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -13,6 +13,8 @@ * - Get the key and enable EVM */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/uaccess.h> #include <linux/module.h> #include "evm.h" @@ -79,9 +81,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, error = evm_init_key(); if (!error) { evm_initialized = 1; - pr_info("EVM: initialized\n"); + pr_info("initialized\n"); } else - pr_err("EVM: initialization failed\n"); + pr_err("initialization failed\n"); return count; } diff --git a/security/integrity/iint.c b/security/integrity/iint.c index c49d3f1..a521edf 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -151,7 +151,7 @@ static void init_once(void *foo) { struct integrity_iint_cache *iint = foo; - memset(iint, 0, sizeof *iint); + memset(iint, 0, sizeof(*iint)); iint->version = 0; iint->flags = 0UL; iint->ima_file_status = INTEGRITY_UNKNOWN; diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 0356e1d..f79fa8b 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -27,7 +27,7 @@ #include "../integrity.h" enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, - IMA_SHOW_ASCII }; + IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; /* digest size for IMA, fits SHA1 or MD5 */ diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c38bbce..ba9e4d7 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -92,8 +92,8 @@ int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename) { - const char *op = "add_template_measure"; - const char *audit_cause = "hashing_error"; + static const char op[] = "add_template_measure"; + static const char audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; int result; struct { @@ -132,7 +132,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, const char *op, const char *cause) { struct ima_template_entry *entry; - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file_inode(file); int violation = 1; int result; @@ -160,10 +160,10 @@ err_out: * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK) * * The policy is defined in terms of keypairs: - * subj=, obj=, type=, func=, mask=, fsmagic= + * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. - * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK - * mask: contains the permission mask + * func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK + * mask: contains the permission mask * fsmagic: hex value * * Returns IMA_MEASURE, IMA_APPRAISE mask. @@ -248,7 +248,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, * * We only get here if the inode has not already been measured, * but the measurement could already exist: - * - multiple copies of the same file on either the same or + * - multiple copies of the same file on either the same or * different filesystems. * - the inode was previously flushed as well as the iint info, * containing the hashing info. @@ -260,8 +260,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len) { - const char *op = "add_template_measure"; - const char *audit_cause = "ENOMEM"; + static const char op[] = "add_template_measure"; + static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); struct ima_template_entry *entry; @@ -332,5 +332,5 @@ const char *ima_d_path(struct path *path, char **pathbuf) pathname = NULL; } } - return pathname; + return pathname ?: (const char *)path->dentry->d_name.name; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 734e946..291bf0f 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -177,11 +177,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len) { + static const char op[] = "appraise_data"; + char *cause = "unknown"; struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; enum integrity_status status = INTEGRITY_UNKNOWN; - const char *op = "appraise_data"; - char *cause = "unknown"; int rc = xattr_len, hash_start = 0; if (!ima_appraise) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index fdf60de..1bde8e6 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -10,9 +10,11 @@ * the Free Software Foundation, version 2 of the License. * * File: ima_crypto.c - * Calculates md5/sha1 file hash, template hash, boot-aggreate hash + * Calculates md5/sha1 file hash, template hash, boot-aggreate hash */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/file.h> #include <linux/crypto.h> @@ -85,16 +87,20 @@ static int ima_calc_file_hash_tfm(struct file *file, if (rc != 0) return rc; - rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!rbuf) { - rc = -ENOMEM; + i_size = i_size_read(file_inode(file)); + + if (i_size == 0) goto out; - } + + rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!rbuf) + return -ENOMEM; + if (!(file->f_mode & FMODE_READ)) { file->f_mode |= FMODE_READ; read = 1; } - i_size = i_size_read(file_inode(file)); + while (offset < i_size) { int rbuf_len; @@ -111,12 +117,12 @@ static int ima_calc_file_hash_tfm(struct file *file, if (rc) break; } - kfree(rbuf); - if (!rc) - rc = crypto_shash_final(&desc.shash, hash->digest); if (read) file->f_mode &= ~FMODE_READ; + kfree(rbuf); out: + if (!rc) + rc = crypto_shash_final(&desc.shash, hash->digest); return rc; } @@ -161,15 +167,22 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, return rc; for (i = 0; i < num_fields; i++) { + u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 }; + u8 *data_to_hash = field_data[i].data; + u32 datalen = field_data[i].len; + if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { rc = crypto_shash_update(&desc.shash, (const u8 *) &field_data[i].len, sizeof(field_data[i].len)); if (rc) break; + } else if (strcmp(td->fields[i]->field_id, "n") == 0) { + memcpy(buffer, data_to_hash, datalen); + data_to_hash = buffer; + datalen = IMA_EVENT_NAME_LEN_MAX + 1; } - rc = crypto_shash_update(&desc.shash, field_data[i].data, - field_data[i].len); + rc = crypto_shash_update(&desc.shash, data_to_hash, datalen); if (rc) break; } @@ -205,7 +218,7 @@ static void __init ima_pcrread(int idx, u8 *pcr) return; if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) - pr_err("IMA: Error Communicating to TPM chip\n"); + pr_err("Error Communicating to TPM chip\n"); } /* diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index db01125..da92fcc 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -133,14 +133,14 @@ static int ima_measurements_show(struct seq_file *m, void *v) * PCR used is always the same (config option) in * little-endian format */ - ima_putc(m, &pcr, sizeof pcr); + ima_putc(m, &pcr, sizeof(pcr)); /* 2nd: template digest */ ima_putc(m, e->digest, TPM_DIGEST_SIZE); /* 3rd: template name size */ namelen = strlen(e->template_desc->name); - ima_putc(m, &namelen, sizeof namelen); + ima_putc(m, &namelen, sizeof(namelen)); /* 4th: template name */ ima_putc(m, e->template_desc->name, namelen); @@ -160,6 +160,8 @@ static int ima_measurements_show(struct seq_file *m, void *v) if (is_ima_template && strcmp(field->field_id, "d") == 0) show = IMA_SHOW_BINARY_NO_FIELD_LEN; + if (is_ima_template && strcmp(field->field_id, "n") == 0) + show = IMA_SHOW_BINARY_OLD_STRING_FMT; field->field_show(m, show, &e->template_data[i]); } return 0; @@ -290,7 +292,7 @@ static atomic_t policy_opencount = ATOMIC_INIT(1); /* * ima_open_policy: sequentialize access to the policy file */ -static int ima_open_policy(struct inode * inode, struct file * filp) +static int ima_open_policy(struct inode *inode, struct file *filp) { /* No point in being allowed to open it if you aren't going to write */ if (!(filp->f_flags & O_WRONLY)) diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 3712276..e8f9d70 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -14,6 +14,9 @@ * File: ima_init.c * initialization and cleanup functions */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/scatterlist.h> #include <linux/slab.h> @@ -42,10 +45,10 @@ int ima_used_chip; */ static void __init ima_add_boot_aggregate(void) { + static const char op[] = "add_boot_aggregate"; + const char *audit_cause = "ENOMEM"; struct ima_template_entry *entry; struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; - const char *op = "add_boot_aggregate"; - const char *audit_cause = "ENOMEM"; int result = -ENOMEM; int violation = 0; struct { @@ -93,7 +96,7 @@ int __init ima_init(void) ima_used_chip = 1; if (!ima_used_chip) - pr_info("IMA: No TPM chip found, activating TPM-bypass!\n"); + pr_info("No TPM chip found, activating TPM-bypass!\n"); rc = ima_init_crypto(); if (rc) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 149ee11..52ac6cf 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -71,15 +71,14 @@ __setup("ima_hash=", hash_setup); * ima_rdwr_violation_check * * Only invalidate the PCR for measured files: - * - Opening a file for write when already open for read, + * - Opening a file for write when already open for read, * results in a time of measure, time of use (ToMToU) error. * - Opening a file for read when already open for write, - * could result in a file measurement error. + * could result in a file measurement error. * */ static void ima_rdwr_violation_check(struct file *file) { - struct dentry *dentry = file->f_path.dentry; struct inode *inode = file_inode(file); fmode_t mode = file->f_mode; int must_measure; @@ -111,8 +110,6 @@ out: return; pathname = ima_d_path(&file->f_path, &pathbuf); - if (!pathname || strlen(pathname) > IMA_EVENT_NAME_LEN_MAX) - pathname = dentry->d_name.name; if (send_tomtou) ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); @@ -220,9 +217,7 @@ static int process_measurement(struct file *file, const char *filename, if (rc != 0) goto out_digsig; - pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename; - if (!pathname) - pathname = (const char *)file->f_dentry->d_name.name; + pathname = filename ?: ima_d_path(&file->f_path, &pathbuf); if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index a9c3d3c..93873a4 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -7,7 +7,7 @@ * the Free Software Foundation, version 2 of the License. * * ima_policy.c - * - initialize default measure policy rules + * - initialize default measure policy rules * */ #include <linux/module.h> @@ -21,8 +21,8 @@ #include "ima.h" /* flags definitions */ -#define IMA_FUNC 0x0001 -#define IMA_MASK 0x0002 +#define IMA_FUNC 0x0001 +#define IMA_MASK 0x0002 #define IMA_FSMAGIC 0x0004 #define IMA_UID 0x0008 #define IMA_FOWNER 0x0010 @@ -69,35 +69,35 @@ struct ima_rule_entry { * and running executables. */ static struct ima_rule_entry default_rules[] = { - {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, - {.action = MEASURE,.func = MMAP_CHECK,.mask = MAY_EXEC, + {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, + {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, + {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, - {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC}, + {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry default_appraise_rules[] = { - {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC}, - {.action = APPRAISE,.fowner = GLOBAL_ROOT_UID,.flags = IMA_FOWNER}, + {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, + {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, }; static LIST_HEAD(ima_default_rules); @@ -122,12 +122,12 @@ static int __init default_appraise_policy_setup(char *str) } __setup("ima_appraise_tcb", default_appraise_policy_setup); -/* +/* * Although the IMA policy does not change, the LSM policy can be * reloaded, leaving the IMA LSM based rules referring to the old, * stale LSM policy. * - * Update the IMA LSM based rules to reflect the reloaded LSM policy. + * Update the IMA LSM based rules to reflect the reloaded LSM policy. * We assume the rules still exist; and BUG_ON() if they don't. */ static void ima_lsm_update_rules(void) @@ -167,9 +167,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, const struct cred *cred = current_cred(); int i; - if ((rule->flags & IMA_FUNC) && rule->func != func) + if ((rule->flags & IMA_FUNC) && + (rule->func != func && func != POST_SETATTR)) return false; - if ((rule->flags & IMA_MASK) && rule->mask != mask) + if ((rule->flags & IMA_MASK) && + (rule->mask != mask && func != POST_SETATTR)) return false; if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) @@ -216,7 +218,7 @@ retry: retried = 1; ima_lsm_update_rules(); goto retry; - } + } if (!rc) return false; } @@ -232,7 +234,7 @@ static int get_subaction(struct ima_rule_entry *rule, int func) if (!(rule->flags & IMA_FUNC)) return IMA_FILE_APPRAISE; - switch(func) { + switch (func) { case MMAP_CHECK: return IMA_MMAP_APPRAISE; case BPRM_CHECK: @@ -304,7 +306,7 @@ void __init ima_init_policy(void) measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0; appraise_entries = ima_use_appraise_tcb ? ARRAY_SIZE(default_appraise_rules) : 0; - + for (i = 0; i < measure_entries + appraise_entries; i++) { if (i < measure_entries) list_add_tail(&default_rules[i].list, @@ -329,7 +331,7 @@ void __init ima_init_policy(void) */ void ima_update_policy(void) { - const char *op = "policy_update"; + static const char op[] = "policy_update"; const char *cause = "already exists"; int result = 1; int audit_info = 0; @@ -520,8 +522,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 16, - &entry->fsmagic); + result = kstrtoul(args[0].from, 16, &entry->fsmagic); if (!result) entry->flags |= IMA_FSMAGIC; break; @@ -547,7 +548,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 10, &lnum); + result = kstrtoul(args[0].from, 10, &lnum); if (!result) { entry->uid = make_kuid(current_user_ns(), (uid_t)lnum); if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum)) @@ -564,7 +565,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; } - result = strict_strtoul(args[0].from, 10, &lnum); + result = kstrtoul(args[0].from, 10, &lnum); if (!result) { entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) @@ -645,7 +646,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) */ ssize_t ima_parse_add_rule(char *rule) { - const char *op = "update_policy"; + static const char op[] = "update_policy"; char *p; struct ima_rule_entry *entry; ssize_t result, len; diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index d85e997..552705d 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -18,6 +18,9 @@ * The measurement list is append-only. No entry is * ever removed or changed during the boot-cycle. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/rculist.h> #include <linux/slab.h> @@ -72,7 +75,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) qe = kmalloc(sizeof(*qe), GFP_KERNEL); if (qe == NULL) { - pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n"); + pr_err("OUT OF MEMORY ERROR creating queue entry\n"); return -ENOMEM; } qe->entry = entry; @@ -95,8 +98,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("IMA: Error Communicating to TPM chip, result: %d\n", - result); + pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; } @@ -115,7 +117,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, mutex_lock(&ima_extend_list_mutex); if (!violation) { - memcpy(digest, entry->digest, sizeof digest); + memcpy(digest, entry->digest, sizeof(digest)); if (ima_lookup_digest_entry(digest)) { audit_cause = "hash_exists"; result = -EEXIST; @@ -131,7 +133,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, } if (violation) /* invalidate pcr */ - memset(digest, 0xff, sizeof digest); + memset(digest, 0xff, sizeof(digest)); tpmresult = ima_pcr_extend(digest); if (tpmresult != 0) { diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 635695f..a076a96 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -12,6 +12,9 @@ * File: ima_template.c * Helpers to manage template descriptors. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <crypto/hash_info.h> #include "ima.h" @@ -19,20 +22,20 @@ static struct ima_template_desc defined_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, - {.name = "ima-ng",.fmt = "d-ng|n-ng"}, - {.name = "ima-sig",.fmt = "d-ng|n-ng|sig"}, + {.name = "ima-ng", .fmt = "d-ng|n-ng"}, + {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, }; static struct ima_template_field supported_fields[] = { - {.field_id = "d",.field_init = ima_eventdigest_init, + {.field_id = "d", .field_init = ima_eventdigest_init, .field_show = ima_show_template_digest}, - {.field_id = "n",.field_init = ima_eventname_init, + {.field_id = "n", .field_init = ima_eventname_init, .field_show = ima_show_template_string}, - {.field_id = "d-ng",.field_init = ima_eventdigest_ng_init, + {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init, .field_show = ima_show_template_digest_ng}, - {.field_id = "n-ng",.field_init = ima_eventname_ng_init, + {.field_id = "n-ng", .field_init = ima_eventname_ng_init, .field_show = ima_show_template_string}, - {.field_id = "sig",.field_init = ima_eventsig_init, + {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, }; @@ -58,7 +61,7 @@ static int __init ima_template_setup(char *str) */ if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 && ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) { - pr_err("IMA: template does not support hash alg\n"); + pr_err("template does not support hash alg\n"); return 1; } diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 1683bbf..1506f02 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -27,7 +27,6 @@ static bool ima_template_hash_algo_allowed(u8 algo) enum data_formats { DATA_FMT_DIGEST = 0, DATA_FMT_DIGEST_WITH_ALGO, - DATA_FMT_EVENT_NAME, DATA_FMT_STRING, DATA_FMT_HEX }; @@ -37,18 +36,10 @@ static int ima_write_template_field_data(const void *data, const u32 datalen, struct ima_field_data *field_data) { u8 *buf, *buf_ptr; - u32 buflen; + u32 buflen = datalen; - switch (datafmt) { - case DATA_FMT_EVENT_NAME: - buflen = IMA_EVENT_NAME_LEN_MAX + 1; - break; - case DATA_FMT_STRING: + if (datafmt == DATA_FMT_STRING) buflen = datalen + 1; - break; - default: - buflen = datalen; - } buf = kzalloc(buflen, GFP_KERNEL); if (!buf) @@ -63,7 +54,7 @@ static int ima_write_template_field_data(const void *data, const u32 datalen, * split into multiple template fields (the space is the delimitator * character for measurements lists in ASCII format). */ - if (datafmt == DATA_FMT_EVENT_NAME || datafmt == DATA_FMT_STRING) { + if (datafmt == DATA_FMT_STRING) { for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++) if (*buf_ptr == ' ') *buf_ptr = '_'; @@ -109,13 +100,16 @@ static void ima_show_template_data_binary(struct seq_file *m, enum data_formats datafmt, struct ima_field_data *field_data) { + u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ? + strlen(field_data->data) : field_data->len; + if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) - ima_putc(m, &field_data->len, sizeof(u32)); + ima_putc(m, &len, sizeof(len)); - if (!field_data->len) + if (!len) return; - ima_putc(m, field_data->data, field_data->len); + ima_putc(m, field_data->data, len); } static void ima_show_template_field_data(struct seq_file *m, @@ -129,6 +123,7 @@ static void ima_show_template_field_data(struct seq_file *m, break; case IMA_SHOW_BINARY: case IMA_SHOW_BINARY_NO_FIELD_LEN: + case IMA_SHOW_BINARY_OLD_STRING_FMT: ima_show_template_data_binary(m, show, datafmt, field_data); break; default: @@ -277,8 +272,6 @@ static int ima_eventname_init_common(struct integrity_iint_cache *iint, { const char *cur_filename = NULL; u32 cur_filename_len = 0; - enum data_formats fmt = size_limit ? - DATA_FMT_EVENT_NAME : DATA_FMT_STRING; BUG_ON(filename == NULL && file == NULL); @@ -301,7 +294,7 @@ static int ima_eventname_init_common(struct integrity_iint_cache *iint, cur_filename_len = IMA_EVENT_NAME_LEN_MAX; out: return ima_write_template_field_data(cur_filename, cur_filename_len, - fmt, field_data); + DATA_FMT_STRING, field_data); } /* diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index d7efb30..90987d1 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -7,7 +7,7 @@ * the Free Software Foundation, version 2 of the License. * * File: integrity_audit.c - * Audit calls for the integrity subsystem + * Audit calls for the integrity subsystem */ #include <linux/fs.h> @@ -22,7 +22,7 @@ static int __init integrity_audit_setup(char *str) { unsigned long audit; - if (!strict_strtoul(str, 0, &audit)) + if (!kstrtoul(str, 0, &audit)) integrity_audit_info = audit ? 1 : 0; return 1; } @@ -33,13 +33,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, const char *cause, int result, int audit_info) { struct audit_buffer *ab; + char name[TASK_COMM_LEN]; if (!integrity_audit_info && audit_info == 1) /* Skip info messages */ return; ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", - current->pid, + task_pid_nr(current), from_kuid(&init_user_ns, current_cred()->uid), from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); @@ -49,7 +50,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, audit_log_format(ab, " cause="); audit_log_string(ab, cause); audit_log_format(ab, " comm="); - audit_log_untrustedstring(ab, current->comm); + audit_log_untrustedstring(ab, get_task_comm(name, current)); if (fname) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, fname); diff --git a/security/keys/compat.c b/security/keys/compat.c index bbd32c7..3478965 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -65,8 +65,8 @@ no_payload: * taking a 32-bit syscall are zero. If you can, you should call sys_keyctl() * directly. */ -asmlinkage long compat_sys_keyctl(u32 option, - u32 arg2, u32 arg3, u32 arg4, u32 arg5) +COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, + u32, arg2, u32, arg3, u32, arg4, u32, arg5) { switch (option) { case KEYCTL_GET_KEYRING_ID: diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 9e1e005..5fe443d 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -609,7 +609,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, long dlen; int ret; - ret = strict_strtol(datalen, 10, &dlen); + ret = kstrtol(datalen, 10, &dlen); if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) return ERR_PTR(-EINVAL); diff --git a/security/keys/trusted.c b/security/keys/trusted.c index e13fcf7..6b804aa 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -753,7 +753,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; break; case Opt_keyhandle: - res = strict_strtoul(args[0].from, 16, &handle); + res = kstrtoul(args[0].from, 16, &handle); if (res < 0) return -EINVAL; opt->keytype = SEAL_keytype; @@ -782,7 +782,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; break; case Opt_pcrlock: - res = strict_strtoul(args[0].from, 10, &lock); + res = kstrtoul(args[0].from, 10, &lock); if (res < 0) return -EINVAL; opt->pcrlock = lock; @@ -820,7 +820,7 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p, c = strsep(&datablob, " \t"); if (!c) return -EINVAL; - ret = strict_strtol(c, 10, &keylen); + ret = kstrtol(c, 10, &keylen); if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) return -EINVAL; p->key_len = keylen; diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 9a62045..69fdf3b 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -220,7 +220,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, */ BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); - audit_log_format(ab, " pid=%d comm=", tsk->pid); + audit_log_format(ab, " pid=%d comm=", task_pid_nr(tsk)); audit_log_untrustedstring(ab, tsk->comm); switch (a->type) { @@ -278,9 +278,12 @@ static void dump_common_audit_data(struct audit_buffer *ab, } case LSM_AUDIT_DATA_TASK: tsk = a->u.tsk; - if (tsk && tsk->pid) { - audit_log_format(ab, " pid=%d comm=", tsk->pid); - audit_log_untrustedstring(ab, tsk->comm); + if (tsk) { + pid_t pid = task_pid_nr(tsk); + if (pid) { + audit_log_format(ab, " pid=%d comm=", pid); + audit_log_untrustedstring(ab, tsk->comm); + } } break; case LSM_AUDIT_DATA_NET: diff --git a/security/security.c b/security/security.c index 919cad9..8b774f3 100644 --- a/security/security.c +++ b/security/security.c @@ -433,11 +433,20 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, } int security_path_rename(struct path *old_dir, struct dentry *old_dentry, - struct path *new_dir, struct dentry *new_dentry) + struct path *new_dir, struct dentry *new_dentry, + unsigned int flags) { if (unlikely(IS_PRIVATE(old_dentry->d_inode) || (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode)))) return 0; + + if (flags & RENAME_EXCHANGE) { + int err = security_ops->path_rename(new_dir, new_dentry, + old_dir, old_dentry); + if (err) + return err; + } + return security_ops->path_rename(old_dir, old_dentry, new_dir, new_dentry); } @@ -524,11 +533,20 @@ int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, } int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) { if (unlikely(IS_PRIVATE(old_dentry->d_inode) || (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode)))) return 0; + + if (flags & RENAME_EXCHANGE) { + int err = security_ops->inode_rename(new_dir, new_dentry, + old_dir, old_dentry); + if (err) + return err; + } + return security_ops->inode_rename(old_dir, old_dentry, new_dir, new_dentry); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b03b077..336f0a0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -106,7 +106,7 @@ int selinux_enforcing; static int __init enforcing_setup(char *str) { unsigned long enforcing; - if (!strict_strtoul(str, 0, &enforcing)) + if (!kstrtoul(str, 0, &enforcing)) selinux_enforcing = enforcing ? 1 : 0; return 1; } @@ -119,7 +119,7 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; static int __init selinux_enabled_setup(char *str) { unsigned long enabled; - if (!strict_strtoul(str, 0, &enabled)) + if (!kstrtoul(str, 0, &enabled)) selinux_enabled = enabled ? 1 : 0; return 1; } @@ -3320,6 +3320,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, case F_GETLK: case F_SETLK: case F_SETLKW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: #if BITS_PER_LONG == 32 case F_GETLK64: case F_SETLK64: diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 9f05847..1450f85 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -46,10 +46,11 @@ static inline void selinux_xfrm_notify_policyload(void) { struct net *net; - atomic_inc(&flow_cache_genid); rtnl_lock(); - for_each_net(net) + for_each_net(net) { + atomic_inc(&net->xfrm.flow_cache_genid); rt_genid_bump_all(net); + } rtnl_unlock(); } #else diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d60c0ee..c71737f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -54,7 +54,7 @@ unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; static int __init checkreqprot_setup(char *str) { unsigned long checkreqprot; - if (!strict_strtoul(str, 0, &checkreqprot)) + if (!kstrtoul(str, 0, &checkreqprot)) selinux_checkreqprot = checkreqprot ? 1 : 0; return 1; } diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 80a09c3..a3386d1 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -173,7 +173,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, * Use filesystem name if filesystem does not support rename() * operation. */ - if (inode->i_op && !inode->i_op->rename) + if (!inode->i_op->rename) goto prepend_filesystem_name; } /* Prepend device name. */ @@ -282,7 +282,7 @@ char *tomoyo_realpath_from_path(struct path *path) * Get local name for filesystems without rename() operation * or dentry without vfsmount. */ - if (!path->mnt || (inode->i_op && !inode->i_op->rename)) + if (!path->mnt || !inode->i_op->rename) pos = tomoyo_get_local_path(path->dentry, buf, buf_len - 1); /* Get absolute name for the rest. */ |