diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/lsm_audit.c | 17 | ||||
-rw-r--r-- | security/security.c | 27 | ||||
-rw-r--r-- | security/selinux/Kconfig | 38 | ||||
-rw-r--r-- | security/selinux/hooks.c | 106 | ||||
-rw-r--r-- | security/selinux/include/security.h | 4 | ||||
-rw-r--r-- | security/selinux/ss/conditional.c | 2 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.c | 3 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 12 | ||||
-rw-r--r-- | security/smack/Kconfig | 12 | ||||
-rw-r--r-- | security/smack/smack.h | 10 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 14 | ||||
-rw-r--r-- | security/smack/smack_netfilter.c | 4 | ||||
-rw-r--r-- | security/smack/smackfs.c | 11 |
13 files changed, 172 insertions, 88 deletions
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 45d927a..37f04da 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -99,7 +99,7 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, } return ret; } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) /** * ipv6_skb_to_auditdata : fill auditdata from skb * @skb : the skb @@ -245,6 +245,19 @@ static void dump_common_audit_data(struct audit_buffer *ab, } break; } + case LSM_AUDIT_DATA_FILE: { + struct inode *inode; + + audit_log_d_path(ab, " path=", &a->u.file->f_path); + + inode = file_inode(a->u.file); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } + break; + } case LSM_AUDIT_DATA_IOCTL_OP: { struct inode *inode; @@ -257,7 +270,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_format(ab, " ino=%lu", inode->i_ino); } - audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd); + audit_log_format(ab, " ioctlcmd=0x%hx", a->u.op->cmd); break; } case LSM_AUDIT_DATA_DENTRY: { diff --git a/security/security.c b/security/security.c index 4838e7f..f825304 100644 --- a/security/security.c +++ b/security/security.c @@ -364,6 +364,15 @@ int security_dentry_init_security(struct dentry *dentry, int mode, } EXPORT_SYMBOL(security_dentry_init_security); +int security_dentry_create_files_as(struct dentry *dentry, int mode, + struct qstr *name, + const struct cred *old, struct cred *new) +{ + return call_int_hook(dentry_create_files_as, 0, dentry, mode, + name, old, new); +} +EXPORT_SYMBOL(security_dentry_create_files_as); + int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) @@ -748,6 +757,18 @@ void security_inode_getsecid(struct inode *inode, u32 *secid) call_void_hook(inode_getsecid, inode, secid); } +int security_inode_copy_up(struct dentry *src, struct cred **new) +{ + return call_int_hook(inode_copy_up, 0, src, new); +} +EXPORT_SYMBOL(security_inode_copy_up); + +int security_inode_copy_up_xattr(const char *name) +{ + return call_int_hook(inode_copy_up_xattr, -EOPNOTSUPP, name); +} +EXPORT_SYMBOL(security_inode_copy_up_xattr); + int security_file_permission(struct file *file, int mask) { int ret; @@ -1623,6 +1644,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str), .dentry_init_security = LIST_HEAD_INIT(security_hook_heads.dentry_init_security), + .dentry_create_files_as = + LIST_HEAD_INIT(security_hook_heads.dentry_create_files_as), #ifdef CONFIG_SECURITY_PATH .path_unlink = LIST_HEAD_INIT(security_hook_heads.path_unlink), .path_mkdir = LIST_HEAD_INIT(security_hook_heads.path_mkdir), @@ -1684,6 +1707,10 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.inode_listsecurity), .inode_getsecid = LIST_HEAD_INIT(security_hook_heads.inode_getsecid), + .inode_copy_up = + LIST_HEAD_INIT(security_hook_heads.inode_copy_up), + .inode_copy_up_xattr = + LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr), .file_permission = LIST_HEAD_INIT(security_hook_heads.file_permission), .file_alloc_security = diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 8691e92..ea7e3ef 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -93,41 +93,3 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE via /selinux/checkreqprot if authorized by policy. If you are unsure how to answer this question, answer 0. - -config SECURITY_SELINUX_POLICYDB_VERSION_MAX - bool "NSA SELinux maximum supported policy format version" - depends on SECURITY_SELINUX - default n - help - This option enables the maximum policy format version supported - by SELinux to be set to a particular value. This value is reported - to userspace via /selinux/policyvers and used at policy load time. - It can be adjusted downward to support legacy userland (init) that - does not correctly handle kernels that support newer policy versions. - - Examples: - For the Fedora Core 3 or 4 Linux distributions, enable this option - and set the value via the next option. For Fedora Core 5 and later, - do not enable this option. - - If you are unsure how to answer this question, answer N. - -config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE - int "NSA SELinux maximum supported policy format version value" - depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX - range 15 23 - default 19 - help - This option sets the value for the maximum policy format version - supported by SELinux. - - Examples: - For Fedora Core 3, use 18. - For Fedora Core 4, use 19. - - If you are unsure how to answer this question, look for the - policy format version supported by your policy toolchain, by - running 'checkpolicy -V'. Or look at what policy you have - installed under /etc/selinux/$SELINUXTYPE/policy, where - SELINUXTYPE is defined in your /etc/selinux/config. - diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 13185a6..2205ea2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1761,8 +1761,8 @@ static inline int file_path_has_perm(const struct cred *cred, { struct common_audit_data ad; - ad.type = LSM_AUDIT_DATA_PATH; - ad.u.path = file->f_path; + ad.type = LSM_AUDIT_DATA_FILE; + ad.u.file = file; return inode_has_perm(cred, file_inode(file), av, &ad); } @@ -1784,8 +1784,8 @@ static int file_has_perm(const struct cred *cred, u32 sid = cred_sid(cred); int rc; - ad.type = LSM_AUDIT_DATA_PATH; - ad.u.path = file->f_path; + ad.type = LSM_AUDIT_DATA_FILE; + ad.u.file = file; if (sid != fsec->sid) { rc = avc_has_perm(sid, fsec->sid, @@ -1808,13 +1808,13 @@ out: /* * Determine the label for an inode that might be unioned. */ -static int selinux_determine_inode_label(struct inode *dir, - const struct qstr *name, - u16 tclass, - u32 *_new_isid) +static int +selinux_determine_inode_label(const struct task_security_struct *tsec, + struct inode *dir, + const struct qstr *name, u16 tclass, + u32 *_new_isid) { const struct superblock_security_struct *sbsec = dir->i_sb->s_security; - const struct task_security_struct *tsec = current_security(); if ((sbsec->flags & SE_SBINITIALIZED) && (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { @@ -1857,8 +1857,8 @@ static int may_create(struct inode *dir, if (rc) return rc; - rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, - &newsid); + rc = selinux_determine_inode_label(current_security(), dir, + &dentry->d_name, tclass, &newsid); if (rc) return rc; @@ -2365,8 +2365,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) new_tsec->sid = old_tsec->sid; } - ad.type = LSM_AUDIT_DATA_PATH; - ad.u.path = bprm->file->f_path; + ad.type = LSM_AUDIT_DATA_FILE; + ad.u.file = bprm->file; if (new_tsec->sid == old_tsec->sid) { rc = avc_has_perm(old_tsec->sid, isec->sid, @@ -2838,7 +2838,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, u32 newsid; int rc; - rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, + rc = selinux_determine_inode_label(current_security(), + d_inode(dentry->d_parent), name, inode_mode_to_security_class(mode), &newsid); if (rc) @@ -2847,6 +2848,27 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, return security_sid_to_context(newsid, (char **)ctx, ctxlen); } +static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, + struct qstr *name, + const struct cred *old, + struct cred *new) +{ + u32 newsid; + int rc; + struct task_security_struct *tsec; + + rc = selinux_determine_inode_label(old->security, + d_inode(dentry->d_parent), name, + inode_mode_to_security_class(mode), + &newsid); + if (rc) + return rc; + + tsec = new->security; + tsec->create_sid = newsid; + return 0; +} + static int selinux_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, @@ -2863,7 +2885,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - rc = selinux_determine_inode_label( + rc = selinux_determine_inode_label(current_security(), dir, qstr, inode_mode_to_security_class(inode->i_mode), &newsid); @@ -3293,6 +3315,41 @@ static void selinux_inode_getsecid(struct inode *inode, u32 *secid) *secid = isec->sid; } +static int selinux_inode_copy_up(struct dentry *src, struct cred **new) +{ + u32 sid; + struct task_security_struct *tsec; + struct cred *new_creds = *new; + + if (new_creds == NULL) { + new_creds = prepare_creds(); + if (!new_creds) + return -ENOMEM; + } + + tsec = new_creds->security; + /* Get label from overlay inode and set it in create_sid */ + selinux_inode_getsecid(d_inode(src), &sid); + tsec->create_sid = sid; + *new = new_creds; + return 0; +} + +static int selinux_inode_copy_up_xattr(const char *name) +{ + /* The copy_up hook above sets the initial context on an inode, but we + * don't then want to overwrite it by blindly copying all the lower + * xattrs up. Instead, we have to filter out SELinux-related xattrs. + */ + if (strcmp(name, XATTR_NAME_SELINUX) == 0) + return 1; /* Discard */ + /* + * Any other attribute apart from SELINUX is not claimed, supported + * by selinux. + */ + return -EOPNOTSUPP; +} + /* file security operations */ static int selinux_revalidate_file_permission(struct file *file, int mask) @@ -3776,8 +3833,8 @@ static int selinux_kernel_module_from_file(struct file *file) /* finit_module */ - ad.type = LSM_AUDIT_DATA_PATH; - ad.u.path = file->f_path; + ad.type = LSM_AUDIT_DATA_FILE; + ad.u.file = file; fsec = file->f_security; if (sid != fsec->sid) { @@ -3984,7 +4041,7 @@ out: return ret; } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv6(struct sk_buff *skb, @@ -4075,7 +4132,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, &ad->u.net->v4info.daddr); goto okay; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) case PF_INET6: ret = selinux_parse_skb_ipv6(skb, ad, proto); if (ret) @@ -5029,7 +5086,7 @@ static unsigned int selinux_ipv4_forward(void *priv, return selinux_ip_forward(skb, state->in, PF_INET); } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) static unsigned int selinux_ipv6_forward(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) @@ -5087,7 +5144,7 @@ static unsigned int selinux_ipv4_output(void *priv, return selinux_ip_output(skb, PF_INET); } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) static unsigned int selinux_ipv6_output(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) @@ -5273,7 +5330,7 @@ static unsigned int selinux_ipv4_postroute(void *priv, return selinux_ip_postroute(skb, state->out, PF_INET); } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) static unsigned int selinux_ipv6_postroute(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) @@ -6062,6 +6119,7 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str), LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), + LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security), LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security), @@ -6088,6 +6146,8 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity), LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity), LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), + LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), + LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), @@ -6317,7 +6377,7 @@ static struct nf_hook_ops selinux_nf_ops[] = { .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_SELINUX_FIRST, }, -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) { .hook = selinux_ipv6_postroute, .pf = NFPROTO_IPV6, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 38feb55..308a286 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -39,11 +39,7 @@ /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX -#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE -#else #define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL -#endif /* Mask for just the mount related flags */ #define SE_MNTMASK 0x0f diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 456e1a9..34afead 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -242,6 +242,8 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, 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); diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 894b6cd..7d10e5d 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -374,6 +374,9 @@ int ebitmap_read(struct ebitmap *e, void *fp) goto ok; } + if (e->highbit && !count) + goto bad; + for (i = 0; i < count; i++) { rc = next_entry(&startbit, fp, sizeof(u32)); if (rc < 0) { diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 992a315..ace6838 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -541,21 +541,21 @@ static int policydb_index(struct policydb *p) rc = -ENOMEM; p->class_val_to_struct = - kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), + kzalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL); if (!p->class_val_to_struct) goto out; rc = -ENOMEM; p->role_val_to_struct = - kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), + kzalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), GFP_KERNEL); if (!p->role_val_to_struct) goto out; rc = -ENOMEM; p->user_val_to_struct = - kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), + kzalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), GFP_KERNEL); if (!p->user_val_to_struct) goto out; @@ -964,7 +964,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c) * Role must be authorized for the type. */ role = p->role_val_to_struct[c->role - 1]; - if (!ebitmap_get_bit(&role->types, c->type - 1)) + if (!role || !ebitmap_get_bit(&role->types, c->type - 1)) /* role may not be associated with type */ return 0; @@ -1094,6 +1094,9 @@ static int str_read(char **strp, gfp_t flags, void *fp, u32 len) int rc; char *str; + if ((len == 0) || (len == (u32)-1)) + return -EINVAL; + str = kmalloc(len + 1, flags); if (!str) return -ENOMEM; @@ -2414,6 +2417,7 @@ int policydb_read(struct policydb *p, void *fp) } else tr->tclass = p->process_class; + rc = -EINVAL; if (!policydb_role_isvalid(p, tr->role) || !policydb_type_isvalid(p, tr->type) || !policydb_class_isvalid(p, tr->tclass) || diff --git a/security/smack/Kconfig b/security/smack/Kconfig index 271adae..923b120 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig @@ -40,3 +40,15 @@ config SECURITY_SMACK_NETFILTER This enables security marking of network packets using Smack labels. If you are unsure how to answer this question, answer N. + +config SECURITY_SMACK_APPEND_SIGNALS + bool "Treat delivering signals as an append operation" + depends on SECURITY_SMACK + default n + help + Sending a signal has been treated as a write operation to the + receiving process. If this option is selected, the delivery + will be an append operation instead. This makes it possible + to differentiate between delivering a network packet and + delivering a signal in the Smack rules. + If you are unsure how to answer this question, answer N. diff --git a/security/smack/smack.h b/security/smack/smack.h index 26e58f1..51fd301 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -256,6 +256,16 @@ enum { #define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */ #define MAY_BRINGUP 0x00004000 /* Report use of this rule */ +/* + * The policy for delivering signals is configurable. + * It is usually "write", but can be "append". + */ +#ifdef CONFIG_SECURITY_SMACK_APPEND_SIGNALS +#define MAY_DELIVER MAY_APPEND /* Signal delivery requires append */ +#else +#define MAY_DELIVER MAY_WRITE /* Signal delivery requires write */ +#endif + #define SMACK_BRINGUP_ALLOW 1 /* Allow bringup mode */ #define SMACK_UNCONFINED_SUBJECT 2 /* Allow unconfined label */ #define SMACK_UNCONFINED_OBJECT 3 /* Allow unconfined label */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 87a9741..caec225 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1857,14 +1857,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, /* we don't log here as rc can be overriden */ skp = file->f_security; - rc = smk_access(skp, tkp, MAY_WRITE, NULL); - rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc); + rc = smk_access(skp, tkp, MAY_DELIVER, NULL); + rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, tsk); - smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad); + smack_log(skp->smk_known, tkp->smk_known, MAY_DELIVER, rc, &ad); return rc; } @@ -2265,8 +2265,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) { - rc = smk_curacc(tkp, MAY_WRITE, &ad); - rc = smk_bu_task(p, MAY_WRITE, rc); + rc = smk_curacc(tkp, MAY_DELIVER, &ad); + rc = smk_bu_task(p, MAY_DELIVER, rc); return rc; } /* @@ -2275,8 +2275,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * we can't take privilege into account. */ skp = smack_from_secid(secid); - rc = smk_access(skp, tkp, MAY_WRITE, &ad); - rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc); + rc = smk_access(skp, tkp, MAY_DELIVER, &ad); + rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc); return rc; } diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index aa6bf1b..205b785 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -20,7 +20,7 @@ #include <net/inet_sock.h> #include "smack.h" -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) static unsigned int smack_ipv6_output(void *priv, struct sk_buff *skb, @@ -64,7 +64,7 @@ static struct nf_hook_ops smack_nf_ops[] = { .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_SELINUX_FIRST, }, -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) { .hook = smack_ipv6_output, .pf = NFPROTO_IPV6, diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index e249a66..6492fe9 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2523,14 +2523,9 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, if (count == 0 || count > SMK_LONGLABEL) return -EINVAL; - data = kzalloc(count, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if (copy_from_user(data, buf, count) != 0) { - rc = -EFAULT; - goto out_data; - } + data = memdup_user(buf, count); + if (IS_ERR(data)) + return PTR_ERR(data); cp = smk_parse_smack(data, count); if (IS_ERR(cp)) { |