From 1a93a6eac32a2853177f10e274b9b761b42356eb Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 8 Aug 2016 13:08:25 -0400 Subject: [PATCH 01/47] security: Use IS_ENABLED() instead of checking for built-in or module The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Signed-off-by: Javier Martinez Canillas Acked-by: Casey Schaufler Signed-off-by: Paul Moore --- security/lsm_audit.c | 2 +- security/selinux/hooks.c | 12 ++++++------ security/smack/smack_netfilter.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/security/lsm_audit.c b/security/lsm_audit.c index cccbf3068cdc..5369036cf905 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 diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 13185a6c266a..880f9533863f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3984,7 +3984,7 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, 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 +4075,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 +5029,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 +5087,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 +5273,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) @@ -6317,7 +6317,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/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index aa6bf1b22ec5..205b785fb400 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -20,7 +20,7 @@ #include #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, From 8b31f456c72e53ee97474a538bcd91bfb1b93fb7 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 8 Aug 2016 13:08:34 -0400 Subject: [PATCH 02/47] selinux: print leading 0x on ioctlcmd audits ioctlcmd is currently printing hex numbers, but their is no leading 0x. Thus things like ioctlcmd=1234 are misleading, as the base is not evident. Correct this by adding 0x as a prefix, so ioctlcmd=1234 becomes ioctlcmd=0x1234. Signed-off-by: William Roberts Signed-off-by: Paul Moore --- security/lsm_audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 5369036cf905..9bf851884800 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -257,7 +257,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: { From d8ad8b49618410ddeafd78465b63a6cedd6c9484 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 11:13:56 -0400 Subject: [PATCH 03/47] security, overlayfs: provide copy up security hook for unioned files Provide a security hook to label new file correctly when a file is copied up from lower layer to upper layer of a overlay/union mount. This hook can prepare a new set of creds which are suitable for new file creation during copy up. Caller will use new creds to create file and then revert back to old creds and release new creds. Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley [PM: whitespace cleanup to appease checkpatch.pl] Signed-off-by: Paul Moore --- fs/overlayfs/copy_up.c | 15 +++++++++++++++ include/linux/lsm_hooks.h | 11 +++++++++++ include/linux/security.h | 6 ++++++ security/security.c | 8 ++++++++ 4 files changed, 40 insertions(+) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 54e5d6681786..c297b1f5a05e 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -246,6 +246,8 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, struct dentry *upper = NULL; umode_t mode = stat->mode; int err; + const struct cred *old_creds = NULL; + struct cred *new_creds = NULL; newdentry = ovl_lookup_temp(workdir, dentry); err = PTR_ERR(newdentry); @@ -258,10 +260,23 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, if (IS_ERR(upper)) goto out1; + err = security_inode_copy_up(dentry, &new_creds); + if (err < 0) + goto out2; + + if (new_creds) + old_creds = override_creds(new_creds); + /* Can't properly set mode on creation because of the umask */ stat->mode &= S_IFMT; err = ovl_create_real(wdir, newdentry, stat, link, NULL, true); stat->mode = mode; + + if (new_creds) { + revert_creds(old_creds); + put_cred(new_creds); + } + if (err) goto out2; diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 101bf19c0f41..cb69fc829053 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -401,6 +401,15 @@ * @inode contains a pointer to the inode. * @secid contains a pointer to the location where result will be saved. * In case of failure, @secid will be set to zero. + * @inode_copy_up: + * A file is about to be copied up from lower layer to upper layer of + * overlay filesystem. Security module can prepare a set of new creds + * and modify as need be and return new creds. Caller will switch to + * new creds temporarily to create new file and release newly allocated + * creds. + * @src indicates the union dentry of file that is being copied up. + * @new pointer to pointer to return newly allocated creds. + * Returns 0 on success or a negative error code on error. * * Security hooks for file operations * @@ -1425,6 +1434,7 @@ union security_list_options { int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); void (*inode_getsecid)(struct inode *inode, u32 *secid); + int (*inode_copy_up)(struct dentry *src, struct cred **new); int (*file_permission)(struct file *file, int mask); int (*file_alloc_security)(struct file *file); @@ -1696,6 +1706,7 @@ struct security_hook_heads { struct list_head inode_setsecurity; struct list_head inode_listsecurity; struct list_head inode_getsecid; + struct list_head inode_copy_up; struct list_head file_permission; struct list_head file_alloc_security; struct list_head file_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index 7831cd57bcf7..c5b0ccd6c8b6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -282,6 +282,7 @@ int security_inode_getsecurity(struct inode *inode, const char *name, void **buf int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size); void security_inode_getsecid(struct inode *inode, u32 *secid); +int security_inode_copy_up(struct dentry *src, struct cred **new); int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -758,6 +759,11 @@ static inline void security_inode_getsecid(struct inode *inode, u32 *secid) *secid = 0; } +static inline int security_inode_copy_up(struct dentry *src, struct cred **new) +{ + return 0; +} + static inline int security_file_permission(struct file *file, int mask) { return 0; diff --git a/security/security.c b/security/security.c index 4838e7fefa1f..f2a7f27bd3e9 100644 --- a/security/security.c +++ b/security/security.c @@ -748,6 +748,12 @@ 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_file_permission(struct file *file, int mask) { int ret; @@ -1684,6 +1690,8 @@ 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), .file_permission = LIST_HEAD_INIT(security_hook_heads.file_permission), .file_alloc_security = From 56909eb3f559103196ecbf2c08c923e0804980fb Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:48 -0400 Subject: [PATCH 04/47] selinux: Implementation for inode_copy_up() hook A file is being copied up for overlay file system. Prepare a new set of creds and set create_sid appropriately so that new file is created with appropriate label. Overlay inode has right label for both context and non-context mount cases. In case of non-context mount, overlay inode will have the label of lower file and in case of context mount, overlay inode will have the label from context= mount option. Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 880f9533863f..40597ed00ba9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3293,6 +3293,26 @@ 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; +} + /* file security operations */ static int selinux_revalidate_file_permission(struct file *file, int mask) @@ -6088,6 +6108,7 @@ 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(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), From 121ab822ef21914adac2fa3730efeeb8fd762473 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:49 -0400 Subject: [PATCH 05/47] security,overlayfs: Provide security hook for copy up of xattrs for overlay file Provide a security hook which is called when xattrs of a file are being copied up. This hook is called once for each xattr and LSM can return 0 if the security module wants the xattr to be copied up, 1 if the security module wants the xattr to be discarded on the copy, -EOPNOTSUPP if the security module does not handle/manage the xattr, or a -errno upon an error. Signed-off-by: David Howells Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley [PM: whitespace cleanup for checkpatch.pl] Signed-off-by: Paul Moore --- fs/overlayfs/copy_up.c | 7 +++++++ include/linux/lsm_hooks.h | 10 ++++++++++ include/linux/security.h | 6 ++++++ security/security.c | 8 ++++++++ 4 files changed, 31 insertions(+) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index c297b1f5a05e..cd65f12b3464 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -103,6 +103,13 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) goto retry; } + error = security_inode_copy_up_xattr(name); + if (error < 0 && error != -EOPNOTSUPP) + break; + if (error == 1) { + error = 0; + continue; /* Discard */ + } error = vfs_setxattr(new, name, value, size, 0); if (error) break; diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index cb69fc829053..57971229551b 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -410,6 +410,14 @@ * @src indicates the union dentry of file that is being copied up. * @new pointer to pointer to return newly allocated creds. * Returns 0 on success or a negative error code on error. + * @inode_copy_up_xattr: + * Filter the xattrs being copied up when a unioned file is copied + * up from a lower layer to the union/overlay layer. + * @name indicates the name of the xattr. + * Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP if + * security module does not know about attribute or a negative error code + * to abort the copy up. Note that the caller is responsible for reading + * and writing the xattrs as this hook is merely a filter. * * Security hooks for file operations * @@ -1435,6 +1443,7 @@ union security_list_options { size_t buffer_size); void (*inode_getsecid)(struct inode *inode, u32 *secid); int (*inode_copy_up)(struct dentry *src, struct cred **new); + int (*inode_copy_up_xattr)(const char *name); int (*file_permission)(struct file *file, int mask); int (*file_alloc_security)(struct file *file); @@ -1707,6 +1716,7 @@ struct security_hook_heads { struct list_head inode_listsecurity; struct list_head inode_getsecid; struct list_head inode_copy_up; + struct list_head inode_copy_up_xattr; struct list_head file_permission; struct list_head file_alloc_security; struct list_head file_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index c5b0ccd6c8b6..536fafdfa10a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -283,6 +283,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size); void security_inode_getsecid(struct inode *inode, u32 *secid); int security_inode_copy_up(struct dentry *src, struct cred **new); +int security_inode_copy_up_xattr(const char *name); int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -764,6 +765,11 @@ static inline int security_inode_copy_up(struct dentry *src, struct cred **new) return 0; } +static inline int security_inode_copy_up_xattr(const char *name) +{ + return -EOPNOTSUPP; +} + static inline int security_file_permission(struct file *file, int mask) { return 0; diff --git a/security/security.c b/security/security.c index f2a7f27bd3e9..a9e2bb9fb9d3 100644 --- a/security/security.c +++ b/security/security.c @@ -754,6 +754,12 @@ int security_inode_copy_up(struct dentry *src, struct cred **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; @@ -1692,6 +1698,8 @@ struct security_hook_heads security_hook_heads = { 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 = From 19472b69d639d58415866bf127d5f9005038c105 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:50 -0400 Subject: [PATCH 06/47] selinux: Implementation for inode_copy_up_xattr() hook When a file is copied up in overlay, we have already created file on upper/ with right label and there is no need to copy up selinux label/xattr from lower file to upper file. In fact in case of context mount, we don't want to copy up label as newly created file got its label from context= option. Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 40597ed00ba9..a2d510895ff3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3313,6 +3313,21 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new) 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) @@ -6109,6 +6124,7 @@ static struct security_hook_list selinux_hooks[] = { 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), From c957f6df52c509ccfbb96659fd1a0f7812de333f Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:51 -0400 Subject: [PATCH 07/47] selinux: Pass security pointer to determine_inode_label() Right now selinux_determine_inode_label() works on security pointer of current task. Soon I need this to work on a security pointer retrieved from a set of creds. So start passing in a pointer and caller can decide where to fetch security pointer from. Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a2d510895ff3..f9d398bc9dcd 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1808,13 +1808,13 @@ static int file_has_perm(const struct cred *cred, /* * 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; @@ -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) @@ -2863,7 +2864,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); From 2602625b7e46576b00db619ac788c508ba3bcb2c Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:52 -0400 Subject: [PATCH 08/47] security, overlayfs: Provide hook to correctly label newly created files During a new file creation we need to make sure new file is created with the right label. New file is created in upper/ so effectively file should get label as if task had created file in upper/. We switched to mounter's creds for actual file creation. Also if there is a whiteout present, then file will be created in work/ dir first and then renamed in upper. In none of the cases file will be labeled as we want it to be. This patch introduces a new hook dentry_create_files_as(), which determines the label/context dentry will get if it had been created by task in upper and modify passed set of creds appropriately. Caller makes use of these new creds for file creation. Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley [PM: fix whitespace issues found with checkpatch.pl] [PM: changes to use stat->mode in ovl_create_or_link()] Signed-off-by: Paul Moore --- fs/overlayfs/dir.c | 10 ++++++++++ include/linux/lsm_hooks.h | 15 +++++++++++++++ include/linux/security.h | 12 ++++++++++++ security/security.c | 11 +++++++++++ 4 files changed, 48 insertions(+) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 12bcd07b9e32..a155e52db9fe 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -435,6 +435,15 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, if (override_cred) { override_cred->fsuid = inode->i_uid; override_cred->fsgid = inode->i_gid; + if (!hardlink) { + err = security_dentry_create_files_as(dentry, + stat->mode, &dentry->d_name, old_cred, + override_cred); + if (err) { + put_cred(override_cred); + goto out_revert_creds; + } + } put_cred(override_creds(override_cred)); put_cred(override_cred); @@ -445,6 +454,7 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, err = ovl_create_over_whiteout(dentry, inode, stat, link, hardlink); } +out_revert_creds: revert_creds(old_cred); if (!err) { struct inode *realinode = d_inode(ovl_dentry_upper(dentry)); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 57971229551b..f2af2af131ac 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -151,6 +151,16 @@ * @name name of the last path component used to create file * @ctx pointer to place the pointer to the resulting context in. * @ctxlen point to place the length of the resulting context. + * @dentry_create_files_as: + * Compute a context for a dentry as the inode is not yet available + * and set that context in passed in creds so that new files are + * created using that context. Context is calculated using the + * passed in creds and not the creds of the caller. + * @dentry dentry to use in calculating the context. + * @mode mode used to determine resource type. + * @name name of the last path component used to create file + * @old creds which should be used for context calculation + * @new creds to modify * * * Security hooks for inode operations. @@ -1375,6 +1385,10 @@ union security_list_options { int (*dentry_init_security)(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); + int (*dentry_create_files_as)(struct dentry *dentry, int mode, + struct qstr *name, + const struct cred *old, + struct cred *new); #ifdef CONFIG_SECURITY_PATH @@ -1675,6 +1689,7 @@ struct security_hook_heads { struct list_head sb_clone_mnt_opts; struct list_head sb_parse_opts_str; struct list_head dentry_init_security; + struct list_head dentry_create_files_as; #ifdef CONFIG_SECURITY_PATH struct list_head path_unlink; struct list_head path_mkdir; diff --git a/include/linux/security.h b/include/linux/security.h index 536fafdfa10a..a6c6d5d0fa5d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -242,6 +242,10 @@ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); +int security_dentry_create_files_as(struct dentry *dentry, int mode, + struct qstr *name, + const struct cred *old, + struct cred *new); int security_inode_alloc(struct inode *inode); void security_inode_free(struct inode *inode); @@ -600,6 +604,14 @@ static inline int security_dentry_init_security(struct dentry *dentry, return -EOPNOTSUPP; } +static inline int security_dentry_create_files_as(struct dentry *dentry, + int mode, struct qstr *name, + const struct cred *old, + struct cred *new) +{ + return 0; +} + static inline int security_inode_init_security(struct inode *inode, struct inode *dir, diff --git a/security/security.c b/security/security.c index a9e2bb9fb9d3..f825304f04a7 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) @@ -1635,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), From a4f4528a3174646e654989262afdc8303835fcd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Sat, 9 Jul 2016 20:19:15 +0200 Subject: [PATCH 09/47] module: Fully remove the kernel_module_from_file hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove remaining kernel_module_from_file hook left by commit a1db74209483 ("module: replace copy_module_from_fd with kernel version") Signed-off-by: Mickaël Salaün Cc: Rusty Russell Acked-by: Kees Cook Signed-off-by: Mimi Zohar Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 1 - include/linux/security.h | 1 - 2 files changed, 2 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 101bf19c0f41..dc56ae3a68cd 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1455,7 +1455,6 @@ union security_list_options { int (*kernel_act_as)(struct cred *new, u32 secid); int (*kernel_create_files_as)(struct cred *new, struct inode *inode); int (*kernel_module_request)(char *kmod_name); - int (*kernel_module_from_file)(struct file *file); int (*kernel_read_file)(struct file *file, enum kernel_read_file_id id); int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); diff --git a/include/linux/security.h b/include/linux/security.h index 7831cd57bcf7..4c7412943b81 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -307,7 +307,6 @@ void security_transfer_creds(struct cred *new, const struct cred *old); int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_module_request(char *kmod_name); -int security_kernel_module_from_file(struct file *file); int security_kernel_read_file(struct file *file, enum kernel_read_file_id id); int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); From 09b09cb9c569dcc3577cf064e2561ebf08605454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Mon, 1 Aug 2016 23:01:55 +0200 Subject: [PATCH 10/47] um/ptrace: Fix the syscall_trace_leave call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the same semantic as before the commit 26703c636c1f: deallocate audit context and fake a proper syscall exit. This fix a kernel panic triggered by the seccomp_bpf test: > [ RUN ] global.ERRNO_valid > BUG: failure at kernel/auditsc.c:1504/__audit_syscall_entry()! > Kernel panic - not syncing: BUG! Fixes: 26703c636c1f ("um/ptrace: run seccomp after ptrace") Signed-off-by: Mickaël Salaün Acked-by: Kees Cook Cc: Jeff Dike Cc: Richard Weinberger Cc: James Morris Cc: user-mode-linux-devel@lists.sourceforge.net Signed-off-by: James Morris --- arch/um/kernel/skas/syscall.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index ef4b8f949b51..0728fee94398 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -21,11 +21,11 @@ void handle_syscall(struct uml_pt_regs *r) PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS); if (syscall_trace_enter(regs)) - return; + goto out; /* Do the seccomp check after ptrace; failures should be fast. */ if (secure_computing(NULL) == -1) - return; + goto out; /* Update the syscall number after orig_ax has potentially been updated * with ptrace. @@ -37,5 +37,6 @@ void handle_syscall(struct uml_pt_regs *r) PT_REGS_SET_SYSCALL_RETURN(regs, EXECUTE_SYSCALL(syscall, regs)); +out: syscall_trace_leave(regs); } From 4b056a4bee006c4bd2e210d632e0ac41b3121aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Mon, 1 Aug 2016 23:01:56 +0200 Subject: [PATCH 11/47] um/ptrace: Fix the syscall number update after a ptrace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the syscall number after each PTRACE_SETREGS on ORIG_*AX. This is needed to get the potentially altered syscall number in the seccomp filters after RET_TRACE. This fix four seccomp_bpf tests: > [ RUN ] TRACE_syscall.skip_after_RET_TRACE > seccomp_bpf.c:1560:TRACE_syscall.skip_after_RET_TRACE:Expected -1 (18446744073709551615) == syscall(39) (26) > seccomp_bpf.c:1561:TRACE_syscall.skip_after_RET_TRACE:Expected 1 (1) == (*__errno_location ()) (22) > [ FAIL ] TRACE_syscall.skip_after_RET_TRACE > [ RUN ] TRACE_syscall.kill_after_RET_TRACE > TRACE_syscall.kill_after_RET_TRACE: Test exited normally instead of by signal (code: 1) > [ FAIL ] TRACE_syscall.kill_after_RET_TRACE > [ RUN ] TRACE_syscall.skip_after_ptrace > seccomp_bpf.c:1622:TRACE_syscall.skip_after_ptrace:Expected -1 (18446744073709551615) == syscall(39) (26) > seccomp_bpf.c:1623:TRACE_syscall.skip_after_ptrace:Expected 1 (1) == (*__errno_location ()) (22) > [ FAIL ] TRACE_syscall.skip_after_ptrace > [ RUN ] TRACE_syscall.kill_after_ptrace > TRACE_syscall.kill_after_ptrace: Test exited normally instead of by signal (code: 1) > [ FAIL ] TRACE_syscall.kill_after_ptrace Fixes: 26703c636c1f ("um/ptrace: run seccomp after ptrace") Signed-off-by: Mickaël Salaün Acked-by: Kees Cook Cc: Jeff Dike Cc: Richard Weinberger Cc: James Morris Cc: user-mode-linux-devel@lists.sourceforge.net Signed-off-by: James Morris --- arch/um/kernel/skas/syscall.c | 5 ----- arch/x86/um/ptrace_32.c | 3 +++ arch/x86/um/ptrace_64.c | 4 ++++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 0728fee94398..b783ac87d98a 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -27,12 +27,7 @@ void handle_syscall(struct uml_pt_regs *r) if (secure_computing(NULL) == -1) goto out; - /* Update the syscall number after orig_ax has potentially been updated - * with ptrace. - */ - UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp); syscall = UPT_SYSCALL_NR(r); - if (syscall >= 0 && syscall <= __NR_syscall_max) PT_REGS_SET_SYSCALL_RETURN(regs, EXECUTE_SYSCALL(syscall, regs)); diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index ebd4dd6ef73b..a7ef7b131e25 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -84,7 +84,10 @@ int putreg(struct task_struct *child, int regno, unsigned long value) case EAX: case EIP: case UESP: + break; case ORIG_EAX: + /* Update the syscall number. */ + UPT_SYSCALL_NR(&child->thread.regs.regs) = value; break; case FS: if (value && (value & 3) != 3) diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index faab418876ce..0b5c184dd5b3 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -78,7 +78,11 @@ int putreg(struct task_struct *child, int regno, unsigned long value) case RSI: case RDI: case RBP: + break; + case ORIG_RAX: + /* Update the syscall number. */ + UPT_SYSCALL_NR(&child->thread.regs.regs) = value; break; case FS: From 8ccc7d6bad84bebf1f1a6364d1fa04d3d7b575f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Mon, 1 Aug 2016 23:01:57 +0200 Subject: [PATCH 12/47] seccomp: Remove 2-phase API documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 8112c4f140fa ("seccomp: remove 2-phase API") Signed-off-by: Mickaël Salaün Acked-by: Kees Cook Cc: Andy Lutomirski Cc: James Morris Signed-off-by: James Morris --- arch/Kconfig | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index bd8056b5b246..4620a11ef092 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -336,17 +336,6 @@ config HAVE_ARCH_SECCOMP_FILTER results in the system call being skipped immediately. - seccomp syscall wired up - For best performance, an arch should use seccomp_phase1 and - seccomp_phase2 directly. It should call seccomp_phase1 for all - syscalls if TIF_SECCOMP is set, but seccomp_phase1 does not - need to be called from a ptrace-safe context. It must then - call seccomp_phase2 if seccomp_phase1 returns anything other - than SECCOMP_PHASE1_OK or SECCOMP_PHASE1_SKIP. - - As an additional optimization, an arch may provide seccomp_data - directly to seccomp_phase1; this avoids multiple calls - to the syscall_xyz helpers for every syscall. - config SECCOMP_FILTER def_bool y depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET From a518b0a5b0d7f3397e065acb956bca9635aa892d Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 13 Jul 2016 10:44:53 -0400 Subject: [PATCH 13/47] selinux: Implement dentry_create_files_as() hook Calculate what would be the label of newly created file and set that secid in the passed creds. Context of the task which is actually creating file is retrieved from set of creds passed in. (old->security). Signed-off-by: Vivek Goyal Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f9d398bc9dcd..e15e56081c0c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2848,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, @@ -6098,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), From 348a0db9e69e4c214bf5d7677f17cb99cdc47db0 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Mon, 15 Aug 2016 12:42:12 -0700 Subject: [PATCH 14/47] selinux: drop SECURITY_SELINUX_POLICYDB_VERSION_MAX Remove the SECURITY_SELINUX_POLICYDB_VERSION_MAX Kconfig option Per: https://github.com/SELinuxProject/selinux/wiki/Kernel-Todo This was only needed on Fedora 3 and 4 and just causes issues now, so drop it. The MAX and MIN should just be whatever the kernel can support. Signed-off-by: William Roberts Signed-off-by: Paul Moore --- security/selinux/Kconfig | 38 ----------------------------- security/selinux/include/security.h | 4 --- 2 files changed, 42 deletions(-) diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 8691e92f27e5..ea7e3efbe0f7 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/include/security.h b/security/selinux/include/security.h index 38feb55d531a..308a286c6cbe 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 From 63e24c497158c066583b9c06378d89ace694265a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 21 Aug 2016 20:17:36 +0200 Subject: [PATCH 15/47] Smack: Use memdup_user() rather than duplicating its implementation Reuse existing functionality from memdup_user() instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Casey Schaufler --- security/smack/smackfs.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index e249a66db533..6492fe96cae4 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)) { From 74d977b65e45bc9b536b429e7f3b5e3a8e459026 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Tue, 23 Aug 2016 13:49:23 -0700 Subject: [PATCH 16/47] selinux: detect invalid ebitmap When count is 0 and the highbit is not zero, the ebitmap is not valid and the internal node is not allocated. This causes issues when routines, like mls_context_isvalid() attempt to use the ebitmap_for_each_bit() and ebitmap_node_get_bit() as they assume a highbit > 0 will have a node allocated. Signed-off-by: William Roberts Signed-off-by: Paul Moore --- security/selinux/ss/ebitmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 894b6cdc11c5..7d10e5d418bb 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) { From 3bc7bcf69bbe763359454b2c40efcba22730e181 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Tue, 23 Aug 2016 13:49:24 -0700 Subject: [PATCH 17/47] selinux: initialize structures libsepol pointed out an issue where its possible to have an unitialized jmp and invalid dereference, fix this. While we're here, zero allocate all the *_val_to_struct structures. Signed-off-by: William Roberts Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 992a31530825..4b243855ed7b 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; From 7c686af071ade663d0995aa30b262495a6c68c88 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Tue, 30 Aug 2016 09:28:11 -0700 Subject: [PATCH 18/47] selinux: fix overflow and 0 length allocations Throughout the SELinux LSM, values taken from sepolicy are used in places where length == 0 or length == matter, find and fix these. Signed-off-by: William Roberts Signed-off-by: Paul Moore --- security/selinux/ss/conditional.c | 2 ++ security/selinux/ss/policydb.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 456e1a9bcfde..34afeadd9e73 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/policydb.c b/security/selinux/ss/policydb.c index 4b243855ed7b..8c661f0451ec 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -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; From c60b906673eebb4f65840fa9dc204401caf276ea Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 30 Aug 2016 10:31:39 -0700 Subject: [PATCH 19/47] Smack: Signal delivery as an append operation Under a strict subject/object security policy delivering a signal or delivering network IPC could be considered either a write or an append operation. The original choice to make both write operations leads to an issue where IPC delivery is desired under policy, but delivery of signals is not. This patch provides the option of making signal delivery an append operation, allowing Smack rules that deny signal delivery while allowing IPC. This was requested for Tizen. Signed-off-by: Casey Schaufler --- security/smack/Kconfig | 12 ++++++++++++ security/smack/smack.h | 10 ++++++++++ security/smack/smack_lsm.c | 14 +++++++------- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/security/smack/Kconfig b/security/smack/Kconfig index 271adae81796..923b120e0fa5 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 26e58f1804b1..51fd30192c08 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 87a9741b0d02..caec2256ab22 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; } From 9b6a9ecc2d88ccdc57efc22d69436b9dd7e2eceb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 07:43:48 +0000 Subject: [PATCH 20/47] selinux: fix error return code in policydb_read() Fix to return error code -EINVAL from the error handling case instead of 0 (rc is overwrite to 0 when policyvers >= POLICYDB_VERSION_ROLETRANS), as done elsewhere in this function. Signed-off-by: Wei Yongjun [PM: normalize "selinux" in patch subject, description line wrap] Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 8c661f0451ec..ace683838d80 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2417,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) || From b7d7b28471072fc23e7b573aef89c14438092223 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 2 Sep 2016 02:36:58 +0300 Subject: [PATCH 21/47] tpm: invalid self test error message The driver emits invalid self test error message even though the init succeeds. Signed-off-by: Jarkko Sakkinen Fixes: cae8b441fc20 ("tpm: Factor out common startup code") Reviewed-by: James Morris --- drivers/char/tpm/tpm2-cmd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 08c7e23ed535..0c75c3f1689f 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -957,7 +957,7 @@ int tpm2_auto_startup(struct tpm_chip *chip) goto out; rc = tpm2_do_selftest(chip); - if (rc != TPM2_RC_INITIALIZE) { + if (rc != 0 && rc != TPM2_RC_INITIALIZE) { dev_err(&chip->dev, "TPM self test failed\n"); goto out; } @@ -974,7 +974,6 @@ int tpm2_auto_startup(struct tpm_chip *chip) } } - return rc; out: if (rc > 0) rc = -ENODEV; From d4816edfe706497a8525480c1685ceb9871bc118 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 16 Aug 2016 22:00:38 +0300 Subject: [PATCH 22/47] tpm: fix a race condition in tpm2_unseal_trusted() Unseal and load operations should be done as an atomic operation. This commit introduces unlocked tpm_transmit() so that tpm2_unseal_trusted() can do the locking by itself. Fixes: 0fe5480303a1 ("keys, trusted: seal/unseal with TPM 2.0 chips") Cc: stable@vger.kernel.org Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe --- drivers/char/tpm/tpm-dev.c | 2 +- drivers/char/tpm/tpm-interface.c | 51 +++++++++------- drivers/char/tpm/tpm-sysfs.c | 2 +- drivers/char/tpm/tpm.h | 12 ++-- drivers/char/tpm/tpm2-cmd.c | 101 ++++++++++++++++++++----------- 5 files changed, 103 insertions(+), 65 deletions(-) diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index f5d452151c6b..912ad30be585 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -145,7 +145,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, return -EPIPE; } out_size = tpm_transmit(priv->chip, priv->data_buffer, - sizeof(priv->data_buffer)); + sizeof(priv->data_buffer), 0); tpm_put_ops(priv->chip); if (out_size < 0) { diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1abe2d7a2610..aef20ee2331a 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -330,8 +330,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); /* * Internal kernel interface to transmit TPM commands */ -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, - size_t bufsiz) +ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, + unsigned int flags) { ssize_t rc; u32 count, ordinal; @@ -350,7 +350,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, return -E2BIG; } - mutex_lock(&chip->tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_lock(&chip->tpm_mutex); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { @@ -393,20 +394,21 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - mutex_unlock(&chip->tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_unlock(&chip->tpm_mutex); return rc; } #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, - int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, + int len, unsigned int flags, const char *desc) { - struct tpm_output_header *header; + const struct tpm_output_header *header; int err; - len = tpm_transmit(chip, (u8 *) cmd, len); + len = tpm_transmit(chip, (const u8 *)cmd, len, flags); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) @@ -453,7 +455,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, + desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -469,7 +472,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -490,7 +493,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) start_cmd.header.in = tpm_startup_header; start_cmd.params.startup_in.startup_type = startup_type; - return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, + return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to start the TPM"); } @@ -521,7 +524,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, + NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. @@ -535,7 +539,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - NULL); + 0, NULL); } if (rc) { dev_err(&chip->dev, @@ -596,7 +600,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to determine the durations"); if (rc) return rc; @@ -652,7 +656,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, "continue selftest"); return rc; } @@ -672,7 +676,7 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0, "attempting to read a pcr value"); if (rc == 0) @@ -770,7 +774,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, "attempting extend a PCR value"); tpm_put_ops(chip); @@ -809,7 +813,7 @@ int tpm_do_selftest(struct tpm_chip *chip) /* Attempt to read a PCR value */ cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); - rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE); + rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE, 0); /* Some buggy TPMs will not respond to tpm_tis_ready() for * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ @@ -879,7 +883,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); tpm_put_ops(chip); return rc; @@ -981,14 +985,15 @@ int tpm_pm_suspend(struct device *dev) cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; - rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, + NULL); /* * If the TPM indicates that it is too busy to respond to @@ -1072,8 +1077,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); err = tpm_transmit_cmd(chip, &tpm_cmd, - TPM_GETRANDOM_RESULT_SIZE + num_bytes, - "attempting get random"); + TPM_GETRANDOM_RESULT_SIZE + num_bytes, + 0, "attempting get random"); if (err) break; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index b46cf70c8b16..e1f7236c115c 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -39,7 +39,7 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = to_tpm_chip(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0, "attempting to read the PUBEK"); if (err) goto out; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 3e32d5bd2dc6..b0585e99da49 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -476,12 +476,16 @@ extern dev_t tpm_devt; extern const struct file_operations tpm_fops; extern struct idr dev_nums_idr; +enum tpm_transmit_flags { + TPM_TRANSMIT_UNLOCKED = BIT(0), +}; + +ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, + unsigned int flags); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, + unsigned int flags, const char *desc); ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, const char *desc); -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, - size_t bufsiz); -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len, - const char *desc); extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 0c75c3f1689f..ef5a58b986f6 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -282,7 +282,7 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) sizeof(cmd.params.pcrread_in.pcr_select)); cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "attempting to read a pcr value"); if (rc == 0) { buf = cmd.params.pcrread_out.digest; @@ -330,7 +330,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "attempting extend a PCR value"); return rc; @@ -376,7 +376,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) cmd.header.in = tpm2_getrandom_header; cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); - err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "attempting get random"); if (err) break; @@ -434,12 +434,12 @@ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, } /** - * tpm2_seal_trusted() - seal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options + * tpm2_seal_trusted() - seal the payload of a trusted key + * @chip_num: TPM chip to use * @payload: the key data in clear and encrypted form + * @options: authentication values and other options * - * Returns < 0 on error and 0 on success. + * Return: < 0 on error and 0 on success. */ int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -512,7 +512,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "sealing data"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data"); if (rc) goto out; @@ -538,10 +538,18 @@ int tpm2_seal_trusted(struct tpm_chip *chip, return rc; } -static int tpm2_load(struct tpm_chip *chip, - struct trusted_key_payload *payload, - struct trusted_key_options *options, - u32 *blob_handle) +/** + * tpm2_load_cmd() - execute a TPM2_Load command + * @chip_num: TPM chip to use + * @payload: the key data in clear and encrypted form + * @options: authentication values and other options + * + * Return: same as with tpm_transmit_cmd + */ +static int tpm2_load_cmd(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options, + u32 *blob_handle, unsigned int flags) { struct tpm_buf buf; unsigned int private_len; @@ -576,7 +584,7 @@ static int tpm2_load(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob"); if (!rc) *blob_handle = be32_to_cpup( (__be32 *) &buf.data[TPM_HEADER_SIZE]); @@ -590,7 +598,16 @@ static int tpm2_load(struct tpm_chip *chip, return rc; } -static void tpm2_flush_context(struct tpm_chip *chip, u32 handle) +/** + * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command + * @chip_num: TPM chip to use + * @payload: the key data in clear and encrypted form + * @options: authentication values and other options + * + * Return: same as with tpm_transmit_cmd + */ +static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, + unsigned int flags) { struct tpm_buf buf; int rc; @@ -604,7 +621,8 @@ static void tpm2_flush_context(struct tpm_chip *chip, u32 handle) tpm_buf_append_u32(&buf, handle); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, + "flushing context"); if (rc) dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, rc); @@ -612,10 +630,18 @@ static void tpm2_flush_context(struct tpm_chip *chip, u32 handle) tpm_buf_destroy(&buf); } -static int tpm2_unseal(struct tpm_chip *chip, - struct trusted_key_payload *payload, - struct trusted_key_options *options, - u32 blob_handle) +/** + * tpm2_unseal_cmd() - execute a TPM2_Unload command + * @chip_num: TPM chip to use + * @payload: the key data in clear and encrypted form + * @options: authentication values and other options + * + * Return: same as with tpm_transmit_cmd + */ +static int tpm2_unseal_cmd(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options, + u32 blob_handle, unsigned int flags) { struct tpm_buf buf; u16 data_len; @@ -635,7 +661,7 @@ static int tpm2_unseal(struct tpm_chip *chip, options->blobauth /* hmac */, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "unsealing"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing"); if (rc > 0) rc = -EPERM; @@ -654,12 +680,12 @@ static int tpm2_unseal(struct tpm_chip *chip, } /** - * tpm_unseal_trusted() - unseal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options + * tpm_unseal_trusted() - unseal the payload of a trusted key + * @chip_num: TPM chip to use * @payload: the key data in clear and encrypted form + * @options: authentication values and other options * - * Returns < 0 on error and 0 on success. + * Return: < 0 on error and 0 on success. */ int tpm2_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -668,14 +694,17 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, u32 blob_handle; int rc; - rc = tpm2_load(chip, payload, options, &blob_handle); + mutex_lock(&chip->tpm_mutex); + rc = tpm2_load_cmd(chip, payload, options, &blob_handle, + TPM_TRANSMIT_UNLOCKED); if (rc) - return rc; - - rc = tpm2_unseal(chip, payload, options, blob_handle); - - tpm2_flush_context(chip, blob_handle); + goto out; + rc = tpm2_unseal_cmd(chip, payload, options, blob_handle, + TPM_TRANSMIT_UNLOCKED); + tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED); +out: + mutex_unlock(&chip->tpm_mutex); return rc; } @@ -701,7 +730,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc); if (!rc) *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); @@ -735,7 +764,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) cmd.header.in = tpm2_startup_header; cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); - return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "attempting to start the TPM"); } @@ -763,7 +792,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) cmd.header.in = tpm2_shutdown_header; cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM"); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM"); /* In places where shutdown command is sent there's no much we can do * except print the error code on a system failure. @@ -828,7 +857,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) cmd.header.in = tpm2_selftest_header; cmd.params.selftest_in.full_test = full; - rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, "continue selftest"); /* At least some prototype chips seem to give RC_TESTING error @@ -880,7 +909,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) cmd.params.pcrread_in.pcr_select[1] = 0x00; cmd.params.pcrread_in.pcr_select[2] = 0x00; - rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); if (rc < 0) break; @@ -928,7 +957,7 @@ int tpm2_probe(struct tpm_chip *chip) cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd)); + rc = tpm_transmit(chip, (const u8 *)&cmd, sizeof(cmd), 0); if (rc < 0) return rc; else if (rc < TPM_HEADER_SIZE) From 09dd7703753f6fdd68b184de65b720b040dd1721 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 19 Jul 2016 14:38:55 -0600 Subject: [PATCH 23/47] tpm/st33zp24: Remove useless tpm_gen_interrupt This function should only be called as part of an IRQ probing protocol and st33 does not have any code to detect that the IRQ it tries to generate was not generated and disable the IRQ. Since st33 is primarily a DT binding driver it should not be doing IRQ probing anyhow, so let us just delete this useless call. Signed-off-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/st33zp24/st33zp24.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index c2ee30451e41..6f060c76217b 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -589,8 +589,6 @@ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, chip->flags |= TPM_CHIP_FLAG_IRQ; disable_irq_nosync(tpm_dev->irq); - - tpm_gen_interrupt(chip); } return tpm_chip_register(chip); From d4abd9565dd6da1ab2a402af77617d32949ed06c Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sat, 25 Jun 2016 23:33:09 +0300 Subject: [PATCH 24/47] tpm: remove unnecessary externs from tpm.h Removed unnecessary externs from tpm.h. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe --- drivers/char/tpm/tpm.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index b0585e99da49..e92f4b1a449c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -486,26 +486,26 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, unsigned int flags, const char *desc); ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, const char *desc); -extern int tpm_get_timeouts(struct tpm_chip *); -extern void tpm_gen_interrupt(struct tpm_chip *); +int tpm_get_timeouts(struct tpm_chip *); +void tpm_gen_interrupt(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); -extern int tpm_do_selftest(struct tpm_chip *); -extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); -extern int tpm_pm_suspend(struct device *); -extern int tpm_pm_resume(struct device *); -extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, - wait_queue_head_t *, bool); +int tpm_do_selftest(struct tpm_chip *chip); +unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); +int tpm_pm_suspend(struct device *dev); +int tpm_pm_resume(struct device *dev); +int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, + wait_queue_head_t *queue, bool check_cancel); struct tpm_chip *tpm_chip_find_get(int chip_num); __must_check int tpm_try_get_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip); -extern struct tpm_chip *tpm_chip_alloc(struct device *dev, - const struct tpm_class_ops *ops); -extern struct tpm_chip *tpmm_chip_alloc(struct device *pdev, - const struct tpm_class_ops *ops); -extern int tpm_chip_register(struct tpm_chip *chip); -extern void tpm_chip_unregister(struct tpm_chip *chip); +struct tpm_chip *tpm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops); +struct tpm_chip *tpmm_chip_alloc(struct device *pdev, + const struct tpm_class_ops *ops); +int tpm_chip_register(struct tpm_chip *chip); +void tpm_chip_unregister(struct tpm_chip *chip); void tpm_sysfs_add_device(struct tpm_chip *chip); @@ -532,8 +532,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc); int tpm2_auto_startup(struct tpm_chip *chip); -extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); -extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); -extern int tpm2_gen_interrupt(struct tpm_chip *chip); -extern int tpm2_probe(struct tpm_chip *chip); +void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); +int tpm2_gen_interrupt(struct tpm_chip *chip); +int tpm2_probe(struct tpm_chip *chip); #endif From eb5854e764b91a71106f159a4ac264ffed1eebf2 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sun, 12 Jun 2016 16:42:09 +0300 Subject: [PATCH 25/47] tpm: replace tpm_gen_interrupt() with tpm_tis_gen_interrupt() Since tpm_gen_interrupt() is only used in tpm_tis_core.c this commit replaces it with an internal tpm_tis_gen_interrupt(). The semantics also changed in a way that on a system error the driver initialization is failed. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe --- drivers/char/tpm/tpm-interface.c | 16 +--------------- drivers/char/tpm/tpm.h | 2 -- drivers/char/tpm/tpm2-cmd.c | 18 +----------------- drivers/char/tpm/tpm_tis_core.c | 19 +++++++++++++++---- 4 files changed, 17 insertions(+), 38 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index aef20ee2331a..6bffb13fb189 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -461,21 +461,7 @@ ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, *cap = tpm_cmd.params.getcap_out.cap; return rc; } - -void tpm_gen_interrupt(struct tpm_chip *chip) -{ - struct tpm_cmd_t tpm_cmd; - ssize_t rc; - - tpm_cmd.header.in = tpm_getcap_header; - tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); - tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - "attempting to determine the timeouts"); -} -EXPORT_SYMBOL_GPL(tpm_gen_interrupt); +EXPORT_SYMBOL_GPL(tpm_getcap); #define TPM_ORD_STARTUP cpu_to_be32(153) #define TPM_ST_CLEAR cpu_to_be16(1) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e92f4b1a449c..4d183c97f6a6 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -487,7 +487,6 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, const char *desc); int tpm_get_timeouts(struct tpm_chip *); -void tpm_gen_interrupt(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); int tpm_do_selftest(struct tpm_chip *chip); unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); @@ -534,6 +533,5 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, int tpm2_auto_startup(struct tpm_chip *chip); void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); -int tpm2_gen_interrupt(struct tpm_chip *chip); int tpm2_probe(struct tpm_chip *chip); #endif diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index ef5a58b986f6..a5aa8de23c3d 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -736,6 +736,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, return rc; } +EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); #define TPM2_STARTUP_IN_SIZE \ (sizeof(struct tpm_input_header) + \ @@ -923,23 +924,6 @@ static int tpm2_do_selftest(struct tpm_chip *chip) return rc; } -/** - * tpm2_gen_interrupt() - generate an interrupt - * @chip: TPM chip to use - * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. - */ -int tpm2_gen_interrupt(struct tpm_chip *chip) -{ - u32 dummy; - - return tpm2_get_tpm_pt(chip, 0x100, &dummy, - "attempting to generate an interrupt"); -} -EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); - /** * tpm2_probe() - probe TPM 2.0 * @chip: TPM chip to use diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index d66f51b3648e..f22caf802e56 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -526,6 +526,18 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) return IRQ_HANDLED; } +static int tpm_tis_gen_interrupt(struct tpm_chip *chip) +{ + const char *desc = "attempting to generate an interrupt"; + u32 cap2; + cap_t cap; + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); + else + return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc); +} + /* Register the IRQ and issue a command that will cause an interrupt. If an * irq is seen then leave the chip setup for IRQ operation, otherwise reverse * everything and leave in polling mode. Returns 0 on success. @@ -575,10 +587,9 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, /* Generate an interrupt by having the core call through to * tpm_tis_send */ - if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm2_gen_interrupt(chip); - else - tpm_gen_interrupt(chip); + rc = tpm_tis_gen_interrupt(chip); + if (rc < 0) + return rc; /* tpm_tis_send will either confirm the interrupt is working or it * will call disable_irq which undoes all of the above. From ae7e190a3e3498551a1e222eaa84c0ec7e5b41c7 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 17 Jun 2016 10:20:14 +0200 Subject: [PATCH 26/47] tpm: use tpm_transmit_cmd() in tpm2_probe() It is better to tpm_transmit_cmd() in tpm2_probe() in order to get consistent command handling throughout the subsystem. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe --- drivers/char/tpm/tpm2-cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a5aa8de23c3d..7df55d58c939 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -941,11 +941,9 @@ int tpm2_probe(struct tpm_chip *chip) cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit(chip, (const u8 *)&cmd, sizeof(cmd), 0); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); if (rc < 0) return rc; - else if (rc < TPM_HEADER_SIZE) - return -EFAULT; if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS) chip->flags |= TPM_CHIP_FLAG_TPM2; From 0c541332231e7957f23013e37f3720db33e7804c Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 17 Jun 2016 13:12:20 +0200 Subject: [PATCH 27/47] tpm: use tpm_pcr_read_dev() in tpm_do_selftest() Instead of a ad-hoc protocol message construction it is better to call tpm_pcr_read_dev(). Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe --- drivers/char/tpm/tpm-interface.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6bffb13fb189..3edf2e8798ca 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -782,7 +782,7 @@ int tpm_do_selftest(struct tpm_chip *chip) unsigned int loops; unsigned int delay_msec = 100; unsigned long duration; - struct tpm_cmd_t cmd; + u8 dummy[TPM_DIGEST_SIZE]; duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST); @@ -797,9 +797,8 @@ int tpm_do_selftest(struct tpm_chip *chip) do { /* Attempt to read a PCR value */ - cmd.header.in = pcrread_header; - cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); - rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE, 0); + rc = tpm_pcr_read_dev(chip, 0, dummy); + /* Some buggy TPMs will not respond to tpm_tis_ready() for * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ @@ -814,7 +813,6 @@ int tpm_do_selftest(struct tpm_chip *chip) if (rc < TPM_HEADER_SIZE) return -EFAULT; - rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { dev_info(&chip->dev, "TPM is disabled/deactivated (0x%X)\n", rc); From 72fd50e14e46dc0edf360631bdece87c2f066a97 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 2 Sep 2016 22:34:17 +0300 Subject: [PATCH 28/47] tpm_crb: fix crb_req_canceled behavior The req_canceled() callback is used by tpm_transmit() periodically to check whether the request has been canceled while it is receiving a response from the TPM. The TPM_CRB_CTRL_CANCEL register was cleared already in the crb_cancel callback, which has two consequences: * Cancel might not happen. * req_canceled() always returns zero. A better place to clear the register is when starting to send a new command. The behavior of TPM_CRB_CTRL_CANCEL is described in the section 5.5.3.6 of the PTP specification. CC: stable@vger.kernel.org Fixes: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface") Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 018c382554ba..1801f382377e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -142,6 +142,11 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) struct crb_priv *priv = dev_get_drvdata(&chip->dev); int rc = 0; + /* Zero the cancel register so that the next command will not get + * canceled. + */ + iowrite32(0, &priv->cca->cancel); + if (len > ioread32(&priv->cca->cmd_size)) { dev_err(&chip->dev, "invalid command count value %x %zx\n", @@ -175,8 +180,6 @@ static void crb_cancel(struct tpm_chip *chip) if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) dev_err(&chip->dev, "ACPI Start failed\n"); - - iowrite32(0, &priv->cca->cancel); } static bool crb_req_canceled(struct tpm_chip *chip, u8 status) From 35fec6f1eb27cd62998a98c3f1b0ecf0578f55e2 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 2 Sep 2016 22:34:18 +0300 Subject: [PATCH 29/47] tpm_crb: remove wmb()'s wmb()'s are not needed as iowrite32() is used. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 1801f382377e..358c47577a2e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -175,9 +175,6 @@ static void crb_cancel(struct tpm_chip *chip) iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel); - /* Make sure that cmd is populated before issuing cancel. */ - wmb(); - if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) dev_err(&chip->dev, "ACPI Start failed\n"); } From 7fd10d61852d1947005c05575849f21bc32f0acf Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 2 Sep 2016 22:34:19 +0300 Subject: [PATCH 30/47] tpm_crb: refine the naming of constants Renamed CRB protocol specific constants to match the TCG PC Client Platform TPM Profile (PTP) Specification and driver status constants to be explicit that they are driver specific. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 358c47577a2e..c8b0d91d9790 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -34,14 +34,14 @@ enum crb_defaults { CRB_ACPI_START_INDEX = 1, }; -enum crb_ca_request { - CRB_CA_REQ_GO_IDLE = BIT(0), - CRB_CA_REQ_CMD_READY = BIT(1), +enum crb_ctrl_req { + CRB_CTRL_REQ_GO_IDLE = BIT(0), + CRB_CTRL_REQ_CMD_READY = BIT(1), }; -enum crb_ca_status { - CRB_CA_STS_ERROR = BIT(0), - CRB_CA_STS_TPM_IDLE = BIT(1), +enum crb_ctrl_sts { + CRB_CTRL_STS_ERROR = BIT(0), + CRB_CTRL_STS_TPM_IDLE = BIT(1), }; enum crb_start { @@ -67,7 +67,7 @@ struct crb_control_area { } __packed; enum crb_status { - CRB_STS_COMPLETE = BIT(0), + CRB_DRV_STS_COMPLETE = BIT(0), }; enum crb_flags { @@ -92,7 +92,7 @@ static u8 crb_status(struct tpm_chip *chip) if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) != CRB_START_INVOKE) - sts |= CRB_STS_COMPLETE; + sts |= CRB_DRV_STS_COMPLETE; return sts; } @@ -106,7 +106,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) if (count < 6) return -EIO; - if (ioread32(&priv->cca->sts) & CRB_CA_STS_ERROR) + if (ioread32(&priv->cca->sts) & CRB_CTRL_STS_ERROR) return -EIO; memcpy_fromio(buf, priv->rsp, 6); @@ -194,8 +194,8 @@ static const struct tpm_class_ops tpm_crb = { .send = crb_send, .cancel = crb_cancel, .req_canceled = crb_req_canceled, - .req_complete_mask = CRB_STS_COMPLETE, - .req_complete_val = CRB_STS_COMPLETE, + .req_complete_mask = CRB_DRV_STS_COMPLETE, + .req_complete_val = CRB_DRV_STS_COMPLETE, }; static int crb_init(struct acpi_device *device, struct crb_priv *priv) From f39a9e97d77cae603e70c78ac82c181f93455fd1 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 2 Sep 2016 22:34:20 +0300 Subject: [PATCH 31/47] tpm_crb: fix incorrect values of cmdReady and goIdle bits CRB_CTRL_CMD_READY and CRB_CTRL_GO_IDLE have incorrect values. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index c8b0d91d9790..7f602dc1f9bb 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -35,8 +35,8 @@ enum crb_defaults { }; enum crb_ctrl_req { - CRB_CTRL_REQ_GO_IDLE = BIT(0), - CRB_CTRL_REQ_CMD_READY = BIT(1), + CRB_CTRL_REQ_CMD_READY = BIT(0), + CRB_CTRL_REQ_GO_IDLE = BIT(1), }; enum crb_ctrl_sts { From 56af322156dbe93b3fdc80ac4dff1fc93cb44825 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 8 Sep 2016 02:01:02 +0300 Subject: [PATCH 32/47] tpm/tpm_tis: remove unused itpm variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the warning: drivers/char/tpm/tpm_tis_core.c:443:7: warning: variable ‘itpm’ set but not used [-Wunused-but-set-variable] bool itpm; ^~~~ Signed-off-by: Tomas Winkler Acked-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index f22caf802e56..e3bf31b37138 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -440,7 +440,6 @@ static int probe_itpm(struct tpm_chip *chip) 0x00, 0x00, 0x00, 0xf1 }; size_t len = sizeof(cmd_getticks); - bool itpm; u16 vendor; rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor); @@ -451,8 +450,6 @@ static int probe_itpm(struct tpm_chip *chip) if (vendor != TPM_VID_INTEL) return 0; - itpm = false; - rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) goto out; @@ -460,8 +457,6 @@ static int probe_itpm(struct tpm_chip *chip) tpm_tis_ready(chip); release_locality(chip, priv->locality, 0); - itpm = true; - rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) { dev_info(&chip->dev, "Detected an iTPM.\n"); From 71801310b12b65b1fd3285cc899ecbf52c4f8ff3 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 12 Sep 2016 02:03:52 +0300 Subject: [PATCH 33/47] tmp/tpm_crb: drop include to platform_device The platform device is not used in this driver, drop the include to linux/platform_device.h Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 7f602dc1f9bb..e76a8ee20074 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "tpm.h" #define ACPI_SIG_TPM2 "TPM2" From aa77ea0e43dc5bb0c1dcc9bad76afaa7faca8cab Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 12 Sep 2016 13:52:10 +0300 Subject: [PATCH 34/47] tpm/tpm_crb: cache cmd_size register value. Instead of expensive register access on retrieving cmd_size on each send, save the value during initialization in the private context. The value doesn't change. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index e76a8ee20074..18b5b83af36d 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -80,6 +80,7 @@ struct crb_priv { struct crb_control_area __iomem *cca; u8 __iomem *cmd; u8 __iomem *rsp; + u32 cmd_size; }; static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); @@ -146,11 +147,9 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) */ iowrite32(0, &priv->cca->cancel); - if (len > ioread32(&priv->cca->cmd_size)) { - dev_err(&chip->dev, - "invalid command count value %x %zx\n", - (unsigned int) len, - (size_t) ioread32(&priv->cca->cmd_size)); + if (len > priv->cmd_size) { + dev_err(&chip->dev, "invalid command count value %zd %d\n", + len, priv->cmd_size); return -E2BIG; } @@ -301,6 +300,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); return -EINVAL; } + priv->cmd_size = cmd_size; priv->rsp = priv->cmd; return 0; From 47de683afa7d1b9638a7d6817826d0cdc72b0e1a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 12 Sep 2016 14:27:09 +0300 Subject: [PATCH 35/47] tpm/tpm_crb: drop useless cpu_to_le32 when writing to registers Don't apply endianity conversion when writing to the registers this is already handled by the system. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 18b5b83af36d..ceea7e256a6d 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -159,7 +159,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) wmb(); if (priv->flags & CRB_FL_CRB_START) - iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start); + iowrite32(CRB_START_INVOKE, &priv->cca->start); if (priv->flags & CRB_FL_ACPI_START) rc = crb_do_acpi_start(chip); @@ -171,7 +171,7 @@ static void crb_cancel(struct tpm_chip *chip) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); - iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel); + iowrite32(CRB_CANCEL_INVOKE, &priv->cca->cancel); if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) dev_err(&chip->dev, "ACPI Start failed\n"); From 64fba530e9ef81469b6dc65bf8e00ed9e90192c7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 12 Sep 2016 02:03:55 +0300 Subject: [PATCH 36/47] tpm/tpm_crb: fix the over 80 characters checkpatch warring Because of the line break in the debug print the chackpatch is not silent on 80 characters limitation. The easiest fix is to straighten the lines, it's also more readable. WARNING: line over 80 characters + FW_BUG "TPM2 ACPI table does not define a memory resource\n"); Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index ceea7e256a6d..a7c870af916c 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -263,8 +263,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, acpi_dev_free_resource_list(&resources); if (resource_type(&io_res) != IORESOURCE_MEM) { - dev_err(dev, - FW_BUG "TPM2 ACPI table does not define a memory resource\n"); + dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n"); return -EINVAL; } From 0014777f989b54193bec95a0a153fa4a139183c7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Sep 2016 15:05:52 +0200 Subject: [PATCH 37/47] tpm: constify TPM 1.x header structures Constify TPM 1.x header structures in order to move them to rodata section as they are meant to be never changed during runtime. Signed-off-by: Julia Lawall Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 10 +++++----- drivers/char/tpm/tpm-sysfs.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3edf2e8798ca..3970f843acd1 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -623,7 +623,7 @@ EXPORT_SYMBOL_GPL(tpm_get_timeouts); #define TPM_ORD_CONTINUE_SELFTEST 83 #define CONTINUE_SELFTEST_RESULT_SIZE 10 -static struct tpm_input_header continue_selftest_header = { +static const struct tpm_input_header continue_selftest_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(10), .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST), @@ -649,7 +649,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip) #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 -static struct tpm_input_header pcrread_header = { +static const struct tpm_input_header pcrread_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(14), .ordinal = TPM_ORDINAL_PCRREAD @@ -735,7 +735,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); */ #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) #define EXTEND_PCR_RESULT_SIZE 34 -static struct tpm_input_header pcrextend_header = { +static const struct tpm_input_header pcrextend_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(34), .ordinal = TPM_ORD_PCR_EXTEND @@ -937,7 +937,7 @@ EXPORT_SYMBOL_GPL(wait_for_tpm_stat); #define TPM_ORD_SAVESTATE cpu_to_be32(152) #define SAVESTATE_RESULT_SIZE 10 -static struct tpm_input_header savestate_header = { +static const struct tpm_input_header savestate_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(10), .ordinal = TPM_ORD_SAVESTATE @@ -1021,7 +1021,7 @@ int tpm_pm_resume(struct device *dev) EXPORT_SYMBOL_GPL(tpm_pm_resume); #define TPM_GETRANDOM_RESULT_SIZE 18 -static struct tpm_input_header tpm_getrandom_header = { +static const struct tpm_input_header tpm_getrandom_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(14), .ordinal = TPM_ORD_GET_RANDOM diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index e1f7236c115c..a76ab4af9fb2 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -22,7 +22,7 @@ #define READ_PUBEK_RESULT_SIZE 314 #define TPM_ORD_READPUBEK cpu_to_be32(124) -static struct tpm_input_header tpm_readpubek_header = { +static const struct tpm_input_header tpm_readpubek_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(30), .ordinal = TPM_ORD_READPUBEK From ebfd7532e985818a327906e011f3e43c8ddfdd74 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 12 Sep 2016 13:43:30 +0300 Subject: [PATCH 38/47] tpm: add check for minimum buffer size in tpm_transmit() tpm_transmit() does not check that bufsiz is at least TPM_HEADER_SIZE before accessing data. This commit adds this check and returns -EINVAL if it fails. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3970f843acd1..8de61876f633 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -337,6 +337,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, u32 count, ordinal; unsigned long stop; + if (bufsiz < TPM_HEADER_SIZE) + return -EINVAL; + if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; From e17acbbb69d30836a8c12e2c09bbefab8656693e Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Thu, 15 Sep 2016 10:27:38 +0300 Subject: [PATCH 39/47] tpm/tpm_crb: implement tpm crb idle state The register TPM_CRB_CTRL_REQ_x contains bits goIdle and cmdReady for SW to indicate that the device can enter or should exit the idle state. The legacy ACPI-start (SMI + DMA) based devices do not support these bits and the idle state management is not exposed to the host SW. Thus, this functionality only is enabled only for a CRB start (MMIO) based devices. Based on Jarkko Sakkinen original patch: 'tpm_crb: implement power tpm crb power management' To keep the implementation local to the hw we don't use wait_for_tpm_stat for polling the TPM_CRB_CTRL_REQ. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index a7c870af916c..466d12b7fd46 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -83,6 +83,75 @@ struct crb_priv { u32 cmd_size; }; +/** + * crb_go_idle - request tpm crb device to go the idle state + * + * @dev: crb device + * @priv: crb private data + * + * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ + * The device should respond within TIMEOUT_C by clearing the bit. + * Anyhow, we do not wait here as a consequent CMD_READY request + * will be handled correctly even if idle was not completed. + * + * The function does nothing for devices with ACPI-start method. + * + * Return: 0 always + */ +static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) +{ + if (priv->flags & CRB_FL_ACPI_START) + return 0; + + iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); + /* we don't really care when this settles */ + + return 0; +} + +/** + * crb_cmd_ready - request tpm crb device to enter ready state + * + * @dev: crb device + * @priv: crb private data + * + * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ + * and poll till the device acknowledge it by clearing the bit. + * The device should respond within TIMEOUT_C. + * + * The function does nothing for devices with ACPI-start method + * + * Return: 0 on success -ETIME on timeout; + */ +static int __maybe_unused crb_cmd_ready(struct device *dev, + struct crb_priv *priv) +{ + ktime_t stop, start; + + if (priv->flags & CRB_FL_ACPI_START) + return 0; + + iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); + do { + if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) { + dev_dbg(dev, "cmdReady in %lld usecs\n", + ktime_to_us(ktime_sub(ktime_get(), start))); + return 0; + } + usleep_range(50, 100); + } while (ktime_before(ktime_get(), stop)); + + if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { + dev_warn(dev, "cmdReady timed out\n"); + return -ETIME; + } + + return 0; +} + static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); static u8 crb_status(struct tpm_chip *chip) From 9514ff1961c6f0f5983ba72d94f384bc13e0d4a1 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 12 Sep 2016 16:04:19 +0300 Subject: [PATCH 40/47] tmp/tpm_crb: fix Intel PTT hw bug during idle state There is a HW bug in Skylake, and Broxton PCH Intel PTT device, where most of the registers in the control area except START, REQUEST, CANCEL, and LOC_CTRL lost retention when the device is in the idle state. Hence we need to bring the device to ready state before accessing the other registers. The fix brings device to ready state before trying to read command and response buffer addresses in order to remap the for access. Signed-off-by: Tomas Winkler Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 47 +++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 466d12b7fd46..2d1669c0f6c0 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -318,6 +318,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, struct list_head resources; struct resource io_res; struct device *dev = &device->dev; + u32 pa_high, pa_low; u64 cmd_pa; u32 cmd_size; u64 rsp_pa; @@ -345,12 +346,27 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (IS_ERR(priv->cca)) return PTR_ERR(priv->cca); - cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) | - (u64) ioread32(&priv->cca->cmd_pa_low); + /* + * PTT HW bug w/a: wake up the device to access + * possibly not retained registers. + */ + ret = crb_cmd_ready(dev, priv); + if (ret) + return ret; + + pa_high = ioread32(&priv->cca->cmd_pa_high); + pa_low = ioread32(&priv->cca->cmd_pa_low); + cmd_pa = ((u64)pa_high << 32) | pa_low; cmd_size = ioread32(&priv->cca->cmd_size); + + dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", + pa_high, pa_low, cmd_size); + priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); - if (IS_ERR(priv->cmd)) - return PTR_ERR(priv->cmd); + if (IS_ERR(priv->cmd)) { + ret = PTR_ERR(priv->cmd); + goto out; + } memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); rsp_pa = le64_to_cpu(rsp_pa); @@ -358,7 +374,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (cmd_pa != rsp_pa) { priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); - return PTR_ERR_OR_ZERO(priv->rsp); + ret = PTR_ERR_OR_ZERO(priv->rsp); + goto out; } /* According to the PTP specification, overlapping command and response @@ -366,12 +383,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, */ if (cmd_size != rsp_size) { dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); - return -EINVAL; + ret = -EINVAL; + goto out; } + priv->cmd_size = cmd_size; priv->rsp = priv->cmd; - return 0; + +out: + crb_go_idle(dev, priv); + + return ret; } static int crb_acpi_add(struct acpi_device *device) @@ -415,7 +438,15 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; - return crb_init(device, priv); + rc = crb_cmd_ready(dev, priv); + if (rc) + return rc; + + rc = crb_init(device, priv); + if (rc) + crb_go_idle(dev, priv); + + return rc; } static int crb_acpi_remove(struct acpi_device *device) From 0c22db435bf79d3cf3089df7ff198d4867df3c27 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 12 Sep 2016 16:04:20 +0300 Subject: [PATCH 41/47] tpm/tpm_crb: open code the crb_init into acpi_add This is preparation step for implementing tpm crb runtime pm. We need to have tpm chip allocated and populated before we access the runtime handlers. Signed-off-by: Tomas Winkler Tested-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 2d1669c0f6c0..d385e63008a6 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -265,21 +265,6 @@ static const struct tpm_class_ops tpm_crb = { .req_complete_val = CRB_DRV_STS_COMPLETE, }; -static int crb_init(struct acpi_device *device, struct crb_priv *priv) -{ - struct tpm_chip *chip; - - chip = tpmm_chip_alloc(&device->dev, &tpm_crb); - if (IS_ERR(chip)) - return PTR_ERR(chip); - - dev_set_drvdata(&chip->dev, priv); - chip->acpi_dev_handle = device->handle; - chip->flags = TPM_CHIP_FLAG_TPM2; - - return tpm_chip_register(chip); -} - static int crb_check_resource(struct acpi_resource *ares, void *data) { struct resource *io_res = data; @@ -401,6 +386,7 @@ static int crb_acpi_add(struct acpi_device *device) { struct acpi_table_tpm2 *buf; struct crb_priv *priv; + struct tpm_chip *chip; struct device *dev = &device->dev; acpi_status status; u32 sm; @@ -438,11 +424,19 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; + chip = tpmm_chip_alloc(dev, &tpm_crb); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + dev_set_drvdata(&chip->dev, priv); + chip->acpi_dev_handle = device->handle; + chip->flags = TPM_CHIP_FLAG_TPM2; + rc = crb_cmd_ready(dev, priv); if (rc) return rc; - rc = crb_init(device, priv); + rc = tpm_chip_register(chip); if (rc) crb_go_idle(dev, priv); From e350e24694e447e6ab7312fffae5ca31a0bb5165 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 12 Sep 2016 16:04:21 +0300 Subject: [PATCH 42/47] tmp/tpm_crb: implement runtime pm for tpm_crb Utilize runtime_pm for driving tpm crb idle states. The framework calls cmd_ready from the pm_runtime_resume handler and go idle from the pm_runtime_suspend handler. The TPM framework should wake the device before transmit and receive. In case the runtime_pm framework is not enabled, the device will be in ready state. [jarkko.sakkinen@linux.intel.com: changed pm_runtime_put_sync() to pm_runtime_put()] Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 5 +++++ drivers/char/tpm/tpm_crb.c | 37 +++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 8de61876f633..77d83c98d67f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -356,6 +357,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); + pm_runtime_get_sync(chip->dev.parent); + rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, @@ -397,6 +400,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: + pm_runtime_put(chip->dev.parent); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index d385e63008a6..aa0ef742ac03 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "tpm.h" #define ACPI_SIG_TPM2 "TPM2" @@ -152,8 +153,6 @@ static int __maybe_unused crb_cmd_ready(struct device *dev, return 0; } -static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); - static u8 crb_status(struct tpm_chip *chip) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); @@ -436,9 +435,16 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + rc = tpm_chip_register(chip); - if (rc) + if (rc) { crb_go_idle(dev, priv); + pm_runtime_disable(dev); + } + + pm_runtime_put(dev); return rc; } @@ -450,9 +456,34 @@ static int crb_acpi_remove(struct acpi_device *device) tpm_chip_unregister(chip); + pm_runtime_disable(dev); + return 0; } +#ifdef CONFIG_PM +static int crb_pm_runtime_suspend(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return crb_go_idle(dev, priv); +} + +static int crb_pm_runtime_resume(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return crb_cmd_ready(dev, priv); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops crb_pm = { + SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) + SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) +}; + static struct acpi_device_id crb_device_ids[] = { {"MSFT0101", 0}, {"", 0}, From 43af5de74288a7cdc3684902c5259346ae67adf8 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Fri, 9 Sep 2016 11:37:49 -0400 Subject: [PATCH 43/47] lsm,audit,selinux: Introduce a new audit data type LSM_AUDIT_DATA_FILE Right now LSM_AUDIT_DATA_PATH type contains "struct path" in union "u" of common_audit_data. This information is used to print path of file at the same time it is also used to get to dentry and inode. And this inode information is used to get to superblock and device and print device information. This does not work well for layered filesystems like overlay where dentry contained in path is overlay dentry and not the real dentry of underlying file system. That means inode retrieved from dentry is also overlay inode and not the real inode. SELinux helpers like file_path_has_perm() are doing checks on inode retrieved from file_inode(). This returns the real inode and not the overlay inode. That means we are doing check on real inode but for audit purposes we are printing details of overlay inode and that can be confusing while debugging. Hence, introduce a new type LSM_AUDIT_DATA_FILE which carries file information and inode retrieved is real inode using file_inode(). That way right avc denied information is given to user. For example, following is one example avc before the patch. type=AVC msg=audit(1473360868.399:214): avc: denied { read open } for pid=1765 comm="cat" path="/root/.../overlay/container1/merged/readfile" dev="overlay" ino=21443 scontext=unconfined_u:unconfined_r:test_overlay_client_t:s0:c10,c20 tcontext=unconfined_u:object_r:test_overlay_files_ro_t:s0 tclass=file permissive=0 It looks as follows after the patch. type=AVC msg=audit(1473360017.388:282): avc: denied { read open } for pid=2530 comm="cat" path="/root/.../overlay/container1/merged/readfile" dev="dm-0" ino=2377915 scontext=unconfined_u:unconfined_r:test_overlay_client_t:s0:c10,c20 tcontext=unconfined_u:object_r:test_overlay_files_ro_t:s0 tclass=file permissive=0 Notice that now dev information points to "dm-0" device instead of "overlay" device. This makes it clear that check failed on underlying inode and not on the overlay inode. Signed-off-by: Vivek Goyal [PM: slight tweaks to the description to make checkpatch.pl happy] Signed-off-by: Paul Moore --- include/linux/lsm_audit.h | 2 ++ security/lsm_audit.c | 13 +++++++++++++ security/selinux/hooks.c | 16 ++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index ffb9c9da4f39..e58e577117b6 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -59,6 +59,7 @@ struct common_audit_data { #define LSM_AUDIT_DATA_INODE 9 #define LSM_AUDIT_DATA_DENTRY 10 #define LSM_AUDIT_DATA_IOCTL_OP 11 +#define LSM_AUDIT_DATA_FILE 12 union { struct path path; struct dentry *dentry; @@ -75,6 +76,7 @@ struct common_audit_data { #endif char *kmod_name; struct lsm_ioctlop_audit *op; + struct file *file; } u; /* this union contains LSM specific data */ union { diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 9bf851884800..8bfa3147fd54 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -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; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e15e56081c0c..2205ea27aa0a 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, @@ -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, @@ -3833,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) { From 4886cd80cb8eab175a527f82ea8fc676e70309fa Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 27 Sep 2016 12:00:13 +0300 Subject: [PATCH 44/47] Revert "tmp/tpm_crb: implement runtime pm for tpm_crb" This reverts commit e350e24694e447e6ab7312fffae5ca31a0bb5165. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 5 ----- drivers/char/tpm/tpm_crb.c | 37 +++----------------------------- 2 files changed, 3 insertions(+), 39 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 77d83c98d67f..8de61876f633 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "tpm.h" #include "tpm_eventlog.h" @@ -357,8 +356,6 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); - pm_runtime_get_sync(chip->dev.parent); - rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, @@ -400,8 +397,6 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - pm_runtime_put(chip->dev.parent); - if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index aa0ef742ac03..d385e63008a6 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "tpm.h" #define ACPI_SIG_TPM2 "TPM2" @@ -153,6 +152,8 @@ static int __maybe_unused crb_cmd_ready(struct device *dev, return 0; } +static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); + static u8 crb_status(struct tpm_chip *chip) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); @@ -435,16 +436,9 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - rc = tpm_chip_register(chip); - if (rc) { + if (rc) crb_go_idle(dev, priv); - pm_runtime_disable(dev); - } - - pm_runtime_put(dev); return rc; } @@ -456,34 +450,9 @@ static int crb_acpi_remove(struct acpi_device *device) tpm_chip_unregister(chip); - pm_runtime_disable(dev); - return 0; } -#ifdef CONFIG_PM -static int crb_pm_runtime_suspend(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_go_idle(dev, priv); -} - -static int crb_pm_runtime_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_cmd_ready(dev, priv); -} -#endif /* CONFIG_PM */ - -static const struct dev_pm_ops crb_pm = { - SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) - SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) -}; - static struct acpi_device_id crb_device_ids[] = { {"MSFT0101", 0}, {"", 0}, From 2b7926ae1cd44efb006e16d5d165700e5f673294 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 27 Sep 2016 12:01:13 +0300 Subject: [PATCH 45/47] Revert "tpm/tpm_crb: open code the crb_init into acpi_add" This reverts commit 0c22db435bf79d3cf3089df7ff198d4867df3c27. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index d385e63008a6..2d1669c0f6c0 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -265,6 +265,21 @@ static const struct tpm_class_ops tpm_crb = { .req_complete_val = CRB_DRV_STS_COMPLETE, }; +static int crb_init(struct acpi_device *device, struct crb_priv *priv) +{ + struct tpm_chip *chip; + + chip = tpmm_chip_alloc(&device->dev, &tpm_crb); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + dev_set_drvdata(&chip->dev, priv); + chip->acpi_dev_handle = device->handle; + chip->flags = TPM_CHIP_FLAG_TPM2; + + return tpm_chip_register(chip); +} + static int crb_check_resource(struct acpi_resource *ares, void *data) { struct resource *io_res = data; @@ -386,7 +401,6 @@ static int crb_acpi_add(struct acpi_device *device) { struct acpi_table_tpm2 *buf; struct crb_priv *priv; - struct tpm_chip *chip; struct device *dev = &device->dev; acpi_status status; u32 sm; @@ -424,19 +438,11 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; - chip = tpmm_chip_alloc(dev, &tpm_crb); - if (IS_ERR(chip)) - return PTR_ERR(chip); - - dev_set_drvdata(&chip->dev, priv); - chip->acpi_dev_handle = device->handle; - chip->flags = TPM_CHIP_FLAG_TPM2; - rc = crb_cmd_ready(dev, priv); if (rc) return rc; - rc = tpm_chip_register(chip); + rc = crb_init(device, priv); if (rc) crb_go_idle(dev, priv); From cfa188220363647c332028c094eb4cae86c918ad Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 27 Sep 2016 12:01:43 +0300 Subject: [PATCH 46/47] Revert "tmp/tpm_crb: fix Intel PTT hw bug during idle state" This reverts commit 9514ff1961c6f0f5983ba72d94f384bc13e0d4a1. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 47 +++++++------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 2d1669c0f6c0..466d12b7fd46 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -318,7 +318,6 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, struct list_head resources; struct resource io_res; struct device *dev = &device->dev; - u32 pa_high, pa_low; u64 cmd_pa; u32 cmd_size; u64 rsp_pa; @@ -346,27 +345,12 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (IS_ERR(priv->cca)) return PTR_ERR(priv->cca); - /* - * PTT HW bug w/a: wake up the device to access - * possibly not retained registers. - */ - ret = crb_cmd_ready(dev, priv); - if (ret) - return ret; - - pa_high = ioread32(&priv->cca->cmd_pa_high); - pa_low = ioread32(&priv->cca->cmd_pa_low); - cmd_pa = ((u64)pa_high << 32) | pa_low; + cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) | + (u64) ioread32(&priv->cca->cmd_pa_low); cmd_size = ioread32(&priv->cca->cmd_size); - - dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", - pa_high, pa_low, cmd_size); - priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); - if (IS_ERR(priv->cmd)) { - ret = PTR_ERR(priv->cmd); - goto out; - } + if (IS_ERR(priv->cmd)) + return PTR_ERR(priv->cmd); memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); rsp_pa = le64_to_cpu(rsp_pa); @@ -374,8 +358,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (cmd_pa != rsp_pa) { priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); - ret = PTR_ERR_OR_ZERO(priv->rsp); - goto out; + return PTR_ERR_OR_ZERO(priv->rsp); } /* According to the PTP specification, overlapping command and response @@ -383,18 +366,12 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, */ if (cmd_size != rsp_size) { dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); - ret = -EINVAL; - goto out; + return -EINVAL; } - priv->cmd_size = cmd_size; priv->rsp = priv->cmd; - -out: - crb_go_idle(dev, priv); - - return ret; + return 0; } static int crb_acpi_add(struct acpi_device *device) @@ -438,15 +415,7 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; - rc = crb_cmd_ready(dev, priv); - if (rc) - return rc; - - rc = crb_init(device, priv); - if (rc) - crb_go_idle(dev, priv); - - return rc; + return crb_init(device, priv); } static int crb_acpi_remove(struct acpi_device *device) From 324152502b0ef2f65a3fe039b7dcd27b223d14ac Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 27 Sep 2016 12:02:13 +0300 Subject: [PATCH 47/47] Revert "tpm/tpm_crb: implement tpm crb idle state" This reverts commit e17acbbb69d30836a8c12e2c09bbefab8656693e. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 69 -------------------------------------- 1 file changed, 69 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 466d12b7fd46..a7c870af916c 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -83,75 +83,6 @@ struct crb_priv { u32 cmd_size; }; -/** - * crb_go_idle - request tpm crb device to go the idle state - * - * @dev: crb device - * @priv: crb private data - * - * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ - * The device should respond within TIMEOUT_C by clearing the bit. - * Anyhow, we do not wait here as a consequent CMD_READY request - * will be handled correctly even if idle was not completed. - * - * The function does nothing for devices with ACPI-start method. - * - * Return: 0 always - */ -static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) -{ - if (priv->flags & CRB_FL_ACPI_START) - return 0; - - iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); - /* we don't really care when this settles */ - - return 0; -} - -/** - * crb_cmd_ready - request tpm crb device to enter ready state - * - * @dev: crb device - * @priv: crb private data - * - * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ - * and poll till the device acknowledge it by clearing the bit. - * The device should respond within TIMEOUT_C. - * - * The function does nothing for devices with ACPI-start method - * - * Return: 0 on success -ETIME on timeout; - */ -static int __maybe_unused crb_cmd_ready(struct device *dev, - struct crb_priv *priv) -{ - ktime_t stop, start; - - if (priv->flags & CRB_FL_ACPI_START) - return 0; - - iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); - - start = ktime_get(); - stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); - do { - if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) { - dev_dbg(dev, "cmdReady in %lld usecs\n", - ktime_to_us(ktime_sub(ktime_get(), start))); - return 0; - } - usleep_range(50, 100); - } while (ktime_before(ktime_get(), stop)); - - if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { - dev_warn(dev, "cmdReady timed out\n"); - return -ETIME; - } - - return 0; -} - static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); static u8 crb_status(struct tpm_chip *chip)