Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752740Ab3IJVpT (ORCPT ); Tue, 10 Sep 2013 17:45:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:5520 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752397Ab3IJVpE (ORCPT ); Tue, 10 Sep 2013 17:45:04 -0400 From: Vivek Goyal To: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, kexec@lists.infradead.org Cc: akpm@linux-foundation.org, zohar@linux.vnet.ibm.com, d.kasatkin@samsung.com, ebiederm@xmission.com, hpa@zytor.com, matthew.garrett@nebula.com, vgoyal@redhat.com Subject: [PATCH 10/16] keyctl: Introduce a new operation KEYCTL_VERIFY_SIGNATURE Date: Tue, 10 Sep 2013 17:44:25 -0400 Message-Id: <1378849471-10521-11-git-send-email-vgoyal@redhat.com> In-Reply-To: <1378849471-10521-1-git-send-email-vgoyal@redhat.com> References: <1378849471-10521-1-git-send-email-vgoyal@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6873 Lines: 221 This is based on a patch david howells sent me. I have modified that patch to meet my needs. Extend kecytl() to add an option to verify signature of a user buffer. One needs to pass in the signature type also so that respective handler can be called. Currently I have defined a new signature type KEYCTL_SIG_TYPE_IMA_DIGSIG, which sinifies signatures generated by IMA subsystem. Signed-off-by: Vivek Goyal --- include/uapi/linux/keyctl.h | 16 +++++++++ security/keys/compat.c | 28 ++++++++++++++++ security/keys/internal.h | 2 ++ security/keys/keyctl.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 840cb99..d7c7471 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h @@ -12,6 +12,17 @@ #ifndef _LINUX_KEYCTL_H #define _LINUX_KEYCTL_H +/* Data required to verify signature of a user buffer */ +struct keyctl_sig_data { + void *data; + size_t datalen; + void *sig; + size_t siglen; + unsigned long sig_type; + unsigned long keyring_id; + unsigned long flags; +}; + /* special process keyring shortcut IDs */ #define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ #define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ @@ -57,5 +68,10 @@ #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ #define KEYCTL_INVALIDATE 21 /* invalidate a key */ #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ +#define KEYCTL_VERIFY_SIGNATURE 23 /* use a key to verify a signature */ + +/* Type of signatures */ +#define KEYCTL_SIG_TYPE_UNKNOWN 0 +#define KEYCTL_SIG_TYPE_INTEGRITY_DIGSIG 1 /* Digital Signature generated by integrity subsystem utilities */ #endif /* _LINUX_KEYCTL_H */ diff --git a/security/keys/compat.c b/security/keys/compat.c index bbd32c7..3af2cf2 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -15,6 +15,31 @@ #include #include "internal.h" +struct compat_keyctl_sig_data { + compat_uptr_t data; + compat_size_t datalen; + compat_uptr_t sig; + compat_size_t siglen; + compat_ulong_t sig_type; + compat_ulong_t keyring_id; + compat_ulong_t flags; +}; + +static long compat_keyctl_verify_signature(const void __user *_sig_data) +{ + struct compat_keyctl_sig_data csig_data; + int result; + + result = copy_from_user(&csig_data, _sig_data, sizeof(csig_data)); + if (result) + return -EFAULT; + + return __keyctl_verify_signature(csig_data.keyring_id, + compat_ptr(csig_data.data), csig_data.datalen, + compat_ptr(csig_data.sig), csig_data.siglen, + csig_data.sig_type, csig_data.flags); +} + /* * Instantiate a key with the specified compatibility multipart payload and * link the key into the destination keyring if one is given. @@ -141,6 +166,9 @@ asmlinkage long compat_sys_keyctl(u32 option, case KEYCTL_GET_PERSISTENT: return keyctl_get_persistent(arg2, arg3); + case KEYCTL_VERIFY_SIGNATURE: + return compat_keyctl_verify_signature(compat_ptr(arg2)); + default: return -EOPNOTSUPP; } diff --git a/security/keys/internal.h b/security/keys/internal.h index 80b2aac..f15acee 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -255,6 +255,8 @@ extern long keyctl_invalidate_key(key_serial_t); extern long keyctl_instantiate_key_common(key_serial_t, const struct iovec *, unsigned, size_t, key_serial_t); +extern long keyctl_verify_signature(const void __user *_sig_data); +extern long __keyctl_verify_signature(key_serial_t keyring_id, void __user *_data, size_t dlen, void __user *_sig, size_t siglen, unsigned long sig_type, unsigned long flags); #ifdef CONFIG_PERSISTENT_KEYRINGS extern long keyctl_get_persistent(uid_t, key_serial_t); extern unsigned persistent_keyring_expiry; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cee72ce..84b7c3d 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include "internal.h" @@ -1564,6 +1566,80 @@ error_keyring: return ret; } +long __keyctl_verify_signature(key_serial_t keyring_id, void __user *_data, + size_t dlen, void __user *_sig, size_t siglen, + unsigned long sig_type, unsigned long flags) +{ + void *sig; + long ret; + key_ref_t keyring_ref; + + pr_devel("-->keyctl_verify_signature(,%zu,,%zu,%lu)\n", + dlen, siglen, sig_type); + + if (!_data || !dlen || !_sig || !siglen || !keyring_id) + return -EINVAL; + /* + * Possibly various signature handlers could scan signature and + * claim it belongs to them and verify. + */ + if (sig_type == KEYCTL_SIG_TYPE_UNKNOWN) + return -EOPNOTSUPP; + + /* Get the keyring which should be used */ + keyring_ref = lookup_user_key(keyring_id, 0, KEY_SEARCH); + if (IS_ERR(keyring_ref)) + return PTR_ERR(keyring_ref); + + + ret = -ENOMEM; + sig = kmalloc(siglen, GFP_KERNEL); + if (!sig) + goto error_keyref_put; + + ret = -EFAULT; + if (copy_from_user(sig, _sig, siglen) != 0) + goto error_free_sig; + + switch(sig_type) { + case KEYCTL_SIG_TYPE_INTEGRITY_DIGSIG: + ret = integrity_verify_user_buffer_digsig( + key_ref_to_ptr(keyring_ref), + _data, dlen, sig, siglen); + break; + default: + ret = -EINVAL; + break; + } +error_free_sig: + kfree(sig); +error_keyref_put: + key_ref_put(keyring_ref); + return ret; +} + +/* + * Use a key to verify a signature. + * + * The key argument gives a key to use or a keyring in which a suitable key + * might be found. The signature will be examined and an attempt will be made + * to determine the key to use from the information contained therein. + */ +long keyctl_verify_signature(const void __user *_sig_data) +{ + struct keyctl_sig_data sig_data; + int result; + + result = copy_from_user(&sig_data, _sig_data, sizeof(sig_data)); + if (result) + return -EFAULT; + + return __keyctl_verify_signature(sig_data.keyring_id, sig_data.data, + sig_data.datalen, sig_data.sig, sig_data.siglen, + sig_data.sig_type, sig_data.flags); + +} + /* * The key control system call */ @@ -1670,6 +1746,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, case KEYCTL_GET_PERSISTENT: return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3); + case KEYCTL_VERIFY_SIGNATURE: + return keyctl_verify_signature((const void __user *)arg2); + default: return -EOPNOTSUPP; } -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/