Commit bb2cbf5e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem updates from James Morris:
 "In this release:

   - PKCS#7 parser for the key management subsystem from David Howells
   - appoint Kees Cook as seccomp maintainer
   - bugfixes and general maintenance across the subsystem"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits)
  X.509: Need to export x509_request_asymmetric_key()
  netlabel: shorter names for the NetLabel catmap funcs/structs
  netlabel: fix the catmap walking functions
  netlabel: fix the horribly broken catmap functions
  netlabel: fix a problem when setting bits below the previously lowest bit
  PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1
  tpm: simplify code by using %*phN specifier
  tpm: Provide a generic means to override the chip returned timeouts
  tpm: missing tpm_chip_put in tpm_get_random()
  tpm: Properly clean sysfs entries in error path
  tpm: Add missing tpm_do_selftest to ST33 I2C driver
  PKCS#7: Use x509_request_asymmetric_key()
  Revert "selinux: fix the default socket labeling in sock_graft()"
  X.509: x509_request_asymmetric_keys() doesn't need string length arguments
  PKCS#7: fix sparse non static symbol warning
  KEYS: revert encrypted key change
  ima: add support for measuring and appraising firmware
  firmware_class: perform new LSM checks
  security: introduce kernel_fw_from_file hook
  PKCS#7: Missing inclusion of linux/err.h
  ...
parents e7fda6c4 478d0855
......@@ -26,6 +26,7 @@ Description:
option: [[appraise_type=]] [permit_directio]
base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
fsmagic:= hex value
fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6)
......@@ -57,7 +58,8 @@ Description:
measure func=BPRM_CHECK
measure func=FILE_MMAP mask=MAY_EXEC
measure func=FILE_CHECK mask=MAY_READ uid=0
measure func=MODULE_CHECK uid=0
measure func=MODULE_CHECK
measure func=FIRMWARE_CHECK
appraise fowner=0
The default policy measures all executables in bprm_check,
......
......@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
possible to determine what the correct size should be.
This option provides an override for these situations.
ca_keys= [KEYS] This parameter identifies a specific key(s) on
the system trusted keyring to be used for certificate
trust validation.
format: { id:<keyid> | builtin }
ccw_timeout_log [S390]
See Documentation/s390/CommonIO for details.
......@@ -1319,6 +1324,23 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Formats: { "ima" | "ima-ng" }
Default: "ima-ng"
ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
Format: <min_file_size>
Set the minimal file size for using asynchronous hash.
If left unspecified, ahash usage is disabled.
ahash performance varies for different data sizes on
different crypto accelerators. This option can be used
to achieve the best performance for a particular HW.
ima.ahash_bufsize= [IMA] Asynchronous hash buffer size
Format: <bufsize>
Set hashing buffer size. Default: 4k.
ahash performance varies for different chunk sizes on
different crypto accelerators. This option can be used
to achieve best performance for particular HW.
init= [KNL]
Format: <full_path>
Run specified binary instead of /sbin/init as init
......
......@@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory:
const void *data;
size_t datalen;
size_t quotalen;
time_t expiry;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type and the rest will be cleared.
quota size from the key type; expiry will be set to TIME_T_MAX and the
rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to type_data[] and payload. These
are merely passed along to the instantiate() or update() operations.
are merely passed along to the instantiate() or update() operations. If
set, the expiry time will be applied to the key if it is instantiated from
this data.
The method should return 0 if success ful or a negative error code
The method should return 0 if successful or a negative error code
otherwise.
......@@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory:
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the
description, type_data and payload fields of the key_preparsed_payload
struct as filled in by the preparse() method.
struct as filled in by the preparse() method. It will always be called
after preparse() returns successfully, even if instantiate() or update()
succeed.
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
......
......@@ -8002,6 +8002,16 @@ S: Maintained
F: drivers/mmc/host/sdhci.*
F: drivers/mmc/host/sdhci-pltfm.[ch]
SECURE COMPUTING
M: Kees Cook <keescook@chromium.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
S: Supported
F: kernel/seccomp.c
F: include/uapi/linux/seccomp.h
F: include/linux/seccomp.h
K: \bsecure_computing
K: \bTIF_SECCOMP\b
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
M: Anton Vorontsov <anton@enomsg.org>
L: linuxppc-dev@lists.ozlabs.org
......
......@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
- secure_computing is called from a ptrace_event()-safe context
- secure_computing return value is checked and a return value of -1
results in the system call being skipped immediately.
- seccomp syscall wired up
config SECCOMP_FILTER
def_bool y
......
......@@ -409,6 +409,7 @@
#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
#define __NR_seccomp (__NR_SYSCALL_BASE+383)
/*
* The following SWIs are ARM private.
......
......@@ -392,6 +392,7 @@
/* 380 */ CALL(sys_sched_setattr)
CALL(sys_sched_getattr)
CALL(sys_renameat2)
CALL(sys_seccomp)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
......
......@@ -372,16 +372,17 @@
#define __NR_sched_setattr (__NR_Linux + 349)
#define __NR_sched_getattr (__NR_Linux + 350)
#define __NR_renameat2 (__NR_Linux + 351)
#define __NR_seccomp (__NR_Linux + 352)
/*
* Offset of the last Linux o32 flavoured syscall
*/
#define __NR_Linux_syscalls 351
#define __NR_Linux_syscalls 352
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000
#define __NR_O32_Linux_syscalls 351
#define __NR_O32_Linux_syscalls 352
#if _MIPS_SIM == _MIPS_SIM_ABI64
......@@ -701,16 +702,17 @@
#define __NR_sched_setattr (__NR_Linux + 309)
#define __NR_sched_getattr (__NR_Linux + 310)
#define __NR_renameat2 (__NR_Linux + 311)
#define __NR_seccomp (__NR_Linux + 312)
/*
* Offset of the last Linux 64-bit flavoured syscall
*/
#define __NR_Linux_syscalls 311
#define __NR_Linux_syscalls 312
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000
#define __NR_64_Linux_syscalls 311
#define __NR_64_Linux_syscalls 312
#if _MIPS_SIM == _MIPS_SIM_NABI32
......@@ -1034,15 +1036,16 @@
#define __NR_sched_setattr (__NR_Linux + 313)
#define __NR_sched_getattr (__NR_Linux + 314)
#define __NR_renameat2 (__NR_Linux + 315)
#define __NR_seccomp (__NR_Linux + 316)
/*
* Offset of the last N32 flavoured syscall
*/
#define __NR_Linux_syscalls 315
#define __NR_Linux_syscalls 316
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
#define __NR_N32_Linux_syscalls 315
#define __NR_N32_Linux_syscalls 316
#endif /* _UAPI_ASM_UNISTD_H */
......@@ -578,3 +578,4 @@ EXPORT(sys_call_table)
PTR sys_sched_setattr
PTR sys_sched_getattr /* 4350 */
PTR sys_renameat2
PTR sys_seccomp
......@@ -431,4 +431,5 @@ EXPORT(sys_call_table)
PTR sys_sched_setattr
PTR sys_sched_getattr /* 5310 */
PTR sys_renameat2
PTR sys_seccomp
.size sys_call_table,.-sys_call_table
......@@ -424,4 +424,5 @@ EXPORT(sysn32_call_table)
PTR sys_sched_setattr
PTR sys_sched_getattr
PTR sys_renameat2 /* 6315 */
PTR sys_seccomp
.size sysn32_call_table,.-sysn32_call_table
......@@ -557,4 +557,5 @@ EXPORT(sys32_call_table)
PTR sys_sched_setattr
PTR sys_sched_getattr /* 4350 */
PTR sys_renameat2
PTR sys_seccomp
.size sys32_call_table,.-sys32_call_table
......@@ -360,3 +360,4 @@
351 i386 sched_setattr sys_sched_setattr
352 i386 sched_getattr sys_sched_getattr
353 i386 renameat2 sys_renameat2
354 i386 seccomp sys_seccomp
......@@ -323,6 +323,7 @@
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
#
# x32-specific system call numbers start at 512 to avoid cache impact
......
......@@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
config PUBLIC_KEY_ALGO_RSA
tristate "RSA public-key algorithm"
select MPILIB_EXTRA
select MPILIB
help
This option enables support for the RSA algorithm (PKCS#1, RFC3447).
......@@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER
select ASN1
select OID_REGISTRY
help
This option procides support for parsing X.509 format blobs for key
This option provides support for parsing X.509 format blobs for key
data and provides the ability to instantiate a crypto key from a
public key packet found inside the certificate.
config PKCS7_MESSAGE_PARSER
tristate "PKCS#7 message parser"
depends on X509_CERTIFICATE_PARSER
select ASN1
select OID_REGISTRY
help
This option provides support for parsing PKCS#7 format messages for
signature data and provides the ability to verify the signature.
config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
depends on PKCS7_MESSAGE_PARSER
select SYSTEM_TRUSTED_KEYRING
help
This option provides a type of key that can be loaded up from a
PKCS#7 message - provided the message is signed by a trusted key. If
it is, the PKCS#7 wrapper is discarded and reading the key returns
just the payload. If it isn't, adding the key will fail with an
error.
This is intended for testing the PKCS#7 parser.
config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
select ASN1
select OID_REGISTRY
help
This option provides support for verifying the signature(s) on a
signed PE binary.
endif # ASYMMETRIC_KEY_TYPE
......@@ -25,3 +25,40 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
#
# PKCS#7 message handling
#
obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
pkcs7_message-y := \
pkcs7-asn1.o \
pkcs7_parser.o \
pkcs7_trust.o \
pkcs7_verify.o
$(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
$(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
clean-files += pkcs7-asn1.c pkcs7-asn1.h
#
# PKCS#7 parser testing key
#
obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o
pkcs7_test_key-y := \
pkcs7_key_type.o
#
# Signed PE binary-wrapped key handling
#
obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o
verify_signed_pefile-y := \
verify_pefile.o \
mscode_parser.o \
mscode-asn1.o
$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
clean-files += mscode-asn1.c mscode-asn1.h
......@@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version.
*/
int asymmetric_keyid_match(const char *kid, const char *id);
static inline const char *asymmetric_key_id(const struct key *key)
{
return key->type_data.p[1];
......
......@@ -22,6 +22,35 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
/*
* Match asymmetric key id with partial match
* @id: key id to match in a form "id:<id>"
*/
int asymmetric_keyid_match(const char *kid, const char *id)
{
size_t idlen, kidlen;
if (!kid || !id)
return 0;
/* make it possible to use id as in the request: "id:<id>" */
if (strncmp(id, "id:", 3) == 0)
id += 3;
/* Anything after here requires a partial match on the ID string */
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
return 1;
}
EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
/*
* Match asymmetric keys on (part of) their name
* We have some shorthand methods for matching keys. We allow:
......@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *spec = description;
const char *id, *kid;
const char *id;
ptrdiff_t speclen;
size_t idlen, kidlen;
if (!subtype || !spec || !*spec)
return 0;
......@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
speclen = id - spec;
id++;
/* Anything after here requires a partial match on the ID string */
kid = asymmetric_key_id(key);
if (!kid)
return 0;
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
if (speclen == 2 &&
memcmp(spec, "id", 2) == 0)
return 1;
if (speclen == 2 && memcmp(spec, "id", 2) == 0)
return asymmetric_keyid_match(asymmetric_key_id(key), id);
if (speclen == subtype->name_len &&
memcmp(spec, subtype->name, speclen) == 0)
......@@ -156,36 +169,13 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload);
subtype->destroy(prep->payload[0]);
module_put(subtype->owner);
}
kfree(prep->type_data[1]);
kfree(prep->description);
}
/*
* Instantiate a asymmetric_key defined key. The key was preparsed, so we just
* have to transfer the data here.
*/
static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
int ret;
pr_devel("==>%s()\n", __func__);
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
key->type_data.p[0] = prep->type_data[0];
key->type_data.p[1] = prep->type_data[1];
key->payload.data = prep->payload;
prep->type_data[0] = NULL;
prep->type_data[1] = NULL;
prep->payload = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* dispose of the data dangling from the corpse of a asymmetric key
*/
......@@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = {
.name = "asymmetric",
.preparse = asymmetric_key_preparse,
.free_preparse = asymmetric_key_free_preparse,
.instantiate = asymmetric_key_instantiate,
.instantiate = generic_key_instantiate,
.match = asymmetric_key_match,
.destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe,
......
--- Microsoft individual code signing data blob parser
---
--- Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
--- Written by David Howells (dhowells@redhat.com)
---
--- This program is free software; you can redistribute it and/or
--- modify it under the terms of the GNU General Public Licence
--- as published by the Free Software Foundation; either version
--- 2 of the Licence, or (at your option) any later version.
---
MSCode ::= SEQUENCE {
type SEQUENCE {
contentType ContentType,
parameters ANY
},
content SEQUENCE {
digestAlgorithm DigestAlgorithmIdentifier,
digest OCTET STRING ({ mscode_note_digest })
}
}
ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
DigestAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
parameters ANY OPTIONAL
}
/* Parse a Microsoft Individual Code Signing blob
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "MSCODE: "fmt
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
#include <crypto/pkcs7.h>
#include "verify_pefile.h"
#include "mscode-asn1.h"
/*
* Parse a Microsoft Individual Code Signing blob
*/
int mscode_parse(struct pefile_context *ctx)
{
const void *content_data;
size_t data_len;
int ret;
ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
if (ret) {
pr_debug("PKCS#7 message does not contain data\n");
return ret;
}
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
content_data);
return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
}
/*
* Check the content type OID
*/
int mscode_note_content_type(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
enum OID oid;
oid = look_up_OID(value, vlen);
if (oid == OID__NR) {
char buffer[50];
sprint_oid(value, vlen, buffer, sizeof(buffer));
pr_err("Unknown OID: %s\n", buffer);
return -EBADMSG;
}
/*
* pesign utility had a bug where it was putting
* OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
* So allow both OIDs.
*/
if (oid != OID_msPeImageDataObjId &&
oid != OID_msIndividualSPKeyPurpose) {
pr_err("Unexpected content type OID %u\n", oid);
return -EBADMSG;
}
return 0;
}
/*
* Note the digest algorithm OID
*/
int mscode_note_digest_algo(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pefile_context *ctx = context;
char buffer[50];
enum OID oid;
oid = look_up_OID(value, vlen);
switch (oid) {
case OID_md4:
ctx->digest_algo = HASH_ALGO_MD4;
break;
case OID_md5:
ctx->digest_algo = HASH_ALGO_MD5;
break;
case OID_sha1:
ctx->digest_algo = HASH_ALGO_SHA1;
break;
case OID_sha256:
ctx->digest_algo = HASH_ALGO_SHA256;
break;
case OID__NR:
sprint_oid(value, vlen, buffer, sizeof(buffer));
pr_err("Unknown OID: %s\n", buffer);
return -EBADMSG;
default:
pr_err("Unsupported content type: %u\n", oid);
return -ENOPKG;
}
return 0;
}
/*
* Note the digest we're guaranteeing with this certificate
*/
int mscode_note_digest(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pefile_context *ctx = context;
ctx->digest = value;
ctx->digest_len = vlen;
return 0;
}
PKCS7ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT SignedData OPTIONAL
}
ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
SignedData ::= SEQUENCE {
version INTEGER,
digestAlgorithms DigestAlgorithmIdentifiers,
contentInfo ContentInfo,
certificates CHOICE {
certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
certSequence [2] IMPLICIT Certificates
} OPTIONAL ({ pkcs7_note_certificate_list }),
crls CHOICE {
crlSet [1] IMPLICIT CertificateRevocationLists,
crlSequence [3] IMPLICIT CRLSequence
} OPTIONAL,
signerInfos SignerInfos
}
ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT Data OPTIONAL
}
Data ::= ANY ({ pkcs7_note_data })
DigestAlgorithmIdentifiers ::= CHOICE {
daSet SET OF DigestAlgorithmIdentifier,
daSequence SEQUENCE OF DigestAlgorithmIdentifier
}
DigestAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
parameters ANY OPTIONAL
}
--
-- Certificates and certificate lists
--
ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
ExtendedCertificateOrCertificate ::= CHOICE {
certificate Certificate, -- X.509
extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
}
ExtendedCertificate ::= Certificate -- cheating
Certificates ::= SEQUENCE OF Certificate
CertificateRevocationLists ::= SET OF CertificateList
CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
CRLSequence ::= SEQUENCE OF CertificateList
Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
--
-- Signer information
--
SignerInfos ::= CHOICE {
siSet SET OF SignerInfo,
siSequence SEQUENCE OF SignerInfo
}
SignerInfo ::= SEQUENCE {
version INTEGER,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
authenticatedAttributes CHOICE {
aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
({ pkcs7_sig_note_set_of_authattrs }),
aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
-- Explicit because easier to compute digest on
-- sequence of attributes and then reuse encoded
-- sequence in aaSequence.
} OPTIONAL,
digestEncryptionAlgorithm
DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
encryptedDigest EncryptedDigest,
unauthenticatedAttributes CHOICE {
uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
} OPTIONAL
} ({ pkcs7_note_signed_info })
IssuerAndSerialNumber ::= SEQUENCE {
issuer Name ({ pkcs7_sig_note_issuer }),
serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
}
CertificateSerialNumber ::= INTEGER
SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
AuthenticatedAttribute ::= SEQUENCE {
type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
values SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
}
UnauthenticatedAttribute ::= SEQUENCE {
type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
values SET OF ANY
}
DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
parameters ANY OPTIONAL
}
EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
---
--- X.500 Name
---
Name ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
AttributeValueAssertion ::= SEQUENCE {
attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
attributeValue ANY
}
/* Testing module to load key from trusted PKCS#7 message
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKCS7key: "fmt
#include <linux/key.h>
#include <linux/err.h>
#include <linux/key-type.h>
#include <crypto/pkcs7.h>
#include <keys/user-type.h>
#include <keys/system_keyring.h>
#include "pkcs7_parser.h"
/*
* Preparse a PKCS#7 wrapped and validated data blob.
*/
static int pkcs7_preparse(struct key_preparsed_payload *prep)
{
struct pkcs7_message *pkcs7;
const void *data, *saved_prep_data;
size_t datalen, saved_prep_datalen;
bool trusted;
int ret;
kenter("");
saved_prep_data = prep->data;
saved_prep_datalen = prep->datalen;
pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
if (IS_ERR(pkcs7)) {
ret = PTR_ERR(pkcs7);
goto error;
}
ret = pkcs7_verify(pkcs7);
if (ret < 0)
goto error_free;
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
if (ret < 0)
goto error_free;
if (!trusted)
pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
if (ret < 0)
goto error_free;
prep->data = data;
prep->datalen = datalen;
ret = user_preparse(prep);
prep->data = saved_prep_data;
prep->datalen = saved_prep_datalen;
error_free:
pkcs7_free_message(pkcs7);
error:
kleave(" = %d", ret);
return ret;
}
/*
* user defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
static struct key_type key_type_pkcs7 = {
.name = "pkcs7_test",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.preparse = pkcs7_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
.read = user_read,
};
/*
* Module stuff
*/
static int __init pkcs7_key_init(void)
{
return register_key_type(&key_type_pkcs7);
}
static void __exit pkcs7_key_cleanup(void)
{
unregister_key_type(&key_type_pkcs7);
}
module_init(pkcs7_key_init);
module_exit(pkcs7_key_cleanup);
This diff is collapsed.
/* PKCS#7 crypto data parser internal definitions
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/oid_registry.h>
#include <crypto/pkcs7.h>
#include "x509_parser.h"
#define kenter(FMT, ...) \
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
struct pkcs7_signed_info {
struct pkcs7_signed_info *next;
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
unsigned index;
bool trusted;
/* Message digest - the digest of the Content Data (or NULL) */
const void *msgdigest;
unsigned msgdigest_len;
/* Authenticated Attribute data (or NULL) */
unsigned authattrs_len;
const void *authattrs;
/* Issuing cert serial number and issuer's name */
const void *raw_serial;
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer;
/* Message signature.
*
* This contains the generated digest of _either_ the Content Data or
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
* the attributes contains the digest of the the Content Data within
* it.
*/
struct public_key_signature sig;
};
struct pkcs7_message {
struct x509_certificate *certs; /* Certificate list */
struct x509_certificate *crl; /* Revocation list */
struct pkcs7_signed_info *signed_infos;
/* Content Data (or NULL) */
enum OID data_type; /* Type of Data */
size_t data_len; /* Length of Data */
size_t data_hdrlen; /* Length of Data ASN.1 header */
const void *data; /* Content Data (or 0) */
};
/* Validate the trust chain of a PKCS#7 message.
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKCS7: "fmt
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/asn1.h>
#include <linux/key.h>
#include <keys/asymmetric-type.h>
#include "public_key.h"
#include "pkcs7_parser.h"
/**
* Check the trust on one PKCS#7 SignedInfo block.
*/
int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo,
struct key *trust_keyring)
{
struct public_key_signature *sig = &sinfo->sig;
struct x509_certificate *x509, *last = NULL, *p;
struct key *key;
bool trusted;
int ret;
kenter(",%u,", sinfo->index);
for (x509 = sinfo->signer; x509; x509 = x509->signer) {
if (x509->seen) {
if (x509->verified) {
trusted = x509->trusted;
goto verified;
}
kleave(" = -ENOKEY [cached]");
return -ENOKEY;
}
x509->seen = true;
/* Look to see if this certificate is present in the trusted
* keys.
*/
key = x509_request_asymmetric_key(trust_keyring, x509->subject,
x509->fingerprint);
if (!IS_ERR(key))
/* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust.
* Verify that the trusted variant can also validate
* the signature on the descendant.
*/
goto matched;
if (key == ERR_PTR(-ENOMEM))
return -ENOMEM;
/* Self-signed certificates form roots of their own, and if we
* don't know them, then we can't accept them.
*/
if (x509->next == x509) {
kleave(" = -ENOKEY [unknown self-signed]");
return -ENOKEY;
}
might_sleep();
last = x509;
sig = &last->sig;
}
/* No match - see if the root certificate has a signer amongst the
* trusted keys.
*/
if (!last || !last->issuer || !last->authority) {
kleave(" = -ENOKEY [no backref]");
return -ENOKEY;
}
key = x509_request_asymmetric_key(trust_keyring, last->issuer,
last->authority);
if (IS_ERR(key))
return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
x509 = last;
matched:
ret = verify_signature(key, sig);
trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
key_put(key);
if (ret < 0) {
if (ret == -ENOMEM)
return ret;
kleave(" = -EKEYREJECTED [verify %d]", ret);
return -EKEYREJECTED;
}
verified:
x509->verified = true;
for (p = sinfo->signer; p != x509; p = p->signer) {
p->verified = true;
p->trusted = trusted;
}
sinfo->trusted = trusted;
kleave(" = 0");
return 0;
}
/**
* pkcs7_validate_trust - Validate PKCS#7 trust chain
* @pkcs7: The PKCS#7 certificate to validate
* @trust_keyring: Signing certificates to use as starting points
* @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message intersects
* keys we already know and trust.
*
* Returns, in order of descending priority:
*
* (*) -EKEYREJECTED if a signature failed to match for which we have a valid
* key, or:
*
* (*) 0 if at least one signature chain intersects with the keys in the trust
* keyring, or:
*
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
* chain.
*
* (*) -ENOKEY if we couldn't find a match for any of the signature chains in
* the message.
*
* May also return -ENOMEM.
*/
int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring,
bool *_trusted)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *p;
int cached_ret = 0, ret;
for (p = pkcs7->certs; p; p = p->next)
p->seen = false;
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
if (ret < 0) {
if (ret == -ENOPKG) {
cached_ret = -ENOPKG;
} else if (ret == -ENOKEY) {
if (cached_ret == 0)
cached_ret = -ENOKEY;
} else {
return ret;
}
}
*_trusted |= sinfo->trusted;
}
return cached_ret;
}
EXPORT_SYMBOL_GPL(pkcs7_validate_trust);
/* Verify the signature on a PKCS#7 message.
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKCS7: "fmt
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/asn1.h>
#include <crypto/hash.h>
#include "public_key.h"
#include "pkcs7_parser.h"
/*
* Digest the relevant parts of the PKCS#7 data
*/
static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
void *digest;
int ret;
kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
!hash_algo_name[sinfo->sig.pkey_hash_algo])
return -ENOPKG;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
if (!digest)
goto error_no_desc;
desc = digest + digest_size;
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
/* Digest the message [RFC2315 9.3] */
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
if (ret < 0)
goto error;
pr_devel("MsgDigest = [%*ph]\n", 8, digest);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
* digest we just calculated.
*/
if (sinfo->msgdigest) {
u8 tag;
if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
pr_debug("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
pr_debug("Sig %u: Message digest doesn't match\n",
sinfo->index);
ret = -EKEYREJECTED;
goto error;
}
/* We then calculate anew, using the authenticated attributes
* as the contents of the digest instead. Note that we need to
* convert the attributes from a CONT.0 into a SET before we
* hash it.
*/
memset(digest, 0, sinfo->sig.digest_size);
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
tag = ASN1_CONS_BIT | ASN1_SET;
ret = crypto_shash_update(desc, &tag, 1);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, sinfo->authattrs,
sinfo->authattrs_len, digest);
if (ret < 0)
goto error;
pr_devel("AADigest = [%*ph]\n", 8, digest);
}
sinfo->sig.digest = digest;
digest = NULL;
error:
kfree(digest);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
return ret;
}
/*
* Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
* uses the issuer's name and the issuing certificate serial number for
* matching purposes. These must match the certificate issuer's name (not
* subject's name) and the certificate serial number [RFC 2315 6.7].
*/
static int pkcs7_find_key(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *x509;
unsigned certix = 1;
kenter("%u,%u,%u",
sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
/* I'm _assuming_ that the generator of the PKCS#7 message will
* encode the fields from the X.509 cert in the same way in the
* PKCS#7 message - but I can't be 100% sure of that. It's
* possible this will need element-by-element comparison.
*/
if (x509->raw_serial_size != sinfo->raw_serial_size ||
memcmp(x509->raw_serial, sinfo->raw_serial,
sinfo->raw_serial_size) != 0)
continue;
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
sinfo->index, certix);
if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
memcmp(x509->raw_issuer, sinfo->raw_issuer,
sinfo->raw_issuer_size) != 0) {
pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
sinfo->index);
continue;
}
if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
sinfo->index);
continue;
}
sinfo->signer = x509;
return 0;
}
pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
return -ENOKEY;
}
/*
* Verify the internal certificate chain as best we can.
*/
static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *x509 = sinfo->signer, *p;
int ret;
kenter("");
for (p = pkcs7->certs; p; p = p->next)
p->seen = false;
for (;;) {
pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
x509->seen = true;
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
pr_debug("- issuer %s\n", x509->issuer);
if (x509->authority)
pr_debug("- authkeyid %s\n", x509->authority);
if (!x509->authority ||
strcmp(x509->subject, x509->issuer) == 0) {
/* If there's no authority certificate specified, then
* the certificate must be self-signed and is the root
* of the chain. Likewise if the cert is its own
* authority.
*/
pr_debug("- no auth?\n");
if (x509->raw_subject_size != x509->raw_issuer_size ||
memcmp(x509->raw_subject, x509->raw_issuer,
x509->raw_issuer_size) != 0)
return 0;
ret = x509_check_signature(x509->pub, x509);
if (ret < 0)
return ret;
x509->signer = x509;
pr_debug("- self-signed\n");
return 0;
}
/* Look through the X.509 certificates in the PKCS#7 message's
* list to see if the next one is there.
*/
pr_debug("- want %s\n", x509->authority);
for (p = pkcs7->certs; p; p = p->next) {
pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
if (p->raw_subject_size == x509->raw_issuer_size &&
strcmp(p->fingerprint, x509->authority) == 0 &&
memcmp(p->raw_subject, x509->raw_issuer,
x509->raw_issuer_size) == 0)
goto found_issuer;
}
/* We didn't find the root of this chain */
pr_debug("- top\n");
return 0;
found_issuer:
pr_debug("- issuer %s\n", p->subject);
if (p->seen) {
pr_warn("Sig %u: X.509 chain contains loop\n",
sinfo->index);
return 0;
}
ret = x509_check_signature(p->pub, x509);
if (ret < 0)
return ret;
x509->signer = p;
if (x509 == p) {
pr_debug("- self-signed\n");
return 0;
}
x509 = p;
might_sleep();
}
}
/*
* Verify one signed information block from a PKCS#7 message.
*/
static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
int ret;
kenter(",%u", sinfo->index);
/* First of all, digest the data in the PKCS#7 message and the
* signed information block
*/
ret = pkcs7_digest(pkcs7, sinfo);
if (ret < 0)
return ret;
/* Find the key for the signature */
ret = pkcs7_find_key(pkcs7, sinfo);
if (ret < 0)
return ret;
pr_devel("Using X.509[%u] for sig %u\n",
sinfo->signer->index, sinfo->index);
/* Verify the PKCS#7 binary against the key */
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
if (ret < 0)
return ret;
pr_devel("Verified signature %u\n", sinfo->index);
/* Verify the internal certificate chain */
return pkcs7_verify_sig_chain(pkcs7, sinfo);
}
/**
* pkcs7_verify - Verify a PKCS#7 message
* @pkcs7: The PKCS#7 message to be verified
*/
int pkcs7_verify(struct pkcs7_message *pkcs7)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *x509;
int ret, n;
kenter("");
for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
pr_debug("X.509[%u] %s\n", n, x509->authority);
}
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_verify_one(pkcs7, sinfo);
if (ret < 0) {
kleave(" = %d", ret);
return ret;
}
}
kleave(" = 0");
return 0;
}
EXPORT_SYMBOL_GPL(pkcs7_verify);
This diff is collapsed.
/* PE Binary parser bits
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/verify_pefile.h>
#include <crypto/pkcs7.h>
#include <crypto/hash_info.h>
struct pefile_context {
unsigned header_size;
unsigned image_checksum_offset;
unsigned cert_dirent_offset;
unsigned n_data_dirents;
unsigned n_sections;
unsigned certs_size;
unsigned sig_offset;
unsigned sig_len;
const struct section_header *secs;
struct pkcs7_message *pkcs7;
/* PKCS#7 MS Individual Code Signing content */
const void *digest; /* Digest */
unsigned digest_len; /* Digest length */
enum hash_algo digest_algo; /* Digest algorithm */
};
#define kenter(FMT, ...) \
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
/*
* mscode_parser.c
*/
extern int mscode_parse(struct pefile_context *ctx);
......@@ -6,7 +6,7 @@ Certificate ::= SEQUENCE {
TBSCertificate ::= SEQUENCE {
version [ 0 ] Version DEFAULT,
serialNumber CertificateSerialNumber,
serialNumber CertificateSerialNumber ({ x509_note_serial }),
signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
issuer Name ({ x509_note_issuer }),
validity Validity,
......
......@@ -11,6 +11,7 @@
#define pr_fmt(fmt) "X.509: "fmt
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
......@@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert);
}
}
EXPORT_SYMBOL_GPL(x509_free_certificate);
/*
* Parse an X.509 certificate
......@@ -97,6 +99,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
error_no_cert:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(x509_cert_parse);
/*
* Note an OID when we find one for later processing when we know how
......@@ -210,6 +213,19 @@ int x509_note_signature(void *context, size_t hdrlen,
return 0;
}
/*
* Note the certificate serial number
*/
int x509_note_serial(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_serial = value;
ctx->cert->raw_serial_size = vlen;
return 0;
}
/*
* Note some of the name segments from which we'll fabricate a name.
*/
......@@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_issuer = value;
ctx->cert->raw_issuer_size = vlen;
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
}
......@@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_subject = value;
ctx->cert->raw_subject_size = vlen;
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
}
......
......@@ -14,7 +14,9 @@
struct x509_certificate {
struct x509_certificate *next;
struct x509_certificate *signer; /* Certificate that signed this one */
struct public_key *pub; /* Public key details */
struct public_key_signature sig; /* Signature parameters */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
char *fingerprint; /* Key fingerprint as hex */
......@@ -25,7 +27,16 @@ struct x509_certificate {
unsigned tbs_size; /* Size of signed data */
unsigned raw_sig_size; /* Size of sigature */
const void *raw_sig; /* Signature data */
struct public_key_signature sig; /* Signature parameters */
const void *raw_serial; /* Raw serial number in ASN.1 */
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer; /* Raw issuer name in ASN.1 */
const void *raw_subject; /* Raw subject name in ASN.1 */
unsigned raw_subject_size;
unsigned index;
bool seen; /* Infinite recursion prevention */
bool verified;
bool trusted;
};
/*
......
......@@ -18,11 +18,86 @@
#include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <keys/system_keyring.h>
#include <crypto/hash.h>
#include "asymmetric_keys.h"
#include "public_key.h"
#include "x509_parser.h"
static bool use_builtin_keys;
static char *ca_keyid;
#ifndef MODULE
static int __init ca_keys_setup(char *str)
{
if (!str) /* default system keyring */
return 1;
if (strncmp(str, "id:", 3) == 0)
ca_keyid = str; /* owner key 'id:xxxxxx' */
else if (strcmp(str, "builtin") == 0)
use_builtin_keys = true;
return 1;
}
__setup("ca_keys=", ca_keys_setup);
#endif
/**
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
* @keyring: The keys to search.
* @subject: The name of the subject to whom the key belongs.
* @key_id: The subject key ID as a hex string.
*
* Find a key in the given keyring by subject name and key ID. These might,
* for instance, be the issuer name and the authority key ID of an X.509
* certificate that needs to be verified.
*/
struct key *x509_request_asymmetric_key(struct key *keyring,
const char *subject,
const char *key_id)
{
key_ref_t key;
size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
char *id;
/* Construct an identifier "<subjname>:<keyid>". */
id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
if (!id)
return ERR_PTR(-ENOMEM);
memcpy(id, subject, subject_len);
id[subject_len + 0] = ':';
id[subject_len + 1] = ' ';
memcpy(id + subject_len + 2, key_id, key_id_len);
id[subject_len + 2 + key_id_len] = 0;
pr_debug("Look up: \"%s\"\n", id);
key = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, id);
if (IS_ERR(key))
pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
kfree(id);
if (IS_ERR(key)) {
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return ERR_CAST(key);
}
}
pr_devel("<==%s() = 0 [%x]\n", __func__,
key_serial(key_ref_to_ptr(key)));
return key_ref_to_ptr(key);
}
EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
/*
* Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature.
......@@ -102,6 +177,38 @@ int x509_check_signature(const struct public_key *pub,
}
EXPORT_SYMBOL_GPL(x509_check_signature);
/*
* Check the new certificate against the ones in the trust keyring. If one of
* those is the signing key and validates the new certificate, then mark the
* new certificate as being trusted.
*
* Return 0 if the new certificate was successfully validated, 1 if we couldn't
* find a matching parent certificate in the trusted list and an error if there
* is a matching certificate but the signature check fails.
*/
static int x509_validate_trust(struct x509_certificate *cert,
struct key *trust_keyring)
{
struct key *key;
int ret = 1;
if (!trust_keyring)
return -EOPNOTSUPP;
if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
return -EPERM;
key = x509_request_asymmetric_key(trust_keyring,
cert->issuer, cert->authority);
if (!IS_ERR(key)) {
if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = x509_check_signature(key->payload.data, cert);
key_put(key);
}
return ret;
}
/*
* Attempt to parse a data blob for a key as an X509 certificate.
*/
......@@ -155,9 +262,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
/* Check the signature on the key if it appears to be self-signed */
if (!cert->authority ||
strcmp(cert->fingerprint, cert->authority) == 0) {
ret = x509_check_signature(cert->pub, cert);
ret = x509_check_signature(cert->pub, cert); /* self-signed */
if (ret < 0)
goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
if (!ret)
prep->trusted = 1;
}
/* Propose a description */
......@@ -177,7 +288,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
__module_get(public_key_subtype.owner);
prep->type_data[0] = &public_key_subtype;
prep->type_data[1] = cert->fingerprint;
prep->payload = cert->pub;
prep->payload[0] = cert->pub;
prep->description = desc;
prep->quotalen = 100;
......
......@@ -28,6 +28,7 @@
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <linux/security.h>
#include <generated/utsrelease.h>
......@@ -303,12 +304,17 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
if (rc != size) {
if (rc > 0)
rc = -EIO;
vfree(buf);
return rc;
goto fail;
}
rc = security_kernel_fw_from_file(file, buf, size);
if (rc)
goto fail;
fw_buf->data = buf;
fw_buf->size = size;
return 0;
fail:
vfree(buf);
return rc;
}
static int fw_get_filesystem_firmware(struct device *device,
......@@ -612,6 +618,7 @@ static ssize_t firmware_loading_store(struct device *dev,
{
struct firmware_priv *fw_priv = to_firmware_priv(dev);
struct firmware_buf *fw_buf;
ssize_t written = count;
int loading = simple_strtol(buf, NULL, 10);
int i;
......@@ -635,6 +642,8 @@ static ssize_t firmware_loading_store(struct device *dev,
break;
case 0:
if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
int rc;
set_bit(FW_STATUS_DONE, &fw_buf->status);
clear_bit(FW_STATUS_LOADING, &fw_buf->status);
......@@ -644,10 +653,23 @@ static ssize_t firmware_loading_store(struct device *dev,
* see the mapped 'buf->data' once the loading
* is completed.
* */
if (fw_map_pages_buf(fw_buf))
rc = fw_map_pages_buf(fw_buf);
if (rc)
dev_err(dev, "%s: map pages failed\n",
__func__);
else
rc = security_kernel_fw_from_file(NULL,
fw_buf->data, fw_buf->size);
/*
* Same logic as fw_load_abort, only the DONE bit
* is ignored and we set ABORT only on failure.
*/
list_del_init(&fw_buf->pending_list);
if (rc) {
set_bit(FW_STATUS_ABORT, &fw_buf->status);
written = rc;
}
complete_all(&fw_buf->completion);
break;
}
......@@ -661,7 +683,7 @@ static ssize_t firmware_loading_store(struct device *dev,
}
out:
mutex_unlock(&fw_lock);
return count;
return written;
}
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
......
......@@ -491,11 +491,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
int tpm_get_timeouts(struct tpm_chip *chip)
{
struct tpm_cmd_t tpm_cmd;
struct timeout_t *timeout_cap;
unsigned long new_timeout[4];
unsigned long old_timeout[4];
struct duration_t *duration_cap;
ssize_t rc;
u32 timeout;
unsigned int scale = 1;
tpm_cmd.header.in = tpm_getcap_header;
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
......@@ -529,25 +528,46 @@ int tpm_get_timeouts(struct tpm_chip *chip)
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
return -EINVAL;
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
/* Don't overwrite default if value is 0 */
timeout = be32_to_cpu(timeout_cap->a);
if (timeout && timeout < 1000) {
/* timeouts in msec rather usec */
scale = 1000;
chip->vendor.timeout_adjusted = true;
old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
memcpy(new_timeout, old_timeout, sizeof(new_timeout));
/*
* Provide ability for vendor overrides of timeout values in case
* of misreporting.
*/
if (chip->ops->update_timeouts != NULL)
chip->vendor.timeout_adjusted =
chip->ops->update_timeouts(chip, new_timeout);
if (!chip->vendor.timeout_adjusted) {
/* Don't overwrite default if value is 0 */
if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
int i;
/* timeouts in msec rather usec */
for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
new_timeout[i] *= 1000;
chip->vendor.timeout_adjusted = true;
}
}
/* Report adjusted timeouts */
if (chip->vendor.timeout_adjusted) {
dev_info(chip->dev,
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
old_timeout[0], new_timeout[0],
old_timeout[1], new_timeout[1],
old_timeout[2], new_timeout[2],
old_timeout[3], new_timeout[3]);
}
if (timeout)
chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale);
timeout = be32_to_cpu(timeout_cap->b);
if (timeout)
chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale);
timeout = be32_to_cpu(timeout_cap->c);
if (timeout)
chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale);
timeout = be32_to_cpu(timeout_cap->d);
if (timeout)
chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale);
chip->vendor.timeout_a = usecs_to_jiffies(new_timeout[0]);
chip->vendor.timeout_b = usecs_to_jiffies(new_timeout[1]);
chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
duration:
tpm_cmd.header.in = tpm_getcap_header;
......@@ -991,13 +1011,13 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
int err, total = 0, retries = 5;
u8 *dest = out;
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
chip = tpm_chip_find_get(chip_num);
if (chip == NULL)
return -ENODEV;
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
do {
tpm_cmd.header.in = tpm_getrandom_header;
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
......@@ -1016,6 +1036,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
tpm_chip_put(chip);
return total ? total : -EIO;
}
EXPORT_SYMBOL_GPL(tpm_get_random);
......@@ -1095,7 +1116,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
goto del_misc;
if (tpm_add_ppi(&dev->kobj))
goto del_misc;
goto del_sysfs;
chip->bios_dir = tpm_bios_log_setup(chip->devname);
......@@ -1106,6 +1127,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
return chip;
del_sysfs:
tpm_sysfs_del_device(chip);
del_misc:
tpm_dev_del_device(chip);
put_device:
......
......@@ -235,7 +235,6 @@ static int tpm_bios_measurements_release(struct inode *inode,
static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
{
int len = 0;
int i;
char *eventname;
struct tcpa_event *event = v;
unsigned char *event_entry =
......@@ -251,8 +250,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
seq_printf(m, "%2d ", event->pcr_index);
/* 2nd: SHA1 */
for (i = 0; i < 20; i++)
seq_printf(m, "%02x", event->pcr_value[i]);
seq_printf(m, "%20phN", event->pcr_value);
/* 3rd: event type identifier */
seq_printf(m, " %02x", event->event_type);
......
......@@ -714,6 +714,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
tpm_get_timeouts(chip);
tpm_do_selftest(chip);
dev_info(chip->dev, "TPM I2C Initialized\n");
return 0;
......
......@@ -373,6 +373,36 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
return rc;
}
struct tis_vendor_timeout_override {
u32 did_vid;
unsigned long timeout_us[4];
};
static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
/* Atmel 3204 */
{ 0x32041114, { (TIS_SHORT_TIMEOUT*1000), (TIS_LONG_TIMEOUT*1000),
(TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } },
};
static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
unsigned long *timeout_cap)
{
int i;
u32 did_vid;
did_vid = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
if (vendor_timeout_overrides[i].did_vid != did_vid)
continue;
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
sizeof(vendor_timeout_overrides[i].timeout_us));
return true;
}
return false;
}
/*
* Early probing for iTPM with STS_DATA_EXPECT flaw.
* Try sending command without itpm flag set and if that
......@@ -437,6 +467,7 @@ static const struct tpm_class_ops tpm_tis = {
.recv = tpm_tis_recv,
.send = tpm_tis_send,
.cancel = tpm_tis_ready,
.update_timeouts = tpm_tis_update_timeouts,
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_canceled = tpm_tis_req_canceled,
......
......@@ -1216,7 +1216,7 @@ EXPORT_SYMBOL(install_exec_creds);
/*
* determine how safe it is to execute the proposed program
* - the caller must hold ->cred_guard_mutex to protect against
* PTRACE_ATTACH
* PTRACE_ATTACH or seccomp thread-sync
*/
static void check_unsafe_exec(struct linux_binprm *bprm)
{
......@@ -1234,7 +1234,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
* This isn't strictly necessary, but it makes it harder for LSMs to
* mess up.
*/
if (current->no_new_privs)
if (task_no_new_privs(current))
bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
t = p;
......@@ -1272,7 +1272,7 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm->cred->egid = current_egid();
if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
!current->no_new_privs &&
!task_no_new_privs(current) &&
kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
/* Set-uid? */
......
......@@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
static struct key_type key_type_id_resolver = {
.name = "id_resolver",
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
......@@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
desc, "", 0, idmap);
mutex_unlock(&idmap->idmap_mutex);
}
if (!IS_ERR(rkey))
set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
kfree(desc);
return rkey;
......@@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = {
static struct key_type key_type_id_resolver_legacy = {
.name = "id_legacy",
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
......
......@@ -297,15 +297,11 @@ static void render_cap_t(struct seq_file *m, const char *header,
seq_puts(m, header);
CAP_FOR_EACH_U32(__capi) {
seq_printf(m, "%08x",
a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]);
a->cap[CAP_LAST_U32 - __capi]);
}
seq_putc(m, '\n');
}
/* Remove non-existent capabilities */
#define NORM_CAPS(v) (v.cap[CAP_TO_INDEX(CAP_LAST_CAP)] &= \
CAP_TO_MASK(CAP_LAST_CAP + 1) - 1)
static inline void task_cap(struct seq_file *m, struct task_struct *p)
{
const struct cred *cred;
......@@ -319,11 +315,6 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p)
cap_bset = cred->cap_bset;
rcu_read_unlock();
NORM_CAPS(cap_inheritable);
NORM_CAPS(cap_permitted);
NORM_CAPS(cap_effective);
NORM_CAPS(cap_bset);
render_cap_t(m, "CapInh:\t", &cap_inheritable);
render_cap_t(m, "CapPrm:\t", &cap_permitted);
render_cap_t(m, "CapEff:\t", &cap_effective);
......
/* PKCS#7 crypto data parser
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
struct key;
struct pkcs7_message;
/*
* pkcs7_parser.c
*/
extern struct pkcs7_message *pkcs7_parse_message(const void *data,
size_t datalen);
extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_datalen,
bool want_wrapper);
/*
* pkcs7_trust.c
*/
extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring,
bool *_trusted);
/*
* pkcs7_verify.c
*/
extern int pkcs7_verify(struct pkcs7_message *pkcs7);
......@@ -98,4 +98,8 @@ struct key;
extern int verify_signature(const struct key *key,
const struct public_key_signature *sig);
extern struct key *x509_request_asymmetric_key(struct key *keyring,
const char *issuer,
const char *key_id);
#endif /* _LINUX_PUBLIC_KEY_H */
......@@ -16,7 +16,8 @@
extern struct key_type key_type_big_key;
extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int big_key_preparse(struct key_preparsed_payload *prep);
extern void big_key_free_preparse(struct key_preparsed_payload *prep);
extern void big_key_revoke(struct key *key);
extern void big_key_destroy(struct key *key);
extern void big_key_describe(const struct key *big_key, struct seq_file *m);
......
......@@ -17,7 +17,15 @@
#include <linux/key.h>
extern struct key *system_trusted_keyring;
static inline struct key *get_system_trusted_keyring(void)
{
return system_trusted_keyring;
}
#else
static inline struct key *get_system_trusted_keyring(void)
{
return NULL;
}
#endif
#endif /* _KEYS_SYSTEM_KEYRING_H */
......@@ -37,7 +37,8 @@ extern struct key_type key_type_logon;
struct key_preparsed_payload;
extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int user_preparse(struct key_preparsed_payload *prep);
extern void user_free_preparse(struct key_preparsed_payload *prep);
extern int user_update(struct key *key, struct key_preparsed_payload *prep);
extern int user_match(const struct key *key, const void *criterion);
extern void user_revoke(struct key *key);
......
......@@ -78,8 +78,11 @@ extern const kernel_cap_t __cap_init_eff_set;
# error Fix up hand-coded capability macro initializers
#else /* HAND-CODED capability initializers */
#define CAP_LAST_U32 ((_KERNEL_CAPABILITY_U32S) - 1)
#define CAP_LAST_U32_VALID_MASK (CAP_TO_MASK(CAP_LAST_CAP + 1) -1)
# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
# define CAP_FULL_SET ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }})
# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
| CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
CAP_FS_MASK_B1 } })
......
......@@ -19,6 +19,7 @@ extern int ima_file_check(struct file *file, int mask);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
extern int ima_module_check(struct file *file);
extern int ima_fw_from_file(struct file *file, char *buf, size_t size);
#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
......@@ -46,6 +47,11 @@ static inline int ima_module_check(struct file *file)
return 0;
}
static inline int ima_fw_from_file(struct file *file, char *buf, size_t size)
{
return 0;
}
#endif /* CONFIG_IMA */
#ifdef CONFIG_IMA_APPRAISE
......
......@@ -41,10 +41,11 @@ struct key_construction {
struct key_preparsed_payload {
char *description; /* Proposed key description (or NULL) */
void *type_data[2]; /* Private key-type data */
void *payload; /* Proposed payload */
void *payload[2]; /* Proposed payload */
const void *data; /* Raw data */
size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */
time_t expiry; /* Expiry time of key */
bool trusted; /* True if key is trusted */
};
......@@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key,
return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
}
extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
#endif /* CONFIG_KEYS */
#endif /* _LINUX_KEY_TYPE_H */
......@@ -170,6 +170,8 @@ struct key {
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
/* the key type and key description string
* - the desc is used to match a key against search criteria
......
......@@ -52,9 +52,15 @@ enum OID {
OID_md4, /* 1.2.840.113549.2.4 */
OID_md5, /* 1.2.840.113549.2.5 */
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
/* Microsoft Authenticode & Software Publishing */
OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */
OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
OID_sha1, /* 1.3.14.3.2.26 */
OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
/* Distinguished Name attribute IDs [RFC 2256] */
OID_commonName, /* 2.5.4.3 */
......
This diff is collapsed.
......@@ -1304,13 +1304,12 @@ struct task_struct {
* execve */
unsigned in_iowait:1;
/* task may not gain privileges */
unsigned no_new_privs:1;
/* Revert to default priority/policy when forking */
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned long atomic_flags; /* Flags needing atomic access. */
pid_t pid;
pid_t tgid;
......@@ -1962,6 +1961,19 @@ static inline void memalloc_noio_restore(unsigned int flags)
current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
}
/* Per-process atomic flags. */
#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */
static inline bool task_no_new_privs(struct task_struct *p)
{
return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
}
static inline void task_set_no_new_privs(struct task_struct *p)
{
set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
}
/*
* task->jobctl flags
*/
......
......@@ -3,6 +3,8 @@
#include <uapi/linux/seccomp.h>
#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC)
#ifdef CONFIG_SECCOMP
#include <linux/thread_info.h>
......@@ -14,11 +16,11 @@ struct seccomp_filter;
*
* @mode: indicates one of the valid values above for controlled
* system calls available to a process.
* @filter: The metadata and ruleset for determining what system calls
* are allowed for a task.
* @filter: must always point to a valid seccomp-filter or NULL as it is
* accessed without locking during system call entry.
*
* @filter must only be accessed from the context of current as there
* is no locking.
* is no read locking.
*/
struct seccomp {
int mode;
......
......@@ -702,6 +702,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inode points to the inode to use as a reference.
* The current task must be the one that nominated @inode.
* Return 0 if successful.
* @kernel_fw_from_file:
* Load firmware from userspace (not called for built-in firmware).
* @file contains the file structure pointing to the file containing
* the firmware to load. This argument will be NULL if the firmware
* was loaded via the uevent-triggered blob-based interface exposed
* by CONFIG_FW_LOADER_USER_HELPER.
* @buf pointer to buffer containing firmware contents.
* @size length of the firmware contents.
* Return 0 if permission is granted.
* @kernel_module_request:
* Ability to trigger the kernel to automatically upcall to userspace for
* userspace to load a kernel module with the given name.
......@@ -1565,6 +1574,7 @@ struct security_operations {
void (*cred_transfer)(struct cred *new, const struct cred *old);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size);
int (*kernel_module_request)(char *kmod_name);
int (*kernel_module_from_file)(struct file *file);
int (*task_fix_setuid) (struct cred *new, const struct cred *old,
......@@ -1837,6 +1847,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
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_fw_from_file(struct file *file, char *buf, size_t size);
int security_kernel_module_request(char *kmod_name);
int security_kernel_module_from_file(struct file *file);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
......@@ -2363,6 +2374,12 @@ static inline int security_kernel_create_files_as(struct cred *cred,
return 0;
}
static inline int security_kernel_fw_from_file(struct file *file,
char *buf, size_t size)
{
return 0;
}
static inline int security_kernel_module_request(char *kmod_name)
{
return 0;
......
......@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
const char __user *uargs);
#endif
......@@ -39,6 +39,9 @@ struct tpm_class_ops {
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
void (*cancel) (struct tpm_chip *chip);
u8 (*status) (struct tpm_chip *chip);
bool (*update_timeouts)(struct tpm_chip *chip,
unsigned long *timeout_cap);
};
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
......
/* Signed PE file verification
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_VERIFY_PEFILE_H
#define _LINUX_VERIFY_PEFILE_H
extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, bool *_trusted);
#endif /* _LINUX_VERIFY_PEFILE_H */
......@@ -139,7 +139,7 @@ struct netlbl_lsm_cache {
};
/**
* struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap
* struct netlbl_lsm_catmap - NetLabel LSM secattr category bitmap
* @startbit: the value of the lowest order bit in the bitmap
* @bitmap: the category bitmap
* @next: pointer to the next bitmap "node" or NULL
......@@ -162,10 +162,10 @@ struct netlbl_lsm_cache {
#define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \
NETLBL_CATMAP_MAPCNT)
#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01
struct netlbl_lsm_secattr_catmap {
struct netlbl_lsm_catmap {
u32 startbit;
NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
struct netlbl_lsm_secattr_catmap *next;
struct netlbl_lsm_catmap *next;
};
/**
......@@ -209,7 +209,7 @@ struct netlbl_lsm_secattr {
struct netlbl_lsm_cache *cache;
struct {
struct {
struct netlbl_lsm_secattr_catmap *cat;
struct netlbl_lsm_catmap *cat;
u32 lvl;
} mls;
u32 secid;
......@@ -258,7 +258,7 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
}
/**
* netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap
* netlbl_catmap_alloc - Allocate a LSM secattr catmap
* @flags: memory allocation flags
*
* Description:
......@@ -266,30 +266,28 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
* on failure.
*
*/
static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc(
gfp_t flags)
static inline struct netlbl_lsm_catmap *netlbl_catmap_alloc(gfp_t flags)
{
return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags);
return kzalloc(sizeof(struct netlbl_lsm_catmap), flags);
}
/**
* netlbl_secattr_catmap_free - Free a LSM secattr catmap
* netlbl_catmap_free - Free a LSM secattr catmap
* @catmap: the category bitmap
*
* Description:
* Free a LSM secattr catmap.
*
*/
static inline void netlbl_secattr_catmap_free(
struct netlbl_lsm_secattr_catmap *catmap)
static inline void netlbl_catmap_free(struct netlbl_lsm_catmap *catmap)
{
struct netlbl_lsm_secattr_catmap *iter;
struct netlbl_lsm_catmap *iter;
do {
while (catmap) {
iter = catmap;
catmap = catmap->next;
kfree(iter);
} while (catmap);
}
}
/**
......@@ -321,7 +319,7 @@ static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
if (secattr->flags & NETLBL_SECATTR_CACHE)
netlbl_secattr_cache_free(secattr->cache);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT)
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
netlbl_catmap_free(secattr->attr.mls.cat);
}
/**
......@@ -390,17 +388,22 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
/*
* LSM security attribute operations
*/
int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
u32 offset);
int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
u32 offset);
int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
u32 bit,
gfp_t flags);
int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
u32 start,
u32 end,
gfp_t flags);
int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset);
int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset);
int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
u32 *offset,
unsigned long *bitmap);
int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
u32 bit,
gfp_t flags);
int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
u32 start,
u32 end,
gfp_t flags);
int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
u32 offset,
unsigned long bitmap,
gfp_t flags);
/*
* LSM protocol operations (NetLabel LSM/kernel API)
......@@ -492,30 +495,39 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
{
return -ENOSYS;
}
static inline int netlbl_secattr_catmap_walk(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap,
u32 offset)
{
return -ENOENT;
}
static inline int netlbl_secattr_catmap_walk_rng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
static inline int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap,
u32 offset)
{
return -ENOENT;
}
static inline int netlbl_secattr_catmap_setbit(
struct netlbl_lsm_secattr_catmap *catmap,
u32 bit,
gfp_t flags)
static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
u32 *offset,
unsigned long *bitmap)
{
return 0;
}
static inline int netlbl_secattr_catmap_setrng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 start,
u32 end,
gfp_t flags)
static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
u32 bit,
gfp_t flags)
{
return 0;
}
static inline int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
u32 start,
u32 end,
gfp_t flags)
{
return 0;
}
static int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
u32 offset,
unsigned long bitmap,
gfp_t flags)
{
return 0;
}
......
......@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
#define __NR_renameat2 276
__SYSCALL(__NR_renameat2, sys_renameat2)
#define __NR_seccomp 277
__SYSCALL(__NR_seccomp, sys_seccomp)
#undef __NR_syscalls
#define __NR_syscalls 277
#define __NR_syscalls 278
/*
* All syscalls below here should go away really,
......
......@@ -10,6 +10,13 @@
#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */
#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
/* Valid operations for seccomp syscall. */
#define SECCOMP_SET_MODE_STRICT 0
#define SECCOMP_SET_MODE_FILTER 1
/* Valid flags for SECCOMP_SET_MODE_FILTER */
#define SECCOMP_FILTER_FLAG_TSYNC 1
/*
* All BPF programs must return a 32-bit value.
* The bottom 16-bits are for optional return data.
......
......@@ -1677,7 +1677,7 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
audit_log_format(ab, " %s=", prefix);
CAP_FOR_EACH_U32(i) {
audit_log_format(ab, "%08x",
cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
cap->cap[CAP_LAST_U32 - i]);
}
}
......
......@@ -258,6 +258,10 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
i++;
}
effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
new = prepare_creds();
if (!new)
return -ENOMEM;
......
......@@ -315,6 +315,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
goto free_ti;
tsk->stack = ti;
#ifdef CONFIG_SECCOMP
/*
* We must handle setting up seccomp filters once we're under
* the sighand lock in case orig has changed between now and
* then. Until then, filter must be NULL to avoid messing up
* the usage counts on the error path calling free_task.
*/
tsk->seccomp.filter = NULL;
#endif
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
......@@ -1081,6 +1090,39 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
return 0;
}
static void copy_seccomp(struct task_struct *p)
{
#ifdef CONFIG_SECCOMP
/*
* Must be called with sighand->lock held, which is common to
* all threads in the group. Holding cred_guard_mutex is not
* needed because this new task is not yet running and cannot
* be racing exec.
*/
BUG_ON(!spin_is_locked(&current->sighand->siglock));
/* Ref-count the new filter user, and assign it. */
get_seccomp_filter(current);
p->seccomp = current->seccomp;
/*
* Explicitly enable no_new_privs here in case it got set
* between the task_struct being duplicated and holding the
* sighand lock. The seccomp state and nnp must be in sync.
*/
if (task_no_new_privs(current))
task_set_no_new_privs(p);
/*
* If the parent gained a seccomp mode after copying thread
* flags and between before we held the sighand lock, we have
* to manually enable the seccomp thread flag here.
*/
if (p->seccomp.mode != SECCOMP_MODE_DISABLED)
set_tsk_thread_flag(p, TIF_SECCOMP);
#endif
}
SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
{
current->clear_child_tid = tidptr;
......@@ -1195,7 +1237,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto fork_out;
ftrace_graph_init_task(p);
get_seccomp_filter(p);
rt_mutex_init_task(p);
......@@ -1434,6 +1475,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
spin_lock(&current->sighand->siglock);
/*
* Copy seccomp details explicitly here, in case they were changed
* before holding sighand lock.
*/
copy_seccomp(p);
/*
* Process group and session signals need to be delivered to just the
* parent before the fork or both the parent and the child after the
......
This diff is collapsed.
......@@ -1990,12 +1990,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
if (arg2 != 1 || arg3 || arg4 || arg5)
return -EINVAL;
current->no_new_privs = 1;
task_set_no_new_privs(current);
break;
case PR_GET_NO_NEW_PRIVS:
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
return current->no_new_privs ? 1 : 0;
return task_no_new_privs(current) ? 1 : 0;
case PR_GET_THP_DISABLE:
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
......
......@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);
/* compare kernel pointers */
cond_syscall(sys_kcmp);
/* operate on Secure Computing state */
cond_syscall(sys_seccomp);
......@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void)
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
} else {
set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description);
key_ref_put(key);
......
......@@ -451,7 +451,8 @@ config MPILIB
config SIGNATURE
tristate
depends on KEYS && CRYPTO
depends on KEYS
select CRYPTO
select CRYPTO_SHA1
select MPILIB
help
......
......@@ -8,6 +8,7 @@
#include <linux/key-type.h>
#include <keys/ceph-type.h>
#include <keys/user-type.h>
#include <linux/ceph/decode.h>
#include "crypto.h"
......@@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
}
}
static int ceph_key_instantiate(struct key *key,
struct key_preparsed_payload *prep)
static int ceph_key_preparse(struct key_preparsed_payload *prep)
{
struct ceph_crypto_key *ckey;
size_t datalen = prep->datalen;
......@@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key,
if (datalen <= 0 || datalen > 32767 || !prep->data)
goto err;
ret = key_payload_reserve(key, datalen);
if (ret < 0)
goto err;
ret = -ENOMEM;
ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
if (!ckey)
......@@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key,
if (ret < 0)
goto err_ckey;
key->payload.data = ckey;
prep->payload[0] = ckey;
prep->quotalen = datalen;
return 0;
err_ckey:
......@@ -459,12 +456,15 @@ static int ceph_key_instantiate(struct key *key,
return ret;
}
static int ceph_key_match(const struct key *key, const void *description)
static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
{
return strcmp(key->description, description) == 0;
struct ceph_crypto_key *ckey = prep->payload[0];
ceph_crypto_key_destroy(ckey);
kfree(ckey);
}
static void ceph_key_destroy(struct key *key) {
static void ceph_key_destroy(struct key *key)
{
struct ceph_crypto_key *ckey = key->payload.data;
ceph_crypto_key_destroy(ckey);
......@@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) {
struct key_type key_type_ceph = {
.name = "ceph",
.instantiate = ceph_key_instantiate,
.match = ceph_key_match,
.preparse = ceph_key_preparse,
.free_preparse = ceph_key_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.destroy = ceph_key_destroy,
};
......
......@@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache;
#define DNS_ERRORNO_OPTION "dnserror"
/*
* Instantiate a user defined key for dns_resolver.
* Preparse instantiation data for a dns_resolver key.
*
* The data must be a NUL-terminated string, with the NUL char accounted in
* datalen.
......@@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache;
* "ip1,ip2,...#foo=bar"
*/
static int
dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
dns_resolver_preparse(struct key_preparsed_payload *prep)
{
struct user_key_payload *upayload;
unsigned long derrno;
int ret;
size_t datalen = prep->datalen, result_len = 0;
int datalen = prep->datalen, result_len = 0;
const char *data = prep->data, *end, *opt;
kenter("%%%d,%s,'%*.*s',%zu",
key->serial, key->description,
(int)datalen, (int)datalen, data, datalen);
kenter("'%*.*s',%u", datalen, datalen, data, datalen);
if (datalen <= 1 || !data || data[datalen - 1] != '\0')
return -EINVAL;
......@@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
opt_len = next_opt - opt;
if (!opt_len) {
printk(KERN_WARNING
"Empty option to dns_resolver key %d\n",
key->serial);
"Empty option to dns_resolver key\n");
return -EINVAL;
}
......@@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
goto bad_option_value;
kdebug("dns error no. = %lu", derrno);
key->type_data.x[0] = -derrno;
prep->type_data[0] = ERR_PTR(-derrno);
continue;
}
bad_option_value:
printk(KERN_WARNING
"Option '%*.*s' to dns_resolver key %d:"
"Option '%*.*s' to dns_resolver key:"
" bad/missing value\n",
opt_nlen, opt_nlen, opt, key->serial);
opt_nlen, opt_nlen, opt);
return -EINVAL;
} while (opt = next_opt + 1, opt < end);
}
/* don't cache the result if we're caching an error saying there's no
* result */
if (key->type_data.x[0]) {
kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
if (prep->type_data[0]) {
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
return 0;
}
kdebug("store result");
ret = key_payload_reserve(key, result_len);
if (ret < 0)
return -EINVAL;
prep->quotalen = result_len;
upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
if (!upayload) {
......@@ -159,12 +154,22 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
upayload->datalen = result_len;
memcpy(upayload->data, data, result_len);
upayload->data[result_len] = '\0';
rcu_assign_pointer(key->payload.data, upayload);
prep->payload[0] = upayload;
kleave(" = 0");
return 0;
}
/*
* Clean up the preparse data
*/
static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
{
pr_devel("==>%s()\n", __func__);
kfree(prep->payload[0]);
}
/*
* The description is of the form "[<type>:]<domain_name>"
*
......@@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key,
struct key_type key_type_dns_resolver = {
.name = "dns_resolver",
.instantiate = dns_resolver_instantiate,
.preparse = dns_resolver_preparse,
.free_preparse = dns_resolver_free_preparse,
.instantiate = generic_key_instantiate,
.match = dns_resolver_match,
.revoke = user_revoke,
.destroy = user_destroy,
......
......@@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
}
down_read(&rkey->sem);
set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
rkey->perm |= KEY_USR_VIEW;
ret = key_validate(rkey);
......
......@@ -890,8 +890,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
}
for (;;) {
host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
host_spot + 1);
host_spot = netlbl_catmap_walk(secattr->attr.mls.cat,
host_spot + 1);
if (host_spot < 0)
break;
......@@ -973,7 +973,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
return -EPERM;
break;
}
ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
host_spot,
GFP_ATOMIC);
if (ret_val != 0)
......@@ -1039,8 +1039,7 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
u32 cat_iter = 0;
for (;;) {
cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
cat + 1);
cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1);
if (cat < 0)
break;
if ((cat_iter + 2) > net_cat_len)
......@@ -1075,9 +1074,9 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
u32 iter;
for (iter = 0; iter < net_cat_len; iter += 2) {
ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
get_unaligned_be16(&net_cat[iter]),
GFP_ATOMIC);
ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
get_unaligned_be16(&net_cat[iter]),
GFP_ATOMIC);
if (ret_val != 0)
return ret_val;
}
......@@ -1155,8 +1154,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
return -ENOSPC;
for (;;) {
iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
iter + 1);
iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1);
if (iter < 0)
break;
cat_size += (iter == 0 ? 0 : sizeof(u16));
......@@ -1164,8 +1162,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
return -ENOSPC;
array[array_cnt++] = iter;
iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat,
iter);
iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter);
if (iter < 0)
return -EFAULT;
cat_size += sizeof(u16);
......@@ -1217,10 +1214,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
else
cat_low = 0;
ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat,
cat_low,
cat_high,
GFP_ATOMIC);
ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat,
cat_low,
cat_high,
GFP_ATOMIC);
if (ret_val != 0)
return ret_val;
}
......@@ -1335,16 +1332,12 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) {
secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM;
ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
&tag[4],
tag_len - 4,
secattr);
if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
netlbl_catmap_free(secattr->attr.mls.cat);
return ret_val;
}
......@@ -1430,16 +1423,12 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) {
secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM;
ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
&tag[4],
tag_len - 4,
secattr);
if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
netlbl_catmap_free(secattr->attr.mls.cat);
return ret_val;
}
......@@ -1524,16 +1513,12 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) {
secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM;
ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
&tag[4],
tag_len - 4,
secattr);
if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
netlbl_catmap_free(secattr->attr.mls.cat);
return ret_val;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -2,4 +2,3 @@ hostprogs-y := genheaders
HOST_EXTRACFLAGS += -Isecurity/selinux/include
always := $(hostprogs-y)
clean-files := $(hostprogs-y)
......@@ -2,4 +2,4 @@ hostprogs-y := mdp
HOST_EXTRACFLAGS += -Isecurity/selinux/include
always := $(hostprogs-y)
clean-files := $(hostprogs-y) policy.* file_contexts
clean-files := policy.* file_contexts
......@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
* There is no exception for unconfined as change_hat is not
* available.
*/
if (current->no_new_privs)
if (task_no_new_privs(current))
return -EPERM;
/* released below */
......@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
* no_new_privs is set because this aways results in a reduction
* of permissions.
*/
if (current->no_new_privs && !unconfined(profile)) {
if (task_no_new_privs(current) && !unconfined(profile)) {
put_cred(cred);
return -EPERM;
}
......
......@@ -401,6 +401,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
return 0;
}
static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size)
{
return 0;
}
static int cap_kernel_module_request(char *kmod_name)
{
return 0;
......@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, cred_transfer);
set_to_cap_if_null(ops, kernel_act_as);
set_to_cap_if_null(ops, kernel_create_files_as);
set_to_cap_if_null(ops, kernel_fw_from_file);
set_to_cap_if_null(ops, kernel_module_request);
set_to_cap_if_null(ops, kernel_module_from_file);
set_to_cap_if_null(ops, task_fix_setuid);
......
......@@ -421,6 +421,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
}
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
return 0;
}
......@@ -822,15 +825,20 @@ int cap_task_setnice(struct task_struct *p, int nice)
* Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from
* the current task's bounding set. Returns 0 on success, -ve on error.
*/
static long cap_prctl_drop(struct cred *new, unsigned long cap)
static int cap_prctl_drop(unsigned long cap)
{
struct cred *new;
if (!ns_capable(current_user_ns(), CAP_SETPCAP))
return -EPERM;
if (!cap_valid(cap))
return -EINVAL;
new = prepare_creds();
if (!new)
return -ENOMEM;
cap_lower(new->cap_bset, cap);
return 0;
return commit_creds(new);
}
/**
......@@ -848,26 +856,17 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap)
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
const struct cred *old = current_cred();
struct cred *new;
long error = 0;
new = prepare_creds();
if (!new)
return -ENOMEM;
switch (option) {
case PR_CAPBSET_READ:
error = -EINVAL;
if (!cap_valid(arg2))
goto error;
error = !!cap_raised(new->cap_bset, arg2);
goto no_change;
return -EINVAL;
return !!cap_raised(old->cap_bset, arg2);
case PR_CAPBSET_DROP:
error = cap_prctl_drop(new, arg2);
if (error < 0)
goto error;
goto changed;
return cap_prctl_drop(arg2);
/*
* The next four prctl's remain to assist with transitioning a
......@@ -889,10 +888,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* capability-based-privilege environment.
*/
case PR_SET_SECUREBITS:
error = -EPERM;
if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
& (new->securebits ^ arg2)) /*[1]*/
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
if ((((old->securebits & SECURE_ALL_LOCKS) >> 1)
& (old->securebits ^ arg2)) /*[1]*/
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current_cred(),
current_cred()->user_ns, CAP_SETPCAP,
......@@ -906,46 +904,39 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
*/
)
/* cannot change a locked bit */
goto error;
return -EPERM;
new = prepare_creds();
if (!new)
return -ENOMEM;
new->securebits = arg2;
goto changed;
return commit_creds(new);
case PR_GET_SECUREBITS:
error = new->securebits;
goto no_change;
return old->securebits;
case PR_GET_KEEPCAPS:
if (issecure(SECURE_KEEP_CAPS))
error = 1;
goto no_change;
return !!issecure(SECURE_KEEP_CAPS);
case PR_SET_KEEPCAPS:
error = -EINVAL;
if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
goto error;
error = -EPERM;
return -EINVAL;
if (issecure(SECURE_KEEP_CAPS_LOCKED))
goto error;
return -EPERM;
new = prepare_creds();
if (!new)
return -ENOMEM;
if (arg2)
new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
else
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
goto changed;
return commit_creds(new);
default:
/* No functionality available - continue with default */
error = -ENOSYS;
goto error;
return -ENOSYS;
}
/* Functionality provided */
changed:
return commit_creds(new);
no_change:
error:
abort_creds(new);
return error;
}
/**
......
......@@ -13,7 +13,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/rbtree.h>
#include <linux/cred.h>
#include <linux/key-type.h>
#include <linux/digsig.h>
......@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
"_evm",
"_module",
#ifndef CONFIG_IMA_TRUSTED_KEYRING
"_ima",
#else
".ima",
#endif
};
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
......@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP;
}
int integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
int err = 0;
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (!IS_ERR(keyring[id]))
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
else {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
}
return err;
}
......@@ -123,3 +123,13 @@ config IMA_APPRAISE
For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net>
If unsure, say N.
config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.
......@@ -158,7 +158,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
......@@ -171,6 +171,7 @@ void ima_delete_rules(void);
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02
#define IMA_APPRAISE_MODULES 0x04
#define IMA_APPRAISE_FIRMWARE 0x08
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
......@@ -249,4 +250,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
return -EINVAL;
}
#endif /* CONFIG_IMA_LSM_RULES */
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static inline int ima_init_keyring(const unsigned int id)
{
return integrity_init_keyring(id);
}
#else
static inline int ima_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_IMA_TRUSTED_KEYRING */
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -845,6 +845,17 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
return security_ops->kernel_create_files_as(new, inode);
}
int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
{
int ret;
ret = security_ops->kernel_fw_from_file(file, buf, size);
if (ret)
return ret;
return ima_fw_from_file(file, buf, size);
}
EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
int security_kernel_module_request(char *kmod_name)
{
return security_ops->kernel_module_request(kmod_name);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment