Commit 78dc53c4 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull security subsystem updates from James Morris:
 "In this patchset, we finally get an SELinux update, with Paul Moore
  taking over as maintainer of that code.

  Also a significant update for the Keys subsystem, as well as
  maintenance updates to Smack, IMA, TPM, and Apparmor"

and since I wanted to know more about the updates to key handling,
here's the explanation from David Howells on that:

 "Okay.  There are a number of separate bits.  I'll go over the big bits
  and the odd important other bit, most of the smaller bits are just
  fixes and cleanups.  If you want the small bits accounting for, I can
  do that too.

   (1) Keyring capacity expansion.

        KEYS: Consolidate the concept of an 'index key' for key access
        KEYS: Introduce a search context structure
        KEYS: Search for auth-key by name rather than target key ID
        Add a generic associative array implementation.
        KEYS: Expand the capacity of a keyring

     Several of the patches are providing an expansion of the capacity of a
     keyring.  Currently, the maximum size of a keyring payload is one page.
     Subtract a small header and then divide up into pointers, that only gives
     you ~500 pointers on an x86_64 box.  However, since the NFS idmapper uses
     a keyring to store ID mapping data, that has proven to be insufficient to
     the cause.

     Whatever data structure I use to handle the keyring payload, it can only
     store pointers to keys, not the keys themselves because several keyrings
     may point to a single key.  This precludes inserting, say, and rb_node
     struct into the key struct for this purpose.

     I could make an rbtree of records such that each record has an rb_node
     and a key pointer, but that would use four words of space per key stored
     in the keyring.  It would, however, be able to use much existing code.

     I selected instead a non-rebalancing radix-tree type approach as that
     could have a better space-used/key-pointer ratio.  I could have used the
     radix tree implementation that we already have and insert keys into it by
     their serial numbers, but that means any sort of search must iterate over
     the whole radix tree.  Further, its nodes are a bit on the capacious side
     for what I want - especially given that key serial numbers are randomly
     allocated, thus leaving a lot of empty space in the tree.

     So what I have is an associative array that internally is a radix-tree
     with 16 pointers per node where the index key is constructed from the key
     type pointer and the key description.  This means that an exact lookup by
     type+description is very fast as this tells us how to navigate directly to
     the target key.

     I made the data structure general in lib/assoc_array.c as far as it is
     concerned, its index key is just a sequence of bits that leads to a
     pointer.  It's possible that someone else will be able to make use of it
     also.  FS-Cache might, for example.

   (2) Mark keys as 'trusted' and keyrings as 'trusted only'.

        KEYS: verify a certificate is signed by a 'trusted' key
        KEYS: Make the system 'trusted' keyring viewable by userspace
        KEYS: Add a 'trusted' flag and a 'trusted only' flag
        KEYS: Separate the kernel signature checking keyring from module signing

     These patches allow keys carrying asymmetric public keys to be marked as
     being 'trusted' and allow keyrings to be marked as only permitting the
     addition or linkage of trusted keys.

     Keys loaded from hardware during kernel boot or compiled into the kernel
     during build are marked as being trusted automatically.  New keys can be
     loaded at runtime with add_key().  They are checked against the system
     keyring contents and if their signatures can be validated with keys that
     are already marked trusted, then they are marked trusted also and can
     thus be added into the master keyring.

     Patches from Mimi Zohar make this usable with the IMA keyrings also.

   (3) Remove the date checks on the key used to validate a module signature.

        X.509: Remove certificate date checks

     It's not reasonable to reject a signature just because the key that it was
     generated with is no longer valid datewise - especially if the kernel
     hasn't yet managed to set the system clock when the first module is
     loaded - so just remove those checks.

   (4) Make it simpler to deal with additional X.509 being loaded into the kernel.

        KEYS: Load *.x509 files into kernel keyring
        KEYS: Have make canonicalise the paths of the X.509 certs better to deduplicate

     The builder of the kernel now just places files with the extension ".x509"
     into the kernel source or build trees and they're concatenated by the
     kernel build and stuffed into the appropriate section.

   (5) Add support for userspace kerberos to use keyrings.

        KEYS: Add per-user_namespace registers for persistent per-UID kerberos caches
        KEYS: Implement a big key type that can save to tmpfs

     Fedora went to, by default, storing kerberos tickets and tokens in tmpfs.
     We looked at storing it in keyrings instead as that confers certain
     advantages such as tickets being automatically deleted after a certain
     amount of time and the ability for the kernel to get at these tokens more
     easily.

     To make this work, two things were needed:

     (a) A way for the tickets to persist beyond the lifetime of all a user's
         sessions so that cron-driven processes can still use them.

         The problem is that a user's session keyrings are deleted when the
         session that spawned them logs out and the user's user keyring is
         deleted when the UID is deleted (typically when the last log out
         happens), so neither of these places is suitable.

         I've added a system keyring into which a 'persistent' keyring is
         created for each UID on request.  Each time a user requests their
         persistent keyring, the expiry time on it is set anew.  If the user
         doesn't ask for it for, say, three days, the keyring is automatically
         expired and garbage collected using the existing gc.  All the kerberos
         tokens it held are then also gc'd.

     (b) A key type that can hold really big tickets (up to 1MB in size).

         The problem is that Active Directory can return huge tickets with lots
         of auxiliary data attached.  We don't, however, want to eat up huge
         tracts of unswappable kernel space for this, so if the ticket is
         greater than a certain size, we create a swappable shmem file and dump
         the contents in there and just live with the fact we then have an
         inode and a dentry overhead.  If the ticket is smaller than that, we
         slap it in a kmalloc()'d buffer"

* 'for-linus2' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (121 commits)
  KEYS: Fix keyring content gc scanner
  KEYS: Fix error handling in big_key instantiation
  KEYS: Fix UID check in keyctl_get_persistent()
  KEYS: The RSA public key algorithm needs to select MPILIB
  ima: define '_ima' as a builtin 'trusted' keyring
  ima: extend the measurement list to include the file signature
  kernel/system_certificate.S: use real contents instead of macro GLOBAL()
  KEYS: fix error return code in big_key_instantiate()
  KEYS: Fix keyring quota misaccounting on key replacement and unlink
  KEYS: Fix a race between negating a key and reading the error set
  KEYS: Make BIG_KEYS boolean
  apparmor: remove the "task" arg from may_change_ptraced_domain()
  apparmor: remove parent task info from audit logging
  apparmor: remove tsk field from the apparmor_audit_struct
  apparmor: fix capability to not use the current task, during reporting
  Smack: Ptrace access check mode
  ima: provide hash algo info in the xattr
  ima: enable support for larger default filedata hash algorithms
  ima: define kernel parameter 'ima_template=' to change configured default
  ima: add Kconfig default measurement list template
  ...
parents 3eaded86 62fe3182
This diff is collapsed.
...@@ -15,6 +15,7 @@ adi,adt7461 +/-1C TDM Extended Temp Range I.C ...@@ -15,6 +15,7 @@ adi,adt7461 +/-1C TDM Extended Temp Range I.C
adt7461 +/-1C TDM Extended Temp Range I.C adt7461 +/-1C TDM Extended Temp Range I.C
at,24c08 i2c serial eeprom (24cxx) at,24c08 i2c serial eeprom (24cxx)
atmel,24c02 i2c serial eeprom (24cxx) atmel,24c02 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
catalyst,24c32 i2c serial eeprom catalyst,24c32 i2c serial eeprom
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
dallas,ds1338 I2C RTC with 56-Byte NV RAM dallas,ds1338 I2C RTC with 56-Byte NV RAM
...@@ -44,6 +45,7 @@ mc,rv3029c2 Real Time Clock Module with I2C-Bus ...@@ -44,6 +45,7 @@ mc,rv3029c2 Real Time Clock Module with I2C-Bus
national,lm75 I2C TEMP SENSOR national,lm75 I2C TEMP SENSOR
national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor
national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface
nuvoton,npct501 i2c trusted platform module (TPM)
nxp,pca9556 Octal SMBus and I2C registered interface nxp,pca9556 Octal SMBus and I2C registered interface
nxp,pca9557 8-bit I2C-bus and SMBus I/O port with reset nxp,pca9557 8-bit I2C-bus and SMBus I/O port with reset
nxp,pcf8563 Real-time clock/calendar nxp,pcf8563 Real-time clock/calendar
...@@ -61,3 +63,4 @@ taos,tsl2550 Ambient Light Sensor with SMBUS/Two Wire Serial Interface ...@@ -61,3 +63,4 @@ taos,tsl2550 Ambient Light Sensor with SMBUS/Two Wire Serial Interface
ti,tsc2003 I2C Touch-Screen Controller ti,tsc2003 I2C Touch-Screen Controller
ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
ti,tmp275 Digital Temperature Sensor ti,tmp275 Digital Temperature Sensor
winbond,wpct301 i2c trusted platform module (TPM)
...@@ -1190,15 +1190,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1190,15 +1190,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
owned by uid=0. owned by uid=0.
ima_hash= [IMA] ima_hash= [IMA]
Format: { "sha1" | "md5" } Format: { md5 | sha1 | rmd160 | sha256 | sha384
| sha512 | ... }
default: "sha1" default: "sha1"
The list of supported hash algorithms is defined
in crypto/hash_info.h.
ima_tcb [IMA] ima_tcb [IMA]
Load a policy which meets the needs of the Trusted Load a policy which meets the needs of the Trusted
Computing Base. This means IMA will measure all Computing Base. This means IMA will measure all
programs exec'd, files mmap'd for exec, and all files programs exec'd, files mmap'd for exec, and all files
opened for read by uid=0. opened for read by uid=0.
ima_template= [IMA]
Select one of defined IMA measurements template formats.
Formats: { "ima" | "ima-ng" }
Default: "ima-ng"
init= [KNL] init= [KNL]
Format: <full_path> Format: <full_path>
Run specified binary instead of /sbin/init as init Run specified binary instead of /sbin/init as init
......
...@@ -22,3 +22,5 @@ keys.txt ...@@ -22,3 +22,5 @@ keys.txt
- description of the kernel key retention service. - description of the kernel key retention service.
tomoyo.txt tomoyo.txt
- documentation on the TOMOYO Linux Security Module. - documentation on the TOMOYO Linux Security Module.
IMA-templates.txt
- documentation on the template management mechanism for IMA.
IMA Template Management Mechanism
==== INTRODUCTION ====
The original 'ima' template is fixed length, containing the filedata hash
and pathname. The filedata hash is limited to 20 bytes (md5/sha1).
The pathname is a null terminated string, limited to 255 characters.
To overcome these limitations and to add additional file metadata, it is
necessary to extend the current version of IMA by defining additional
templates. For example, information that could be possibly reported are
the inode UID/GID or the LSM labels either of the inode and of the process
that is accessing it.
However, the main problem to introduce this feature is that, each time
a new template is defined, the functions that generate and display
the measurements list would include the code for handling a new format
and, thus, would significantly grow over the time.
The proposed solution solves this problem by separating the template
management from the remaining IMA code. The core of this solution is the
definition of two new data structures: a template descriptor, to determine
which information should be included in the measurement list; a template
field, to generate and display data of a given type.
Managing templates with these structures is very simple. To support
a new data type, developers define the field identifier and implement
two functions, init() and show(), respectively to generate and display
measurement entries. Defining a new template descriptor requires
specifying the template format, a string of field identifiers separated
by the '|' character. While in the current implementation it is possible
to define new template descriptors only by adding their definition in the
template specific code (ima_template.c), in a future version it will be
possible to register a new template on a running kernel by supplying to IMA
the desired format string. In this version, IMA initializes at boot time
all defined template descriptors by translating the format into an array
of template fields structures taken from the set of the supported ones.
After the initialization step, IMA will call ima_alloc_init_template()
(new function defined within the patches for the new template management
mechanism) to generate a new measurement entry by using the template
descriptor chosen through the kernel configuration or through the newly
introduced 'ima_template=' kernel command line parameter. It is during this
phase that the advantages of the new architecture are clearly shown:
the latter function will not contain specific code to handle a given template
but, instead, it simply calls the init() method of the template fields
associated to the chosen template descriptor and store the result (pointer
to allocated data and data length) in the measurement entry structure.
The same mechanism is employed to display measurements entries.
The functions ima[_ascii]_measurements_show() retrieve, for each entry,
the template descriptor used to produce that entry and call the show()
method for each item of the array of template fields structures.
==== SUPPORTED TEMPLATE FIELDS AND DESCRIPTORS ====
In the following, there is the list of supported template fields
('<identifier>': description), that can be used to define new template
descriptors by adding their identifier to the format string
(support for more data types will be added later):
- 'd': the digest of the event (i.e. the digest of a measured file),
calculated with the SHA1 or MD5 hash algorithm;
- 'n': the name of the event (i.e. the file name), with size up to 255 bytes;
- 'd-ng': the digest of the event, calculated with an arbitrary hash
algorithm (field format: [<hash algo>:]digest, where the digest
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'n-ng': the name of the event, without size limitations.
Below, there is the list of defined template descriptors:
- "ima": its format is 'd|n';
- "ima-ng" (default): its format is 'd-ng|n-ng'.
==== USE ====
To specify the template descriptor to be used to generate measurement entries,
currently the following methods are supported:
- select a template descriptor among those supported in the kernel
configuration ('ima-ng' is the default choice);
- specify a template descriptor name from the kernel command line through
the 'ima_template=' parameter.
...@@ -865,15 +865,14 @@ encountered: ...@@ -865,15 +865,14 @@ encountered:
calling processes has a searchable link to the key from one of its calling processes has a searchable link to the key from one of its
keyrings. There are three functions for dealing with these: keyrings. There are three functions for dealing with these:
key_ref_t make_key_ref(const struct key *key, key_ref_t make_key_ref(const struct key *key, bool possession);
unsigned long possession);
struct key *key_ref_to_ptr(const key_ref_t key_ref); struct key *key_ref_to_ptr(const key_ref_t key_ref);
unsigned long is_key_possessed(const key_ref_t key_ref); bool is_key_possessed(const key_ref_t key_ref);
The first function constructs a key reference from a key pointer and The first function constructs a key reference from a key pointer and
possession information (which must be 0 or 1 and not any other value). possession information (which must be true or false).
The second function retrieves the key pointer from a reference and the The second function retrieves the key pointer from a reference and the
third retrieves the possession flag. third retrieves the possession flag.
...@@ -961,14 +960,17 @@ payload contents" for more information. ...@@ -961,14 +960,17 @@ payload contents" for more information.
the argument will not be parsed. the argument will not be parsed.
(*) Extra references can be made to a key by calling the following function: (*) Extra references can be made to a key by calling one of the following
functions:
struct key *__key_get(struct key *key);
struct key *key_get(struct key *key); struct key *key_get(struct key *key);
These need to be disposed of by calling key_put() when they've been Keys so references will need to be disposed of by calling key_put() when
finished with. The key pointer passed in will be returned. If the pointer they've been finished with. The key pointer passed in will be returned.
is NULL or CONFIG_KEYS is not set then the key will not be dereferenced and
no increment will take place. In the case of key_get(), if the pointer is NULL or CONFIG_KEYS is not set
then the key will not be dereferenced and no increment will take place.
(*) A key's serial number can be obtained by calling: (*) A key's serial number can be obtained by calling:
......
...@@ -7515,9 +7515,10 @@ SELINUX SECURITY MODULE ...@@ -7515,9 +7515,10 @@ SELINUX SECURITY MODULE
M: Stephen Smalley <sds@tycho.nsa.gov> M: Stephen Smalley <sds@tycho.nsa.gov>
M: James Morris <james.l.morris@oracle.com> M: James Morris <james.l.morris@oracle.com>
M: Eric Paris <eparis@parisplace.org> M: Eric Paris <eparis@parisplace.org>
M: Paul Moore <paul@paul-moore.com>
L: selinux@tycho.nsa.gov (subscribers-only, general discussion) L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
W: http://selinuxproject.org W: http://selinuxproject.org
T: git git://git.infradead.org/users/eparis/selinux.git T: git git://git.infradead.org/users/pcmoore/selinux
S: Supported S: Supported
F: include/linux/selinux* F: include/linux/selinux*
F: security/selinux/ F: security/selinux/
...@@ -8664,6 +8665,7 @@ F: drivers/media/usb/tm6000/ ...@@ -8664,6 +8665,7 @@ F: drivers/media/usb/tm6000/
TPM DEVICE DRIVER TPM DEVICE DRIVER
M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com> M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
M: Ashley Lai <ashley@ashleylai.com> M: Ashley Lai <ashley@ashleylai.com>
M: Peter Huewe <peterhuewe@gmx.de>
M: Rajiv Andrade <mail@srajiv.net> M: Rajiv Andrade <mail@srajiv.net>
W: http://tpmdd.sourceforge.net W: http://tpmdd.sourceforge.net
M: Marcel Selhorst <tpmdd@selhorst.net> M: Marcel Selhorst <tpmdd@selhorst.net>
......
...@@ -1402,6 +1402,9 @@ config CRYPTO_USER_API_SKCIPHER ...@@ -1402,6 +1402,9 @@ config CRYPTO_USER_API_SKCIPHER
This option enables the user-spaces interface for symmetric This option enables the user-spaces interface for symmetric
key cipher algorithms. key cipher algorithms.
config CRYPTO_HASH_INFO
bool
source "drivers/crypto/Kconfig" source "drivers/crypto/Kconfig"
source crypto/asymmetric_keys/Kconfig source crypto/asymmetric_keys/Kconfig
......
...@@ -104,3 +104,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o ...@@ -104,3 +104,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
obj-$(CONFIG_XOR_BLOCKS) += xor.o obj-$(CONFIG_XOR_BLOCKS) += xor.o
obj-$(CONFIG_ASYNC_CORE) += async_tx/ obj-$(CONFIG_ASYNC_CORE) += async_tx/
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
...@@ -12,6 +12,8 @@ if ASYMMETRIC_KEY_TYPE ...@@ -12,6 +12,8 @@ if ASYMMETRIC_KEY_TYPE
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
tristate "Asymmetric public-key crypto algorithm subtype" tristate "Asymmetric public-key crypto algorithm subtype"
select MPILIB select MPILIB
select PUBLIC_KEY_ALGO_RSA
select CRYPTO_HASH_INFO
help help
This option provides support for asymmetric public key type handling. This option provides support for asymmetric public key type handling.
If signature generation and/or verification are to be used, If signature generation and/or verification are to be used,
...@@ -20,8 +22,8 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE ...@@ -20,8 +22,8 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
config PUBLIC_KEY_ALGO_RSA config PUBLIC_KEY_ALGO_RSA
tristate "RSA public-key algorithm" tristate "RSA public-key algorithm"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select MPILIB_EXTRA select MPILIB_EXTRA
select MPILIB
help help
This option enables support for the RSA algorithm (PKCS#1, RFC3447). This option enables support for the RSA algorithm (PKCS#1, RFC3447).
......
...@@ -209,6 +209,7 @@ struct key_type key_type_asymmetric = { ...@@ -209,6 +209,7 @@ struct key_type key_type_asymmetric = {
.match = asymmetric_key_match, .match = asymmetric_key_match,
.destroy = asymmetric_key_destroy, .destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe, .describe = asymmetric_key_describe,
.def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
}; };
EXPORT_SYMBOL_GPL(key_type_asymmetric); EXPORT_SYMBOL_GPL(key_type_asymmetric);
......
...@@ -22,29 +22,25 @@ ...@@ -22,29 +22,25 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
const char *const pkey_algo[PKEY_ALGO__LAST] = { const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
[PKEY_ALGO_DSA] = "DSA", [PKEY_ALGO_DSA] = "DSA",
[PKEY_ALGO_RSA] = "RSA", [PKEY_ALGO_RSA] = "RSA",
}; };
EXPORT_SYMBOL_GPL(pkey_algo); EXPORT_SYMBOL_GPL(pkey_algo_name);
const char *const pkey_hash_algo[PKEY_HASH__LAST] = { const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = {
[PKEY_HASH_MD4] = "md4", #if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
[PKEY_HASH_MD5] = "md5", defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
[PKEY_HASH_SHA1] = "sha1", [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
[PKEY_HASH_RIPE_MD_160] = "rmd160", #endif
[PKEY_HASH_SHA256] = "sha256",
[PKEY_HASH_SHA384] = "sha384",
[PKEY_HASH_SHA512] = "sha512",
[PKEY_HASH_SHA224] = "sha224",
}; };
EXPORT_SYMBOL_GPL(pkey_hash_algo); EXPORT_SYMBOL_GPL(pkey_algo);
const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
[PKEY_ID_PGP] = "PGP", [PKEY_ID_PGP] = "PGP",
[PKEY_ID_X509] = "X509", [PKEY_ID_X509] = "X509",
}; };
EXPORT_SYMBOL_GPL(pkey_id_type); EXPORT_SYMBOL_GPL(pkey_id_type_name);
/* /*
* Provide a part of a description of the key for /proc/keys. * Provide a part of a description of the key for /proc/keys.
...@@ -56,7 +52,7 @@ static void public_key_describe(const struct key *asymmetric_key, ...@@ -56,7 +52,7 @@ static void public_key_describe(const struct key *asymmetric_key,
if (key) if (key)
seq_printf(m, "%s.%s", seq_printf(m, "%s.%s",
pkey_id_type[key->id_type], key->algo->name); pkey_id_type_name[key->id_type], key->algo->name);
} }
/* /*
...@@ -78,21 +74,45 @@ EXPORT_SYMBOL_GPL(public_key_destroy); ...@@ -78,21 +74,45 @@ EXPORT_SYMBOL_GPL(public_key_destroy);
/* /*
* Verify a signature using a public key. * Verify a signature using a public key.
*/ */
static int public_key_verify_signature(const struct key *key, int public_key_verify_signature(const struct public_key *pk,
const struct public_key_signature *sig) const struct public_key_signature *sig)
{ {
const struct public_key *pk = key->payload.data; const struct public_key_algorithm *algo;
BUG_ON(!pk);
BUG_ON(!pk->mpi[0]);
BUG_ON(!pk->mpi[1]);
BUG_ON(!sig);
BUG_ON(!sig->digest);
BUG_ON(!sig->mpi[0]);
algo = pk->algo;
if (!algo) {
if (pk->pkey_algo >= PKEY_ALGO__LAST)
return -ENOPKG;
algo = pkey_algo[pk->pkey_algo];
if (!algo)
return -ENOPKG;
}
if (!pk->algo->verify_signature) if (!algo->verify_signature)
return -ENOTSUPP; return -ENOTSUPP;
if (sig->nr_mpi != pk->algo->n_sig_mpi) { if (sig->nr_mpi != algo->n_sig_mpi) {
pr_debug("Signature has %u MPI not %u\n", pr_debug("Signature has %u MPI not %u\n",
sig->nr_mpi, pk->algo->n_sig_mpi); sig->nr_mpi, algo->n_sig_mpi);
return -EINVAL; return -EINVAL;
} }
return pk->algo->verify_signature(pk, sig); return algo->verify_signature(pk, sig);
}
EXPORT_SYMBOL_GPL(public_key_verify_signature);
static int public_key_verify_signature_2(const struct key *key,
const struct public_key_signature *sig)
{
const struct public_key *pk = key->payload.data;
return public_key_verify_signature(pk, sig);
} }
/* /*
...@@ -103,6 +123,6 @@ struct asymmetric_key_subtype public_key_subtype = { ...@@ -103,6 +123,6 @@ struct asymmetric_key_subtype public_key_subtype = {
.name = "public_key", .name = "public_key",
.describe = public_key_describe, .describe = public_key_describe,
.destroy = public_key_destroy, .destroy = public_key_destroy,
.verify_signature = public_key_verify_signature, .verify_signature = public_key_verify_signature_2,
}; };
EXPORT_SYMBOL_GPL(public_key_subtype); EXPORT_SYMBOL_GPL(public_key_subtype);
...@@ -28,3 +28,9 @@ struct public_key_algorithm { ...@@ -28,3 +28,9 @@ struct public_key_algorithm {
}; };
extern const struct public_key_algorithm RSA_public_key_algorithm; extern const struct public_key_algorithm RSA_public_key_algorithm;
/*
* public_key.c
*/
extern int public_key_verify_signature(const struct public_key *pk,
const struct public_key_signature *sig);
...@@ -73,13 +73,13 @@ static const struct { ...@@ -73,13 +73,13 @@ static const struct {
size_t size; size_t size;
} RSA_ASN1_templates[PKEY_HASH__LAST] = { } RSA_ASN1_templates[PKEY_HASH__LAST] = {
#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } #define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
[PKEY_HASH_MD5] = _(MD5), [HASH_ALGO_MD5] = _(MD5),
[PKEY_HASH_SHA1] = _(SHA1), [HASH_ALGO_SHA1] = _(SHA1),
[PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), [HASH_ALGO_RIPE_MD_160] = _(RIPE_MD_160),
[PKEY_HASH_SHA256] = _(SHA256), [HASH_ALGO_SHA256] = _(SHA256),
[PKEY_HASH_SHA384] = _(SHA384), [HASH_ALGO_SHA384] = _(SHA384),
[PKEY_HASH_SHA512] = _(SHA512), [HASH_ALGO_SHA512] = _(SHA512),
[PKEY_HASH_SHA224] = _(SHA224), [HASH_ALGO_SHA224] = _(SHA224),
#undef _ #undef _
}; };
......
...@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert) ...@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert->subject); kfree(cert->subject);
kfree(cert->fingerprint); kfree(cert->fingerprint);
kfree(cert->authority); kfree(cert->authority);
kfree(cert->sig.digest);
mpi_free(cert->sig.rsa.s);
kfree(cert); kfree(cert);
} }
} }
...@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, ...@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
return -ENOPKG; /* Unsupported combination */ return -ENOPKG; /* Unsupported combination */
case OID_md4WithRSAEncryption: case OID_md4WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_MD5; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha1WithRSAEncryption: case OID_sha1WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha256WithRSAEncryption: case OID_sha256WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha384WithRSAEncryption: case OID_sha384WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha512WithRSAEncryption: case OID_sha512WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha224WithRSAEncryption: case OID_sha224WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
} }
...@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen, ...@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen,
return -EINVAL; return -EINVAL;
} }
ctx->cert->sig = value; ctx->cert->raw_sig = value;
ctx->cert->sig_size = vlen; ctx->cert->raw_sig_size = vlen;
return 0; return 0;
} }
...@@ -343,8 +345,9 @@ int x509_extract_key_data(void *context, size_t hdrlen, ...@@ -343,8 +345,9 @@ int x509_extract_key_data(void *context, size_t hdrlen,
if (ctx->last_oid != OID_rsaEncryption) if (ctx->last_oid != OID_rsaEncryption)
return -ENOPKG; return -ENOPKG;
/* There seems to be an extraneous 0 byte on the front of the data */ ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA;
ctx->cert->pkey_algo = PKEY_ALGO_RSA;
/* Discard the BIT STRING metadata */
ctx->key = value + 1; ctx->key = value + 1;
ctx->key_size = vlen - 1; ctx->key_size = vlen - 1;
return 0; return 0;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
#include <linux/time.h>
#include <crypto/public_key.h> #include <crypto/public_key.h>
struct x509_certificate { struct x509_certificate {
...@@ -20,13 +21,11 @@ struct x509_certificate { ...@@ -20,13 +21,11 @@ struct x509_certificate {
char *authority; /* Authority key fingerprint as hex */ char *authority; /* Authority key fingerprint as hex */
struct tm valid_from; struct tm valid_from;
struct tm valid_to; struct tm valid_to;
enum pkey_algo pkey_algo : 8; /* Public key algorithm */
enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
const void *tbs; /* Signed data */ const void *tbs; /* Signed data */
size_t tbs_size; /* Size of signed data */ unsigned tbs_size; /* Size of signed data */
const void *sig; /* Signature data */ unsigned raw_sig_size; /* Size of sigature */
size_t sig_size; /* Size of sigature */ const void *raw_sig; /* Signature data */
struct public_key_signature sig; /* Signature parameters */
}; };
/* /*
...@@ -34,3 +33,10 @@ struct x509_certificate { ...@@ -34,3 +33,10 @@ struct x509_certificate {
*/ */
extern void x509_free_certificate(struct x509_certificate *cert); extern void x509_free_certificate(struct x509_certificate *cert);
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
/*
* x509_public_key.c
*/
extern int x509_get_sig_params(struct x509_certificate *cert);
extern int x509_check_signature(const struct public_key *pub,
struct x509_certificate *cert);
...@@ -18,85 +18,162 @@ ...@@ -18,85 +18,162 @@
#include <linux/asn1_decoder.h> #include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h> #include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h> #include <keys/asymmetric-parser.h>
#include <keys/system_keyring.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include "asymmetric_keys.h" #include "asymmetric_keys.h"
#include "public_key.h" #include "public_key.h"
#include "x509_parser.h" #include "x509_parser.h"
static const /*
struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { * Find a key in the given keyring by issuer and authority.
[PKEY_ALGO_DSA] = NULL, */
#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ static struct key *x509_request_asymmetric_key(
defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) struct key *keyring,
[PKEY_ALGO_RSA] = &RSA_public_key_algorithm, const char *signer, size_t signer_len,
#endif const char *authority, size_t auth_len)
}; {
key_ref_t key;
char *id;
/* Construct an identifier. */
id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
if (!id)
return ERR_PTR(-ENOMEM);
memcpy(id, signer, signer_len);
id[signer_len + 0] = ':';
id[signer_len + 1] = ' ';
memcpy(id + signer_len + 2, authority, auth_len);
id[signer_len + 2 + auth_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 module 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);
}
/* /*
* Check the signature on a certificate using the provided public key * Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature.
*/ */
static int x509_check_signature(const struct public_key *pub, int x509_get_sig_params(struct x509_certificate *cert)
const struct x509_certificate *cert)
{ {
struct public_key_signature *sig;
struct crypto_shash *tfm; struct crypto_shash *tfm;
struct shash_desc *desc; struct shash_desc *desc;
size_t digest_size, desc_size; size_t digest_size, desc_size;
void *digest;
int ret; int ret;
pr_devel("==>%s()\n", __func__); pr_devel("==>%s()\n", __func__);
if (cert->sig.rsa.s)
return 0;
cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
if (!cert->sig.rsa.s)
return -ENOMEM;
cert->sig.nr_mpi = 1;
/* Allocate the hashing algorithm we're going to need and find out how /* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be. * big the hash operational data will be.
*/ */
tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
if (IS_ERR(tfm)) if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm); digest_size = crypto_shash_digestsize(tfm);
/* We allocate the hash operational data storage on the end of our /* We allocate the hash operational data storage on the end of the
* context data. * digest storage space.
*/ */
ret = -ENOMEM; ret = -ENOMEM;
sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
if (!sig) if (!digest)
goto error_no_sig; goto error;
sig->pkey_hash_algo = cert->sig_hash_algo; cert->sig.digest = digest;
sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; cert->sig.digest_size = digest_size;
sig->digest_size = digest_size;
desc = (void *)sig + sizeof(*sig); desc = digest + digest_size;
desc->tfm = tfm; desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_init(desc); ret = crypto_shash_init(desc);
if (ret < 0) if (ret < 0)
goto error; goto error;
might_sleep();
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
error:
crypto_free_shash(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL_GPL(x509_get_sig_params);
ret = -ENOMEM; /*
sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); * Check the signature on a certificate using the provided public key
if (!sig->rsa.s) */
goto error; int x509_check_signature(const struct public_key *pub,
struct x509_certificate *cert)
{
int ret;
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); pr_devel("==>%s()\n", __func__);
if (ret < 0)
goto error_mpi;
ret = pub->algo->verify_signature(pub, sig); ret = x509_get_sig_params(cert);
if (ret < 0)
return ret;
ret = public_key_verify_signature(pub, &cert->sig);
pr_debug("Cert Verification: %d\n", ret); pr_debug("Cert Verification: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(x509_check_signature);
error_mpi: /*
mpi_free(sig->rsa.s); * Check the new certificate against the ones in the trust keyring. If one of
error: * those is the signing key and validates the new certificate, then mark the
kfree(sig); * new certificate as being trusted.
error_no_sig: *
crypto_free_shash(tfm); * 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)
{
const struct public_key *pk;
struct key *key;
int ret = 1;
pr_devel("<==%s() = %d\n", __func__, ret); key = x509_request_asymmetric_key(trust_keyring,
cert->issuer, strlen(cert->issuer),
cert->authority,
strlen(cert->authority));
if (!IS_ERR(key)) {
pk = key->payload.data;
ret = x509_check_signature(pk, cert);
}
return ret; return ret;
} }
...@@ -106,7 +183,6 @@ static int x509_check_signature(const struct public_key *pub, ...@@ -106,7 +183,6 @@ static int x509_check_signature(const struct public_key *pub,
static int x509_key_preparse(struct key_preparsed_payload *prep) static int x509_key_preparse(struct key_preparsed_payload *prep)
{ {
struct x509_certificate *cert; struct x509_certificate *cert;
struct tm now;
size_t srlen, sulen; size_t srlen, sulen;
char *desc = NULL; char *desc = NULL;
int ret; int ret;
...@@ -117,7 +193,18 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) ...@@ -117,7 +193,18 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
pr_devel("Cert Issuer: %s\n", cert->issuer); pr_devel("Cert Issuer: %s\n", cert->issuer);
pr_devel("Cert Subject: %s\n", cert->subject); pr_devel("Cert Subject: %s\n", cert->subject);
pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
!pkey_algo[cert->pub->pkey_algo] ||
!pkey_algo[cert->sig.pkey_algo] ||
!hash_algo_name[cert->sig.pkey_hash_algo]) {
ret = -ENOPKG;
goto error_free_cert;
}
pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
cert->valid_from.tm_mday, cert->valid_from.tm_hour, cert->valid_from.tm_mday, cert->valid_from.tm_hour,
...@@ -127,61 +214,29 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) ...@@ -127,61 +214,29 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
cert->valid_to.tm_mday, cert->valid_to.tm_hour, cert->valid_to.tm_mday, cert->valid_to.tm_hour,
cert->valid_to.tm_min, cert->valid_to.tm_sec); cert->valid_to.tm_min, cert->valid_to.tm_sec);
pr_devel("Cert Signature: %s + %s\n", pr_devel("Cert Signature: %s + %s\n",
pkey_algo[cert->sig_pkey_algo], pkey_algo_name[cert->sig.pkey_algo],
pkey_hash_algo[cert->sig_hash_algo]); hash_algo_name[cert->sig.pkey_hash_algo]);
if (!cert->fingerprint || !cert->authority) { if (!cert->fingerprint) {
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
cert->subject); cert->subject);
ret = -EKEYREJECTED; ret = -EKEYREJECTED;
goto error_free_cert; goto error_free_cert;
} }
time_to_tm(CURRENT_TIME.tv_sec, 0, &now); cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
now.tm_hour, now.tm_min, now.tm_sec);
if (now.tm_year < cert->valid_from.tm_year ||
(now.tm_year == cert->valid_from.tm_year &&
(now.tm_mon < cert->valid_from.tm_mon ||
(now.tm_mon == cert->valid_from.tm_mon &&
(now.tm_mday < cert->valid_from.tm_mday ||
(now.tm_mday == cert->valid_from.tm_mday &&
(now.tm_hour < cert->valid_from.tm_hour ||
(now.tm_hour == cert->valid_from.tm_hour &&
(now.tm_min < cert->valid_from.tm_min ||
(now.tm_min == cert->valid_from.tm_min &&
(now.tm_sec < cert->valid_from.tm_sec
))))))))))) {
pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
ret = -EKEYREJECTED;
goto error_free_cert;
}
if (now.tm_year > cert->valid_to.tm_year ||
(now.tm_year == cert->valid_to.tm_year &&
(now.tm_mon > cert->valid_to.tm_mon ||
(now.tm_mon == cert->valid_to.tm_mon &&
(now.tm_mday > cert->valid_to.tm_mday ||
(now.tm_mday == cert->valid_to.tm_mday &&
(now.tm_hour > cert->valid_to.tm_hour ||
(now.tm_hour == cert->valid_to.tm_hour &&
(now.tm_min > cert->valid_to.tm_min ||
(now.tm_min == cert->valid_to.tm_min &&
(now.tm_sec > cert->valid_to.tm_sec
))))))))))) {
pr_warn("Cert %s has expired\n", cert->fingerprint);
ret = -EKEYEXPIRED;
goto error_free_cert;
}
cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
cert->pub->id_type = PKEY_ID_X509; cert->pub->id_type = PKEY_ID_X509;
/* Check the signature on the key */ /* Check the signature on the key if it appears to be self-signed */
if (strcmp(cert->fingerprint, cert->authority) == 0) { if (!cert->authority ||
ret = x509_check_signature(cert->pub, cert); strcmp(cert->fingerprint, cert->authority) == 0) {
ret = x509_check_signature(cert->pub, cert); /* self-signed */
if (ret < 0) if (ret < 0)
goto error_free_cert; goto error_free_cert;
} else {
ret = x509_validate_trust(cert, system_trusted_keyring);
if (!ret)
prep->trusted = 1;
} }
/* Propose a description */ /* Propose a description */
...@@ -237,3 +292,6 @@ static void __exit x509_key_exit(void) ...@@ -237,3 +292,6 @@ static void __exit x509_key_exit(void)
module_init(x509_key_init); module_init(x509_key_init);
module_exit(x509_key_exit); module_exit(x509_key_exit);
MODULE_DESCRIPTION("X.509 certificate parser");
MODULE_LICENSE("GPL");
/*
* Hash Info: Hash algorithms information
*
* Copyright (c) 2013 Dmitry Kasatkin <d.kasatkin@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <linux/export.h>
#include <crypto/hash_info.h>
const char *const hash_algo_name[HASH_ALGO__LAST] = {
[HASH_ALGO_MD4] = "md4",
[HASH_ALGO_MD5] = "md5",
[HASH_ALGO_SHA1] = "sha1",
[HASH_ALGO_RIPE_MD_160] = "rmd160",
[HASH_ALGO_SHA256] = "sha256",
[HASH_ALGO_SHA384] = "sha384",
[HASH_ALGO_SHA512] = "sha512",
[HASH_ALGO_SHA224] = "sha224",
[HASH_ALGO_RIPE_MD_128] = "rmd128",
[HASH_ALGO_RIPE_MD_256] = "rmd256",
[HASH_ALGO_RIPE_MD_320] = "rmd320",
[HASH_ALGO_WP_256] = "wp256",
[HASH_ALGO_WP_384] = "wp384",
[HASH_ALGO_WP_512] = "wp512",
[HASH_ALGO_TGR_128] = "tgr128",
[HASH_ALGO_TGR_160] = "tgr160",
[HASH_ALGO_TGR_192] = "tgr192",
};
EXPORT_SYMBOL_GPL(hash_algo_name);
const int hash_digest_size[HASH_ALGO__LAST] = {
[HASH_ALGO_MD4] = MD5_DIGEST_SIZE,
[HASH_ALGO_MD5] = MD5_DIGEST_SIZE,
[HASH_ALGO_SHA1] = SHA1_DIGEST_SIZE,
[HASH_ALGO_RIPE_MD_160] = RMD160_DIGEST_SIZE,
[HASH_ALGO_SHA256] = SHA256_DIGEST_SIZE,
[HASH_ALGO_SHA384] = SHA384_DIGEST_SIZE,
[HASH_ALGO_SHA512] = SHA512_DIGEST_SIZE,
[HASH_ALGO_SHA224] = SHA224_DIGEST_SIZE,
[HASH_ALGO_RIPE_MD_128] = RMD128_DIGEST_SIZE,
[HASH_ALGO_RIPE_MD_256] = RMD256_DIGEST_SIZE,
[HASH_ALGO_RIPE_MD_320] = RMD320_DIGEST_SIZE,
[HASH_ALGO_WP_256] = WP256_DIGEST_SIZE,
[HASH_ALGO_WP_384] = WP384_DIGEST_SIZE,
[HASH_ALGO_WP_512] = WP512_DIGEST_SIZE,
[HASH_ALGO_TGR_128] = TGR128_DIGEST_SIZE,
[HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE,
[HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE,
};
EXPORT_SYMBOL_GPL(hash_digest_size);
...@@ -33,6 +33,15 @@ config TCG_TIS ...@@ -33,6 +33,15 @@ config TCG_TIS
from within Linux. To compile this driver as a module, choose from within Linux. To compile this driver as a module, choose
M here; the module will be called tpm_tis. M here; the module will be called tpm_tis.
config TCG_TIS_I2C_ATMEL
tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
depends on I2C
---help---
If you have an Atmel I2C TPM security chip say Yes and it will be
accessible from within Linux.
To compile this driver as a module, choose M here; the module will
be called tpm_tis_i2c_atmel.
config TCG_TIS_I2C_INFINEON config TCG_TIS_I2C_INFINEON
tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)"
depends on I2C depends on I2C
...@@ -42,7 +51,17 @@ config TCG_TIS_I2C_INFINEON ...@@ -42,7 +51,17 @@ config TCG_TIS_I2C_INFINEON
Specification 0.20 say Yes and it will be accessible from within Specification 0.20 say Yes and it will be accessible from within
Linux. Linux.
To compile this driver as a module, choose M here; the module To compile this driver as a module, choose M here; the module
will be called tpm_tis_i2c_infineon. will be called tpm_i2c_infineon.
config TCG_TIS_I2C_NUVOTON
tristate "TPM Interface Specification 1.2 Interface (I2C - Nuvoton)"
depends on I2C
---help---
If you have a TPM security chip with an I2C interface from
Nuvoton Technology Corp. say Yes and it will be accessible
from within Linux.
To compile this driver as a module, choose M here; the module
will be called tpm_i2c_nuvoton.
config TCG_NSC config TCG_NSC
tristate "National Semiconductor TPM Interface" tristate "National Semiconductor TPM Interface"
......
...@@ -2,17 +2,20 @@ ...@@ -2,17 +2,20 @@
# Makefile for the kernel tpm device drivers. # Makefile for the kernel tpm device drivers.
# #
obj-$(CONFIG_TCG_TPM) += tpm.o obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o
ifdef CONFIG_ACPI ifdef CONFIG_ACPI
obj-$(CONFIG_TCG_TPM) += tpm_bios.o tpm-y += tpm_eventlog.o tpm_acpi.o
tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o
else else
ifdef CONFIG_TCG_IBMVTPM ifdef CONFIG_TCG_IBMVTPM
obj-$(CONFIG_TCG_TPM) += tpm_bios.o tpm-y += tpm_eventlog.o tpm_of.o
tpm_bios-objs += tpm_eventlog.o tpm_of.o
endif endif
endif endif
obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
......
...@@ -371,13 +371,14 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, ...@@ -371,13 +371,14 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
return -ENODATA; return -ENODATA;
if (count > bufsiz) { if (count > bufsiz) {
dev_err(chip->dev, dev_err(chip->dev,
"invalid count value %x %zx \n", count, bufsiz); "invalid count value %x %zx\n", count, bufsiz);
return -E2BIG; return -E2BIG;
} }
mutex_lock(&chip->tpm_mutex); mutex_lock(&chip->tpm_mutex);
if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { rc = chip->vendor.send(chip, (u8 *) buf, count);
if (rc < 0) {
dev_err(chip->dev, dev_err(chip->dev,
"tpm_transmit: tpm_send: error %zd\n", rc); "tpm_transmit: tpm_send: error %zd\n", rc);
goto out; goto out;
...@@ -444,7 +445,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, ...@@ -444,7 +445,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
{ {
int err; int err;
len = tpm_transmit(chip,(u8 *) cmd, len); len = tpm_transmit(chip, (u8 *) cmd, len);
if (len < 0) if (len < 0)
return len; return len;
else if (len < TPM_HEADER_SIZE) else if (len < TPM_HEADER_SIZE)
...@@ -658,7 +659,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip) ...@@ -658,7 +659,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
return rc; return rc;
} }
ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
cap_t cap; cap_t cap;
...@@ -674,7 +675,7 @@ ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, ...@@ -674,7 +675,7 @@ ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
} }
EXPORT_SYMBOL_GPL(tpm_show_enabled); EXPORT_SYMBOL_GPL(tpm_show_enabled);
ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
cap_t cap; cap_t cap;
...@@ -690,7 +691,7 @@ ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, ...@@ -690,7 +691,7 @@ ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
} }
EXPORT_SYMBOL_GPL(tpm_show_active); EXPORT_SYMBOL_GPL(tpm_show_active);
ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
cap_t cap; cap_t cap;
...@@ -706,8 +707,8 @@ ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, ...@@ -706,8 +707,8 @@ ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
} }
EXPORT_SYMBOL_GPL(tpm_show_owned); EXPORT_SYMBOL_GPL(tpm_show_owned);
ssize_t tpm_show_temp_deactivated(struct device * dev, ssize_t tpm_show_temp_deactivated(struct device *dev,
struct device_attribute * attr, char *buf) struct device_attribute *attr, char *buf)
{ {
cap_t cap; cap_t cap;
ssize_t rc; ssize_t rc;
...@@ -847,8 +848,7 @@ int tpm_do_selftest(struct tpm_chip *chip) ...@@ -847,8 +848,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
unsigned long duration; unsigned long duration;
struct tpm_cmd_t cmd; struct tpm_cmd_t cmd;
duration = tpm_calc_ordinal_duration(chip, duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST);
TPM_ORD_CONTINUE_SELFTEST);
loops = jiffies_to_msecs(duration) / delay_msec; loops = jiffies_to_msecs(duration) / delay_msec;
...@@ -1020,43 +1020,33 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, ...@@ -1020,43 +1020,33 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(cap.manufacturer_id)); be32_to_cpu(cap.manufacturer_id));
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
"attempting to determine the 1.2 version");
if (!rc) {
str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n",
cap.tpm_version_1_2.Major,
cap.tpm_version_1_2.Minor,
cap.tpm_version_1_2.revMajor,
cap.tpm_version_1_2.revMinor);
} else {
/* Otherwise just use TPM_STRUCT_VER */
rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version"); "attempting to determine the 1.1 version");
if (rc) if (rc)
return 0; return 0;
str += sprintf(str, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
cap.tpm_version.Major, cap.tpm_version.Minor, cap.tpm_version.Major,
cap.tpm_version.revMajor, cap.tpm_version.revMinor); cap.tpm_version.Minor,
return str - buf; cap.tpm_version.revMajor,
} cap.tpm_version.revMinor);
EXPORT_SYMBOL_GPL(tpm_show_caps); }
ssize_t tpm_show_caps_1_2(struct device * dev,
struct device_attribute * attr, char *buf)
{
cap_t cap;
ssize_t rc;
char *str = buf;
rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
"attempting to determine the manufacturer");
if (rc)
return 0;
str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(cap.manufacturer_id));
rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
"attempting to determine the 1.2 version");
if (rc)
return 0;
str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n",
cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
cap.tpm_version_1_2.revMajor,
cap.tpm_version_1_2.revMinor);
return str - buf; return str - buf;
} }
EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); EXPORT_SYMBOL_GPL(tpm_show_caps);
ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
...@@ -1102,8 +1092,8 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, ...@@ -1102,8 +1092,8 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
} }
EXPORT_SYMBOL_GPL(tpm_store_cancel); EXPORT_SYMBOL_GPL(tpm_store_cancel);
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel, static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
bool *canceled) bool check_cancel, bool *canceled)
{ {
u8 status = chip->vendor.status(chip); u8 status = chip->vendor.status(chip);
...@@ -1170,38 +1160,25 @@ EXPORT_SYMBOL_GPL(wait_for_tpm_stat); ...@@ -1170,38 +1160,25 @@ EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
*/ */
int tpm_open(struct inode *inode, struct file *file) int tpm_open(struct inode *inode, struct file *file)
{ {
int minor = iminor(inode); struct miscdevice *misc = file->private_data;
struct tpm_chip *chip = NULL, *pos; struct tpm_chip *chip = container_of(misc, struct tpm_chip,
vendor.miscdev);
rcu_read_lock();
list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
if (pos->vendor.miscdev.minor == minor) {
chip = pos;
get_device(chip->dev);
break;
}
}
rcu_read_unlock();
if (!chip)
return -ENODEV;
if (test_and_set_bit(0, &chip->is_open)) { if (test_and_set_bit(0, &chip->is_open)) {
dev_dbg(chip->dev, "Another process owns this TPM\n"); dev_dbg(chip->dev, "Another process owns this TPM\n");
put_device(chip->dev);
return -EBUSY; return -EBUSY;
} }
chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
if (chip->data_buffer == NULL) { if (chip->data_buffer == NULL) {
clear_bit(0, &chip->is_open); clear_bit(0, &chip->is_open);
put_device(chip->dev);
return -ENOMEM; return -ENOMEM;
} }
atomic_set(&chip->data_pending, 0); atomic_set(&chip->data_pending, 0);
file->private_data = chip; file->private_data = chip;
get_device(chip->dev);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(tpm_open); EXPORT_SYMBOL_GPL(tpm_open);
...@@ -1463,7 +1440,6 @@ void tpm_dev_vendor_release(struct tpm_chip *chip) ...@@ -1463,7 +1440,6 @@ void tpm_dev_vendor_release(struct tpm_chip *chip)
chip->vendor.release(chip->dev); chip->vendor.release(chip->dev);
clear_bit(chip->dev_num, dev_mask); clear_bit(chip->dev_num, dev_mask);
kfree(chip->vendor.miscdev.name);
} }
EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
...@@ -1496,17 +1472,13 @@ EXPORT_SYMBOL_GPL(tpm_dev_release); ...@@ -1496,17 +1472,13 @@ EXPORT_SYMBOL_GPL(tpm_dev_release);
struct tpm_chip *tpm_register_hardware(struct device *dev, struct tpm_chip *tpm_register_hardware(struct device *dev,
const struct tpm_vendor_specific *entry) const struct tpm_vendor_specific *entry)
{ {
#define DEVNAME_SIZE 7
char *devname;
struct tpm_chip *chip; struct tpm_chip *chip;
/* Driver specific per-device data */ /* Driver specific per-device data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL); chip = kzalloc(sizeof(*chip), GFP_KERNEL);
devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
if (chip == NULL || devname == NULL) if (chip == NULL)
goto out_free; return NULL;
mutex_init(&chip->buffer_mutex); mutex_init(&chip->buffer_mutex);
mutex_init(&chip->tpm_mutex); mutex_init(&chip->tpm_mutex);
...@@ -1531,8 +1503,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, ...@@ -1531,8 +1503,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
set_bit(chip->dev_num, dev_mask); set_bit(chip->dev_num, dev_mask);
scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
chip->vendor.miscdev.name = devname; chip->dev_num);
chip->vendor.miscdev.name = chip->devname;
chip->vendor.miscdev.parent = dev; chip->vendor.miscdev.parent = dev;
chip->dev = get_device(dev); chip->dev = get_device(dev);
...@@ -1558,7 +1531,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, ...@@ -1558,7 +1531,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
goto put_device; goto put_device;
} }
chip->bios_dir = tpm_bios_log_setup(devname); chip->bios_dir = tpm_bios_log_setup(chip->devname);
/* Make chip available */ /* Make chip available */
spin_lock(&driver_lock); spin_lock(&driver_lock);
...@@ -1571,7 +1544,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, ...@@ -1571,7 +1544,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
put_device(chip->dev); put_device(chip->dev);
out_free: out_free:
kfree(chip); kfree(chip);
kfree(devname);
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(tpm_register_hardware); EXPORT_SYMBOL_GPL(tpm_register_hardware);
......
...@@ -59,8 +59,6 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, ...@@ -59,8 +59,6 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
char *); char *);
extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
char *); char *);
extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr,
char *);
extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
const char *, size_t); const char *, size_t);
extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr,
...@@ -122,6 +120,7 @@ struct tpm_chip { ...@@ -122,6 +120,7 @@ struct tpm_chip {
struct device *dev; /* Device stuff */ struct device *dev; /* Device stuff */
int dev_num; /* /dev/tpm# */ int dev_num; /* /dev/tpm# */
char devname[7];
unsigned long is_open; /* only one allowed */ unsigned long is_open; /* only one allowed */
int time_expired; int time_expired;
......
...@@ -202,7 +202,7 @@ static int __init init_atmel(void) ...@@ -202,7 +202,7 @@ static int __init init_atmel(void)
have_region = have_region =
(atmel_request_region (atmel_request_region
(tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
......
...@@ -406,7 +406,6 @@ struct dentry **tpm_bios_log_setup(char *name) ...@@ -406,7 +406,6 @@ struct dentry **tpm_bios_log_setup(char *name)
out: out:
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
void tpm_bios_log_teardown(struct dentry **lst) void tpm_bios_log_teardown(struct dentry **lst)
{ {
...@@ -415,5 +414,3 @@ void tpm_bios_log_teardown(struct dentry **lst) ...@@ -415,5 +414,3 @@ void tpm_bios_log_teardown(struct dentry **lst)
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
securityfs_remove(lst[i]); securityfs_remove(lst[i]);
} }
EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
MODULE_LICENSE("GPL");
/*
* ATMEL I2C TPM AT97SC3204T
*
* Copyright (C) 2012 V Lab Technologies
* Teddy Reed <teddy@prosauce.org>
* Copyright (C) 2013, Obsidian Research Corp.
* Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
* Device driver for ATMEL I2C TPMs.
*
* Teddy Reed determined the basic I2C command flow, unlike other I2C TPM
* devices the raw TCG formatted TPM command data is written via I2C and then
* raw TCG formatted TPM command data is returned via I2C.
*
* TGC status/locality/etc functions seen in the LPC implementation do not
* seem to be present.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include "tpm.h"
#define I2C_DRIVER_NAME "tpm_i2c_atmel"
#define TPM_I2C_SHORT_TIMEOUT 750 /* ms */
#define TPM_I2C_LONG_TIMEOUT 2000 /* 2 sec */
#define ATMEL_STS_OK 1
struct priv_data {
size_t len;
/* This is the amount we read on the first try. 25 was chosen to fit a
* fair number of read responses in the buffer so a 2nd retry can be
* avoided in small message cases. */
u8 buffer[sizeof(struct tpm_output_header) + 25];
};
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
s32 status;
priv->len = 0;
if (len <= 2)
return -EIO;
status = i2c_master_send(client, buf, len);
dev_dbg(chip->dev,
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
(int)min_t(size_t, 64, len), buf, len, status);
return status;
}
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
struct tpm_output_header *hdr =
(struct tpm_output_header *)priv->buffer;
u32 expected_len;
int rc;
if (priv->len == 0)
return -EIO;
/* Get the message size from the message header, if we didn't get the
* whole message in read_status then we need to re-read the
* message. */
expected_len = be32_to_cpu(hdr->length);
if (expected_len > count)
return -ENOMEM;
if (priv->len >= expected_len) {
dev_dbg(chip->dev,
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
memcpy(buf, priv->buffer, expected_len);
return expected_len;
}
rc = i2c_master_recv(client, buf, expected_len);
dev_dbg(chip->dev,
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
return rc;
}
static void i2c_atmel_cancel(struct tpm_chip *chip)
{
dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported");
}
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
int rc;
/* The TPM fails the I2C read until it is ready, so we do the entire
* transfer here and buffer it locally. This way the common code can
* properly handle the timeouts. */
priv->len = 0;
memset(priv->buffer, 0, sizeof(priv->buffer));
/* Once the TPM has completed the command the command remains readable
* until another command is issued. */
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
dev_dbg(chip->dev,
"%s: sts=%d", __func__, rc);
if (rc <= 0)
return 0;
priv->len = rc;
return ATMEL_STS_OK;
}
static const struct file_operations i2c_atmel_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
.read = tpm_read,
.write = tpm_write,
.release = tpm_release,
};
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
static struct attribute *i2c_atmel_attrs[] = {
&dev_attr_pubek.attr,
&dev_attr_pcrs.attr,
&dev_attr_enabled.attr,
&dev_attr_active.attr,
&dev_attr_owned.attr,
&dev_attr_temp_deactivated.attr,
&dev_attr_caps.attr,
&dev_attr_cancel.attr,
&dev_attr_durations.attr,
&dev_attr_timeouts.attr,
NULL,
};
static struct attribute_group i2c_atmel_attr_grp = {
.attrs = i2c_atmel_attrs
};
static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status)
{
return 0;
}
static const struct tpm_vendor_specific i2c_atmel = {
.status = i2c_atmel_read_status,
.recv = i2c_atmel_recv,
.send = i2c_atmel_send,
.cancel = i2c_atmel_cancel,
.req_complete_mask = ATMEL_STS_OK,
.req_complete_val = ATMEL_STS_OK,
.req_canceled = i2c_atmel_req_canceled,
.attr_group = &i2c_atmel_attr_grp,
.miscdev.fops = &i2c_atmel_ops,
};
static int i2c_atmel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
struct tpm_chip *chip;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
chip = tpm_register_hardware(dev, &i2c_atmel);
if (!chip) {
dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
return -ENODEV;
}
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
GFP_KERNEL);
/* Default timeouts */
chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
chip->vendor.timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT);
chip->vendor.timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
chip->vendor.irq = 0;
/* There is no known way to probe for this device, and all version
* information seems to be read via TPM commands. Thus we rely on the
* TPM startup process in the common code to detect the device. */
if (tpm_get_timeouts(chip)) {
rc = -ENODEV;
goto out_err;
}
if (tpm_do_selftest(chip)) {
rc = -ENODEV;
goto out_err;
}
return 0;
out_err:
tpm_dev_vendor_release(chip);
tpm_remove_hardware(chip->dev);
return rc;
}
static int i2c_atmel_remove(struct i2c_client *client)
{
struct device *dev = &(client->dev);
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip)
tpm_dev_vendor_release(chip);
tpm_remove_hardware(dev);
kfree(chip);
return 0;
}
static const struct i2c_device_id i2c_atmel_id[] = {
{I2C_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, i2c_atmel_id);
#ifdef CONFIG_OF
static const struct of_device_id i2c_atmel_of_match[] = {
{.compatible = "atmel,at97sc3204t"},
{},
};
MODULE_DEVICE_TABLE(of, i2c_atmel_of_match);
#endif
static SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume);
static struct i2c_driver i2c_atmel_driver = {
.id_table = i2c_atmel_id,
.probe = i2c_atmel_probe,
.remove = i2c_atmel_remove,
.driver = {
.name = I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &i2c_atmel_pm_ops,
.of_match_table = of_match_ptr(i2c_atmel_of_match),
},
};
module_i2c_driver(i2c_atmel_driver);
MODULE_AUTHOR("Jason Gunthorpe <jgunthorpe@obsidianresearch.com>");
MODULE_DESCRIPTION("Atmel TPM I2C Driver");
MODULE_LICENSE("GPL");
...@@ -581,7 +581,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); ...@@ -581,7 +581,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
...@@ -685,7 +685,6 @@ static int tpm_tis_i2c_init(struct device *dev) ...@@ -685,7 +685,6 @@ static int tpm_tis_i2c_init(struct device *dev)
chip->dev->release = NULL; chip->dev->release = NULL;
chip->release = NULL; chip->release = NULL;
tpm_dev.client = NULL; tpm_dev.client = NULL;
dev_set_drvdata(chip->dev, chip);
out_err: out_err:
return rc; return rc;
} }
...@@ -766,7 +765,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client) ...@@ -766,7 +765,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client)
chip->dev->release = NULL; chip->dev->release = NULL;
chip->release = NULL; chip->release = NULL;
tpm_dev.client = NULL; tpm_dev.client = NULL;
dev_set_drvdata(chip->dev, chip);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -584,7 +584,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); ...@@ -584,7 +584,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
static struct attribute *stm_tpm_attrs[] = { static struct attribute *stm_tpm_attrs[] = {
...@@ -746,8 +746,6 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -746,8 +746,6 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
tpm_get_timeouts(chip); tpm_get_timeouts(chip);
i2c_set_clientdata(client, chip);
dev_info(chip->dev, "TPM I2C Initialized\n"); dev_info(chip->dev, "TPM I2C Initialized\n");
return 0; return 0;
_irq_set: _irq_set:
...@@ -807,24 +805,18 @@ static int tpm_st33_i2c_remove(struct i2c_client *client) ...@@ -807,24 +805,18 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/* /*
* tpm_st33_i2c_pm_suspend suspend the TPM device * tpm_st33_i2c_pm_suspend suspend the TPM device
* Added: Work around when suspend and no tpm application is running, suspend
* may fail because chip->data_buffer is not set (only set in tpm_open in Linux
* TPM core)
* @param: client, the i2c_client drescription (TPM I2C description). * @param: client, the i2c_client drescription (TPM I2C description).
* @param: mesg, the power management message. * @param: mesg, the power management message.
* @return: 0 in case of success. * @return: 0 in case of success.
*/ */
static int tpm_st33_i2c_pm_suspend(struct device *dev) static int tpm_st33_i2c_pm_suspend(struct device *dev)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev);
struct st33zp24_platform_data *pin_infos = dev->platform_data; struct st33zp24_platform_data *pin_infos = dev->platform_data;
int ret = 0; int ret = 0;
if (power_mgt) { if (power_mgt) {
gpio_set_value(pin_infos->io_lpcpd, 0); gpio_set_value(pin_infos->io_lpcpd, 0);
} else { } else {
if (chip->data_buffer == NULL)
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
ret = tpm_pm_suspend(dev); ret = tpm_pm_suspend(dev);
} }
return ret; return ret;
...@@ -849,8 +841,6 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) ...@@ -849,8 +841,6 @@ static int tpm_st33_i2c_pm_resume(struct device *dev)
TPM_STS_VALID) == TPM_STS_VALID, TPM_STS_VALID) == TPM_STS_VALID,
chip->vendor.timeout_b); chip->vendor.timeout_b);
} else { } else {
if (chip->data_buffer == NULL)
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
ret = tpm_pm_resume(dev); ret = tpm_pm_resume(dev);
if (!ret) if (!ret)
tpm_do_selftest(chip); tpm_do_selftest(chip);
......
...@@ -98,7 +98,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -98,7 +98,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
if (count < len) { if (count < len) {
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"Invalid size in recv: count=%ld, crq_size=%d\n", "Invalid size in recv: count=%zd, crq_size=%d\n",
count, len); count, len);
return -EIO; return -EIO;
} }
...@@ -136,7 +136,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -136,7 +136,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
if (count > ibmvtpm->rtce_size) { if (count > ibmvtpm->rtce_size) {
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"Invalid size in send: count=%ld, rtce_size=%d\n", "Invalid size in send: count=%zd, rtce_size=%d\n",
count, ibmvtpm->rtce_size); count, ibmvtpm->rtce_size);
return -EIO; return -EIO;
} }
...@@ -419,7 +419,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); ...@@ -419,7 +419,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
NULL); NULL);
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
......
...@@ -452,12 +452,8 @@ int tpm_add_ppi(struct kobject *parent) ...@@ -452,12 +452,8 @@ int tpm_add_ppi(struct kobject *parent)
{ {
return sysfs_create_group(parent, &ppi_attr_grp); return sysfs_create_group(parent, &ppi_attr_grp);
} }
EXPORT_SYMBOL_GPL(tpm_add_ppi);
void tpm_remove_ppi(struct kobject *parent) void tpm_remove_ppi(struct kobject *parent)
{ {
sysfs_remove_group(parent, &ppi_attr_grp); sysfs_remove_group(parent, &ppi_attr_grp);
} }
EXPORT_SYMBOL_GPL(tpm_remove_ppi);
MODULE_LICENSE("GPL");
...@@ -448,7 +448,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); ...@@ -448,7 +448,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
NULL); NULL);
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
......
...@@ -351,8 +351,6 @@ static int tpmfront_probe(struct xenbus_device *dev, ...@@ -351,8 +351,6 @@ static int tpmfront_probe(struct xenbus_device *dev,
tpm_get_timeouts(priv->chip); tpm_get_timeouts(priv->chip);
dev_set_drvdata(&dev->dev, priv->chip);
return rv; return rv;
} }
......
/*
* Hash Info: Hash algorithms information
*
* Copyright (c) 2013 Dmitry Kasatkin <d.kasatkin@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _CRYPTO_HASH_INFO_H
#define _CRYPTO_HASH_INFO_H
#include <crypto/sha.h>
#include <crypto/md5.h>
#include <uapi/linux/hash_info.h>
/* not defined in include/crypto/ */
#define RMD128_DIGEST_SIZE 16
#define RMD160_DIGEST_SIZE 20
#define RMD256_DIGEST_SIZE 32
#define RMD320_DIGEST_SIZE 40
/* not defined in include/crypto/ */
#define WP512_DIGEST_SIZE 64
#define WP384_DIGEST_SIZE 48
#define WP256_DIGEST_SIZE 32
/* not defined in include/crypto/ */
#define TGR128_DIGEST_SIZE 16
#define TGR160_DIGEST_SIZE 20
#define TGR192_DIGEST_SIZE 24
extern const char *const hash_algo_name[HASH_ALGO__LAST];
extern const int hash_digest_size[HASH_ALGO__LAST];
#endif /* _CRYPTO_HASH_INFO_H */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H
#include <linux/mpi.h> #include <linux/mpi.h>
#include <crypto/hash_info.h>
enum pkey_algo { enum pkey_algo {
PKEY_ALGO_DSA, PKEY_ALGO_DSA,
...@@ -22,21 +23,11 @@ enum pkey_algo { ...@@ -22,21 +23,11 @@ enum pkey_algo {
PKEY_ALGO__LAST PKEY_ALGO__LAST
}; };
extern const char *const pkey_algo[PKEY_ALGO__LAST]; extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
enum pkey_hash_algo { /* asymmetric key implementation supports only up to SHA224 */
PKEY_HASH_MD4, #define PKEY_HASH__LAST (HASH_ALGO_SHA224 + 1)
PKEY_HASH_MD5,
PKEY_HASH_SHA1,
PKEY_HASH_RIPE_MD_160,
PKEY_HASH_SHA256,
PKEY_HASH_SHA384,
PKEY_HASH_SHA512,
PKEY_HASH_SHA224,
PKEY_HASH__LAST
};
extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
enum pkey_id_type { enum pkey_id_type {
PKEY_ID_PGP, /* OpenPGP generated key ID */ PKEY_ID_PGP, /* OpenPGP generated key ID */
...@@ -44,7 +35,7 @@ enum pkey_id_type { ...@@ -44,7 +35,7 @@ enum pkey_id_type {
PKEY_ID_TYPE__LAST PKEY_ID_TYPE__LAST
}; };
extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST]; extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
/* /*
* Cryptographic data for the public-key subtype of the asymmetric key type. * Cryptographic data for the public-key subtype of the asymmetric key type.
...@@ -59,6 +50,7 @@ struct public_key { ...@@ -59,6 +50,7 @@ struct public_key {
#define PKEY_CAN_DECRYPT 0x02 #define PKEY_CAN_DECRYPT 0x02
#define PKEY_CAN_SIGN 0x04 #define PKEY_CAN_SIGN 0x04
#define PKEY_CAN_VERIFY 0x08 #define PKEY_CAN_VERIFY 0x08
enum pkey_algo pkey_algo : 8;
enum pkey_id_type id_type : 8; enum pkey_id_type id_type : 8;
union { union {
MPI mpi[5]; MPI mpi[5];
...@@ -88,7 +80,8 @@ struct public_key_signature { ...@@ -88,7 +80,8 @@ struct public_key_signature {
u8 *digest; u8 *digest;
u8 digest_size; /* Number of bytes in digest */ u8 digest_size; /* Number of bytes in digest */
u8 nr_mpi; /* Occupancy of mpi[] */ u8 nr_mpi; /* Occupancy of mpi[] */
enum pkey_hash_algo pkey_hash_algo : 8; enum pkey_algo pkey_algo : 8;
enum hash_algo pkey_hash_algo : 8;
union { union {
MPI mpi[2]; MPI mpi[2];
struct { struct {
......
/* Big capacity key type.
*
* Copyright (C) 2013 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 License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _KEYS_BIG_KEY_TYPE_H
#define _KEYS_BIG_KEY_TYPE_H
#include <linux/key-type.h>
extern struct key_type key_type_big_key;
extern int big_key_instantiate(struct key *key, 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);
extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen);
#endif /* _KEYS_BIG_KEY_TYPE_H */
/* Keyring key type /* Keyring key type
* *
* Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. * Copyright (C) 2008, 2013 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com) * Written by David Howells (dhowells@redhat.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -13,19 +13,6 @@ ...@@ -13,19 +13,6 @@
#define _KEYS_KEYRING_TYPE_H #define _KEYS_KEYRING_TYPE_H
#include <linux/key.h> #include <linux/key.h>
#include <linux/rcupdate.h> #include <linux/assoc_array.h>
/*
* the keyring payload contains a list of the keys to which the keyring is
* subscribed
*/
struct keyring_list {
struct rcu_head rcu; /* RCU deletion hook */
unsigned short maxkeys; /* max keys this list can hold */
unsigned short nkeys; /* number of keys currently held */
unsigned short delkey; /* key to be unlinked by RCU */
struct key __rcu *keys[0];
};
#endif /* _KEYS_KEYRING_TYPE_H */ #endif /* _KEYS_KEYRING_TYPE_H */
/* System keyring containing trusted public keys.
*
* Copyright (C) 2013 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 _KEYS_SYSTEM_KEYRING_H
#define _KEYS_SYSTEM_KEYRING_H
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
#include <linux/key.h>
extern struct key *system_trusted_keyring;
#endif
#endif /* _KEYS_SYSTEM_KEYRING_H */
/* Generic associative array implementation.
*
* See Documentation/assoc_array.txt for information.
*
* Copyright (C) 2013 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_ASSOC_ARRAY_H
#define _LINUX_ASSOC_ARRAY_H
#ifdef CONFIG_ASSOCIATIVE_ARRAY
#include <linux/types.h>
#define ASSOC_ARRAY_KEY_CHUNK_SIZE BITS_PER_LONG /* Key data retrieved in chunks of this size */
/*
* Generic associative array.
*/
struct assoc_array {
struct assoc_array_ptr *root; /* The node at the root of the tree */
unsigned long nr_leaves_on_tree;
};
/*
* Operations on objects and index keys for use by array manipulation routines.
*/
struct assoc_array_ops {
/* Method to get a chunk of an index key from caller-supplied data */
unsigned long (*get_key_chunk)(const void *index_key, int level);
/* Method to get a piece of an object's index key */
unsigned long (*get_object_key_chunk)(const void *object, int level);
/* Is this the object we're looking for? */
bool (*compare_object)(const void *object, const void *index_key);
/* How different are two objects, to a bit position in their keys? (or
* -1 if they're the same)
*/
int (*diff_objects)(const void *a, const void *b);
/* Method to free an object. */
void (*free_object)(void *object);
};
/*
* Access and manipulation functions.
*/
struct assoc_array_edit;
static inline void assoc_array_init(struct assoc_array *array)
{
array->root = NULL;
array->nr_leaves_on_tree = 0;
}
extern int assoc_array_iterate(const struct assoc_array *array,
int (*iterator)(const void *object,
void *iterator_data),
void *iterator_data);
extern void *assoc_array_find(const struct assoc_array *array,
const struct assoc_array_ops *ops,
const void *index_key);
extern void assoc_array_destroy(struct assoc_array *array,
const struct assoc_array_ops *ops);
extern struct assoc_array_edit *assoc_array_insert(struct assoc_array *array,
const struct assoc_array_ops *ops,
const void *index_key,
void *object);
extern void assoc_array_insert_set_object(struct assoc_array_edit *edit,
void *object);
extern struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
const struct assoc_array_ops *ops,
const void *index_key);
extern struct assoc_array_edit *assoc_array_clear(struct assoc_array *array,
const struct assoc_array_ops *ops);
extern void assoc_array_apply_edit(struct assoc_array_edit *edit);
extern void assoc_array_cancel_edit(struct assoc_array_edit *edit);
extern int assoc_array_gc(struct assoc_array *array,
const struct assoc_array_ops *ops,
bool (*iterator)(void *object, void *iterator_data),
void *iterator_data);
#endif /* CONFIG_ASSOCIATIVE_ARRAY */
#endif /* _LINUX_ASSOC_ARRAY_H */
/* Private definitions for the generic associative array implementation.
*
* See Documentation/assoc_array.txt for information.
*
* Copyright (C) 2013 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_ASSOC_ARRAY_PRIV_H
#define _LINUX_ASSOC_ARRAY_PRIV_H
#ifdef CONFIG_ASSOCIATIVE_ARRAY
#include <linux/assoc_array.h>
#define ASSOC_ARRAY_FAN_OUT 16 /* Number of slots per node */
#define ASSOC_ARRAY_FAN_MASK (ASSOC_ARRAY_FAN_OUT - 1)
#define ASSOC_ARRAY_LEVEL_STEP (ilog2(ASSOC_ARRAY_FAN_OUT))
#define ASSOC_ARRAY_LEVEL_STEP_MASK (ASSOC_ARRAY_LEVEL_STEP - 1)
#define ASSOC_ARRAY_KEY_CHUNK_MASK (ASSOC_ARRAY_KEY_CHUNK_SIZE - 1)
#define ASSOC_ARRAY_KEY_CHUNK_SHIFT (ilog2(BITS_PER_LONG))
/*
* Undefined type representing a pointer with type information in the bottom
* two bits.
*/
struct assoc_array_ptr;
/*
* An N-way node in the tree.
*
* Each slot contains one of four things:
*
* (1) Nothing (NULL).
*
* (2) A leaf object (pointer types 0).
*
* (3) A next-level node (pointer type 1, subtype 0).
*
* (4) A shortcut (pointer type 1, subtype 1).
*
* The tree is optimised for search-by-ID, but permits reasonable iteration
* also.
*
* The tree is navigated by constructing an index key consisting of an array of
* segments, where each segment is ilog2(ASSOC_ARRAY_FAN_OUT) bits in size.
*
* The segments correspond to levels of the tree (the first segment is used at
* level 0, the second at level 1, etc.).
*/
struct assoc_array_node {
struct assoc_array_ptr *back_pointer;
u8 parent_slot;
struct assoc_array_ptr *slots[ASSOC_ARRAY_FAN_OUT];
unsigned long nr_leaves_on_branch;
};
/*
* A shortcut through the index space out to where a collection of nodes/leaves
* with the same IDs live.
*/
struct assoc_array_shortcut {
struct assoc_array_ptr *back_pointer;
int parent_slot;
int skip_to_level;
struct assoc_array_ptr *next_node;
unsigned long index_key[];
};
/*
* Preallocation cache.
*/
struct assoc_array_edit {
struct rcu_head rcu;
struct assoc_array *array;
const struct assoc_array_ops *ops;
const struct assoc_array_ops *ops_for_excised_subtree;
struct assoc_array_ptr *leaf;
struct assoc_array_ptr **leaf_p;
struct assoc_array_ptr *dead_leaf;
struct assoc_array_ptr *new_meta[3];
struct assoc_array_ptr *excised_meta[1];
struct assoc_array_ptr *excised_subtree;
struct assoc_array_ptr **set_backpointers[ASSOC_ARRAY_FAN_OUT];
struct assoc_array_ptr *set_backpointers_to;
struct assoc_array_node *adjust_count_on;
long adjust_count_by;
struct {
struct assoc_array_ptr **ptr;
struct assoc_array_ptr *to;
} set[2];
struct {
u8 *p;
u8 to;
} set_parent_slot[1];
u8 segment_cache[ASSOC_ARRAY_FAN_OUT + 1];
};
/*
* Internal tree member pointers are marked in the bottom one or two bits to
* indicate what type they are so that we don't have to look behind every
* pointer to see what it points to.
*
* We provide functions to test type annotations and to create and translate
* the annotated pointers.
*/
#define ASSOC_ARRAY_PTR_TYPE_MASK 0x1UL
#define ASSOC_ARRAY_PTR_LEAF_TYPE 0x0UL /* Points to leaf (or nowhere) */
#define ASSOC_ARRAY_PTR_META_TYPE 0x1UL /* Points to node or shortcut */
#define ASSOC_ARRAY_PTR_SUBTYPE_MASK 0x2UL
#define ASSOC_ARRAY_PTR_NODE_SUBTYPE 0x0UL
#define ASSOC_ARRAY_PTR_SHORTCUT_SUBTYPE 0x2UL
static inline bool assoc_array_ptr_is_meta(const struct assoc_array_ptr *x)
{
return (unsigned long)x & ASSOC_ARRAY_PTR_TYPE_MASK;
}
static inline bool assoc_array_ptr_is_leaf(const struct assoc_array_ptr *x)
{
return !assoc_array_ptr_is_meta(x);
}
static inline bool assoc_array_ptr_is_shortcut(const struct assoc_array_ptr *x)
{
return (unsigned long)x & ASSOC_ARRAY_PTR_SUBTYPE_MASK;
}
static inline bool assoc_array_ptr_is_node(const struct assoc_array_ptr *x)
{
return !assoc_array_ptr_is_shortcut(x);
}
static inline void *assoc_array_ptr_to_leaf(const struct assoc_array_ptr *x)
{
return (void *)((unsigned long)x & ~ASSOC_ARRAY_PTR_TYPE_MASK);
}
static inline
unsigned long __assoc_array_ptr_to_meta(const struct assoc_array_ptr *x)
{
return (unsigned long)x &
~(ASSOC_ARRAY_PTR_SUBTYPE_MASK | ASSOC_ARRAY_PTR_TYPE_MASK);
}
static inline
struct assoc_array_node *assoc_array_ptr_to_node(const struct assoc_array_ptr *x)
{
return (struct assoc_array_node *)__assoc_array_ptr_to_meta(x);
}
static inline
struct assoc_array_shortcut *assoc_array_ptr_to_shortcut(const struct assoc_array_ptr *x)
{
return (struct assoc_array_shortcut *)__assoc_array_ptr_to_meta(x);
}
static inline
struct assoc_array_ptr *__assoc_array_x_to_ptr(const void *p, unsigned long t)
{
return (struct assoc_array_ptr *)((unsigned long)p | t);
}
static inline
struct assoc_array_ptr *assoc_array_leaf_to_ptr(const void *p)
{
return __assoc_array_x_to_ptr(p, ASSOC_ARRAY_PTR_LEAF_TYPE);
}
static inline
struct assoc_array_ptr *assoc_array_node_to_ptr(const struct assoc_array_node *p)
{
return __assoc_array_x_to_ptr(
p, ASSOC_ARRAY_PTR_META_TYPE | ASSOC_ARRAY_PTR_NODE_SUBTYPE);
}
static inline
struct assoc_array_ptr *assoc_array_shortcut_to_ptr(const struct assoc_array_shortcut *p)
{
return __assoc_array_x_to_ptr(
p, ASSOC_ARRAY_PTR_META_TYPE | ASSOC_ARRAY_PTR_SHORTCUT_SUBTYPE);
}
#endif /* CONFIG_ASSOCIATIVE_ARRAY */
#endif /* _LINUX_ASSOC_ARRAY_PRIV_H */
...@@ -45,6 +45,7 @@ struct key_preparsed_payload { ...@@ -45,6 +45,7 @@ struct key_preparsed_payload {
const void *data; /* Raw data */ const void *data; /* Raw data */
size_t datalen; /* Raw datalen */ size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */ size_t quotalen; /* Quota length for proposed payload */
bool trusted; /* True if key is trusted */
}; };
typedef int (*request_key_actor_t)(struct key_construction *key, typedef int (*request_key_actor_t)(struct key_construction *key,
...@@ -63,6 +64,11 @@ struct key_type { ...@@ -63,6 +64,11 @@ struct key_type {
*/ */
size_t def_datalen; size_t def_datalen;
/* Default key search algorithm. */
unsigned def_lookup_type;
#define KEYRING_SEARCH_LOOKUP_DIRECT 0x0000 /* Direct lookup by description. */
#define KEYRING_SEARCH_LOOKUP_ITERATE 0x0001 /* Iterative search. */
/* vet a description */ /* vet a description */
int (*vet_description)(const char *description); int (*vet_description)(const char *description);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/assoc_array.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/uidgid.h> #include <linux/uidgid.h>
...@@ -82,6 +83,12 @@ struct key_owner; ...@@ -82,6 +83,12 @@ struct key_owner;
struct keyring_list; struct keyring_list;
struct keyring_name; struct keyring_name;
struct keyring_index_key {
struct key_type *type;
const char *description;
size_t desc_len;
};
/*****************************************************************************/ /*****************************************************************************/
/* /*
* key reference with possession attribute handling * key reference with possession attribute handling
...@@ -99,7 +106,7 @@ struct keyring_name; ...@@ -99,7 +106,7 @@ struct keyring_name;
typedef struct __key_reference_with_attributes *key_ref_t; typedef struct __key_reference_with_attributes *key_ref_t;
static inline key_ref_t make_key_ref(const struct key *key, static inline key_ref_t make_key_ref(const struct key *key,
unsigned long possession) bool possession)
{ {
return (key_ref_t) ((unsigned long) key | possession); return (key_ref_t) ((unsigned long) key | possession);
} }
...@@ -109,7 +116,7 @@ static inline struct key *key_ref_to_ptr(const key_ref_t key_ref) ...@@ -109,7 +116,7 @@ static inline struct key *key_ref_to_ptr(const key_ref_t key_ref)
return (struct key *) ((unsigned long) key_ref & ~1UL); return (struct key *) ((unsigned long) key_ref & ~1UL);
} }
static inline unsigned long is_key_possessed(const key_ref_t key_ref) static inline bool is_key_possessed(const key_ref_t key_ref)
{ {
return (unsigned long) key_ref & 1UL; return (unsigned long) key_ref & 1UL;
} }
...@@ -129,7 +136,6 @@ struct key { ...@@ -129,7 +136,6 @@ struct key {
struct list_head graveyard_link; struct list_head graveyard_link;
struct rb_node serial_node; struct rb_node serial_node;
}; };
struct key_type *type; /* type of key */
struct rw_semaphore sem; /* change vs change sem */ struct rw_semaphore sem; /* change vs change sem */
struct key_user *user; /* owner of this key */ struct key_user *user; /* owner of this key */
void *security; /* security data for this key */ void *security; /* security data for this key */
...@@ -162,13 +168,21 @@ struct key { ...@@ -162,13 +168,21 @@ struct key {
#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ #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 */
/* the description string /* the key type and key description string
* - this is used to match a key against search criteria * - the desc is used to match a key against search criteria
* - this should be a printable string * - it should be a printable string
* - eg: for krb5 AFS, this might be "afs@REDHAT.COM" * - eg: for krb5 AFS, this might be "afs@REDHAT.COM"
*/ */
union {
struct keyring_index_key index_key;
struct {
struct key_type *type; /* type of key */
char *description; char *description;
};
};
/* type specific data /* type specific data
* - this is used by the keyring type to index the name * - this is used by the keyring type to index the name
...@@ -184,12 +198,15 @@ struct key { ...@@ -184,12 +198,15 @@ struct key {
* - this is used to hold the data actually used in cryptography or * - this is used to hold the data actually used in cryptography or
* whatever * whatever
*/ */
union {
union { union {
unsigned long value; unsigned long value;
void __rcu *rcudata; void __rcu *rcudata;
void *data; void *data;
struct keyring_list __rcu *subscriptions; void *data2[2];
} payload; } payload;
struct assoc_array keys;
};
}; };
extern struct key *key_alloc(struct key_type *type, extern struct key *key_alloc(struct key_type *type,
...@@ -203,18 +220,23 @@ extern struct key *key_alloc(struct key_type *type, ...@@ -203,18 +220,23 @@ extern struct key *key_alloc(struct key_type *type,
#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
extern void key_revoke(struct key *key); extern void key_revoke(struct key *key);
extern void key_invalidate(struct key *key); extern void key_invalidate(struct key *key);
extern void key_put(struct key *key); extern void key_put(struct key *key);
static inline struct key *key_get(struct key *key) static inline struct key *__key_get(struct key *key)
{ {
if (key)
atomic_inc(&key->usage); atomic_inc(&key->usage);
return key; return key;
} }
static inline struct key *key_get(struct key *key)
{
return key ? __key_get(key) : key;
}
static inline void key_ref_put(key_ref_t key_ref) static inline void key_ref_put(key_ref_t key_ref)
{ {
key_put(key_ref_to_ptr(key_ref)); key_put(key_ref_to_ptr(key_ref));
......
...@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @xfrm_policy_delete_security: * @xfrm_policy_delete_security:
* @ctx contains the xfrm_sec_ctx. * @ctx contains the xfrm_sec_ctx.
* Authorize deletion of xp->security. * Authorize deletion of xp->security.
* @xfrm_state_alloc_security: * @xfrm_state_alloc:
* @x contains the xfrm_state being added to the Security Association * @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system. * Database by the XFRM system.
* @sec_ctx contains the security context information being provided by * @sec_ctx contains the security context information being provided by
* the user-level SA generation program (e.g., setkey or racoon). * the user-level SA generation program (e.g., setkey or racoon).
* @secid contains the secid from which to take the mls portion of the context.
* Allocate a security structure to the x->security field; the security * Allocate a security structure to the x->security field; the security
* field is initialized to NULL when the xfrm_state is allocated. Set the * field is initialized to NULL when the xfrm_state is allocated. Set the
* context to correspond to either sec_ctx or polsec, with the mls portion * context to correspond to sec_ctx. Return 0 if operation was successful
* taken from secid in the latter case. * (memory to allocate, legal context).
* Return 0 if operation was successful (memory to allocate, legal context). * @xfrm_state_alloc_acquire:
* @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system.
* @polsec contains the policy's security context.
* @secid contains the secid from which to take the mls portion of the
* context.
* Allocate a security structure to the x->security field; the security
* field is initialized to NULL when the xfrm_state is allocated. Set the
* context to correspond to secid. Return 0 if operation was successful
* (memory to allocate, legal context).
* @xfrm_state_free_security: * @xfrm_state_free_security:
* @x contains the xfrm_state. * @x contains the xfrm_state.
* Deallocate x->security. * Deallocate x->security.
...@@ -1679,8 +1687,10 @@ struct security_operations { ...@@ -1679,8 +1687,10 @@ struct security_operations {
int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_state_alloc_security) (struct xfrm_state *x, int (*xfrm_state_alloc) (struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_user_sec_ctx *sec_ctx);
int (*xfrm_state_alloc_acquire) (struct xfrm_state *x,
struct xfrm_sec_ctx *polsec,
u32 secid); u32 secid);
void (*xfrm_state_free_security) (struct xfrm_state *x); void (*xfrm_state_free_security) (struct xfrm_state *x);
int (*xfrm_state_delete_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x);
......
...@@ -27,6 +27,12 @@ struct user_namespace { ...@@ -27,6 +27,12 @@ struct user_namespace {
kuid_t owner; kuid_t owner;
kgid_t group; kgid_t group;
unsigned int proc_inum; unsigned int proc_inum;
/* Register of per-UID persistent keyrings for this namespace */
#ifdef CONFIG_PERSISTENT_KEYRINGS
struct key *persistent_keyring_register;
struct rw_semaphore persistent_keyring_register_sem;
#endif
}; };
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
......
/*
* Hash Info: Hash algorithms information
*
* Copyright (c) 2013 Dmitry Kasatkin <d.kasatkin@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _UAPI_LINUX_HASH_INFO_H
#define _UAPI_LINUX_HASH_INFO_H
enum hash_algo {
HASH_ALGO_MD4,
HASH_ALGO_MD5,
HASH_ALGO_SHA1,
HASH_ALGO_RIPE_MD_160,
HASH_ALGO_SHA256,
HASH_ALGO_SHA384,
HASH_ALGO_SHA512,
HASH_ALGO_SHA224,
HASH_ALGO_RIPE_MD_128,
HASH_ALGO_RIPE_MD_256,
HASH_ALGO_RIPE_MD_320,
HASH_ALGO_WP_256,
HASH_ALGO_WP_384,
HASH_ALGO_WP_512,
HASH_ALGO_TGR_128,
HASH_ALGO_TGR_160,
HASH_ALGO_TGR_192,
HASH_ALGO__LAST
};
#endif /* _UAPI_LINUX_HASH_INFO_H */
...@@ -56,5 +56,6 @@ ...@@ -56,5 +56,6 @@
#define KEYCTL_REJECT 19 /* reject a partially constructed key */ #define KEYCTL_REJECT 19 /* reject a partially constructed key */
#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
#define KEYCTL_INVALIDATE 21 /* invalidate a key */ #define KEYCTL_INVALIDATE 21 /* invalidate a key */
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
#endif /* _LINUX_KEYCTL_H */ #endif /* _LINUX_KEYCTL_H */
...@@ -1655,6 +1655,18 @@ config BASE_SMALL ...@@ -1655,6 +1655,18 @@ config BASE_SMALL
default 0 if BASE_FULL default 0 if BASE_FULL
default 1 if !BASE_FULL default 1 if !BASE_FULL
config SYSTEM_TRUSTED_KEYRING
bool "Provide system-wide ring of trusted keys"
depends on KEYS
help
Provide a system keyring to which trusted keys can be added. Keys in
the keyring are considered to be trusted. Keys may be added at will
by the kernel from compiled-in data and from hardware key stores, but
userspace may only add extra keys if those keys can be verified by
keys already in the keyring.
Keys in this keyring are used by module signature checking.
menuconfig MODULES menuconfig MODULES
bool "Enable loadable module support" bool "Enable loadable module support"
option modules option modules
...@@ -1728,6 +1740,7 @@ config MODULE_SRCVERSION_ALL ...@@ -1728,6 +1740,7 @@ config MODULE_SRCVERSION_ALL
config MODULE_SIG config MODULE_SIG
bool "Module signature verification" bool "Module signature verification"
depends on MODULES depends on MODULES
select SYSTEM_TRUSTED_KEYRING
select KEYS select KEYS
select CRYPTO select CRYPTO
select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_KEY_TYPE
......
...@@ -41,8 +41,9 @@ ifneq ($(CONFIG_SMP),y) ...@@ -41,8 +41,9 @@ ifneq ($(CONFIG_SMP),y)
obj-y += up.o obj-y += up.o
endif endif
obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o obj-$(CONFIG_MODULE_SIG) += module_signing.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_KEXEC) += kexec.o
...@@ -122,19 +123,52 @@ targets += timeconst.h ...@@ -122,19 +123,52 @@ targets += timeconst.h
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
$(call if_changed,bc) $(call if_changed,bc)
ifeq ($(CONFIG_MODULE_SIG),y) ###############################################################################
#
# Roll all the X.509 certificates that we can find together and pull them into
# the kernel so that they get loaded into the system trusted keyring during
# boot.
# #
# Pull the signing certificate and any extra certificates into the kernel # We look in the source root and the build root for all files whose name ends
# in ".x509". Unfortunately, this will generate duplicate filenames, so we
# have make canonicalise the pathnames and then sort them to discard the
# duplicates.
# #
###############################################################################
ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
X509_CERTIFICATES := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \
$(or $(realpath $(CERT)),$(CERT))))
ifeq ($(X509_CERTIFICATES),)
$(warning *** No X.509 certificates found ***)
endif
ifneq ($(wildcard $(obj)/.x509.list),)
ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES))
$(info X.509 certificate list changed)
$(shell rm $(obj)/.x509.list)
endif
endif
kernel/system_certificates.o: $(obj)/x509_certificate_list
quiet_cmd_touch = TOUCH $@ quiet_cmd_x509certs = CERTS $@
cmd_touch = touch $@ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)")
extra_certificates: targets += $(obj)/x509_certificate_list
$(call cmd,touch) $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
$(call if_changed,x509certs)
kernel/modsign_certificate.o: signing_key.x509 extra_certificates targets += $(obj)/.x509.list
$(obj)/.x509.list:
@echo $(X509_CERTIFICATES) >$@
clean-files := x509_certificate_list .x509.list
endif
ifeq ($(CONFIG_MODULE_SIG),y)
############################################################################### ###############################################################################
# #
# If module signing is requested, say by allyesconfig, but a key has not been # If module signing is requested, say by allyesconfig, but a key has not been
......
#include <linux/export.h>
#define GLOBAL(name) \
.globl VMLINUX_SYMBOL(name); \
VMLINUX_SYMBOL(name):
.section ".init.data","aw"
GLOBAL(modsign_certificate_list)
.incbin "signing_key.x509"
.incbin "extra_certificates"
GLOBAL(modsign_certificate_list_end)
...@@ -9,6 +9,4 @@ ...@@ -9,6 +9,4 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
extern struct key *modsign_keyring;
extern int mod_verify_sig(const void *mod, unsigned long *_modlen); extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <crypto/public_key.h> #include <crypto/public_key.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <keys/asymmetric-type.h> #include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include "module-internal.h" #include "module-internal.h"
/* /*
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
*/ */
struct module_signature { struct module_signature {
u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */ u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */
u8 hash; /* Digest algorithm [enum pkey_hash_algo] */ u8 hash; /* Digest algorithm [enum hash_algo] */
u8 id_type; /* Key identifier type [enum pkey_id_type] */ u8 id_type; /* Key identifier type [enum pkey_id_type] */
u8 signer_len; /* Length of signer's name */ u8 signer_len; /* Length of signer's name */
u8 key_id_len; /* Length of key identifier */ u8 key_id_len; /* Length of key identifier */
...@@ -39,7 +40,7 @@ struct module_signature { ...@@ -39,7 +40,7 @@ struct module_signature {
/* /*
* Digest the module contents. * Digest the module contents.
*/ */
static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash, static struct public_key_signature *mod_make_digest(enum hash_algo hash,
const void *mod, const void *mod,
unsigned long modlen) unsigned long modlen)
{ {
...@@ -54,7 +55,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash, ...@@ -54,7 +55,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
/* Allocate the hashing algorithm we're going to need and find out how /* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be. * big the hash operational data will be.
*/ */
tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0); tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
if (IS_ERR(tfm)) if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
...@@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, ...@@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
pr_debug("Look up: \"%s\"\n", id); pr_debug("Look up: \"%s\"\n", id);
key = keyring_search(make_key_ref(modsign_keyring, 1), key = keyring_search(make_key_ref(system_trusted_keyring, 1),
&key_type_asymmetric, id); &key_type_asymmetric, id);
if (IS_ERR(key)) if (IS_ERR(key))
pr_warn("Request for unknown module key '%s' err %ld\n", pr_warn("Request for unknown module key '%s' err %ld\n",
...@@ -217,7 +218,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) ...@@ -217,7 +218,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
return -ENOPKG; return -ENOPKG;
if (ms.hash >= PKEY_HASH__LAST || if (ms.hash >= PKEY_HASH__LAST ||
!pkey_hash_algo[ms.hash]) !hash_algo_name[ms.hash])
return -ENOPKG; return -ENOPKG;
key = request_asymmetric_key(sig, ms.signer_len, key = request_asymmetric_key(sig, ms.signer_len,
......
#include <linux/export.h>
#include <linux/init.h>
__INITRODATA
.globl VMLINUX_SYMBOL(system_certificate_list)
VMLINUX_SYMBOL(system_certificate_list):
.incbin "kernel/x509_certificate_list"
.globl VMLINUX_SYMBOL(system_certificate_list_end)
VMLINUX_SYMBOL(system_certificate_list_end):
/* Public keys for module signature verification /* System trusted keyring for trusted public keys
* *
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com) * Written by David Howells (dhowells@redhat.com)
...@@ -9,61 +9,59 @@ ...@@ -9,61 +9,59 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
#include <linux/export.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/err.h> #include <linux/err.h>
#include <keys/asymmetric-type.h> #include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include "module-internal.h" #include "module-internal.h"
struct key *modsign_keyring; struct key *system_trusted_keyring;
EXPORT_SYMBOL_GPL(system_trusted_keyring);
extern __initconst const u8 modsign_certificate_list[]; extern __initconst const u8 system_certificate_list[];
extern __initconst const u8 modsign_certificate_list_end[]; extern __initconst const u8 system_certificate_list_end[];
/*
* We need to make sure ccache doesn't cache the .o file as it doesn't notice
* if modsign.pub changes.
*/
static __initconst const char annoy_ccache[] = __TIME__ "foo";
/* /*
* Load the compiled-in keys * Load the compiled-in keys
*/ */
static __init int module_verify_init(void) static __init int system_trusted_keyring_init(void)
{ {
pr_notice("Initialise module verification\n"); pr_notice("Initialise system trusted keyring\n");
modsign_keyring = keyring_alloc(".module_sign", system_trusted_keyring =
KUIDT_INIT(0), KGIDT_INIT(0), keyring_alloc(".system_keyring",
current_cred(), KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ), KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL); KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(modsign_keyring)) if (IS_ERR(system_trusted_keyring))
panic("Can't allocate module signing keyring\n"); panic("Can't allocate system trusted keyring\n");
set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
return 0; return 0;
} }
/* /*
* Must be initialised before we try and load the keys into the keyring. * Must be initialised before we try and load the keys into the keyring.
*/ */
device_initcall(module_verify_init); device_initcall(system_trusted_keyring_init);
/* /*
* Load the compiled-in keys * Load the compiled-in list of X.509 certificates.
*/ */
static __init int load_module_signing_keys(void) static __init int load_system_certificate_list(void)
{ {
key_ref_t key; key_ref_t key;
const u8 *p, *end; const u8 *p, *end;
size_t plen; size_t plen;
pr_notice("Loading module verification certificates\n"); pr_notice("Loading compiled-in X.509 certificates\n");
end = modsign_certificate_list_end; end = system_certificate_list_end;
p = modsign_certificate_list; p = system_certificate_list;
while (p < end) { while (p < end) {
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
* than 256 bytes in size. * than 256 bytes in size.
...@@ -78,27 +76,30 @@ static __init int load_module_signing_keys(void) ...@@ -78,27 +76,30 @@ static __init int load_module_signing_keys(void)
if (plen > end - p) if (plen > end - p)
goto dodgy_cert; goto dodgy_cert;
key = key_create_or_update(make_key_ref(modsign_keyring, 1), key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
"asymmetric", "asymmetric",
NULL, NULL,
p, p,
plen, plen,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW, KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA |
if (IS_ERR(key)) KEY_ALLOC_TRUSTED);
pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n", if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key)); PTR_ERR(key));
else } else {
pr_notice("MODSIGN: Loaded cert '%s'\n", pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description); key_ref_to_ptr(key)->description);
key_ref_put(key);
}
p += plen; p += plen;
} }
return 0; return 0;
dodgy_cert: dodgy_cert:
pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n"); pr_err("Problem parsing in-kernel X.509 certificate list\n");
return 0; return 0;
} }
late_initcall(load_module_signing_keys); late_initcall(load_system_certificate_list);
...@@ -51,6 +51,10 @@ struct user_namespace init_user_ns = { ...@@ -51,6 +51,10 @@ struct user_namespace init_user_ns = {
.owner = GLOBAL_ROOT_UID, .owner = GLOBAL_ROOT_UID,
.group = GLOBAL_ROOT_GID, .group = GLOBAL_ROOT_GID,
.proc_inum = PROC_USER_INIT_INO, .proc_inum = PROC_USER_INIT_INO,
#ifdef CONFIG_KEYS_KERBEROS_CACHE
.krb_cache_register_sem =
__RWSEM_INITIALIZER(init_user_ns.krb_cache_register_sem),
#endif
}; };
EXPORT_SYMBOL_GPL(init_user_ns); EXPORT_SYMBOL_GPL(init_user_ns);
......
...@@ -101,6 +101,9 @@ int create_user_ns(struct cred *new) ...@@ -101,6 +101,9 @@ int create_user_ns(struct cred *new)
set_cred_user_ns(new, ns); set_cred_user_ns(new, ns);
#ifdef CONFIG_PERSISTENT_KEYRINGS
init_rwsem(&ns->persistent_keyring_register_sem);
#endif
return 0; return 0;
} }
...@@ -130,6 +133,9 @@ void free_user_ns(struct user_namespace *ns) ...@@ -130,6 +133,9 @@ void free_user_ns(struct user_namespace *ns)
do { do {
parent = ns->parent; parent = ns->parent;
#ifdef CONFIG_PERSISTENT_KEYRINGS
key_put(ns->persistent_keyring_register);
#endif
proc_free_inum(ns->proc_inum); proc_free_inum(ns->proc_inum);
kmem_cache_free(user_ns_cachep, ns); kmem_cache_free(user_ns_cachep, ns);
ns = parent; ns = parent;
......
...@@ -322,6 +322,20 @@ config TEXTSEARCH_FSM ...@@ -322,6 +322,20 @@ config TEXTSEARCH_FSM
config BTREE config BTREE
boolean boolean
config ASSOCIATIVE_ARRAY
bool
help
Generic associative array. Can be searched and iterated over whilst
it is being modified. It is also reasonably quick to search and
modify. The algorithms are non-recursive, and the trees are highly
capacious.
See:
Documentation/assoc_array.txt
for more information.
config HAS_IOMEM config HAS_IOMEM
boolean boolean
depends on !NO_IOMEM depends on !NO_IOMEM
......
...@@ -47,6 +47,7 @@ CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS)) ...@@ -47,6 +47,7 @@ CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
obj-$(CONFIG_BTREE) += btree.o obj-$(CONFIG_BTREE) += btree.o
obj-$(CONFIG_ASSOCIATIVE_ARRAY) += assoc_array.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
obj-$(CONFIG_DEBUG_LIST) += list_debug.o obj-$(CONFIG_DEBUG_LIST) += list_debug.o
obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o
......
This diff is collapsed.
...@@ -121,3 +121,6 @@ void mpi_free(MPI a) ...@@ -121,3 +121,6 @@ void mpi_free(MPI a)
kfree(a); kfree(a);
} }
EXPORT_SYMBOL_GPL(mpi_free); EXPORT_SYMBOL_GPL(mpi_free);
MODULE_DESCRIPTION("Multiprecision maths library");
MODULE_LICENSE("GPL");
...@@ -1353,6 +1353,8 @@ static void render_out_of_line_list(FILE *out) ...@@ -1353,6 +1353,8 @@ static void render_out_of_line_list(FILE *out)
render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
render_opcode(out, "_jump_target(%u),\n", entry); render_opcode(out, "_jump_target(%u),\n", entry);
break; break;
default:
break;
} }
if (e->action) if (e->action)
render_opcode(out, "_action(ACT_%s),\n", render_opcode(out, "_action(ACT_%s),\n",
......
...@@ -16,7 +16,6 @@ obj-$(CONFIG_MMU) += min_addr.o ...@@ -16,7 +16,6 @@ obj-$(CONFIG_MMU) += min_addr.o
# Object file lists # Object file lists
obj-$(CONFIG_SECURITY) += security.o capability.o obj-$(CONFIG_SECURITY) += security.o capability.o
obj-$(CONFIG_SECURITYFS) += inode.o obj-$(CONFIG_SECURITYFS) += inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_AUDIT) += lsm_audit.o
......
...@@ -111,7 +111,6 @@ static const char *const aa_audit_type[] = { ...@@ -111,7 +111,6 @@ static const char *const aa_audit_type[] = {
static void audit_pre(struct audit_buffer *ab, void *ca) static void audit_pre(struct audit_buffer *ab, void *ca)
{ {
struct common_audit_data *sa = ca; struct common_audit_data *sa = ca;
struct task_struct *tsk = sa->aad->tsk ? sa->aad->tsk : current;
if (aa_g_audit_header) { if (aa_g_audit_header) {
audit_log_format(ab, "apparmor="); audit_log_format(ab, "apparmor=");
...@@ -132,11 +131,6 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -132,11 +131,6 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
if (sa->aad->profile) { if (sa->aad->profile) {
struct aa_profile *profile = sa->aad->profile; struct aa_profile *profile = sa->aad->profile;
pid_t pid;
rcu_read_lock();
pid = rcu_dereference(tsk->real_parent)->pid;
rcu_read_unlock();
audit_log_format(ab, " parent=%d", pid);
if (profile->ns != root_ns) { if (profile->ns != root_ns) {
audit_log_format(ab, " namespace="); audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab, profile->ns->base.hname); audit_log_untrustedstring(ab, profile->ns->base.hname);
...@@ -149,12 +143,6 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -149,12 +143,6 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, sa->aad->name); audit_log_untrustedstring(ab, sa->aad->name);
} }
if (sa->aad->tsk) {
audit_log_format(ab, " pid=%d comm=", tsk->pid);
audit_log_untrustedstring(ab, tsk->comm);
}
} }
/** /**
...@@ -212,7 +200,7 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, ...@@ -212,7 +200,7 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
if (sa->aad->type == AUDIT_APPARMOR_KILL) if (sa->aad->type == AUDIT_APPARMOR_KILL)
(void)send_sig_info(SIGKILL, NULL, (void)send_sig_info(SIGKILL, NULL,
sa->aad->tsk ? sa->aad->tsk : current); sa->u.tsk ? sa->u.tsk : current);
if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(sa->aad->error); return complain_error(sa->aad->error);
......
...@@ -53,8 +53,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -53,8 +53,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/** /**
* audit_caps - audit a capability * audit_caps - audit a capability
* @profile: profile confining task (NOT NULL) * @profile: profile being tested for confinement (NOT NULL)
* @task: task capability test was performed against (NOT NULL)
* @cap: capability tested * @cap: capability tested
* @error: error code returned by test * @error: error code returned by test
* *
...@@ -63,8 +62,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -63,8 +62,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
* *
* Returns: 0 or sa->error on success, error code on failure * Returns: 0 or sa->error on success, error code on failure
*/ */
static int audit_caps(struct aa_profile *profile, struct task_struct *task, static int audit_caps(struct aa_profile *profile, int cap, int error)
int cap, int error)
{ {
struct audit_cache *ent; struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO; int type = AUDIT_APPARMOR_AUTO;
...@@ -73,7 +71,6 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task, ...@@ -73,7 +71,6 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
sa.type = LSM_AUDIT_DATA_CAP; sa.type = LSM_AUDIT_DATA_CAP;
sa.aad = &aad; sa.aad = &aad;
sa.u.cap = cap; sa.u.cap = cap;
sa.aad->tsk = task;
sa.aad->op = OP_CAPABLE; sa.aad->op = OP_CAPABLE;
sa.aad->error = error; sa.aad->error = error;
...@@ -124,8 +121,7 @@ static int profile_capable(struct aa_profile *profile, int cap) ...@@ -124,8 +121,7 @@ static int profile_capable(struct aa_profile *profile, int cap)
/** /**
* aa_capable - test permission to use capability * aa_capable - test permission to use capability
* @task: task doing capability test against (NOT NULL) * @profile: profile being tested against (NOT NULL)
* @profile: profile confining @task (NOT NULL)
* @cap: capability to be tested * @cap: capability to be tested
* @audit: whether an audit record should be generated * @audit: whether an audit record should be generated
* *
...@@ -133,8 +129,7 @@ static int profile_capable(struct aa_profile *profile, int cap) ...@@ -133,8 +129,7 @@ static int profile_capable(struct aa_profile *profile, int cap)
* *
* Returns: 0 on success, or else an error code. * Returns: 0 on success, or else an error code.
*/ */
int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap, int aa_capable(struct aa_profile *profile, int cap, int audit)
int audit)
{ {
int error = profile_capable(profile, cap); int error = profile_capable(profile, cap);
...@@ -144,5 +139,5 @@ int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap, ...@@ -144,5 +139,5 @@ int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
return error; return error;
} }
return audit_caps(profile, task, cap, error); return audit_caps(profile, cap, error);
} }
...@@ -50,23 +50,21 @@ void aa_free_domain_entries(struct aa_domain *domain) ...@@ -50,23 +50,21 @@ void aa_free_domain_entries(struct aa_domain *domain)
/** /**
* may_change_ptraced_domain - check if can change profile on ptraced task * may_change_ptraced_domain - check if can change profile on ptraced task
* @task: task we want to change profile of (NOT NULL)
* @to_profile: profile to change to (NOT NULL) * @to_profile: profile to change to (NOT NULL)
* *
* Check if the task is ptraced and if so if the tracing task is allowed * Check if current is ptraced and if so if the tracing task is allowed
* to trace the new domain * to trace the new domain
* *
* Returns: %0 or error if change not allowed * Returns: %0 or error if change not allowed
*/ */
static int may_change_ptraced_domain(struct task_struct *task, static int may_change_ptraced_domain(struct aa_profile *to_profile)
struct aa_profile *to_profile)
{ {
struct task_struct *tracer; struct task_struct *tracer;
struct aa_profile *tracerp = NULL; struct aa_profile *tracerp = NULL;
int error = 0; int error = 0;
rcu_read_lock(); rcu_read_lock();
tracer = ptrace_parent(task); tracer = ptrace_parent(current);
if (tracer) if (tracer)
/* released below */ /* released below */
tracerp = aa_get_task_profile(tracer); tracerp = aa_get_task_profile(tracer);
...@@ -75,7 +73,7 @@ static int may_change_ptraced_domain(struct task_struct *task, ...@@ -75,7 +73,7 @@ static int may_change_ptraced_domain(struct task_struct *task,
if (!tracer || unconfined(tracerp)) if (!tracer || unconfined(tracerp))
goto out; goto out;
error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH); error = aa_may_ptrace(tracerp, to_profile, PTRACE_MODE_ATTACH);
out: out:
rcu_read_unlock(); rcu_read_unlock();
...@@ -477,7 +475,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -477,7 +475,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
} }
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
error = may_change_ptraced_domain(current, new_profile); error = may_change_ptraced_domain(new_profile);
if (error) { if (error) {
aa_put_profile(new_profile); aa_put_profile(new_profile);
goto audit; goto audit;
...@@ -690,7 +688,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) ...@@ -690,7 +688,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
} }
} }
error = may_change_ptraced_domain(current, hat); error = may_change_ptraced_domain(hat);
if (error) { if (error) {
info = "ptraced"; info = "ptraced";
error = -EPERM; error = -EPERM;
...@@ -829,7 +827,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, ...@@ -829,7 +827,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
} }
/* check if tracing task is allowed to trace target domain */ /* check if tracing task is allowed to trace target domain */
error = may_change_ptraced_domain(current, target); error = may_change_ptraced_domain(target);
if (error) { if (error) {
info = "ptrace prevents transition"; info = "ptrace prevents transition";
goto audit; goto audit;
......
...@@ -109,7 +109,6 @@ struct apparmor_audit_data { ...@@ -109,7 +109,6 @@ struct apparmor_audit_data {
void *profile; void *profile;
const char *name; const char *name;
const char *info; const char *info;
struct task_struct *tsk;
union { union {
void *target; void *target;
struct { struct {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file contains AppArmor capability mediation definitions. * This file contains AppArmor capability mediation definitions.
* *
* Copyright (C) 1998-2008 Novell/SUSE * Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd. * Copyright 2009-2013 Canonical Ltd.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -38,8 +38,7 @@ struct aa_caps { ...@@ -38,8 +38,7 @@ struct aa_caps {
extern struct aa_fs_entry aa_fs_entry_caps[]; extern struct aa_fs_entry aa_fs_entry_caps[];
int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap, int aa_capable(struct aa_profile *profile, int cap, int audit);
int audit);
static inline void aa_free_cap_rules(struct aa_caps *caps) static inline void aa_free_cap_rules(struct aa_caps *caps)
{ {
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
struct aa_profile; struct aa_profile;
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee,
struct aa_profile *tracee, unsigned int mode); unsigned int mode);
int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode); unsigned int mode);
......
...@@ -54,15 +54,14 @@ static int aa_audit_ptrace(struct aa_profile *profile, ...@@ -54,15 +54,14 @@ static int aa_audit_ptrace(struct aa_profile *profile,
/** /**
* aa_may_ptrace - test if tracer task can trace the tracee * aa_may_ptrace - test if tracer task can trace the tracee
* @tracer_task: task who will do the tracing (NOT NULL)
* @tracer: profile of the task doing the tracing (NOT NULL) * @tracer: profile of the task doing the tracing (NOT NULL)
* @tracee: task to be traced * @tracee: task to be traced
* @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
* *
* Returns: %0 else error code if permission denied or error * Returns: %0 else error code if permission denied or error
*/ */
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee,
struct aa_profile *tracee, unsigned int mode) unsigned int mode)
{ {
/* TODO: currently only based on capability, not extended ptrace /* TODO: currently only based on capability, not extended ptrace
* rules, * rules,
...@@ -72,7 +71,7 @@ int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer, ...@@ -72,7 +71,7 @@ int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
if (unconfined(tracer) || tracer == tracee) if (unconfined(tracer) || tracer == tracee)
return 0; return 0;
/* log this capability request */ /* log this capability request */
return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1); return aa_capable(tracer, CAP_SYS_PTRACE, 1);
} }
/** /**
...@@ -101,7 +100,7 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, ...@@ -101,7 +100,7 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
if (!unconfined(tracer_p)) { if (!unconfined(tracer_p)) {
struct aa_profile *tracee_p = aa_get_task_profile(tracee); struct aa_profile *tracee_p = aa_get_task_profile(tracee);
error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_may_ptrace(tracer_p, tracee_p, mode);
error = aa_audit_ptrace(tracer_p, tracee_p, error); error = aa_audit_ptrace(tracer_p, tracee_p, error);
aa_put_profile(tracee_p); aa_put_profile(tracee_p);
......
...@@ -145,7 +145,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, ...@@ -145,7 +145,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
if (!error) { if (!error) {
profile = aa_cred_profile(cred); profile = aa_cred_profile(cred);
if (!unconfined(profile)) if (!unconfined(profile))
error = aa_capable(current, profile, cap, audit); error = aa_capable(profile, cap, audit);
} }
return error; return error;
} }
......
...@@ -777,8 +777,14 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) ...@@ -777,8 +777,14 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
return 0; return 0;
} }
static int cap_xfrm_state_alloc_security(struct xfrm_state *x, static int cap_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_user_sec_ctx *sec_ctx)
{
return 0;
}
static int cap_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec,
u32 secid) u32 secid)
{ {
return 0; return 0;
...@@ -1101,7 +1107,8 @@ void __init security_fixup_ops(struct security_operations *ops) ...@@ -1101,7 +1107,8 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, xfrm_policy_clone_security); set_to_cap_if_null(ops, xfrm_policy_clone_security);
set_to_cap_if_null(ops, xfrm_policy_free_security); set_to_cap_if_null(ops, xfrm_policy_free_security);
set_to_cap_if_null(ops, xfrm_policy_delete_security); set_to_cap_if_null(ops, xfrm_policy_delete_security);
set_to_cap_if_null(ops, xfrm_state_alloc_security); set_to_cap_if_null(ops, xfrm_state_alloc);
set_to_cap_if_null(ops, xfrm_state_alloc_acquire);
set_to_cap_if_null(ops, xfrm_state_free_security); set_to_cap_if_null(ops, xfrm_state_free_security);
set_to_cap_if_null(ops, xfrm_state_delete_security); set_to_cap_if_null(ops, xfrm_state_delete_security);
set_to_cap_if_null(ops, xfrm_policy_lookup); set_to_cap_if_null(ops, xfrm_policy_lookup);
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h> #include <linux/err.h>
#include <linux/sched.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/cred.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/digsig.h> #include <linux/digsig.h>
...@@ -21,11 +23,19 @@ ...@@ -21,11 +23,19 @@
static struct key *keyring[INTEGRITY_KEYRING_MAX]; static struct key *keyring[INTEGRITY_KEYRING_MAX];
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
".evm",
".module",
".ima",
};
#else
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
"_evm", "_evm",
"_module", "_module",
"_ima", "_ima",
}; };
#endif
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen) const char *digest, int digestlen)
...@@ -44,9 +54,10 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, ...@@ -44,9 +54,10 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
} }
} }
switch (sig[0]) { switch (sig[1]) {
case 1: case 1:
return digsig_verify(keyring[id], sig, siglen, /* v1 API expect signature without xattr type */
return digsig_verify(keyring[id], sig + 1, siglen - 1,
digest, digestlen); digest, digestlen);
case 2: case 2:
return asymmetric_verify(keyring[id], sig, siglen, return asymmetric_verify(keyring[id], sig, siglen,
...@@ -55,3 +66,21 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, ...@@ -55,3 +66,21 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
int integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
const struct user_struct *user = cred->user;
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_ALLOC_NOT_IN_QUOTA, user->uid_keyring);
if (!IS_ERR(keyring[id]))
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
else
pr_info("Can't allocate %s keyring (%ld)\n",
keyring_name[id], PTR_ERR(keyring[id]));
return 0;
}
...@@ -19,17 +19,6 @@ ...@@ -19,17 +19,6 @@
#include "integrity.h" #include "integrity.h"
/*
* signature format v2 - for using with asymmetric keys
*/
struct signature_v2_hdr {
uint8_t version; /* signature format version */
uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/
uint16_t sig_size; /* signature size */
uint8_t sig[0]; /* signature payload */
} __packed;
/* /*
* Request an asymmetric key. * Request an asymmetric key.
*/ */
......
...@@ -123,7 +123,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -123,7 +123,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
goto out; goto out;
} }
xattr_len = rc - 1; xattr_len = rc;
/* check value type */ /* check value type */
switch (xattr_data->type) { switch (xattr_data->type) {
...@@ -143,7 +143,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, ...@@ -143,7 +143,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
if (rc) if (rc)
break; break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
xattr_data->digest, xattr_len, (const char *)xattr_data, xattr_len,
calc.digest, sizeof(calc.digest)); calc.digest, sizeof(calc.digest));
if (!rc) { if (!rc) {
/* we probably want to replace rsa with hmac here */ /* we probably want to replace rsa with hmac here */
......
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/evm.h>
int posix_xattr_acl(char *xattr) int posix_xattr_acl(const char *xattr)
{ {
int xattr_len = strlen(xattr); int xattr_len = strlen(xattr);
......
...@@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) ...@@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
static void iint_free(struct integrity_iint_cache *iint) static void iint_free(struct integrity_iint_cache *iint)
{ {
kfree(iint->ima_hash);
iint->ima_hash = NULL;
iint->version = 0; iint->version = 0;
iint->flags = 0UL; iint->flags = 0UL;
iint->ima_file_status = INTEGRITY_UNKNOWN; iint->ima_file_status = INTEGRITY_UNKNOWN;
......
...@@ -9,6 +9,7 @@ config IMA ...@@ -9,6 +9,7 @@ config IMA
select CRYPTO_HMAC select CRYPTO_HMAC
select CRYPTO_MD5 select CRYPTO_MD5
select CRYPTO_SHA1 select CRYPTO_SHA1
select CRYPTO_HASH_INFO
select TCG_TPM if HAS_IOMEM && !UML select TCG_TPM if HAS_IOMEM && !UML
select TCG_TIS if TCG_TPM && X86 select TCG_TIS if TCG_TPM && X86
select TCG_IBMVTPM if TCG_TPM && PPC64 select TCG_IBMVTPM if TCG_TPM && PPC64
...@@ -45,6 +46,69 @@ config IMA_LSM_RULES ...@@ -45,6 +46,69 @@ config IMA_LSM_RULES
help help
Disabling this option will disregard LSM based policy rules. Disabling this option will disregard LSM based policy rules.
choice
prompt "Default template"
default IMA_NG_TEMPLATE
depends on IMA
help
Select the default IMA measurement template.
The original 'ima' measurement list template contains a
hash, defined as 20 bytes, and a null terminated pathname,
limited to 255 characters. The 'ima-ng' measurement list
template permits both larger hash digests and longer
pathnames.
config IMA_TEMPLATE
bool "ima"
config IMA_NG_TEMPLATE
bool "ima-ng (default)"
config IMA_SIG_TEMPLATE
bool "ima-sig"
endchoice
config IMA_DEFAULT_TEMPLATE
string
depends on IMA
default "ima" if IMA_TEMPLATE
default "ima-ng" if IMA_NG_TEMPLATE
default "ima-sig" if IMA_SIG_TEMPLATE
choice
prompt "Default integrity hash algorithm"
default IMA_DEFAULT_HASH_SHA1
depends on IMA
help
Select the default hash algorithm used for the measurement
list, integrity appraisal and audit log. The compiled default
hash algorithm can be overwritten using the kernel command
line 'ima_hash=' option.
config IMA_DEFAULT_HASH_SHA1
bool "SHA1 (default)"
depends on CRYPTO_SHA1
config IMA_DEFAULT_HASH_SHA256
bool "SHA256"
depends on CRYPTO_SHA256 && !IMA_TEMPLATE
config IMA_DEFAULT_HASH_SHA512
bool "SHA512"
depends on CRYPTO_SHA512 && !IMA_TEMPLATE
config IMA_DEFAULT_HASH_WP512
bool "WP512"
depends on CRYPTO_WP512 && !IMA_TEMPLATE
endchoice
config IMA_DEFAULT_HASH
string
depends on IMA
default "sha1" if IMA_DEFAULT_HASH_SHA1
default "sha256" if IMA_DEFAULT_HASH_SHA256
default "sha512" if IMA_DEFAULT_HASH_SHA512
default "wp512" if IMA_DEFAULT_HASH_WP512
config IMA_APPRAISE config IMA_APPRAISE
bool "Appraise integrity measurements" bool "Appraise integrity measurements"
depends on IMA depends on IMA
...@@ -59,3 +123,11 @@ config IMA_APPRAISE ...@@ -59,3 +123,11 @@ config IMA_APPRAISE
For more information on integrity appraisal refer to: For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net> <http://linux-ima.sourceforge.net>
If unsure, say N. 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
default y
help
This option requires that all keys added to the _ima
keyring be signed by a key on the system trusted keyring.
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
obj-$(CONFIG_IMA) += ima.o obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_policy.o ima_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
...@@ -36,23 +36,48 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; ...@@ -36,23 +36,48 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_HASH_BITS 9 #define IMA_HASH_BITS 9
#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
#define IMA_TEMPLATE_FIELD_ID_MAX_LEN 16
#define IMA_TEMPLATE_NUM_FIELDS_MAX 15
#define IMA_TEMPLATE_IMA_NAME "ima"
#define IMA_TEMPLATE_IMA_FMT "d|n"
/* set during initialization */ /* set during initialization */
extern int ima_initialized; extern int ima_initialized;
extern int ima_used_chip; extern int ima_used_chip;
extern char *ima_hash; extern int ima_hash_algo;
extern int ima_appraise; extern int ima_appraise;
/* IMA inode template definition */ /* IMA template field data definition */
struct ima_template_data { struct ima_field_data {
u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */ u8 *data;
char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */ u32 len;
};
/* IMA template field definition */
struct ima_template_field {
const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN];
int (*field_init) (struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, struct ima_field_data *field_data);
void (*field_show) (struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
};
/* IMA template descriptor definition */
struct ima_template_desc {
char *name;
char *fmt;
int num_fields;
struct ima_template_field **fields;
}; };
struct ima_template_entry { struct ima_template_entry {
u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
const char *template_name; struct ima_template_desc *template_desc; /* template descriptor */
int template_len; u32 template_data_len;
struct ima_template_data template; struct ima_field_data template_data[0]; /* template related data */
}; };
struct ima_queue_entry { struct ima_queue_entry {
...@@ -69,13 +94,21 @@ int ima_fs_init(void); ...@@ -69,13 +94,21 @@ int ima_fs_init(void);
void ima_fs_cleanup(void); void ima_fs_cleanup(void);
int ima_inode_alloc(struct inode *inode); int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation, int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode); const char *op, struct inode *inode,
int ima_calc_file_hash(struct file *file, char *digest); const unsigned char *filename);
int ima_calc_buffer_hash(const void *data, int len, char *digest); int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
int ima_calc_boot_aggregate(char *digest); int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields,
void ima_add_violation(struct inode *inode, const unsigned char *filename, struct ima_digest_data *hash);
int __init ima_calc_boot_aggregate(struct ima_digest_data *hash);
void ima_add_violation(struct file *file, const unsigned char *filename,
const char *op, const char *cause); const char *op, const char *cause);
int ima_init_crypto(void); int ima_init_crypto(void);
void ima_putc(struct seq_file *m, void *data, int datalen);
void ima_print_digest(struct seq_file *m, u8 *digest, int size);
struct ima_template_desc *ima_template_desc_current(void);
int ima_init_template(void);
int ima_init_template(void);
/* /*
* used to protect h_table and sha_table * used to protect h_table and sha_table
...@@ -98,14 +131,21 @@ static inline unsigned long ima_hash_key(u8 *digest) ...@@ -98,14 +131,21 @@ static inline unsigned long ima_hash_key(u8 *digest)
int ima_get_action(struct inode *inode, int mask, int function); int ima_get_action(struct inode *inode, int mask, int function);
int ima_must_measure(struct inode *inode, int mask, int function); int ima_must_measure(struct inode *inode, int mask, int function);
int ima_collect_measurement(struct integrity_iint_cache *iint, int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file); struct file *file,
struct evm_ima_xattr_data **xattr_value,
int *xattr_len);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename); const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len);
void ima_audit_measurement(struct integrity_iint_cache *iint, void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename); const unsigned char *filename);
int ima_alloc_init_template(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, struct ima_template_entry **entry);
int ima_store_template(struct ima_template_entry *entry, int violation, int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode); struct inode *inode, const unsigned char *filename);
void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
const char *ima_d_path(struct path *path, char **pathbuf); const char *ima_d_path(struct path *path, char **pathbuf);
/* rbtree tree calls to lookup, insert, delete /* rbtree tree calls to lookup, insert, delete
...@@ -131,17 +171,25 @@ void ima_delete_rules(void); ...@@ -131,17 +171,25 @@ void ima_delete_rules(void);
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename); struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
int func); int func);
void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
struct ima_digest_data *hash);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);
#else #else
static inline int ima_appraise_measurement(int func, static inline int ima_appraise_measurement(int func,
struct integrity_iint_cache *iint, struct integrity_iint_cache *iint,
struct file *file, struct file *file,
const unsigned char *filename) const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{ {
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
} }
...@@ -162,6 +210,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c ...@@ -162,6 +210,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c
{ {
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
} }
static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
int xattr_len,
struct ima_digest_data *hash)
{
}
static inline int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
return 0;
}
#endif #endif
/* LSM based policy rules require audit */ /* LSM based policy rules require audit */
......
...@@ -18,9 +18,46 @@ ...@@ -18,9 +18,46 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/evm.h> #include <linux/evm.h>
#include <crypto/hash_info.h>
#include "ima.h" #include "ima.h"
static const char *IMA_TEMPLATE_NAME = "ima"; /*
* ima_alloc_init_template - create and initialize a new template entry
*/
int ima_alloc_init_template(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, struct ima_template_entry **entry)
{
struct ima_template_desc *template_desc = ima_template_desc_current();
int i, result = 0;
*entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
sizeof(struct ima_field_data), GFP_NOFS);
if (!*entry)
return -ENOMEM;
for (i = 0; i < template_desc->num_fields; i++) {
struct ima_template_field *field = template_desc->fields[i];
u32 len;
result = field->field_init(iint, file, filename,
xattr_value, xattr_len,
&((*entry)->template_data[i]));
if (result != 0)
goto out;
len = (*entry)->template_data[i].len;
(*entry)->template_data_len += sizeof(len);
(*entry)->template_data_len += len;
}
(*entry)->template_desc = template_desc;
return 0;
out:
kfree(*entry);
*entry = NULL;
return result;
}
/* /*
* ima_store_template - store ima template measurements * ima_store_template - store ima template measurements
...@@ -39,28 +76,34 @@ static const char *IMA_TEMPLATE_NAME = "ima"; ...@@ -39,28 +76,34 @@ static const char *IMA_TEMPLATE_NAME = "ima";
* Returns 0 on success, error code otherwise * Returns 0 on success, error code otherwise
*/ */
int ima_store_template(struct ima_template_entry *entry, int ima_store_template(struct ima_template_entry *entry,
int violation, struct inode *inode) int violation, struct inode *inode,
const unsigned char *filename)
{ {
const char *op = "add_template_measure"; const char *op = "add_template_measure";
const char *audit_cause = "hashing_error"; const char *audit_cause = "hashing_error";
char *template_name = entry->template_desc->name;
int result; int result;
struct {
memset(entry->digest, 0, sizeof(entry->digest)); struct ima_digest_data hdr;
entry->template_name = IMA_TEMPLATE_NAME; char digest[TPM_DIGEST_SIZE];
entry->template_len = sizeof(entry->template); } hash;
if (!violation) { if (!violation) {
result = ima_calc_buffer_hash(&entry->template, int num_fields = entry->template_desc->num_fields;
entry->template_len,
entry->digest); /* this function uses default algo */
hash.hdr.algo = HASH_ALGO_SHA1;
result = ima_calc_field_array_hash(&entry->template_data[0],
num_fields, &hash.hdr);
if (result < 0) { if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
entry->template_name, op, template_name, op,
audit_cause, result, 0); audit_cause, result, 0);
return result; return result;
} }
memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
} }
result = ima_add_template_entry(entry, violation, op, inode); result = ima_add_template_entry(entry, violation, op, inode, filename);
return result; return result;
} }
...@@ -71,24 +114,24 @@ int ima_store_template(struct ima_template_entry *entry, ...@@ -71,24 +114,24 @@ int ima_store_template(struct ima_template_entry *entry,
* By extending the PCR with 0xFF's instead of with zeroes, the PCR * By extending the PCR with 0xFF's instead of with zeroes, the PCR
* value is invalidated. * value is invalidated.
*/ */
void ima_add_violation(struct inode *inode, const unsigned char *filename, void ima_add_violation(struct file *file, const unsigned char *filename,
const char *op, const char *cause) const char *op, const char *cause)
{ {
struct ima_template_entry *entry; struct ima_template_entry *entry;
struct inode *inode = file->f_dentry->d_inode;
int violation = 1; int violation = 1;
int result; int result;
/* can overflow, only indicator */ /* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations); atomic_long_inc(&ima_htable.violations);
entry = kmalloc(sizeof(*entry), GFP_KERNEL); result = ima_alloc_init_template(NULL, file, filename,
if (!entry) { NULL, 0, &entry);
if (result < 0) {
result = -ENOMEM; result = -ENOMEM;
goto err_out; goto err_out;
} }
memset(&entry->template, 0, sizeof(entry->template)); result = ima_store_template(entry, violation, inode, filename);
strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
result = ima_store_template(entry, violation, inode);
if (result < 0) if (result < 0)
kfree(entry); kfree(entry);
err_out: err_out:
...@@ -138,20 +181,42 @@ int ima_must_measure(struct inode *inode, int mask, int function) ...@@ -138,20 +181,42 @@ int ima_must_measure(struct inode *inode, int mask, int function)
* Return 0 on success, error code otherwise * Return 0 on success, error code otherwise
*/ */
int ima_collect_measurement(struct integrity_iint_cache *iint, int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file) struct file *file,
struct evm_ima_xattr_data **xattr_value,
int *xattr_len)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
const char *filename = file->f_dentry->d_name.name; const char *filename = file->f_dentry->d_name.name;
int result = 0; int result = 0;
struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
if (xattr_value)
*xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
if (!(iint->flags & IMA_COLLECTED)) { if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file_inode(file)->i_version; u64 i_version = file_inode(file)->i_version;
iint->ima_xattr.type = IMA_XATTR_DIGEST; /* use default hash algorithm */
result = ima_calc_file_hash(file, iint->ima_xattr.digest); hash.hdr.algo = ima_hash_algo;
if (xattr_value)
ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr);
result = ima_calc_file_hash(file, &hash.hdr);
if (!result) { if (!result) {
int length = sizeof(hash.hdr) + hash.hdr.length;
void *tmpbuf = krealloc(iint->ima_hash, length,
GFP_NOFS);
if (tmpbuf) {
iint->ima_hash = tmpbuf;
memcpy(iint->ima_hash, &hash, length);
iint->version = i_version; iint->version = i_version;
iint->flags |= IMA_COLLECTED; iint->flags |= IMA_COLLECTED;
} else
result = -ENOMEM;
} }
} }
if (result) if (result)
...@@ -177,7 +242,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -177,7 +242,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
* Must be called with iint->mutex held. * Must be called with iint->mutex held.
*/ */
void ima_store_measurement(struct integrity_iint_cache *iint, void ima_store_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename) struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{ {
const char *op = "add_template_measure"; const char *op = "add_template_measure";
const char *audit_cause = "ENOMEM"; const char *audit_cause = "ENOMEM";
...@@ -189,19 +256,15 @@ void ima_store_measurement(struct integrity_iint_cache *iint, ...@@ -189,19 +256,15 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
if (iint->flags & IMA_MEASURED) if (iint->flags & IMA_MEASURED)
return; return;
entry = kmalloc(sizeof(*entry), GFP_KERNEL); result = ima_alloc_init_template(iint, file, filename,
if (!entry) { xattr_value, xattr_len, &entry);
if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0); op, audit_cause, result, 0);
return; return;
} }
memset(&entry->template, 0, sizeof(entry->template));
memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE);
strcpy(entry->template.file_name,
(strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
file->f_dentry->d_name.name : filename);
result = ima_store_template(entry, violation, inode); result = ima_store_template(entry, violation, inode, filename);
if (!result || result == -EEXIST) if (!result || result == -EEXIST)
iint->flags |= IMA_MEASURED; iint->flags |= IMA_MEASURED;
if (result < 0) if (result < 0)
...@@ -212,14 +275,16 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, ...@@ -212,14 +275,16 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename) const unsigned char *filename)
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
char hash[(IMA_DIGEST_SIZE * 2) + 1]; char hash[(iint->ima_hash->length * 2) + 1];
const char *algo_name = hash_algo_name[iint->ima_hash->algo];
char algo_hash[sizeof(hash) + strlen(algo_name) + 2];
int i; int i;
if (iint->flags & IMA_AUDITED) if (iint->flags & IMA_AUDITED)
return; return;
for (i = 0; i < IMA_DIGEST_SIZE; i++) for (i = 0; i < iint->ima_hash->length; i++)
hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
hash[i * 2] = '\0'; hash[i * 2] = '\0';
ab = audit_log_start(current->audit_context, GFP_KERNEL, ab = audit_log_start(current->audit_context, GFP_KERNEL,
...@@ -230,7 +295,8 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, ...@@ -230,7 +295,8 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
audit_log_format(ab, "file="); audit_log_format(ab, "file=");
audit_log_untrustedstring(ab, filename); audit_log_untrustedstring(ab, filename);
audit_log_format(ab, " hash="); audit_log_format(ab, " hash=");
audit_log_untrustedstring(ab, hash); snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash);
audit_log_untrustedstring(ab, algo_hash);
audit_log_task_info(ab, current); audit_log_task_info(ab, current);
audit_log_end(ab); audit_log_end(ab);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/ima.h> #include <linux/ima.h>
#include <linux/evm.h> #include <linux/evm.h>
#include <crypto/hash_info.h>
#include "ima.h" #include "ima.h"
...@@ -45,17 +46,29 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) ...@@ -45,17 +46,29 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
static int ima_fix_xattr(struct dentry *dentry, static int ima_fix_xattr(struct dentry *dentry,
struct integrity_iint_cache *iint) struct integrity_iint_cache *iint)
{ {
iint->ima_xattr.type = IMA_XATTR_DIGEST; int rc, offset;
return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, u8 algo = iint->ima_hash->algo;
(u8 *)&iint->ima_xattr,
sizeof(iint->ima_xattr), 0); if (algo <= HASH_ALGO_SHA1) {
offset = 1;
iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
} else {
offset = 0;
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
iint->ima_hash->xattr.ng.algo = algo;
}
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
&iint->ima_hash->xattr.data[offset],
(sizeof(iint->ima_hash->xattr) - offset) +
iint->ima_hash->length, 0);
return rc;
} }
/* Return specific func appraised cached result */ /* Return specific func appraised cached result */
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
int func) int func)
{ {
switch(func) { switch (func) {
case MMAP_CHECK: case MMAP_CHECK:
return iint->ima_mmap_status; return iint->ima_mmap_status;
case BPRM_CHECK: case BPRM_CHECK:
...@@ -71,7 +84,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, ...@@ -71,7 +84,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
static void ima_set_cache_status(struct integrity_iint_cache *iint, static void ima_set_cache_status(struct integrity_iint_cache *iint,
int func, enum integrity_status status) int func, enum integrity_status status)
{ {
switch(func) { switch (func) {
case MMAP_CHECK: case MMAP_CHECK:
iint->ima_mmap_status = status; iint->ima_mmap_status = status;
break; break;
...@@ -90,7 +103,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, ...@@ -90,7 +103,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
static void ima_cache_flags(struct integrity_iint_cache *iint, int func) static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
{ {
switch(func) { switch (func) {
case MMAP_CHECK: case MMAP_CHECK:
iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
break; break;
...@@ -107,6 +120,50 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) ...@@ -107,6 +120,50 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
} }
} }
void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
struct ima_digest_data *hash)
{
struct signature_v2_hdr *sig;
if (!xattr_value || xattr_len < 2)
return;
switch (xattr_value->type) {
case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof(*sig))
return;
hash->algo = sig->hash_algo;
break;
case IMA_XATTR_DIGEST_NG:
hash->algo = xattr_value->digest[0];
break;
case IMA_XATTR_DIGEST:
/* this is for backward compatibility */
if (xattr_len == 21) {
unsigned int zero = 0;
if (!memcmp(&xattr_value->digest[16], &zero, 4))
hash->algo = HASH_ALGO_MD5;
else
hash->algo = HASH_ALGO_SHA1;
} else if (xattr_len == 17)
hash->algo = HASH_ALGO_MD5;
break;
}
}
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
struct inode *inode = dentry->d_inode;
if (!inode->i_op->getxattr)
return 0;
return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
0, GFP_NOFS);
}
/* /*
* ima_appraise_measurement - appraise file measurement * ima_appraise_measurement - appraise file measurement
* *
...@@ -116,23 +173,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) ...@@ -116,23 +173,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
* Return 0 on success, error code otherwise * Return 0 on success, error code otherwise
*/ */
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename) struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{ {
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct evm_ima_xattr_data *xattr_value = NULL;
enum integrity_status status = INTEGRITY_UNKNOWN; enum integrity_status status = INTEGRITY_UNKNOWN;
const char *op = "appraise_data"; const char *op = "appraise_data";
char *cause = "unknown"; char *cause = "unknown";
int rc; int rc = xattr_len, hash_start = 0;
if (!ima_appraise) if (!ima_appraise)
return 0; return 0;
if (!inode->i_op->getxattr) if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value,
0, GFP_NOFS);
if (rc <= 0) { if (rc <= 0) {
if (rc && rc != -ENODATA) if (rc && rc != -ENODATA)
goto out; goto out;
...@@ -153,14 +209,25 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -153,14 +209,25 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
goto out; goto out;
} }
switch (xattr_value->type) { switch (xattr_value->type) {
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1;
case IMA_XATTR_DIGEST: case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) { if (iint->flags & IMA_DIGSIG_REQUIRED) {
cause = "IMA signature required"; cause = "IMA signature required";
status = INTEGRITY_FAIL; status = INTEGRITY_FAIL;
break; break;
} }
rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, if (xattr_len - sizeof(xattr_value->type) - hash_start >=
IMA_DIGEST_SIZE); iint->ima_hash->length)
/* xattr length may be longer. md5 hash in previous
version occupied 20 bytes in xattr, instead of 16
*/
rc = memcmp(&xattr_value->digest[hash_start],
iint->ima_hash->digest,
iint->ima_hash->length);
else
rc = -EINVAL;
if (rc) { if (rc) {
cause = "invalid-hash"; cause = "invalid-hash";
status = INTEGRITY_FAIL; status = INTEGRITY_FAIL;
...@@ -171,9 +238,9 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -171,9 +238,9 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
case EVM_IMA_XATTR_DIGSIG: case EVM_IMA_XATTR_DIGSIG:
iint->flags |= IMA_DIGSIG; iint->flags |= IMA_DIGSIG;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
xattr_value->digest, rc - 1, (const char *)xattr_value, rc,
iint->ima_xattr.digest, iint->ima_hash->digest,
IMA_DIGEST_SIZE); iint->ima_hash->length);
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
status = INTEGRITY_UNKNOWN; status = INTEGRITY_UNKNOWN;
} else if (rc) { } else if (rc) {
...@@ -203,7 +270,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -203,7 +270,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
ima_cache_flags(iint, func); ima_cache_flags(iint, func);
} }
ima_set_cache_status(iint, func, status); ima_set_cache_status(iint, func, status);
kfree(xattr_value);
return status; return status;
} }
...@@ -219,7 +285,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) ...@@ -219,7 +285,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
if (iint->flags & IMA_DIGSIG) if (iint->flags & IMA_DIGSIG)
return; return;
rc = ima_collect_measurement(iint, file); rc = ima_collect_measurement(iint, file, NULL, NULL);
if (rc < 0) if (rc < 0)
return; return;
...@@ -315,3 +381,14 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) ...@@ -315,3 +381,14 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
} }
return result; return result;
} }
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static int __init init_ima_keyring(void)
{
int ret;
ret = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
return 0;
}
late_initcall(init_ima_keyring);
#endif
This diff is collapsed.
This diff is collapsed.
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <crypto/hash_info.h>
#include "ima.h" #include "ima.h"
/* name for boot aggregate entry */ /* name for boot aggregate entry */
...@@ -42,28 +43,38 @@ int ima_used_chip; ...@@ -42,28 +43,38 @@ int ima_used_chip;
static void __init ima_add_boot_aggregate(void) static void __init ima_add_boot_aggregate(void)
{ {
struct ima_template_entry *entry; struct ima_template_entry *entry;
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
const char *op = "add_boot_aggregate"; const char *op = "add_boot_aggregate";
const char *audit_cause = "ENOMEM"; const char *audit_cause = "ENOMEM";
int result = -ENOMEM; int result = -ENOMEM;
int violation = 1; int violation = 0;
struct {
struct ima_digest_data hdr;
char digest[TPM_DIGEST_SIZE];
} hash;
entry = kmalloc(sizeof(*entry), GFP_KERNEL); memset(iint, 0, sizeof(*iint));
if (!entry) memset(&hash, 0, sizeof(hash));
goto err_out; iint->ima_hash = &hash.hdr;
iint->ima_hash->algo = HASH_ALGO_SHA1;
iint->ima_hash->length = SHA1_DIGEST_SIZE;
memset(&entry->template, 0, sizeof(entry->template));
strncpy(entry->template.file_name, boot_aggregate_name,
IMA_EVENT_NAME_LEN_MAX);
if (ima_used_chip) { if (ima_used_chip) {
violation = 0; result = ima_calc_boot_aggregate(&hash.hdr);
result = ima_calc_boot_aggregate(entry->template.digest);
if (result < 0) { if (result < 0) {
audit_cause = "hashing_error"; audit_cause = "hashing_error";
kfree(entry); kfree(entry);
goto err_out; goto err_out;
} }
} }
result = ima_store_template(entry, violation, NULL);
result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
NULL, 0, &entry);
if (result < 0)
return;
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name);
if (result < 0) if (result < 0)
kfree(entry); kfree(entry);
return; return;
...@@ -74,7 +85,7 @@ static void __init ima_add_boot_aggregate(void) ...@@ -74,7 +85,7 @@ static void __init ima_add_boot_aggregate(void)
int __init ima_init(void) int __init ima_init(void)
{ {
u8 pcr_i[IMA_DIGEST_SIZE]; u8 pcr_i[TPM_DIGEST_SIZE];
int rc; int rc;
ima_used_chip = 0; ima_used_chip = 0;
...@@ -88,6 +99,10 @@ int __init ima_init(void) ...@@ -88,6 +99,10 @@ int __init ima_init(void)
rc = ima_init_crypto(); rc = ima_init_crypto();
if (rc) if (rc)
return rc; return rc;
rc = ima_init_template();
if (rc != 0)
return rc;
ima_add_boot_aggregate(); /* boot aggregate must be first entry */ ima_add_boot_aggregate(); /* boot aggregate must be first entry */
ima_init_policy(); ima_init_policy();
......
This diff is collapsed.
...@@ -73,7 +73,6 @@ static struct ima_rule_entry default_rules[] = { ...@@ -73,7 +73,6 @@ static struct ima_rule_entry default_rules[] = {
{.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC},
{.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
......
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.
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.
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