diff options
Diffstat (limited to 'security')
37 files changed, 365 insertions, 307 deletions
diff --git a/security/Kconfig b/security/Kconfig index 28e685f53bd1..f10dbf15c294 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -64,6 +64,11 @@ config SECURITY If you are unsure how to answer this question, answer N. +config HAS_SECURITY_AUDIT + def_bool y + depends on AUDIT + depends on SECURITY + config SECURITYFS bool "Enable the securityfs filesystem" help diff --git a/security/Makefile b/security/Makefile index cc0982214b84..22ff4c8bd8ce 100644 --- a/security/Makefile +++ b/security/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_SECURITY) += security.o obj-$(CONFIG_SECURITYFS) += inode.o obj-$(CONFIG_SECURITY_SELINUX) += selinux/ obj-$(CONFIG_SECURITY_SMACK) += smack/ -obj-$(CONFIG_SECURITY) += lsm_audit.o +obj-$(CONFIG_HAS_SECURITY_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index f6a515640950..6025d3849cf8 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -25,11 +25,10 @@ struct aa_label; extern int apparmor_display_secid_mode; struct aa_label *aa_secid_to_label(u32 secid); -int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); -int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, - u32 *seclen); +int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp); +int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp); int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); -void apparmor_release_secctx(char *secdata, u32 seclen); +void apparmor_release_secctx(struct lsm_context *cp); int aa_alloc_secid(struct aa_label *label, gfp_t gfp); diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 47dc08fc583e..28caf66b9033 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -47,23 +47,21 @@ struct aa_label *aa_secid_to_label(u32 secid) return xa_load(&aa_secids, secid); } -static int apparmor_label_to_secctx(struct aa_label *label, char **secdata, - u32 *seclen) +static int apparmor_label_to_secctx(struct aa_label *label, + struct lsm_context *cp) { /* TODO: cache secctx and ref count so we don't have to recreate */ int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT; int len; - AA_BUG(!seclen); - if (!label) return -EINVAL; if (apparmor_display_secid_mode) flags |= FLAG_SHOW_MODE; - if (secdata) - len = aa_label_asxprint(secdata, root_ns, label, + if (cp) + len = aa_label_asxprint(&cp->context, root_ns, label, flags, GFP_ATOMIC); else len = aa_label_snxprint(NULL, 0, root_ns, label, flags); @@ -71,26 +69,28 @@ static int apparmor_label_to_secctx(struct aa_label *label, char **secdata, if (len < 0) return -ENOMEM; - *seclen = len; + if (cp) { + cp->len = len; + cp->id = LSM_ID_APPARMOR; + } - return 0; + return len; } -int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp) { struct aa_label *label = aa_secid_to_label(secid); - return apparmor_label_to_secctx(label, secdata, seclen); + return apparmor_label_to_secctx(label, cp); } -int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, - u32 *seclen) +int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp) { struct aa_label *label; label = prop->apparmor.label; - return apparmor_label_to_secctx(label, secdata, seclen); + return apparmor_label_to_secctx(label, cp); } int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) @@ -106,9 +106,13 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) return 0; } -void apparmor_release_secctx(char *secdata, u32 seclen) +void apparmor_release_secctx(struct lsm_context *cp) { - kfree(secdata); + if (cp->id == LSM_ID_APPARMOR) { + kfree(cp->context); + cp->context = NULL; + cp->id = LSM_ID_UNDEF; + } } /** diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c0d3b716d11f..24d09ea91b87 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -278,6 +278,7 @@ unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); void ima_init_template_list(void); int __init ima_init_digests(void); +void __init ima_init_reboot_notifier(void); int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, void *lsm_data); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 4e208239a40e..a2f34f2d8ad7 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -152,6 +152,8 @@ int __init ima_init(void) ima_init_key_queue(); + ima_init_reboot_notifier(); + ima_measure_critical_data("kernel_info", "kernel_version", UTS_RELEASE, strlen(UTS_RELEASE), false, NULL, 0); diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 52e00332defe..9d45f4d26f73 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -37,7 +37,8 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, memset(&khdr, 0, sizeof(khdr)); khdr.version = 1; - list_for_each_entry_rcu(qe, &ima_measurements, later) { + /* This is an append-only list, no need to hold the RCU read lock */ + list_for_each_entry_rcu(qe, &ima_measurements, later, true) { if (file.count < file.size) { khdr.count++; ima_measurements_show(&file, qe); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 21a8e54c383f..128fab897930 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -148,7 +148,8 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { {.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 = TMPFS_MAGIC, .func = FILE_CHECK, + .flags = IMA_FSMAGIC | IMA_FUNC}, {.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}, @@ -1431,7 +1432,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) int token; unsigned long lnum; - if (result < 0) + if (result < 0 || *p == '#') /* ignore suffixed comment */ break; if ((*p == '\0') || (*p == ' ') || (*p == '\t')) continue; diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 532da87ce519..83d53824aa98 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -16,6 +16,7 @@ */ #include <linux/rculist.h> +#include <linux/reboot.h> #include <linux/slab.h> #include "ima.h" @@ -44,6 +45,12 @@ struct ima_h_table ima_htable = { */ static DEFINE_MUTEX(ima_extend_list_mutex); +/* + * Used internally by the kernel to suspend measurements. + * Protected by ima_extend_list_mutex. + */ +static bool ima_measurements_suspended; + /* lookup up the digest value in the hash table, and return the entry */ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, int pcr) @@ -168,6 +175,18 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, int result = 0, tpmresult = 0; mutex_lock(&ima_extend_list_mutex); + + /* + * Avoid appending to the measurement log when the TPM subsystem has + * been shut down while preparing for system reboot. + */ + if (ima_measurements_suspended) { + audit_cause = "measurements_suspended"; + audit_info = 0; + result = -ENODEV; + goto out; + } + if (!violation && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) { if (ima_lookup_digest_entry(digest, entry->pcr)) { audit_cause = "hash_exists"; @@ -211,6 +230,31 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry) return result; } +static void ima_measurements_suspend(void) +{ + mutex_lock(&ima_extend_list_mutex); + ima_measurements_suspended = true; + mutex_unlock(&ima_extend_list_mutex); +} + +static int ima_reboot_notifier(struct notifier_block *nb, + unsigned long action, + void *data) +{ + ima_measurements_suspend(); + + return NOTIFY_DONE; +} + +static struct notifier_block ima_reboot_nb = { + .notifier_call = ima_reboot_notifier, +}; + +void __init ima_init_reboot_notifier(void) +{ + register_reboot_notifier(&ima_reboot_nb); +} + int __init ima_init_digests(void) { u16 digest_size; diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c index f2bdbd55aa2b..cf83afa1d879 100644 --- a/security/lockdown/lockdown.c +++ b/security/lockdown/lockdown.c @@ -96,7 +96,7 @@ static int __init lockdown_lsm_init(void) static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - char temp[80]; + char temp[80] = ""; int i, offset = 0; for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) { diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 9a8352972086..52db886dbba8 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -171,7 +171,7 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, static inline void print_ipv6_addr(struct audit_buffer *ab, const struct in6_addr *addr, __be16 port, - char *name1, char *name2) + const char *name1, const char *name2) { if (!ipv6_addr_any(addr)) audit_log_format(ab, " %s=%pI6c", name1, addr); @@ -180,7 +180,7 @@ static inline void print_ipv6_addr(struct audit_buffer *ab, } static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, - __be16 port, char *name1, char *name2) + __be16 port, const char *name1, const char *name2) { if (addr) audit_log_format(ab, " %s=%pI4", name1, &addr); @@ -299,10 +299,10 @@ static void dump_common_audit_data(struct audit_buffer *ab, if (tsk) { pid_t pid = task_tgid_nr(tsk); if (pid) { - char comm[sizeof(tsk->comm)]; + char tskcomm[sizeof(tsk->comm)]; audit_log_format(ab, " opid=%d ocomm=", pid); audit_log_untrustedstring(ab, - get_task_comm(comm, tsk)); + get_task_comm(tskcomm, tsk)); } } break; @@ -425,6 +425,9 @@ static void dump_common_audit_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_ANONINODE: audit_log_format(ab, " anonclass=%s", a->u.anonclass); break; + case LSM_AUDIT_DATA_NLMSGTYPE: + audit_log_format(ab, " nl-msgtype=%hu", a->u.nlmsg_type); + break; } /* switch (a->type) */ } diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c index 25310468bcdd..8e1ffd70b18a 100644 --- a/security/safesetid/securityfs.c +++ b/security/safesetid/securityfs.c @@ -143,6 +143,9 @@ static ssize_t handle_policy_update(struct file *file, char *buf, *p, *end; int err; + if (len >= KMALLOC_MAX_SIZE) + return -EINVAL; + pol = kmalloc(sizeof(struct setid_ruleset), GFP_KERNEL); if (!pol) return -ENOMEM; diff --git a/security/security.c b/security/security.c index 09664e09fec9..39df4451455b 100644 --- a/security/security.c +++ b/security/security.c @@ -1735,8 +1735,7 @@ void security_inode_free(struct inode *inode) * @mode: mode used to determine resource type * @name: name of the last path component * @xattr_name: name of the security/LSM xattr - * @ctx: pointer to the resulting LSM context - * @ctxlen: length of @ctx + * @lsmctx: pointer to the resulting LSM context * * Compute a context for a dentry as the inode is not yet available since NFSv4 * has no label backed by an EA anyway. It is important to note that @@ -1746,11 +1745,11 @@ void security_inode_free(struct inode *inode) */ int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, - const char **xattr_name, void **ctx, - u32 *ctxlen) + const char **xattr_name, + struct lsm_context *lsmctx) { return call_int_hook(dentry_init_security, dentry, mode, name, - xattr_name, ctx, ctxlen); + xattr_name, lsmctx); } EXPORT_SYMBOL(security_dentry_init_security); @@ -4139,10 +4138,8 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, if (base) uctx = (struct lsm_ctx __user *)(base + total); rc = scall->hl->hook.getselfattr(attr, uctx, &entrysize, flags); - if (rc == -EOPNOTSUPP) { - rc = 0; + if (rc == -EOPNOTSUPP) continue; - } if (rc == -E2BIG) { rc = 0; left = 0; @@ -4304,40 +4301,36 @@ EXPORT_SYMBOL(security_ismaclabel); /** * security_secid_to_secctx() - Convert a secid to a secctx * @secid: secid - * @secdata: secctx - * @seclen: secctx length + * @cp: the LSM context * - * Convert secid to security context. If @secdata is NULL the length of the - * result will be returned in @seclen, but no @secdata will be returned. This + * Convert secid to security context. If @cp is NULL the length of the + * result will be returned, but no data will be returned. This * does mean that the length could change between calls to check the length and - * the next call which actually allocates and returns the @secdata. + * the next call which actually allocates and returns the data. * - * Return: Return 0 on success, error on failure. + * Return: Return length of data on success, error on failure. */ -int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +int security_secid_to_secctx(u32 secid, struct lsm_context *cp) { - return call_int_hook(secid_to_secctx, secid, secdata, seclen); + return call_int_hook(secid_to_secctx, secid, cp); } EXPORT_SYMBOL(security_secid_to_secctx); /** * security_lsmprop_to_secctx() - Convert a lsm_prop to a secctx * @prop: lsm specific information - * @secdata: secctx - * @seclen: secctx length + * @cp: the LSM context * - * Convert a @prop entry to security context. If @secdata is NULL the - * length of the result will be returned in @seclen, but no @secdata - * will be returned. This does mean that the length could change between - * calls to check the length and the next call which actually allocates - * and returns the @secdata. + * Convert a @prop entry to security context. If @cp is NULL the + * length of the result will be returned. This does mean that the + * length could change between calls to check the length and the + * next call which actually allocates and returns the @cp. * - * Return: Return 0 on success, error on failure. + * Return: Return length of data on success, error on failure. */ -int security_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, - u32 *seclen) +int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp) { - return call_int_hook(lsmprop_to_secctx, prop, secdata, seclen); + return call_int_hook(lsmprop_to_secctx, prop, cp); } EXPORT_SYMBOL(security_lsmprop_to_secctx); @@ -4360,14 +4353,14 @@ EXPORT_SYMBOL(security_secctx_to_secid); /** * security_release_secctx() - Free a secctx buffer - * @secdata: secctx - * @seclen: length of secctx + * @cp: the security context * * Release the security context. */ -void security_release_secctx(char *secdata, u32 seclen) +void security_release_secctx(struct lsm_context *cp) { - call_void_hook(release_secctx, secdata, seclen); + call_void_hook(release_secctx, cp); + memset(cp, 0, sizeof(*cp)); } EXPORT_SYMBOL(security_release_secctx); @@ -4430,17 +4423,17 @@ EXPORT_SYMBOL(security_inode_setsecctx); /** * security_inode_getsecctx() - Get the security label of an inode * @inode: inode - * @ctx: secctx - * @ctxlen: length of secctx + * @cp: security context * - * On success, returns 0 and fills out @ctx and @ctxlen with the security - * context for the given @inode. + * On success, returns 0 and fills out @cp with the security context + * for the given @inode. * * Return: Returns 0 on success, error on failure. */ -int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +int security_inode_getsecctx(struct inode *inode, struct lsm_context *cp) { - return call_int_hook(inode_getsecctx, inode, ctx, ctxlen); + memset(cp, 0, sizeof(*cp)); + return call_int_hook(inode_getsecctx, inode, cp); } EXPORT_SYMBOL(security_inode_getsecctx); diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 86f0575f670d..66e56e9011df 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -33,11 +33,10 @@ $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs)) cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs)) -# see the note above, replace the $targets and 'flask.h' rule with the lines -# below: -# targets += $(genhdrs) +targets += $(genhdrs) + +# see the note above, replace the 'flask.h' rule with the line below: # $(addprefix $(obj)/,$(genhdrs)) &: $(obj)/genheaders FORCE -targets += flask.h $(obj)/flask.h: $(obj)/genheaders FORCE $(call if_changed,genhdrs) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 171dd7fceac5..22fd7436f372 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -407,7 +407,7 @@ static const struct { static int match_opt_prefix(char *s, int l, char **arg) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(tokens); i++) { size_t len = tokens[i].len; @@ -2869,8 +2869,8 @@ static void selinux_inode_free_security(struct inode *inode) static int selinux_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, - const char **xattr_name, void **ctx, - u32 *ctxlen) + const char **xattr_name, + struct lsm_context *cp) { u32 newsid; int rc; @@ -2885,8 +2885,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, if (xattr_name) *xattr_name = XATTR_NAME_SELINUX; - return security_sid_to_context(newsid, (char **)ctx, - ctxlen); + cp->id = LSM_ID_SELINUX; + return security_sid_to_context(newsid, &cp->context, &cp->len); } static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, @@ -3135,7 +3135,7 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, const struct cred *cred = current_cred(); struct inode *inode = d_backing_inode(dentry); unsigned int ia_valid = iattr->ia_valid; - __u32 av = FILE__WRITE; + u32 av = FILE__WRITE; /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ if (ia_valid & ATTR_FORCE) { @@ -4835,7 +4835,7 @@ out: return err; err_af: /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */ - if (sksec->sclass == SECCLASS_SCTP_SOCKET) + if (sk->sk_protocol == IPPROTO_SCTP) return -EINVAL; return -EAFNOSUPPORT; } @@ -5939,14 +5939,14 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t { struct sk_security_struct *sksec = sk->sk_security; struct common_audit_data ad; - struct lsm_network_audit net; u8 driver; u8 xperm; if (sock_skip_has_perm(sksec->sid)) return 0; - ad_net_init_from_sk(&ad, &net, sk); + ad.type = LSM_AUDIT_DATA_NLMSGTYPE; + ad.u.nlmsg_type = nlmsg_type; driver = nlmsg_type >> 8; xperm = nlmsg_type & 0xff; @@ -6640,15 +6640,28 @@ static int selinux_ismaclabel(const char *name) return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0); } -static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp) { - return security_sid_to_context(secid, secdata, seclen); + u32 seclen; + int ret; + + if (cp) { + cp->id = LSM_ID_SELINUX; + ret = security_sid_to_context(secid, &cp->context, &cp->len); + if (ret < 0) + return ret; + return cp->len; + } + ret = security_sid_to_context(secid, NULL, &seclen); + if (ret < 0) + return ret; + return seclen; } -static int selinux_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, - u32 *seclen) +static int selinux_lsmprop_to_secctx(struct lsm_prop *prop, + struct lsm_context *cp) { - return selinux_secid_to_secctx(prop->selinux.secid, secdata, seclen); + return selinux_secid_to_secctx(prop->selinux.secid, cp); } static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) @@ -6657,9 +6670,13 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) secid, GFP_KERNEL); } -static void selinux_release_secctx(char *secdata, u32 seclen) +static void selinux_release_secctx(struct lsm_context *cp) { - kfree(secdata); + if (cp->id == LSM_ID_SELINUX) { + kfree(cp->context); + cp->context = NULL; + cp->id = LSM_ID_UNDEF; + } } static void selinux_inode_invalidate_secctx(struct inode *inode) @@ -6691,14 +6708,16 @@ static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) ctx, ctxlen, 0, NULL); } -static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +static int selinux_inode_getsecctx(struct inode *inode, struct lsm_context *cp) { - int len = 0; + int len; len = selinux_inode_getsecurity(&nop_mnt_idmap, inode, - XATTR_SELINUX_SUFFIX, ctx, true); + XATTR_SELINUX_SUFFIX, + (void **)&cp->context, true); if (len < 0) return len; - *ctxlen = len; + cp->len = len; + cp->id = LSM_ID_SELINUX; return 0; } #ifdef CONFIG_KEYS diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 2bc20135324a..03e82477dce9 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -179,7 +179,7 @@ const struct security_class_mapping secclass_map[] = { { "anon_inode", { COMMON_FILE_PERMS, NULL } }, { "io_uring", { "override_creds", "sqpoll", "cmd", NULL } }, { "user_namespace", { "create", NULL } }, - { NULL } + /* last one */ { NULL, {} } }; #ifdef __KERNEL__ /* avoid this check when building host programs */ diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h index 5910bb7c2eca..060833e2dba2 100644 --- a/security/selinux/include/conditional.h +++ b/security/selinux/include/conditional.h @@ -16,7 +16,7 @@ int security_get_bools(struct selinux_policy *policy, u32 *len, char ***names, int **values); -int security_set_bools(u32 len, int *values); +int security_set_bools(u32 len, const int *values); int security_get_bool_value(u32 index); diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 700bd6c8bb38..8b4c2aa35839 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -46,10 +46,11 @@ #define POLICYDB_VERSION_INFINIBAND 31 #define POLICYDB_VERSION_GLBLUB 32 #define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */ +#define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */ /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COND_XPERMS /* Mask for just the mount related flags */ #define SE_MNTMASK 0x0f @@ -292,7 +293,7 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len, int security_context_to_sid_force(const char *scontext, u32 scontext_len, u32 *sid); -int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); +int security_get_user_sids(u32 fromsid, const char *username, u32 **sids, u32 *nel); int security_port_sid(u8 protocol, u16 port, u32 *out_sid); @@ -310,7 +311,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass); -int security_bounded_transition(u32 oldsid, u32 newsid); +int security_bounded_transition(u32 old_sid, u32 new_sid); int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 6cd5bb0ba380..47480eb2189b 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1515,7 +1515,7 @@ static const struct file_operations sel_avc_hash_stats_ops = { #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx) { - int cpu; + loff_t cpu; for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) { if (!cpu_possible(cpu)) @@ -2001,7 +2001,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO}, [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops, S_IWUGO}, - /* last one */ {""} + /* last one */ {"", NULL, 0} }; ret = selinux_fs_info_create(sb); diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 8e400dd736b7..c2c31521cace 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -336,10 +336,10 @@ static const uint16_t spec_order[] = { }; /* clang-format on */ -int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, +int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol, int (*insertf)(struct avtab *a, const struct avtab_key *k, const struct avtab_datum *d, void *p), - void *p) + void *p, bool conditional) { __le16 buf16[4]; u16 enabled; @@ -457,6 +457,13 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, "was specified\n", vers); return -EINVAL; + } else if ((vers < POLICYDB_VERSION_COND_XPERMS) && + (key.specified & AVTAB_XPERMS) && conditional) { + pr_err("SELinux: avtab: policy version %u does not " + "support extended permissions rules in conditional " + "policies and one was specified\n", + vers); + return -EINVAL; } else if (key.specified & AVTAB_XPERMS) { memset(&xperms, 0, sizeof(struct avtab_extended_perms)); rc = next_entry(&xperms.specified, fp, sizeof(u8)); @@ -500,7 +507,7 @@ static int avtab_insertf(struct avtab *a, const struct avtab_key *k, return avtab_insert(a, k, d); } -int avtab_read(struct avtab *a, void *fp, struct policydb *pol) +int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol) { int rc; __le32 buf[1]; @@ -523,7 +530,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) goto bad; for (i = 0; i < nel; i++) { - rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL); + rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL, false); if (rc) { if (rc == -ENOMEM) pr_err("SELinux: avtab: out of memory\n"); @@ -543,7 +550,7 @@ bad: goto out; } -int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp) +int avtab_write_item(struct policydb *p, const struct avtab_node *cur, struct policy_file *fp) { __le16 buf16[4]; __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; @@ -579,7 +586,7 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp) return 0; } -int avtab_write(struct policydb *p, struct avtab *a, void *fp) +int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp) { u32 i; int rc = 0; diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index f4407185401c..850b3453f259 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -89,7 +89,7 @@ struct avtab { }; void avtab_init(struct avtab *h); -int avtab_alloc(struct avtab *, u32); +int avtab_alloc(struct avtab *h, u32 nrules); int avtab_alloc_dup(struct avtab *new, const struct avtab *orig); void avtab_destroy(struct avtab *h); @@ -105,15 +105,16 @@ static inline void avtab_hash_eval(struct avtab *h, const char *tag) #endif struct policydb; -int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, +struct policy_file; +int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol, int (*insert)(struct avtab *a, const struct avtab_key *k, const struct avtab_datum *d, void *p), - void *p); + void *p, bool conditional); -int avtab_read(struct avtab *a, void *fp, struct policydb *pol); +int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol); int avtab_write_item(struct policydb *p, const struct avtab_node *cur, - void *fp); -int avtab_write(struct policydb *p, struct avtab *a, void *fp); + struct policy_file *fp); +int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp); struct avtab_node *avtab_insert_nonunique(struct avtab *h, const struct avtab_key *key, diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 64ba95e40a6f..1bebfcb9c6a1 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -206,7 +206,7 @@ static int bool_isvalid(struct cond_bool_datum *b) return 1; } -int cond_read_bool(struct policydb *p, struct symtab *s, void *fp) +int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct cond_bool_datum *booldatum; @@ -230,17 +230,11 @@ int cond_read_bool(struct policydb *p, struct symtab *s, void *fp) goto err; len = le32_to_cpu(buf[2]); - if (((len == 0) || (len == (u32)-1))) - goto err; - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto err; - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto err; - key[len] = '\0'; + rc = symtab_insert(s, key, booldatum); if (rc) goto err; @@ -323,7 +317,7 @@ static int cond_insertf(struct avtab *a, const struct avtab_key *k, return 0; } -static int cond_read_av_list(struct policydb *p, void *fp, +static int cond_read_av_list(struct policydb *p, struct policy_file *fp, struct cond_av_list *list, struct cond_av_list *other) { @@ -349,7 +343,7 @@ static int cond_read_av_list(struct policydb *p, void *fp, for (i = 0; i < len; i++) { data.dst = &list->nodes[i]; rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf, - &data); + &data, true); if (rc) { kfree(list->nodes); list->nodes = NULL; @@ -375,7 +369,7 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr) return 1; } -static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) +static int cond_read_node(struct policydb *p, struct cond_node *node, struct policy_file *fp) { __le32 buf[2]; u32 i, len; @@ -415,7 +409,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) return cond_read_av_list(p, fp, &node->false_list, &node->true_list); } -int cond_read_list(struct policydb *p, void *fp) +int cond_read_list(struct policydb *p, struct policy_file *fp) { __le32 buf[1]; u32 i, len; @@ -453,7 +447,7 @@ int cond_write_bool(void *vkey, void *datum, void *ptr) char *key = vkey; struct cond_bool_datum *booldatum = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[3]; u32 len; int rc; @@ -536,7 +530,7 @@ static int cond_write_node(struct policydb *p, struct cond_node *node, return 0; } -int cond_write_list(struct policydb *p, void *fp) +int cond_write_list(struct policydb *p, struct policy_file *fp) { u32 i; __le32 buf[1]; diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 8827715bad75..468e98ad3ea1 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -68,10 +68,10 @@ int cond_destroy_bool(void *key, void *datum, void *p); int cond_index_bool(void *key, void *datum, void *datap); -int cond_read_bool(struct policydb *p, struct symtab *s, void *fp); -int cond_read_list(struct policydb *p, void *fp); +int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp); +int cond_read_list(struct policydb *p, struct policy_file *fp); int cond_write_bool(void *key, void *datum, void *ptr); -int cond_write_list(struct policydb *p, void *fp); +int cond_write_list(struct policydb *p, struct policy_file *fp); void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd, struct extended_perms *xperms); diff --git a/security/selinux/ss/context.c b/security/selinux/ss/context.c index e39990f494dd..a528b7f76280 100644 --- a/security/selinux/ss/context.c +++ b/security/selinux/ss/context.c @@ -20,7 +20,7 @@ u32 context_compute_hash(const struct context *c) * context struct with only the len & str set (and vice versa) * under a given policy. Since context structs from different * policies should never meet, it is safe to hash valid and - * invalid contexts differently. The context_cmp() function + * invalid contexts differently. The context_equal() function * already operates under the same assumption. */ if (c->len) diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 7ccab2e6965f..dd3b9b5b588e 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -132,13 +132,13 @@ out: return rc; } -static inline int mls_context_cmp(const struct context *c1, - const struct context *c2) +static inline bool mls_context_equal(const struct context *c1, + const struct context *c2) { return ((c1->range.level[0].sens == c2->range.level[0].sens) && - ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && + ebitmap_equal(&c1->range.level[0].cat, &c2->range.level[0].cat) && (c1->range.level[1].sens == c2->range.level[1].sens) && - ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat)); + ebitmap_equal(&c1->range.level[1].cat, &c2->range.level[1].cat)); } static inline void mls_context_destroy(struct context *c) @@ -188,15 +188,15 @@ static inline void context_destroy(struct context *c) mls_context_destroy(c); } -static inline int context_cmp(const struct context *c1, - const struct context *c2) +static inline bool context_equal(const struct context *c1, + const struct context *c2) { if (c1->len && c2->len) return (c1->len == c2->len && !strcmp(c1->str, c2->str)); if (c1->len || c2->len) return 0; return ((c1->user == c2->user) && (c1->role == c2->role) && - (c1->type == c2->type) && mls_context_cmp(c1, c2)); + (c1->type == c2->type) && mls_context_equal(c1, c2)); } u32 context_compute_hash(const struct context *c); diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 99c01be15115..43bc19e21960 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -25,12 +25,12 @@ static struct kmem_cache *ebitmap_node_cachep __ro_after_init; -int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2) +bool ebitmap_equal(const struct ebitmap *e1, const struct ebitmap *e2) { const struct ebitmap_node *n1, *n2; if (e1->highbit != e2->highbit) - return 0; + return false; n1 = e1->node; n2 = e2->node; @@ -41,9 +41,9 @@ int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2) } if (n1 || n2) - return 0; + return false; - return 1; + return true; } int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src) @@ -360,7 +360,7 @@ void ebitmap_destroy(struct ebitmap *e) e->node = NULL; } -int ebitmap_read(struct ebitmap *e, void *fp) +int ebitmap_read(struct ebitmap *e, struct policy_file *fp) { struct ebitmap_node *n = NULL; u32 mapunit, count, startbit, index, i; @@ -478,7 +478,7 @@ bad: goto out; } -int ebitmap_write(const struct ebitmap *e, void *fp) +int ebitmap_write(const struct ebitmap *e, struct policy_file *fp) { struct ebitmap_node *n; u32 bit, count, last_bit, last_startbit; diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index ba2ac3da1153..c9569998f287 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -120,7 +120,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, u32 bit) (bit) < ebitmap_length(e); \ (bit) = ebitmap_next_positive(e, &(n), bit)) -int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2); +bool ebitmap_equal(const struct ebitmap *e1, const struct ebitmap *e2); int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src); int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2); @@ -129,8 +129,9 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, int ebitmap_get_bit(const struct ebitmap *e, u32 bit); int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value); void ebitmap_destroy(struct ebitmap *e); -int ebitmap_read(struct ebitmap *e, void *fp); -int ebitmap_write(const struct ebitmap *e, void *fp); +struct policy_file; +int ebitmap_read(struct ebitmap *e, struct policy_file *fp); +int ebitmap_write(const struct ebitmap *e, struct policy_file *fp); u32 ebitmap_hash(const struct ebitmap *e, u32 hash); #ifdef CONFIG_NETLABEL diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 989c809d310d..a6e49269f535 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -171,7 +171,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l) * levdatum->level->cat and no bit in l->cat is larger than * p->p_cats.nprim. */ - return ebitmap_contains(&levdatum->level->cat, &l->cat, + return ebitmap_contains(&levdatum->level.cat, &l->cat, p->p_cats.nprim); } @@ -289,7 +289,7 @@ int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext, levdatum = symtab_search(&pol->p_levels, sensitivity); if (!levdatum) return -EINVAL; - context->range.level[l].sens = levdatum->level->sens; + context->range.level[l].sens = levdatum->level.sens; /* Extract category set. */ while (next_cat != NULL) { @@ -456,7 +456,7 @@ int mls_convert_context(struct policydb *oldp, struct policydb *newp, if (!levdatum) return -EINVAL; - newc->range.level[l].sens = levdatum->level->sens; + newc->range.level[l].sens = levdatum->level.sens; ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node, i) diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index 7ef6e8cb0cf4..51df2ebd1211 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -29,7 +29,7 @@ struct mls_range { static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2) { - return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); + return ((l1->sens == l2->sens) && ebitmap_equal(&l1->cat, &l2->cat)); } static inline int mls_level_dom(const struct mls_level *l1, diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 383f3ae82a73..9ea971943713 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -155,6 +155,11 @@ static const struct policydb_compat_info policydb_compat[] = { .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_COND_XPERMS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static const struct policydb_compat_info * @@ -296,9 +301,7 @@ static int sens_destroy(void *key, void *datum, void *p) kfree(key); if (datum) { levdatum = datum; - if (levdatum->level) - ebitmap_destroy(&levdatum->level->cat); - kfree(levdatum->level); + ebitmap_destroy(&levdatum->level.cat); } kfree(datum); return 0; @@ -630,11 +633,11 @@ static int sens_index(void *key, void *datum, void *datap) p = datap; if (!levdatum->isalias) { - if (!levdatum->level->sens || - levdatum->level->sens > p->p_levels.nprim) + if (!levdatum->level.sens || + levdatum->level.sens > p->p_levels.nprim) return -EINVAL; - p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key; + p->sym_val_to_name[SYM_LEVELS][levdatum->level.sens - 1] = key; } return 0; @@ -992,7 +995,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c) * Read a MLS range structure from a policydb binary * representation file. */ -static int mls_read_range_helper(struct mls_range *r, void *fp) +static int mls_read_range_helper(struct mls_range *r, struct policy_file *fp) { __le32 buf[2]; u32 items; @@ -1052,7 +1055,7 @@ out: * from a policydb binary representation file. */ static int context_read_and_validate(struct context *c, struct policydb *p, - void *fp) + struct policy_file *fp) { __le32 buf[3]; int rc; @@ -1090,7 +1093,7 @@ out: * binary representation file. */ -static int str_read(char **strp, gfp_t flags, void *fp, u32 len) +int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len) { int rc; char *str; @@ -1113,7 +1116,7 @@ static int str_read(char **strp, gfp_t flags, void *fp, u32 len) return 0; } -static int perm_read(struct policydb *p, struct symtab *s, void *fp) +static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct perm_datum *perdatum; @@ -1146,7 +1149,7 @@ bad: return rc; } -static int common_read(struct policydb *p, struct symtab *s, void *fp) +static int common_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct common_datum *comdatum; @@ -1198,7 +1201,7 @@ static void type_set_init(struct type_set *t) ebitmap_init(&t->negset); } -static int type_set_read(struct type_set *t, void *fp) +static int type_set_read(struct type_set *t, struct policy_file *fp) { __le32 buf[1]; int rc; @@ -1217,7 +1220,7 @@ static int type_set_read(struct type_set *t, void *fp) } static int read_cons_helper(struct policydb *p, struct constraint_node **nodep, - u32 ncons, int allowxtarget, void *fp) + u32 ncons, int allowxtarget, struct policy_file *fp) { struct constraint_node *c, *lc; struct constraint_expr *e, *le; @@ -1311,7 +1314,7 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep, return 0; } -static int class_read(struct policydb *p, struct symtab *s, void *fp) +static int class_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct class_datum *cladatum; @@ -1408,7 +1411,7 @@ bad: return rc; } -static int role_read(struct policydb *p, struct symtab *s, void *fp) +static int role_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct role_datum *role; @@ -1465,7 +1468,7 @@ bad: return rc; } -static int type_read(struct policydb *p, struct symtab *s, void *fp) +static int type_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct type_datum *typdatum; @@ -1517,7 +1520,7 @@ bad: * Read a MLS level structure from a policydb binary * representation file. */ -static int mls_read_level(struct mls_level *lp, void *fp) +static int mls_read_level(struct mls_level *lp, struct policy_file *fp) { __le32 buf[1]; int rc; @@ -1539,7 +1542,7 @@ static int mls_read_level(struct mls_level *lp, void *fp) return 0; } -static int user_read(struct policydb *p, struct symtab *s, void *fp) +static int user_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct user_datum *usrdatum; @@ -1590,7 +1593,7 @@ bad: return rc; } -static int sens_read(struct policydb *p, struct symtab *s, void *fp) +static int sens_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct level_datum *levdatum; @@ -1613,12 +1616,7 @@ static int sens_read(struct policydb *p, struct symtab *s, void *fp) if (rc) goto bad; - rc = -ENOMEM; - levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_KERNEL); - if (!levdatum->level) - goto bad; - - rc = mls_read_level(levdatum->level, fp); + rc = mls_read_level(&levdatum->level, fp); if (rc) goto bad; @@ -1631,7 +1629,7 @@ bad: return rc; } -static int cat_read(struct policydb *p, struct symtab *s, void *fp) +static int cat_read(struct policydb *p, struct symtab *s, struct policy_file *fp) { char *key = NULL; struct cat_datum *catdatum; @@ -1666,7 +1664,7 @@ bad: /* clang-format off */ static int (*const read_f[SYM_NUM])(struct policydb *p, struct symtab *s, - void *fp) = { + struct policy_file *fp) = { common_read, class_read, role_read, @@ -1836,7 +1834,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) return 1U << (perdatum->value - 1); } -static int range_read(struct policydb *p, void *fp) +static int range_read(struct policydb *p, struct policy_file *fp) { struct range_trans *rt = NULL; struct mls_range *r = NULL; @@ -1913,7 +1911,7 @@ out: return rc; } -static int filename_trans_read_helper_compat(struct policydb *p, void *fp) +static int filename_trans_read_helper_compat(struct policydb *p, struct policy_file *fp) { struct filename_trans_key key, *ft = NULL; struct filename_trans_datum *last, *datum = NULL; @@ -1998,7 +1996,7 @@ out: return rc; } -static int filename_trans_read_helper(struct policydb *p, void *fp) +static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp) { struct filename_trans_key *ft = NULL; struct filename_trans_datum **dst, *datum, *first = NULL; @@ -2087,7 +2085,7 @@ out: return rc; } -static int filename_trans_read(struct policydb *p, void *fp) +static int filename_trans_read(struct policydb *p, struct policy_file *fp) { u32 nel, i; __le32 buf[1]; @@ -2128,7 +2126,7 @@ static int filename_trans_read(struct policydb *p, void *fp) return 0; } -static int genfs_read(struct policydb *p, void *fp) +static int genfs_read(struct policydb *p, struct policy_file *fp) { int rc; u32 i, j, nel, nel2, len, len2; @@ -2242,7 +2240,7 @@ out: } static int ocontext_read(struct policydb *p, - const struct policydb_compat_info *info, void *fp) + const struct policydb_compat_info *info, struct policy_file *fp) { int rc; unsigned int i; @@ -2439,7 +2437,7 @@ out: * Read the configuration data from a policy database binary * representation file into a policy database structure. */ -int policydb_read(struct policydb *p, void *fp) +int policydb_read(struct policydb *p, struct policy_file *fp) { struct role_allow *ra, *lra; struct role_trans_key *rtk = NULL; @@ -2475,24 +2473,18 @@ int policydb_read(struct policydb *p, void *fp) goto bad; } - rc = -ENOMEM; - policydb_str = kmalloc(len + 1, GFP_KERNEL); - if (!policydb_str) { - pr_err("SELinux: unable to allocate memory for policydb " - "string of length %d\n", - len); - goto bad; - } - - rc = next_entry(policydb_str, fp, len); + rc = str_read(&policydb_str, GFP_KERNEL, fp, len); if (rc) { - pr_err("SELinux: truncated policydb string identifier\n"); - kfree(policydb_str); + if (rc == -ENOMEM) { + pr_err("SELinux: unable to allocate memory for policydb string of length %d\n", + len); + } else { + pr_err("SELinux: truncated policydb string identifier\n"); + } goto bad; } rc = -EINVAL; - policydb_str[len] = '\0'; if (strcmp(policydb_str, POLICYDB_STRING)) { pr_err("SELinux: policydb string %s does not match " "my string %s\n", @@ -2762,7 +2754,7 @@ bad: * Write a MLS level structure to a policydb binary * representation file. */ -static int mls_write_level(struct mls_level *l, void *fp) +static int mls_write_level(struct mls_level *l, struct policy_file *fp) { __le32 buf[1]; int rc; @@ -2783,7 +2775,7 @@ static int mls_write_level(struct mls_level *l, void *fp) * Write a MLS range structure to a policydb binary * representation file. */ -static int mls_write_range_helper(struct mls_range *r, void *fp) +static int mls_write_range_helper(struct mls_range *r, struct policy_file *fp) { __le32 buf[3]; size_t items; @@ -2823,7 +2815,7 @@ static int sens_write(void *vkey, void *datum, void *ptr) char *key = vkey; struct level_datum *levdatum = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[2]; size_t len; int rc; @@ -2839,7 +2831,7 @@ static int sens_write(void *vkey, void *datum, void *ptr) if (rc) return rc; - rc = mls_write_level(levdatum->level, fp); + rc = mls_write_level(&levdatum->level, fp); if (rc) return rc; @@ -2851,7 +2843,7 @@ static int cat_write(void *vkey, void *datum, void *ptr) char *key = vkey; struct cat_datum *catdatum = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[3]; size_t len; int rc; @@ -2876,7 +2868,7 @@ static int role_trans_write_one(void *key, void *datum, void *ptr) struct role_trans_key *rtk = key; struct role_trans_datum *rtd = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; struct policydb *p = pd->p; __le32 buf[3]; int rc; @@ -2896,7 +2888,7 @@ static int role_trans_write_one(void *key, void *datum, void *ptr) return 0; } -static int role_trans_write(struct policydb *p, void *fp) +static int role_trans_write(struct policydb *p, struct policy_file *fp) { struct policy_data pd = { .p = p, .fp = fp }; __le32 buf[1]; @@ -2910,7 +2902,7 @@ static int role_trans_write(struct policydb *p, void *fp) return hashtab_map(&p->role_tr, role_trans_write_one, &pd); } -static int role_allow_write(struct role_allow *r, void *fp) +static int role_allow_write(struct role_allow *r, struct policy_file *fp) { struct role_allow *ra; __le32 buf[2]; @@ -2938,7 +2930,7 @@ static int role_allow_write(struct role_allow *r, void *fp) * Write a security context structure * to a policydb binary representation file. */ -static int context_write(struct policydb *p, struct context *c, void *fp) +static int context_write(struct policydb *p, struct context *c, struct policy_file *fp) { int rc; __le32 buf[3]; @@ -2991,7 +2983,7 @@ static int common_write(void *vkey, void *datum, void *ptr) char *key = vkey; struct common_datum *comdatum = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[4]; size_t len; int rc; @@ -3016,7 +3008,7 @@ static int common_write(void *vkey, void *datum, void *ptr) return 0; } -static int type_set_write(struct type_set *t, void *fp) +static int type_set_write(struct type_set *t, struct policy_file *fp) { int rc; __le32 buf[1]; @@ -3035,7 +3027,7 @@ static int type_set_write(struct type_set *t, void *fp) } static int write_cons_helper(struct policydb *p, struct constraint_node *node, - void *fp) + struct policy_file *fp) { struct constraint_node *c; struct constraint_expr *e; @@ -3086,7 +3078,7 @@ static int class_write(void *vkey, void *datum, void *ptr) char *key = vkey; struct class_datum *cladatum = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; struct policydb *p = pd->p; struct constraint_node *c; __le32 buf[6]; @@ -3171,7 +3163,7 @@ static int role_write(void *vkey, void *datum, void *ptr) char *key = vkey; struct role_datum *role = datum; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; struct policydb *p = pd->p; __le32 buf[3]; size_t items, len; @@ -3211,7 +3203,7 @@ static int type_write(void *vkey, void *datum, void *ptr) struct type_datum *typdatum = datum; struct policy_data *pd = ptr; struct policydb *p = pd->p; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[4]; int rc; size_t items, len; @@ -3252,7 +3244,7 @@ static int user_write(void *vkey, void *datum, void *ptr) struct user_datum *usrdatum = datum; struct policy_data *pd = ptr; struct policydb *p = pd->p; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; __le32 buf[3]; size_t items, len; int rc; @@ -3301,7 +3293,8 @@ static int (*const write_f[SYM_NUM])(void *key, void *datum, void *datap) = { /* clang-format on */ static int ocontext_write(struct policydb *p, - const struct policydb_compat_info *info, void *fp) + const struct policydb_compat_info *info, + struct policy_file *fp) { unsigned int i, j; int rc; @@ -3437,7 +3430,7 @@ static int ocontext_write(struct policydb *p, return 0; } -static int genfs_write(struct policydb *p, void *fp) +static int genfs_write(struct policydb *p, struct policy_file *fp) { struct genfs *genfs; struct ocontext *c; @@ -3495,7 +3488,7 @@ static int range_write_helper(void *key, void *data, void *ptr) struct range_trans *rt = key; struct mls_range *r = data; struct policy_data *pd = ptr; - void *fp = pd->fp; + struct policy_file *fp = pd->fp; struct policydb *p = pd->p; int rc; @@ -3517,7 +3510,7 @@ static int range_write_helper(void *key, void *data, void *ptr) return 0; } -static int range_write(struct policydb *p, void *fp) +static int range_write(struct policydb *p, struct policy_file *fp) { __le32 buf[1]; int rc; @@ -3544,7 +3537,7 @@ static int filename_write_helper_compat(void *key, void *data, void *ptr) struct filename_trans_key *ft = key; struct filename_trans_datum *datum = data; struct ebitmap_node *node; - void *fp = ptr; + struct policy_file *fp = ptr; __le32 buf[4]; int rc; u32 bit, len = strlen(ft->name); @@ -3581,7 +3574,7 @@ static int filename_write_helper(void *key, void *data, void *ptr) { struct filename_trans_key *ft = key; struct filename_trans_datum *datum; - void *fp = ptr; + struct policy_file *fp = ptr; __le32 buf[3]; int rc; u32 ndatum, len = strlen(ft->name); @@ -3626,7 +3619,7 @@ static int filename_write_helper(void *key, void *data, void *ptr) return 0; } -static int filename_trans_write(struct policydb *p, void *fp) +static int filename_trans_write(struct policydb *p, struct policy_file *fp) { __le32 buf[1]; int rc; @@ -3658,7 +3651,7 @@ static int filename_trans_write(struct policydb *p, void *fp) * structure to a policy database binary representation * file. */ -int policydb_write(struct policydb *p, void *fp) +int policydb_write(struct policydb *p, struct policy_file *fp) { unsigned int num_syms; int rc; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 4bba386264a3..25650224b6e7 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -126,7 +126,7 @@ struct user_datum { /* Sensitivity attributes */ struct level_datum { - struct mls_level *level; /* sensitivity and associated categories */ + struct mls_level level; /* sensitivity and associated categories */ unsigned char isalias; /* is this sensitivity an alias for another? */ }; @@ -144,7 +144,7 @@ struct range_trans { /* Boolean data type */ struct cond_bool_datum { - __u32 value; /* internal type value */ + u32 value; /* internal type value */ int state; }; @@ -312,14 +312,19 @@ struct policydb { u32 process_trans_perms; } __randomize_layout; +struct policy_file { + char *data; + size_t len; +}; + extern void policydb_destroy(struct policydb *p); extern int policydb_load_isids(struct policydb *p, struct sidtab *s); extern int policydb_context_isvalid(struct policydb *p, struct context *c); extern int policydb_class_isvalid(struct policydb *p, unsigned int class); extern int policydb_type_isvalid(struct policydb *p, unsigned int type); extern int policydb_role_isvalid(struct policydb *p, unsigned int role); -extern int policydb_read(struct policydb *p, void *fp); -extern int policydb_write(struct policydb *p, void *fp); +extern int policydb_read(struct policydb *p, struct policy_file *fp); +extern int policydb_write(struct policydb *p, struct policy_file *fp); extern struct filename_trans_datum * policydb_filenametr_search(struct policydb *p, struct filename_trans_key *key); @@ -342,14 +347,9 @@ policydb_roletr_search(struct policydb *p, struct role_trans_key *key); #define POLICYDB_MAGIC SELINUX_MAGIC #define POLICYDB_STRING "SE Linux" -struct policy_file { - char *data; - size_t len; -}; - struct policy_data { struct policydb *p; - void *fp; + struct policy_file *fp; }; static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) @@ -386,6 +386,8 @@ static inline char *sym_name(struct policydb *p, unsigned int sym_num, return p->sym_val_to_name[sym_num][element_nr]; } +extern int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len); + extern u16 string_to_security_class(struct policydb *p, const char *name); extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d9f58b5d0f49..8478842fbf9e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -952,7 +952,7 @@ static void avd_init(struct selinux_policy *policy, struct av_decision *avd) } static void update_xperms_extended_data(u8 specified, - struct extended_perms_data *from, + const struct extended_perms_data *from, struct extended_perms_data *xp_data) { unsigned int i; @@ -973,6 +973,8 @@ static void update_xperms_extended_data(u8 specified, void services_compute_xperms_decision(struct extended_perms_decision *xpermd, struct avtab_node *node) { + u16 specified; + switch (node->datum.u.xperms->specified) { case AVTAB_XPERMS_IOCTLFUNCTION: if (xpermd->base_perm != AVC_EXT_IOCTL || @@ -997,17 +999,19 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd, return; } - if (node->key.specified == AVTAB_XPERMS_ALLOWED) { + specified = node->key.specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); + + if (specified == AVTAB_XPERMS_ALLOWED) { xpermd->used |= XPERMS_ALLOWED; update_xperms_extended_data(node->datum.u.xperms->specified, &node->datum.u.xperms->perms, xpermd->allowed); - } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { + } else if (specified == AVTAB_XPERMS_AUDITALLOW) { xpermd->used |= XPERMS_AUDITALLOW; update_xperms_extended_data(node->datum.u.xperms->specified, &node->datum.u.xperms->perms, xpermd->auditallow); - } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { + } else if (specified == AVTAB_XPERMS_DONTAUDIT) { xpermd->used |= XPERMS_DONTAUDIT; update_xperms_extended_data(node->datum.u.xperms->specified, &node->datum.u.xperms->perms, @@ -2611,17 +2615,15 @@ out: return rc; } -static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) +static bool match_ipv6_addrmask(const u32 input[4], const u32 addr[4], const u32 mask[4]) { - int i, fail = 0; + int i; for (i = 0; i < 4; i++) - if (addr[i] != (input[i] & mask[i])) { - fail = 1; - break; - } + if (addr[i] != (input[i] & mask[i])) + return false; - return !fail; + return true; } /** @@ -2726,7 +2728,7 @@ out: */ int security_get_user_sids(u32 fromsid, - char *username, + const char *username, u32 **sids, u32 *nel) { @@ -3048,7 +3050,7 @@ err: } -int security_set_bools(u32 len, int *values) +int security_set_bools(u32 len, const int *values) { struct selinux_state *state = &selinux_state; struct selinux_policy *newpolicy, *oldpolicy; @@ -3347,7 +3349,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, __func__, xfrm_sid); goto out; } - rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); + rc = (mls_context_equal(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); if (rc) goto out; diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index c8848cbba81f..59f8c09158ef 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -66,7 +66,7 @@ static u32 context_to_sid(struct sidtab *s, struct context *context, u32 hash) hash_for_each_possible_rcu(s->context_to_sid, entry, list, hash) { if (entry->hash != hash) continue; - if (context_cmp(&entry->context, context)) { + if (context_equal(&entry->context, context)) { sid = entry->sid; break; } @@ -114,12 +114,12 @@ int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context) int sidtab_hash_stats(struct sidtab *sidtab, char *page) { - int i; + unsigned int i; int chain_len = 0; int slots_used = 0; int entries = 0; int max_chain_len = 0; - int cur_bucket = 0; + unsigned int cur_bucket = 0; struct sidtab_entry *entry; rcu_read_lock(); diff --git a/security/smack/smack.h b/security/smack/smack.h index dbf8d7226eb5..4608b07607a3 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -280,6 +280,7 @@ int smk_access(struct smack_known *, struct smack_known *, int smk_tskacc(struct task_smack *, struct smack_known *, u32, struct smk_audit_info *); int smk_curacc(struct smack_known *, u32, struct smk_audit_info *); +int smack_str_from_perm(char *string, int access); struct smack_known *smack_from_secid(const u32); char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 585e5e35710b..3727379623e2 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -275,7 +275,6 @@ int smk_curacc(struct smack_known *obj_known, return smk_tskacc(tsp, obj_known, mode, a); } -#ifdef CONFIG_AUDIT /** * smack_str_from_perm : helper to transalate an int to a * readable string @@ -283,7 +282,7 @@ int smk_curacc(struct smack_known *obj_known, * @access : the int * */ -static inline void smack_str_from_perm(char *string, int access) +int smack_str_from_perm(char *string, int access) { int i = 0; @@ -299,8 +298,15 @@ static inline void smack_str_from_perm(char *string, int access) string[i++] = 't'; if (access & MAY_LOCK) string[i++] = 'l'; + if (access & MAY_BRINGUP) + string[i++] = 'b'; + if (i == 0) + string[i++] = '-'; string[i] = '\0'; + return i; } + +#ifdef CONFIG_AUDIT /** * smack_log_callback - SMACK specific information * will be called by generic audit code diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0c476282e279..239773cdcdcf 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -107,23 +107,7 @@ static char *smk_bu_mess[] = { static void smk_bu_mode(int mode, char *s) { - int i = 0; - - if (mode & MAY_READ) - s[i++] = 'r'; - if (mode & MAY_WRITE) - s[i++] = 'w'; - if (mode & MAY_EXEC) - s[i++] = 'x'; - if (mode & MAY_APPEND) - s[i++] = 'a'; - if (mode & MAY_TRANSMUTE) - s[i++] = 't'; - if (mode & MAY_LOCK) - s[i++] = 'l'; - if (i == 0) - s[i++] = '-'; - s[i] = '\0'; + smack_str_from_perm(s, mode); } #endif @@ -4818,40 +4802,47 @@ static int smack_ismaclabel(const char *name) } /** + * smack_to_secctx - fill a lsm_context + * @skp: Smack label + * @cp: destination + * + * Fill the passed @cp and return the length of the string + */ +static int smack_to_secctx(struct smack_known *skp, struct lsm_context *cp) +{ + int len = strlen(skp->smk_known); + + if (cp) { + cp->context = skp->smk_known; + cp->len = len; + cp->id = LSM_ID_SMACK; + } + return len; +} + +/** * smack_secid_to_secctx - return the smack label for a secid * @secid: incoming integer - * @secdata: destination - * @seclen: how long it is + * @cp: destination * * Exists for networking code. */ -static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +static int smack_secid_to_secctx(u32 secid, struct lsm_context *cp) { - struct smack_known *skp = smack_from_secid(secid); - - if (secdata) - *secdata = skp->smk_known; - *seclen = strlen(skp->smk_known); - return 0; + return smack_to_secctx(smack_from_secid(secid), cp); } /** * smack_lsmprop_to_secctx - return the smack label * @prop: includes incoming Smack data - * @secdata: destination - * @seclen: how long it is + * @cp: destination * * Exists for audit code. */ -static int smack_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, - u32 *seclen) +static int smack_lsmprop_to_secctx(struct lsm_prop *prop, + struct lsm_context *cp) { - struct smack_known *skp = prop->smack.skp; - - if (secdata) - *secdata = skp->smk_known; - *seclen = strlen(skp->smk_known); - return 0; + return smack_to_secctx(prop->smack.skp, cp); } /** @@ -4891,12 +4882,13 @@ static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) ctx, ctxlen, 0, NULL); } -static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +static int smack_inode_getsecctx(struct inode *inode, struct lsm_context *cp) { struct smack_known *skp = smk_of_inode(inode); - *ctx = skp->smk_known; - *ctxlen = strlen(skp->smk_known); + cp->context = skp->smk_known; + cp->len = strlen(skp->smk_known); + cp->id = LSM_ID_SMACK; return 0; } diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 1401412fd794..357188f764ce 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -562,6 +562,7 @@ static void smk_seq_stop(struct seq_file *s, void *v) static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) { + char acc[SMK_NUM_ACCESS_TYPE + 1]; /* * Don't show any rules with label names too long for * interface file (/smack/load or /smack/load2) @@ -575,28 +576,11 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) if (srp->smk_access == 0) return; - seq_printf(s, "%s %s", + smack_str_from_perm(acc, srp->smk_access); + seq_printf(s, "%s %s %s\n", srp->smk_subject->smk_known, - srp->smk_object->smk_known); - - seq_putc(s, ' '); - - if (srp->smk_access & MAY_READ) - seq_putc(s, 'r'); - if (srp->smk_access & MAY_WRITE) - seq_putc(s, 'w'); - if (srp->smk_access & MAY_EXEC) - seq_putc(s, 'x'); - if (srp->smk_access & MAY_APPEND) - seq_putc(s, 'a'); - if (srp->smk_access & MAY_TRANSMUTE) - seq_putc(s, 't'); - if (srp->smk_access & MAY_LOCK) - seq_putc(s, 'l'); - if (srp->smk_access & MAY_BRINGUP) - seq_putc(s, 'b'); - - seq_putc(s, '\n'); + srp->smk_object->smk_known, + acc); } /* |