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

Pull security subsystem update from James Morris:
 "This is mostly maintenance updates across the subsystem, with a
  notable update for TPM 2.0, and addition of Jarkko Sakkinen as a
  maintainer of that"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (40 commits)
  apparmor: clarify CRYPTO dependency
  selinux: Use a kmem_cache for allocation struct file_security_struct
  selinux: ioctl_has_perm should be static
  selinux: use sprintf return value
  selinux: use kstrdup() in security_get_bools()
  selinux: use kmemdup in security_sid_to_context_core()
  selinux: remove pointless cast in selinux_inode_setsecurity()
  selinux: introduce security_context_str_to_sid
  selinux: do not check open perm on ftruncate call
  selinux: change CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE default
  KEYS: Merge the type-specific data with the payload data
  KEYS: Provide a script to extract a module signature
  KEYS: Provide a script to extract the sys cert list from a vmlinux file
  keys: Be more consistent in selection of union members used
  certs: add .gitignore to stop git nagging about x509_certificate_list
  KEYS: use kvfree() in add_key
  Smack: limited capability for changing process label
  TPM: remove unnecessary little endian conversion
  vTPM: support little endian guests
  char: Drop owner assignment from i2c_driver
  ...
This commit is contained in:
Linus Torvalds 2015-11-05 15:32:38 -08:00
commit 1873499e13
89 changed files with 1748 additions and 492 deletions

View file

@ -1,4 +1,4 @@
What: /sys/devices/pnp0/<bus-num>/ppi/
What: /sys/class/tpm/tpmX/ppi/
Date: August 2012
Kernel Version: 3.6
Contact: xiaoyan.zhang@intel.com
@ -8,9 +8,14 @@ Description:
folder makes sense. The folder path can be got by command
'find /sys/ -name 'pcrs''. For the detail information of PPI,
please refer to the PPI specification from
http://www.trustedcomputinggroup.org/
What: /sys/devices/pnp0/<bus-num>/ppi/version
In Linux 4.2 ppi was moved to the character device directory.
A symlink from tpmX/device/ppi to tpmX/ppi to provide backwards
compatibility.
What: /sys/class/tpm/tpmX/ppi/version
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
@ -18,7 +23,7 @@ Description:
platform.
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/request
What: /sys/class/tpm/tpmX/ppi/request
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
@ -28,7 +33,7 @@ Description:
integer value range from 1 to 160, and 0 means no request.
This file can be read and written.
What: /sys/devices/pnp0/00:<bus-num>/ppi/response
What: /sys/class/tpm/tpmX/ppi/response
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
@ -37,7 +42,7 @@ Description:
: <response description>".
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/transition_action
What: /sys/class/tpm/tpmX/ppi/transition_action
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
@ -47,7 +52,7 @@ Description:
description>".
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/tcg_operations
What: /sys/class/tpm/tpmX/ppi/tcg_operations
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
@ -58,7 +63,7 @@ Description:
This attribute is only supported by PPI version 1.2+.
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/vs_operations
What: /sys/class/tpm/tpmX/ppi/vs_operations
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:

View file

@ -186,7 +186,7 @@ and looks like the following:
const struct public_key_signature *sig);
};
Asymmetric keys point to this with their type_data[0] member.
Asymmetric keys point to this with their payload[asym_subtype] member.
The owner and name fields should be set to the owning module and the name of
the subtype. Currently, the name is only used for print statements.
@ -269,8 +269,7 @@ mandatory:
struct key_preparsed_payload {
char *description;
void *type_data[2];
void *payload;
void *payload[4];
const void *data;
size_t datalen;
size_t quotalen;
@ -283,16 +282,18 @@ mandatory:
not theirs.
If the parser is happy with the blob, it should propose a description for
the key and attach it to ->description, ->type_data[0] should be set to
point to the subtype to be used, ->payload should be set to point to the
initialised data for that subtype, ->type_data[1] should point to a hex
fingerprint and quotalen should be updated to indicate how much quota this
key should account for.
the key and attach it to ->description, ->payload[asym_subtype] should be
set to point to the subtype to be used, ->payload[asym_crypto] should be
set to point to the initialised data for that subtype,
->payload[asym_key_ids] should point to one or more hex fingerprints and
quotalen should be updated to indicate how much quota this key should
account for.
When clearing up, the data attached to ->type_data[1] and ->description
will be kfree()'d and the data attached to ->payload will be passed to the
subtype's ->destroy() method to be disposed of. A module reference for
the subtype pointed to by ->type_data[0] will be put.
When clearing up, the data attached to ->payload[asym_key_ids] and
->description will be kfree()'d and the data attached to
->payload[asm_crypto] will be passed to the subtype's ->destroy() method
to be disposed of. A module reference for the subtype pointed to by
->payload[asym_subtype] will be put.
If the data format is not recognised, -EBADMSG should be returned. If it

View file

@ -255,6 +255,16 @@ unconfined
the access permitted if it wouldn't be otherwise. Note that this
is dangerous and can ruin the proper labeling of your system.
It should never be used in production.
relabel-self
This interface contains a list of labels to which the process can
transition to, by writing to /proc/self/attr/current.
Normally a process can change its own label to any legal value, but only
if it has CAP_MAC_ADMIN. This interface allows a process without
CAP_MAC_ADMIN to relabel itself to one of labels from predefined list.
A process without CAP_MAC_ADMIN can change its label only once. When it
does, this list will be cleared.
The values are set by writing the desired labels, separated
by spaces, to the file or cleared by writing "-" to the file.
If you are using the smackload utility
you can add access rules in /etc/smack/accesses. They take the form:

View file

@ -1049,12 +1049,12 @@ search a specific keyring, so using keyrings in this way is of limited utility.
NOTES ON ACCESSING PAYLOAD CONTENTS
===================================
The simplest payload is just a number in key->payload.value. In this case,
there's no need to indulge in RCU or locking when accessing the payload.
The simplest payload is just data stored in key->payload directly. In this
case, there's no need to indulge in RCU or locking when accessing the payload.
More complex payload contents must be allocated and a pointer to them set in
key->payload.data. One of the following ways must be selected to access the
data:
More complex payload contents must be allocated and pointers to them set in the
key->payload.data[] array. One of the following ways must be selected to
access the data:
(1) Unmodifiable key type.
@ -1092,6 +1092,13 @@ data:
the payload. key->datalen cannot be relied upon to be consistent with the
payload just dereferenced if the key's semaphore is not held.
Note that key->payload.data[0] has a shadow that is marked for __rcu
usage. This is called key->payload.rcu_data0. The following accessors
wrap the RCU calls to this element:
rcu_assign_keypointer(struct key *key, void *data);
void *rcu_dereference_key(struct key *key);
===================
DEFINING A KEY TYPE
@ -1143,8 +1150,7 @@ The structure has a number of fields, some of which are mandatory:
struct key_preparsed_payload {
char *description;
void *type_data[2];
void *payload;
union key_payload payload;
const void *data;
size_t datalen;
size_t quotalen;
@ -1160,10 +1166,9 @@ The structure has a number of fields, some of which are mandatory:
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to type_data[] and payload. These
are merely passed along to the instantiate() or update() operations. If
set, the expiry time will be applied to the key if it is instantiated from
this data.
The method can attach anything it likes to payload. This is merely passed
along to the instantiate() or update() operations. If set, the expiry
time will be applied to the key if it is instantiated from this data.
The method should return 0 if successful or a negative error code
otherwise.
@ -1172,11 +1177,10 @@ The structure has a number of fields, some of which are mandatory:
(*) void (*free_preparse)(struct key_preparsed_payload *prep);
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the
description, type_data and payload fields of the key_preparsed_payload
struct as filled in by the preparse() method. It will always be called
after preparse() returns successfully, even if instantiate() or update()
succeed.
otherwise it is unused. It cleans up anything attached to the description
and payload fields of the key_preparsed_payload struct as filled in by the
preparse() method. It will always be called after preparse() returns
successfully, even if instantiate() or update() succeed.
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
@ -1197,6 +1201,11 @@ The structure has a number of fields, some of which are mandatory:
It is safe to sleep in this method.
generic_key_instantiate() is provided to simply copy the data from
prep->payload.data[] to key->payload.data[], with RCU-safe assignment on
the first element. It will then clear prep->payload.data[] so that the
free_preparse method doesn't release the data.
(*) int (*update)(struct key *key, const void *data, size_t datalen);

View file

@ -10738,6 +10738,7 @@ F: drivers/media/pci/tw68/
TPM DEVICE DRIVER
M: Peter Huewe <peterhuewe@gmx.de>
M: Marcel Selhorst <tpmdd@selhorst.net>
M: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
R: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
W: http://tpmdd.sourceforge.net
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)

View file

@ -1425,27 +1425,45 @@ static void __init prom_instantiate_sml(void)
{
phandle ibmvtpm_node;
ihandle ibmvtpm_inst;
u32 entry = 0, size = 0;
u32 entry = 0, size = 0, succ = 0;
u64 base;
__be32 val;
prom_debug("prom_instantiate_sml: start...\n");
ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/ibm,vtpm"));
ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/vdevice/vtpm"));
prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
if (!PHANDLE_VALID(ibmvtpm_node))
return;
ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/ibm,vtpm"));
ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/vdevice/vtpm"));
if (!IHANDLE_VALID(ibmvtpm_inst)) {
prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
return;
}
if (call_prom_ret("call-method", 2, 2, &size,
ADDR("sml-get-handover-size"),
ibmvtpm_inst) != 0 || size == 0) {
prom_printf("SML get handover size failed\n");
return;
if (prom_getprop(ibmvtpm_node, "ibm,sml-efi-reformat-supported",
&val, sizeof(val)) != PROM_ERROR) {
if (call_prom_ret("call-method", 2, 2, &succ,
ADDR("reformat-sml-to-efi-alignment"),
ibmvtpm_inst) != 0 || succ == 0) {
prom_printf("Reformat SML to EFI alignment failed\n");
return;
}
if (call_prom_ret("call-method", 2, 2, &size,
ADDR("sml-get-allocated-size"),
ibmvtpm_inst) != 0 || size == 0) {
prom_printf("SML get allocated size failed\n");
return;
}
} else {
if (call_prom_ret("call-method", 2, 2, &size,
ADDR("sml-get-handover-size"),
ibmvtpm_inst) != 0 || size == 0) {
prom_printf("SML get handover size failed\n");
return;
}
}
base = alloc_down(size, PAGE_SIZE, 0);
@ -1454,6 +1472,8 @@ static void __init prom_instantiate_sml(void)
prom_printf("instantiating sml at 0x%x...", base);
memset((void *)base, 0, size);
if (call_prom_ret("call-method", 4, 2, &entry,
ADDR("sml-handover"),
ibmvtpm_inst, size, base) != 0 || entry == 0) {
@ -1464,9 +1484,9 @@ static void __init prom_instantiate_sml(void)
reserve_mem(base, size);
prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-base",
prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-base",
&base, sizeof(base));
prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size",
prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size",
&size, sizeof(size));
prom_debug("sml base = 0x%x\n", base);

4
certs/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
#
# Generated files
#
x509_certificate_list

View file

@ -14,8 +14,3 @@ extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
extern int __asymmetric_key_hex_to_key_id(const char *id,
struct asymmetric_key_id *match_id,
size_t hexlen);
static inline
const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
{
return key->type_data.p[1];
}

View file

@ -307,25 +307,34 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
}
/*
* Clean up the preparse data
* Clean up the key ID list
*/
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
{
struct asymmetric_key_subtype *subtype = prep->type_data[0];
struct asymmetric_key_ids *kids = prep->type_data[1];
int i;
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload[0]);
module_put(subtype->owner);
}
if (kids) {
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
kfree(kids->id[i]);
kfree(kids);
}
}
/*
* Clean up the preparse data
*/
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
{
struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload.data[asym_crypto]);
module_put(subtype->owner);
}
asymmetric_key_free_kids(kids);
kfree(prep->description);
}
@ -335,20 +344,19 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
static void asymmetric_key_destroy(struct key *key)
{
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
struct asymmetric_key_ids *kids = key->type_data.p[1];
struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
void *data = key->payload.data[asym_crypto];
key->payload.data[asym_crypto] = NULL;
key->payload.data[asym_subtype] = NULL;
key->payload.data[asym_key_ids] = NULL;
if (subtype) {
subtype->destroy(key->payload.data);
subtype->destroy(data);
module_put(subtype->owner);
key->type_data.p[0] = NULL;
}
if (kids) {
kfree(kids->id[0]);
kfree(kids->id[1]);
kfree(kids);
key->type_data.p[1] = NULL;
}
asymmetric_key_free_kids(kids);
}
struct key_type key_type_asymmetric = {

View file

@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(pkey_id_type_name);
static void public_key_describe(const struct key *asymmetric_key,
struct seq_file *m)
{
struct public_key *key = asymmetric_key->payload.data;
struct public_key *key = asymmetric_key->payload.data[asym_crypto];
if (key)
seq_printf(m, "%s.%s",
@ -112,7 +112,7 @@ 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;
const struct public_key *pk = key->payload.data[asym_crypto];
return public_key_verify_signature(pk, sig);
}

View file

@ -37,7 +37,7 @@ int verify_signature(const struct key *key,
return -EINVAL;
subtype = asymmetric_key_subtype(key);
if (!subtype ||
!key->payload.data)
!key->payload.data[0])
return -EINVAL;
if (!subtype->verify_signature)
return -ENOTSUPP;

View file

@ -11,6 +11,7 @@
#include <linux/time.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
struct x509_certificate {
struct x509_certificate *next;

View file

@ -267,7 +267,8 @@ static int x509_validate_trust(struct x509_certificate *cert,
if (!IS_ERR(key)) {
if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = x509_check_signature(key->payload.data, cert);
ret = x509_check_signature(key->payload.data[asym_crypto],
cert);
key_put(key);
}
return ret;
@ -353,9 +354,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
/* We're pinning the module by being linked against it */
__module_get(public_key_subtype.owner);
prep->type_data[0] = &public_key_subtype;
prep->type_data[1] = kids;
prep->payload[0] = cert->pub;
prep->payload.data[asym_subtype] = &public_key_subtype;
prep->payload.data[asym_key_ids] = kids;
prep->payload.data[asym_crypto] = cert->pub;
prep->description = desc;
prep->quotalen = 100;

View file

@ -1,6 +1,6 @@
config TCG_TIS_ST33ZP24
tristate "STMicroelectronics TPM Interface Specification 1.2 Interface"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
---help---
STMicroelectronics ST33ZP24 core driver. It implements the core
TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will

View file

@ -258,7 +258,6 @@ static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend,
static struct i2c_driver st33zp24_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = TPM_ST33_I2C,
.pm = &st33zp24_i2c_ops,
.of_match_table = of_match_ptr(of_st33zp24_i2c_match),

View file

@ -119,6 +119,9 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
chip->dev.class = tpm_class;
chip->dev.release = tpm_dev_release;
chip->dev.parent = chip->pdev;
#ifdef CONFIG_ACPI
chip->dev.groups = chip->groups;
#endif
if (chip->dev_num == 0)
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
@ -182,12 +185,6 @@ static int tpm1_chip_register(struct tpm_chip *chip)
if (rc)
return rc;
rc = tpm_add_ppi(chip);
if (rc) {
tpm_sysfs_del_device(chip);
return rc;
}
chip->bios_dir = tpm_bios_log_setup(chip->devname);
return 0;
@ -201,8 +198,6 @@ static void tpm1_chip_unregister(struct tpm_chip *chip)
if (chip->bios_dir)
tpm_bios_log_teardown(chip->bios_dir);
tpm_remove_ppi(chip);
tpm_sysfs_del_device(chip);
}
@ -225,10 +220,20 @@ int tpm_chip_register(struct tpm_chip *chip)
if (rc)
return rc;
tpm_add_ppi(chip);
rc = tpm_dev_add_device(chip);
if (rc)
goto out_err;
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj,
&chip->dev.kobj,
"ppi");
if (rc)
goto out_err;
}
/* Make the chip available. */
spin_lock(&driver_lock);
list_add_rcu(&chip->list, &tpm_chip_list);
@ -263,6 +268,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
spin_unlock(&driver_lock);
synchronize_rcu();
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
sysfs_remove_link(&chip->pdev->kobj, "ppi");
tpm1_chip_unregister(chip);
tpm_dev_del_device(chip);
}

View file

@ -665,6 +665,30 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
return rc;
}
/**
* tpm_is_tpm2 - is the chip a TPM2 chip?
* @chip_num: tpm idx # or ANY
*
* Returns < 0 on error, and 1 or 0 on success depending whether the chip
* is a TPM2 chip.
*/
int tpm_is_tpm2(u32 chip_num)
{
struct tpm_chip *chip;
int rc;
chip = tpm_chip_find_get(chip_num);
if (chip == NULL)
return -ENODEV;
rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
tpm_chip_put(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_is_tpm2);
/**
* tpm_pcr_read - read a pcr value
* @chip_num: tpm idx # or ANY
@ -1021,6 +1045,58 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
}
EXPORT_SYMBOL_GPL(tpm_get_random);
/**
* tpm_seal_trusted() - seal a trusted key
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
* @options: authentication values and other options
* @payload: the key data in clear and encrypted form
*
* Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
* are supported.
*/
int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
struct tpm_chip *chip;
int rc;
chip = tpm_chip_find_get(chip_num);
if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
return -ENODEV;
rc = tpm2_seal_trusted(chip, payload, options);
tpm_chip_put(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_seal_trusted);
/**
* tpm_unseal_trusted() - unseal a trusted key
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
* @options: authentication values and other options
* @payload: the key data in clear and encrypted form
*
* Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
* are supported.
*/
int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
struct tpm_chip *chip;
int rc;
chip = tpm_chip_find_get(chip_num);
if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
return -ENODEV;
rc = tpm2_unseal_trusted(chip, payload, options);
tpm_chip_put(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_unseal_trusted);
static int __init tpm_init(void)
{
int rc;

View file

@ -1,5 +1,6 @@
/*
* Copyright (C) 2004 IBM Corporation
* Copyright (C) 2015 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
@ -28,6 +29,7 @@
#include <linux/tpm.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/highmem.h>
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
@ -88,6 +90,9 @@ enum tpm2_return_codes {
enum tpm2_algorithms {
TPM2_ALG_SHA1 = 0x0004,
TPM2_ALG_KEYEDHASH = 0x0008,
TPM2_ALG_SHA256 = 0x000B,
TPM2_ALG_NULL = 0x0010
};
enum tpm2_command_codes {
@ -95,6 +100,10 @@ enum tpm2_command_codes {
TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_STARTUP = 0x0144,
TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_CREATE = 0x0153,
TPM2_CC_LOAD = 0x0157,
TPM2_CC_UNSEAL = 0x015E,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
@ -115,6 +124,13 @@ enum tpm2_startup_types {
TPM2_SU_STATE = 0x0001,
};
enum tpm2_start_method {
TPM2_START_ACPI = 2,
TPM2_START_FIFO = 6,
TPM2_START_CRB = 7,
TPM2_START_CRB_WITH_ACPI = 8,
};
struct tpm_chip;
struct tpm_vendor_specific {
@ -151,8 +167,7 @@ struct tpm_vendor_specific {
enum tpm_chip_flags {
TPM_CHIP_FLAG_REGISTERED = BIT(0),
TPM_CHIP_FLAG_PPI = BIT(1),
TPM_CHIP_FLAG_TPM2 = BIT(2),
TPM_CHIP_FLAG_TPM2 = BIT(1),
};
struct tpm_chip {
@ -175,6 +190,8 @@ struct tpm_chip {
struct dentry **bios_dir;
#ifdef CONFIG_ACPI
const struct attribute_group *groups[2];
unsigned int groups_cnt;
acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1];
#endif /* CONFIG_ACPI */
@ -182,7 +199,7 @@ struct tpm_chip {
struct list_head list;
};
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
static inline void tpm_chip_put(struct tpm_chip *chip)
{
@ -382,6 +399,101 @@ struct tpm_cmd_t {
tpm_cmd_params params;
} __packed;
/* A string buffer type for constructing TPM commands. This is based on the
* ideas of string buffer code in security/keys/trusted.h but is heap based
* in order to keep the stack usage minimal.
*/
enum tpm_buf_flags {
TPM_BUF_OVERFLOW = BIT(0),
};
struct tpm_buf {
struct page *data_page;
unsigned int flags;
u8 *data;
};
static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
struct tpm_input_header *head;
buf->data_page = alloc_page(GFP_HIGHUSER);
if (!buf->data_page)
return -ENOMEM;
buf->flags = 0;
buf->data = kmap(buf->data_page);
head = (struct tpm_input_header *) buf->data;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
return 0;
}
static inline void tpm_buf_destroy(struct tpm_buf *buf)
{
kunmap(buf->data_page);
__free_page(buf->data_page);
}
static inline u32 tpm_buf_length(struct tpm_buf *buf)
{
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
return be32_to_cpu(head->length);
}
static inline u16 tpm_buf_tag(struct tpm_buf *buf)
{
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
return be16_to_cpu(head->tag);
}
static inline void tpm_buf_append(struct tpm_buf *buf,
const unsigned char *new_data,
unsigned int new_len)
{
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
u32 len = tpm_buf_length(buf);
/* Return silently if overflow has already happened. */
if (buf->flags & TPM_BUF_OVERFLOW)
return;
if ((len + new_len) > PAGE_SIZE) {
WARN(1, "tpm_buf: overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
}
memcpy(&buf->data[len], new_data, new_len);
head->length = cpu_to_be32(len + new_len);
}
static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
{
tpm_buf_append(buf, &value, 1);
}
static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
{
__be16 value2 = cpu_to_be16(value);
tpm_buf_append(buf, (u8 *) &value2, 2);
}
static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
{
__be32 value2 = cpu_to_be32(value);
tpm_buf_append(buf, (u8 *) &value2, 4);
}
extern struct class *tpm_class;
extern dev_t tpm_devt;
extern const struct file_operations tpm_fops;
@ -412,15 +524,9 @@ void tpm_sysfs_del_device(struct tpm_chip *chip);
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
#ifdef CONFIG_ACPI
extern int tpm_add_ppi(struct tpm_chip *chip);
extern void tpm_remove_ppi(struct tpm_chip *chip);
extern void tpm_add_ppi(struct tpm_chip *chip);
#else
static inline int tpm_add_ppi(struct tpm_chip *chip)
{
return 0;
}
static inline void tpm_remove_ppi(struct tpm_chip *chip)
static inline void tpm_add_ppi(struct tpm_chip *chip)
{
}
#endif
@ -428,6 +534,12 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
int tpm2_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
u32 *value, const char *desc);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Intel Corporation
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
@ -16,6 +16,11 @@
*/
#include "tpm.h"
#include <keys/trusted-type.h>
enum tpm2_object_attributes {
TPM2_ATTR_USER_WITH_AUTH = BIT(6),
};
struct tpm2_startup_in {
__be16 startup_type;
@ -380,6 +385,249 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
.ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
};
/**
* Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with
* tpm_buf_alloc().
*
* @param buf: an allocated tpm_buf instance
* @param nonce: the session nonce, may be NULL if not used
* @param nonce_len: the session nonce length, may be 0 if not used
* @param attributes: the session attributes
* @param hmac: the session HMAC or password, may be NULL if not used
* @param hmac_len: the session HMAC or password length, maybe 0 if not used
*/
static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
const u8 *nonce, u16 nonce_len,
u8 attributes,
const u8 *hmac, u16 hmac_len)
{
tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);
tpm_buf_append_u32(buf, session_handle);
tpm_buf_append_u16(buf, nonce_len);
if (nonce && nonce_len)
tpm_buf_append(buf, nonce, nonce_len);
tpm_buf_append_u8(buf, attributes);
tpm_buf_append_u16(buf, hmac_len);
if (hmac && hmac_len)
tpm_buf_append(buf, hmac, hmac_len);
}
/**
* tpm2_seal_trusted() - seal a trusted key
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
* @options: authentication values and other options
* @payload: the key data in clear and encrypted form
*
* Returns < 0 on error and 0 on success.
*/
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
unsigned int blob_len;
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
if (rc)
return rc;
tpm_buf_append_u32(&buf, options->keyhandle);
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
NULL /* nonce */, 0,
0 /* session_attributes */,
options->keyauth /* hmac */,
TPM_DIGEST_SIZE);
/* sensitive */
tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len);
tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
tpm_buf_append_u16(&buf, payload->key_len);
tpm_buf_append(&buf, payload->key, payload->key_len);
/* public */
tpm_buf_append_u16(&buf, 14);
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
tpm_buf_append_u16(&buf, 0); /* policy digest size */
tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
tpm_buf_append_u16(&buf, 0);
/* outside info */
tpm_buf_append_u16(&buf, 0);
/* creation PCR */
tpm_buf_append_u32(&buf, 0);
if (buf.flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
goto out;
}
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "sealing data");
if (rc)
goto out;
blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]);
if (blob_len > MAX_BLOB_SIZE) {
rc = -E2BIG;
goto out;
}
memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
payload->blob_len = blob_len;
out:
tpm_buf_destroy(&buf);
if (rc > 0)
rc = -EPERM;
return rc;
}
static int tpm2_load(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
u32 *blob_handle)
{
struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
int rc;
private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
if (private_len > (payload->blob_len - 2))
return -E2BIG;
public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]);
blob_len = private_len + public_len + 4;
if (blob_len > payload->blob_len)
return -E2BIG;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
if (rc)
return rc;
tpm_buf_append_u32(&buf, options->keyhandle);
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
NULL /* nonce */, 0,
0 /* session_attributes */,
options->keyauth /* hmac */,
TPM_DIGEST_SIZE);
tpm_buf_append(&buf, payload->blob, blob_len);
if (buf.flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
goto out;
}
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob");
if (!rc)
*blob_handle = be32_to_cpup(
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
out:
tpm_buf_destroy(&buf);
if (rc > 0)
rc = -EPERM;
return rc;
}
static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
if (rc) {
dev_warn(chip->pdev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
tpm_buf_append_u32(&buf, handle);
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context");
if (rc)
dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle,
rc);
tpm_buf_destroy(&buf);
}
static int tpm2_unseal(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
u32 blob_handle)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
if (rc)
return rc;
tpm_buf_append_u32(&buf, blob_handle);
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
NULL /* nonce */, 0,
0 /* session_attributes */,
options->blobauth /* hmac */,
TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "unsealing");
if (rc > 0)
rc = -EPERM;
if (!rc) {
payload->key_len = be16_to_cpup(
(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
memcpy(payload->key, &buf.data[TPM_HEADER_SIZE + 6],
payload->key_len);
}
tpm_buf_destroy(&buf);
return rc;
}
/**
* tpm_unseal_trusted() - unseal a trusted key
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
* @options: authentication values and other options
* @payload: the key data in clear and encrypted form
*
* Returns < 0 on error and 0 on success.
*/
int tpm2_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
u32 blob_handle;
int rc;
rc = tpm2_load(chip, payload, options, &blob_handle);
if (rc)
return rc;
rc = tpm2_unseal(chip, payload, options, blob_handle);
tpm2_flush_context(chip, blob_handle);
return rc;
}
/**
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
* @chip: TPM chip to use.

View file

@ -34,12 +34,6 @@ enum crb_defaults {
CRB_ACPI_START_INDEX = 1,
};
enum crb_start_method {
CRB_SM_ACPI_START = 2,
CRB_SM_CRB = 7,
CRB_SM_CRB_WITH_ACPI_START = 8,
};
struct acpi_tpm2 {
struct acpi_table_header hdr;
u16 platform_class;
@ -74,7 +68,8 @@ struct crb_control_area {
u32 int_enable;
u32 int_sts;
u32 cmd_size;
u64 cmd_pa;
u32 cmd_pa_low;
u32 cmd_pa_high;
u32 rsp_size;
u64 rsp_pa;
} __packed;
@ -220,12 +215,6 @@ static int crb_acpi_add(struct acpi_device *device)
u64 pa;
int rc;
chip = tpmm_chip_alloc(dev, &tpm_crb);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->flags = TPM_CHIP_FLAG_TPM2;
status = acpi_get_table(ACPI_SIG_TPM2, 1,
(struct acpi_table_header **) &buf);
if (ACPI_FAILURE(status)) {
@ -233,13 +222,15 @@ static int crb_acpi_add(struct acpi_device *device)
return -ENODEV;
}
/* At least some versions of AMI BIOS have a bug that TPM2 table has
* zero address for the control area and therefore we must fail.
*/
if (!buf->control_area_pa) {
dev_err(dev, "TPM2 ACPI table has a zero address for the control area\n");
return -EINVAL;
}
/* Should the FIFO driver handle this? */
if (buf->start_method == TPM2_START_FIFO)
return -ENODEV;
chip = tpmm_chip_alloc(dev, &tpm_crb);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->flags = TPM_CHIP_FLAG_TPM2;
if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
dev_err(dev, "TPM2 ACPI table has wrong size");
@ -259,11 +250,11 @@ static int crb_acpi_add(struct acpi_device *device)
* report only ACPI start but in practice seems to require both
* ACPI start and CRB start.
*/
if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START ||
if (sm == TPM2_START_CRB || sm == TPM2_START_FIFO ||
!strcmp(acpi_device_hid(device), "MSFT0101"))
priv->flags |= CRB_FL_CRB_START;
if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
if (sm == TPM2_START_ACPI || sm == TPM2_START_CRB_WITH_ACPI)
priv->flags |= CRB_FL_ACPI_START;
priv->cca = (struct crb_control_area __iomem *)
@ -273,8 +264,8 @@ static int crb_acpi_add(struct acpi_device *device)
return -ENOMEM;
}
memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
pa = le64_to_cpu(pa);
pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
(u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
priv->cmd = devm_ioremap_nocache(dev, pa,
ioread32(&priv->cca->cmd_size));
if (!priv->cmd) {

View file

@ -76,15 +76,25 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
void *addr = log->bios_event_log;
void *limit = log->bios_event_log_end;
struct tcpa_event *event;
u32 converted_event_size;
u32 converted_event_type;
/* read over *pos measurements */
for (i = 0; i < *pos; i++) {
event = addr;
converted_event_size =
do_endian_conversion(event->event_size);
converted_event_type =
do_endian_conversion(event->event_type);
if ((addr + sizeof(struct tcpa_event)) < limit) {
if (event->event_type == 0 && event->event_size == 0)
if ((converted_event_type == 0) &&
(converted_event_size == 0))
return NULL;
addr += sizeof(struct tcpa_event) + event->event_size;
addr += (sizeof(struct tcpa_event) +
converted_event_size);
}
}
@ -94,8 +104,12 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
event = addr;
if ((event->event_type == 0 && event->event_size == 0) ||
((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
converted_event_size = do_endian_conversion(event->event_size);
converted_event_type = do_endian_conversion(event->event_type);
if (((converted_event_type == 0) && (converted_event_size == 0))
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
>= limit))
return NULL;
return addr;
@ -107,8 +121,12 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
struct tcpa_event *event = v;
struct tpm_bios_log *log = m->private;
void *limit = log->bios_event_log_end;
u32 converted_event_size;
u32 converted_event_type;
v += sizeof(struct tcpa_event) + event->event_size;
converted_event_size = do_endian_conversion(event->event_size);
v += sizeof(struct tcpa_event) + converted_event_size;
/* now check if current entry is valid */
if ((v + sizeof(struct tcpa_event)) >= limit)
@ -116,11 +134,11 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
event = v;
if (event->event_type == 0 && event->event_size == 0)
return NULL;
converted_event_size = do_endian_conversion(event->event_size);
converted_event_type = do_endian_conversion(event->event_type);
if ((event->event_type == 0 && event->event_size == 0) ||
((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
if (((converted_event_type == 0) && (converted_event_size == 0)) ||
((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
return NULL;
(*pos)++;
@ -140,7 +158,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
int i, n_len = 0, d_len = 0;
struct tcpa_pc_event *pc_event;
switch(event->event_type) {
switch (do_endian_conversion(event->event_type)) {
case PREBOOT:
case POST_CODE:
case UNUSED:
@ -156,14 +174,16 @@ static int get_event_name(char *dest, struct tcpa_event *event,
case NONHOST_CODE:
case NONHOST_CONFIG:
case NONHOST_INFO:
name = tcpa_event_type_strings[event->event_type];
name = tcpa_event_type_strings[do_endian_conversion
(event->event_type)];
n_len = strlen(name);
break;
case SEPARATOR:
case ACTION:
if (MAX_TEXT_EVENT > event->event_size) {
if (MAX_TEXT_EVENT >
do_endian_conversion(event->event_size)) {
name = event_entry;
n_len = event->event_size;
n_len = do_endian_conversion(event->event_size);
}
break;
case EVENT_TAG:
@ -171,7 +191,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
/* ToDo Row data -> Base64 */
switch (pc_event->event_id) {
switch (do_endian_conversion(pc_event->event_id)) {
case SMBIOS:
case BIS_CERT:
case CMOS:
@ -179,7 +199,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
case OPTION_ROM_EXEC:
case OPTION_ROM_CONFIG:
case S_CRTM_VERSION:
name = tcpa_pc_event_id_strings[pc_event->event_id];
name = tcpa_pc_event_id_strings[do_endian_conversion
(pc_event->event_id)];
n_len = strlen(name);
break;
/* hash data */
@ -188,7 +209,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
case OPTION_ROM_MICROCODE:
case S_CRTM_CONTENTS:
case POST_CONTENTS:
name = tcpa_pc_event_id_strings[pc_event->event_id];
name = tcpa_pc_event_id_strings[do_endian_conversion
(pc_event->event_id)];
n_len = strlen(name);
for (i = 0; i < 20; i++)
d_len += sprintf(&data[2*i], "%02x",
@ -209,13 +231,24 @@ static int get_event_name(char *dest, struct tcpa_event *event,
static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
{
struct tcpa_event *event = v;
char *data = v;
struct tcpa_event temp_event;
char *tempPtr;
int i;
for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
seq_putc(m, data[i]);
memcpy(&temp_event, event, sizeof(struct tcpa_event));
/* convert raw integers for endianness */
temp_event.pcr_index = do_endian_conversion(event->pcr_index);
temp_event.event_type = do_endian_conversion(event->event_type);
temp_event.event_size = do_endian_conversion(event->event_size);
tempPtr = (char *)&temp_event;
for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
seq_putc(m, tempPtr[i]);
return 0;
}
static int tpm_bios_measurements_release(struct inode *inode,
@ -238,7 +271,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
char *eventname;
struct tcpa_event *event = v;
unsigned char *event_entry =
(unsigned char *) (v + sizeof(struct tcpa_event));
(unsigned char *)(v + sizeof(struct tcpa_event));
eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
if (!eventname) {
@ -247,13 +280,14 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
return -EFAULT;
}
seq_printf(m, "%2d ", event->pcr_index);
/* 1st: PCR */
seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
/* 2nd: SHA1 */
seq_printf(m, "%20phN", event->pcr_value);
/* 3rd: event type identifier */
seq_printf(m, " %02x", event->event_type);
seq_printf(m, " %02x", do_endian_conversion(event->event_type));
len += get_event_name(eventname, event, event_entry);

View file

@ -6,6 +6,12 @@
#define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
#ifdef CONFIG_PPC64
#define do_endian_conversion(x) be32_to_cpu(x)
#else
#define do_endian_conversion(x) x
#endif
enum bios_platform_class {
BIOS_CLIENT = 0x00,
BIOS_SERVER = 0x01,

View file

@ -217,7 +217,6 @@ static struct i2c_driver i2c_atmel_driver = {
.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),
},

View file

@ -711,7 +711,6 @@ static struct i2c_driver tpm_tis_i2c_driver = {
.remove = tpm_tis_i2c_remove,
.driver = {
.name = "tpm_i2c_infineon",
.owner = THIS_MODULE,
.pm = &tpm_tis_i2c_ops,
.of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
},

View file

@ -641,7 +641,6 @@ static struct i2c_driver i2c_nuvoton_driver = {
.remove = i2c_nuvoton_remove,
.driver = {
.name = I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &i2c_nuvoton_pm_ops,
.of_match_table = of_match_ptr(i2c_nuvoton_of_match),
},

View file

@ -491,7 +491,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
}
ibmvtpm->rtce_size = be16_to_cpu(crq->len);
ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
GFP_KERNEL);
GFP_ATOMIC);
if (!ibmvtpm->rtce_buf) {
dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
return;

View file

@ -24,14 +24,14 @@ int read_log(struct tpm_bios_log *log)
{
struct device_node *np;
const u32 *sizep;
const __be64 *basep;
const u64 *basep;
if (log->bios_event_log != NULL) {
pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
return -EFAULT;
}
np = of_find_node_by_name(NULL, "ibm,vtpm");
np = of_find_node_by_name(NULL, "vtpm");
if (!np) {
pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
return -ENODEV;
@ -63,7 +63,7 @@ int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + *sizep;
memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep);
memcpy(log->bios_event_log, __va(*basep), *sizep);
return 0;

View file

@ -53,7 +53,7 @@ tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
static ssize_t tpm_show_ppi_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
}
@ -63,7 +63,7 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
{
ssize_t size = -EINVAL;
union acpi_object *obj;
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
ACPI_TYPE_PACKAGE, NULL);
@ -100,7 +100,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp;
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
/*
* the function to submit TPM operation request to pre-os environment
@ -156,7 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
.buffer.length = 0,
.buffer.pointer = NULL
};
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
static char *info[] = {
"None",
@ -197,7 +197,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
acpi_status status = -EINVAL;
union acpi_object *obj, *ret_obj;
u64 req, res;
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
ACPI_TYPE_PACKAGE, NULL);
@ -296,7 +296,7 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
PPI_TPM_REQ_MAX);
@ -306,7 +306,7 @@ static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_chip *chip = to_tpm_chip(dev);
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
PPI_VS_REQ_END);
@ -334,17 +334,16 @@ static struct attribute_group ppi_attr_grp = {
.attrs = ppi_attrs
};
int tpm_add_ppi(struct tpm_chip *chip)
void tpm_add_ppi(struct tpm_chip *chip)
{
union acpi_object *obj;
int rc;
if (!chip->acpi_dev_handle)
return 0;
return;
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
return 0;
return;
/* Cache PPI version string. */
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
@ -356,16 +355,5 @@ int tpm_add_ppi(struct tpm_chip *chip)
ACPI_FREE(obj);
}
rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
if (!rc)
chip->flags |= TPM_CHIP_FLAG_PPI;
return rc;
}
void tpm_remove_ppi(struct tpm_chip *chip)
{
if (chip->flags & TPM_CHIP_FLAG_PPI)
sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
chip->groups[chip->groups_cnt++] = &ppi_attr_grp;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (C) 2005, 2006 IBM Corporation
* Copyright (C) 2014 Intel Corporation
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
@ -28,6 +28,7 @@
#include <linux/wait.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
#include <acpi/actbl2.h>
#include "tpm.h"
enum tis_access {
@ -65,6 +66,17 @@ enum tis_defaults {
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
};
struct tpm_info {
unsigned long start;
unsigned long len;
unsigned int irq;
};
static struct tpm_info tis_default_info = {
.start = TIS_MEM_BASE,
.len = TIS_MEM_LEN,
.irq = 0,
};
/* Some timeout values are needed before it is known whether the chip is
* TPM 1.0 or TPM 2.0.
@ -91,26 +103,54 @@ struct priv_data {
};
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int is_itpm(struct pnp_dev *dev)
static int has_hid(struct acpi_device *dev, const char *hid)
{
struct acpi_device *acpi = pnp_acpi_device(dev);
struct acpi_hardware_id *id;
if (!acpi)
return 0;
list_for_each_entry(id, &acpi->pnp.ids, list) {
if (!strcmp("INTC0102", id->id))
list_for_each_entry(id, &dev->pnp.ids, list)
if (!strcmp(hid, id->id))
return 1;
}
return 0;
}
static inline int is_itpm(struct acpi_device *dev)
{
return has_hid(dev, "INTC0102");
}
static inline int is_fifo(struct acpi_device *dev)
{
struct acpi_table_tpm2 *tbl;
acpi_status st;
/* TPM 1.2 FIFO */
if (!has_hid(dev, "MSFT0101"))
return 1;
st = acpi_get_table(ACPI_SIG_TPM2, 1,
(struct acpi_table_header **) &tbl);
if (ACPI_FAILURE(st)) {
dev_err(&dev->dev, "failed to get TPM2 ACPI table\n");
return 0;
}
if (le32_to_cpu(tbl->start_method) != TPM2_START_FIFO)
return 0;
/* TPM 2.0 FIFO */
return 1;
}
#else
static inline int is_itpm(struct pnp_dev *dev)
static inline int is_itpm(struct acpi_device *dev)
{
return 0;
}
static inline int is_fifo(struct acpi_device *dev)
{
return 1;
}
#endif
/* Before we attempt to access the TPM we must see that the valid bit is set.
@ -600,9 +640,8 @@ static void tpm_tis_remove(struct tpm_chip *chip)
release_locality(chip, chip->vendor.locality, 1);
}
static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
resource_size_t start, resource_size_t len,
unsigned int irq)
static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
acpi_handle acpi_dev_handle)
{
u32 vendor, intfcaps, intmask;
int rc, i, irq_s, irq_e, probe;
@ -622,7 +661,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
chip->acpi_dev_handle = acpi_dev_handle;
#endif
chip->vendor.iobase = devm_ioremap(dev, start, len);
chip->vendor.iobase = devm_ioremap(dev, tpm_info->start, tpm_info->len);
if (!chip->vendor.iobase)
return -EIO;
@ -707,7 +746,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
if (interrupts)
chip->vendor.irq = irq;
chip->vendor.irq = tpm_info->irq;
if (interrupts && !chip->vendor.irq) {
irq_s =
ioread8(chip->vendor.iobase +
@ -890,27 +929,27 @@ static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id)
{
resource_size_t start, len;
unsigned int irq = 0;
struct tpm_info tpm_info = tis_default_info;
acpi_handle acpi_dev_handle = NULL;
start = pnp_mem_start(pnp_dev, 0);
len = pnp_mem_len(pnp_dev, 0);
tpm_info.start = pnp_mem_start(pnp_dev, 0);
tpm_info.len = pnp_mem_len(pnp_dev, 0);
if (pnp_irq_valid(pnp_dev, 0))
irq = pnp_irq(pnp_dev, 0);
tpm_info.irq = pnp_irq(pnp_dev, 0);
else
interrupts = false;
if (is_itpm(pnp_dev))
itpm = true;
#ifdef CONFIG_ACPI
if (pnp_acpi_device(pnp_dev))
if (pnp_acpi_device(pnp_dev)) {
if (is_itpm(pnp_acpi_device(pnp_dev)))
itpm = true;
acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
}
#endif
return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
}
static struct pnp_device_id tpm_pnp_tbl[] = {
@ -930,6 +969,7 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
{
struct tpm_chip *chip = pnp_get_drvdata(dev);
tpm_chip_unregister(chip);
tpm_tis_remove(chip);
}
@ -950,6 +990,79 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
#endif
#ifdef CONFIG_ACPI
static int tpm_check_resource(struct acpi_resource *ares, void *data)
{
struct tpm_info *tpm_info = (struct tpm_info *) data;
struct resource res;
if (acpi_dev_resource_interrupt(ares, 0, &res)) {
tpm_info->irq = res.start;
} else if (acpi_dev_resource_memory(ares, &res)) {
tpm_info->start = res.start;
tpm_info->len = resource_size(&res);
}
return 1;
}
static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
{
struct list_head resources;
struct tpm_info tpm_info = tis_default_info;
int ret;
if (!is_fifo(acpi_dev))
return -ENODEV;
INIT_LIST_HEAD(&resources);
ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
&tpm_info);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&resources);
if (!tpm_info.irq)
interrupts = false;
if (is_itpm(acpi_dev))
itpm = true;
return tpm_tis_init(&acpi_dev->dev, &tpm_info, acpi_dev->handle);
}
static int tpm_tis_acpi_remove(struct acpi_device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
tpm_chip_unregister(chip);
tpm_tis_remove(chip);
return 0;
}
static struct acpi_device_id tpm_acpi_tbl[] = {
{"MSFT0101", 0}, /* TPM 2.0 */
/* Add new here */
{"", 0}, /* User Specified */
{"", 0} /* Terminator */
};
MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl);
static struct acpi_driver tis_acpi_driver = {
.name = "tpm_tis",
.ids = tpm_acpi_tbl,
.ops = {
.add = tpm_tis_acpi_init,
.remove = tpm_tis_acpi_remove,
},
.drv = {
.pm = &tpm_tis_pm,
},
};
#endif
static struct platform_driver tis_drv = {
.driver = {
.name = "tpm_tis",
@ -966,9 +1079,25 @@ static int __init init_tis(void)
{
int rc;
#ifdef CONFIG_PNP
if (!force)
return pnp_register_driver(&tis_pnp_driver);
if (!force) {
rc = pnp_register_driver(&tis_pnp_driver);
if (rc)
return rc;
}
#endif
#ifdef CONFIG_ACPI
if (!force) {
rc = acpi_bus_register_driver(&tis_acpi_driver);
if (rc) {
#ifdef CONFIG_PNP
pnp_unregister_driver(&tis_pnp_driver);
#endif
return rc;
}
}
#endif
if (!force)
return 0;
rc = platform_driver_register(&tis_drv);
if (rc < 0)
@ -978,7 +1107,7 @@ static int __init init_tis(void)
rc = PTR_ERR(pdev);
goto err_dev;
}
rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
rc = tpm_tis_init(&pdev->dev, &tis_default_info, NULL);
if (rc)
goto err_init;
return 0;
@ -992,9 +1121,14 @@ static int __init init_tis(void)
static void __exit cleanup_tis(void)
{
struct tpm_chip *chip;
#ifdef CONFIG_PNP
#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
if (!force) {
#ifdef CONFIG_ACPI
acpi_bus_unregister_driver(&tis_acpi_driver);
#endif
#ifdef CONFIG_PNP
pnp_unregister_driver(&tis_pnp_driver);
#endif
return;
}
#endif

View file

@ -42,7 +42,7 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
goto error;
/* attach the data */
key->payload.data = payload;
key->payload.data[0] = payload;
ret = 0;
error:
@ -52,7 +52,7 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
static void
cifs_spnego_key_destroy(struct key *key)
{
kfree(key->payload.data);
kfree(key->payload.data[0]);
}
@ -167,7 +167,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
#ifdef CONFIG_CIFS_DEBUG2
if (cifsFYI && !IS_ERR(spnego_key)) {
struct cifs_spnego_msg *msg = spnego_key->payload.data;
struct cifs_spnego_msg *msg = spnego_key->payload.data[0];
cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
msg->secblob_len + msg->sesskey_len));
}

View file

@ -58,16 +58,15 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
* dereference payload.data!
*/
if (prep->datalen <= sizeof(key->payload)) {
key->payload.value = 0;
memcpy(&key->payload.value, prep->data, prep->datalen);
key->datalen = prep->datalen;
return 0;
key->payload.data[0] = NULL;
memcpy(&key->payload, prep->data, prep->datalen);
} else {
payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
if (!payload)
return -ENOMEM;
key->payload.data[0] = payload;
}
payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
if (!payload)
return -ENOMEM;
key->payload.data = payload;
key->datalen = prep->datalen;
return 0;
}
@ -76,7 +75,7 @@ static inline void
cifs_idmap_key_destroy(struct key *key)
{
if (key->datalen > sizeof(key->payload))
kfree(key->payload.data);
kfree(key->payload.data[0]);
}
static struct key_type cifs_idmap_key_type = {
@ -233,8 +232,8 @@ id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
* it could be.
*/
ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
(struct cifs_sid *)&sidkey->payload.value :
(struct cifs_sid *)sidkey->payload.data;
(struct cifs_sid *)&sidkey->payload :
(struct cifs_sid *)sidkey->payload.data[0];
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
if (ksid_size > sidkey->datalen) {
@ -307,14 +306,14 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
if (sidtype == SIDOWNER) {
kuid_t uid;
uid_t id;
memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
uid = make_kuid(&init_user_ns, id);
if (uid_valid(uid))
fuid = uid;
} else {
kgid_t gid;
gid_t id;
memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
gid = make_kgid(&init_user_ns, id);
if (gid_valid(gid))
fgid = gid;

View file

@ -2325,13 +2325,14 @@ static int
cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
{
int rc = 0;
char *desc, *delim, *payload;
const char *delim, *payload;
char *desc;
ssize_t len;
struct key *key;
struct TCP_Server_Info *server = ses->server;
struct sockaddr_in *sa;
struct sockaddr_in6 *sa6;
struct user_key_payload *upayload;
const struct user_key_payload *upayload;
desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
if (!desc)
@ -2374,14 +2375,14 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
}
down_read(&key->sem);
upayload = key->payload.data;
upayload = user_key_payload(key);
if (IS_ERR_OR_NULL(upayload)) {
rc = upayload ? PTR_ERR(upayload) : -EINVAL;
goto out_key_put;
}
/* find first : in payload */
payload = (char *)upayload->data;
payload = upayload->data;
delim = strnchr(payload, upayload->datalen, ':');
cifs_dbg(FYI, "payload=%s\n", payload);
if (!delim) {

View file

@ -988,7 +988,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
goto out;
}
msg = spnego_key->payload.data;
msg = spnego_key->payload.data[0];
/*
* check version field to make sure that cifs.upcall is
* sending us a response in an expected form

View file

@ -660,7 +660,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
goto ssetup_exit;
}
msg = spnego_key->payload.data;
msg = spnego_key->payload.data[0];
/*
* check version field to make sure that cifs.upcall is
* sending us a response in an expected form

View file

@ -86,7 +86,7 @@ ecryptfs_get_encrypted_key_payload_data(struct key *key)
{
if (key->type == &key_type_encrypted)
return (struct ecryptfs_auth_tok *)
(&((struct encrypted_key_payload *)key->payload.data)->payload_data);
(&((struct encrypted_key_payload *)key->payload.data[0])->payload_data);
else
return NULL;
}
@ -117,8 +117,7 @@ ecryptfs_get_key_payload_data(struct key *key)
auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
if (!auth_tok)
return (struct ecryptfs_auth_tok *)
(((struct user_key_payload *)key->payload.data)->data);
return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
else
return auth_tok;
}

View file

@ -121,7 +121,7 @@ int _ext4_get_encryption_info(struct inode *inode)
struct key *keyring_key = NULL;
struct ext4_encryption_key *master_key;
struct ext4_encryption_context ctx;
struct user_key_payload *ukp;
const struct user_key_payload *ukp;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct crypto_ablkcipher *ctfm;
const char *cipher_str;
@ -209,7 +209,7 @@ int _ext4_get_encryption_info(struct inode *inode)
}
crypt_info->ci_keyring_key = keyring_key;
BUG_ON(keyring_key->type != &key_type_logon);
ukp = ((struct user_key_payload *)keyring_key->payload.data);
ukp = user_key_payload(keyring_key);
if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
res = -EINVAL;
goto out;

View file

@ -122,7 +122,7 @@ int _f2fs_get_encryption_info(struct inode *inode)
struct key *keyring_key = NULL;
struct f2fs_encryption_key *master_key;
struct f2fs_encryption_context ctx;
struct user_key_payload *ukp;
const struct user_key_payload *ukp;
struct crypto_ablkcipher *ctfm;
const char *cipher_str;
char raw_key[F2FS_MAX_KEY_SIZE];
@ -199,7 +199,7 @@ int _f2fs_get_encryption_info(struct inode *inode)
}
crypt_info->ci_keyring_key = keyring_key;
BUG_ON(keyring_key->type != &key_type_logon);
ukp = ((struct user_key_payload *)keyring_key->payload.data);
ukp = user_key_payload(keyring_key);
if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
res = -EINVAL;
goto out;

View file

@ -316,7 +316,7 @@ static const struct seq_operations fscache_objlist_ops = {
static void fscache_objlist_config(struct fscache_objlist_data *data)
{
#ifdef CONFIG_KEYS
struct user_key_payload *confkey;
const struct user_key_payload *confkey;
unsigned long config;
struct key *key;
const char *buf;
@ -329,7 +329,7 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
config = 0;
rcu_read_lock();
confkey = key->payload.data;
confkey = user_key_payload(key);
buf = confkey->data;
for (len = confkey->datalen - 1; len >= 0; len--) {

View file

@ -297,7 +297,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
{
const struct cred *saved_cred;
struct key *rkey;
struct user_key_payload *payload;
const struct user_key_payload *payload;
ssize_t ret;
saved_cred = override_creds(id_resolver_cache);
@ -316,7 +316,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
if (ret < 0)
goto out_up;
payload = rcu_dereference(rkey->payload.rcudata);
payload = user_key_payload(rkey);
if (IS_ERR_OR_NULL(payload)) {
ret = PTR_ERR(payload);
goto out_up;

View file

@ -352,3 +352,47 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
}
}
EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
/**
* __compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing
* to a group or an attribute
* @kobj: The kobject containing the group.
* @target_kobj: The target kobject.
* @target_name: The name of the target group or attribute.
*/
int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
struct kobject *target_kobj,
const char *target_name)
{
struct kernfs_node *target;
struct kernfs_node *entry;
struct kernfs_node *link;
/*
* We don't own @target_kobj and it may be removed at any time.
* Synchronize using sysfs_symlink_target_lock. See sysfs_remove_dir()
* for details.
*/
spin_lock(&sysfs_symlink_target_lock);
target = target_kobj->sd;
if (target)
kernfs_get(target);
spin_unlock(&sysfs_symlink_target_lock);
if (!target)
return -ENOENT;
entry = kernfs_find_and_get(target_kobj->sd, target_name);
if (!entry) {
kernfs_put(target);
return -ENOENT;
}
link = kernfs_create_link(kobj->sd, target_name, entry);
if (IS_ERR(link) && PTR_ERR(link) == -EEXIST)
sysfs_warn_dup(kobj->sd, target_name);
kernfs_put(entry);
kernfs_put(target);
return IS_ERR(link) ? PTR_ERR(link) : 0;
}
EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj);

View file

@ -15,7 +15,6 @@
#define _LINUX_PUBLIC_KEY_H
#include <linux/mpi.h>
#include <keys/asymmetric-type.h>
#include <crypto/hash_info.h>
enum pkey_algo {

View file

@ -49,7 +49,7 @@ struct asymmetric_key_subtype {
static inline
struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
{
return key->type_data.p[0];
return key->payload.data[asym_subtype];
}
#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */

View file

@ -18,6 +18,16 @@
extern struct key_type key_type_asymmetric;
/*
* The key payload is four words. The asymmetric-type key uses them as
* follows:
*/
enum asymmetric_payload_bits {
asym_crypto,
asym_subtype,
asym_key_ids,
};
/*
* Identifiers for an asymmetric key ID. We have three ways of looking up a
* key derived from an X.509 certificate:
@ -58,6 +68,11 @@ extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
size_t len_1,
const void *val_2,
size_t len_2);
static inline
const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
{
return key->payload.data[asym_key_ids];
}
/*
* The payload is at the discretion of the subtype.

View file

@ -12,10 +12,12 @@
#include <linux/key.h>
#include <linux/rcupdate.h>
#include <linux/tpm.h>
#define MIN_KEY_SIZE 32
#define MAX_KEY_SIZE 128
#define MAX_BLOB_SIZE 320
#define MAX_BLOB_SIZE 512
#define MAX_PCRINFO_SIZE 64
struct trusted_key_payload {
struct rcu_head rcu;
@ -26,6 +28,16 @@ struct trusted_key_payload {
unsigned char blob[MAX_BLOB_SIZE];
};
struct trusted_key_options {
uint16_t keytype;
uint32_t keyhandle;
unsigned char keyauth[TPM_DIGEST_SIZE];
unsigned char blobauth[TPM_DIGEST_SIZE];
uint32_t pcrinfo_len;
unsigned char pcrinfo[MAX_PCRINFO_SIZE];
int pcrlock;
};
extern struct key_type key_type_trusted;
#endif /* _KEYS_TRUSTED_TYPE_H */

View file

@ -15,6 +15,8 @@
#include <linux/key.h>
#include <linux/rcupdate.h>
#ifdef CONFIG_KEYS
/*****************************************************************************/
/*
* the payload for a key of type "user" or "logon"
@ -46,5 +48,11 @@ extern void user_describe(const struct key *user, struct seq_file *m);
extern long user_read(const struct key *key,
char __user *buffer, size_t buflen);
static inline const struct user_key_payload *user_key_payload(const struct key *key)
{
return (struct user_key_payload *)rcu_dereference_key(key);
}
#endif /* CONFIG_KEYS */
#endif /* _KEYS_USER_TYPE_H */

View file

@ -40,8 +40,7 @@ struct key_construction {
*/
struct key_preparsed_payload {
char *description; /* Proposed key description (or NULL) */
void *type_data[2]; /* Private key-type data */
void *payload[2]; /* Proposed payload */
union key_payload payload; /* Proposed payload */
const void *data; /* Raw data */
size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */

View file

@ -89,6 +89,11 @@ struct keyring_index_key {
size_t desc_len;
};
union key_payload {
void __rcu *rcu_data0;
void *data[4];
};
/*****************************************************************************/
/*
* key reference with possession attribute handling
@ -186,28 +191,18 @@ struct key {
};
};
/* type specific data
* - this is used by the keyring type to index the name
*/
union {
struct list_head link;
unsigned long x[2];
void *p[2];
int reject_error;
} type_data;
/* key data
* - this is used to hold the data actually used in cryptography or
* whatever
*/
union {
union {
unsigned long value;
void __rcu *rcudata;
void *data;
void *data2[2];
} payload;
struct assoc_array keys;
union key_payload payload;
struct {
/* Keyring bits */
struct list_head name_link;
struct assoc_array keys;
};
int reject_error;
};
};
@ -336,12 +331,12 @@ static inline bool key_is_instantiated(const struct key *key)
}
#define rcu_dereference_key(KEY) \
(rcu_dereference_protected((KEY)->payload.rcudata, \
(rcu_dereference_protected((KEY)->payload.rcu_data0, \
rwsem_is_locked(&((struct key *)(KEY))->sem)))
#define rcu_assign_keypointer(KEY, PAYLOAD) \
do { \
rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD)); \
rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD)); \
} while (0)
#ifdef CONFIG_SYSCTL

View file

@ -268,6 +268,9 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
struct kobject *target, const char *link_name);
void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
const char *link_name);
int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
struct kobject *target_kobj,
const char *target_name);
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
@ -451,6 +454,14 @@ static inline void sysfs_remove_link_from_group(struct kobject *kobj,
{
}
static inline int __compat_only_sysfs_link_entry_to_kobj(
struct kobject *kobj,
struct kobject *target_kobj,
const char *target_name)
{
return 0;
}
static inline void sysfs_notify(struct kobject *kobj, const char *dir,
const char *attr)
{

View file

@ -30,6 +30,8 @@
#define TPM_ANY_NUM 0xFFFF
struct tpm_chip;
struct trusted_key_payload;
struct trusted_key_options;
struct tpm_class_ops {
const u8 req_complete_mask;
@ -46,11 +48,22 @@ struct tpm_class_ops {
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(u32 chip_num);
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
extern int tpm_seal_trusted(u32 chip_num,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
extern int tpm_unseal_trusted(u32 chip_num,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
#else
static inline int tpm_is_tpm2(u32 chip_num)
{
return -ENODEV;
}
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
return -ENODEV;
}
@ -63,5 +76,18 @@ static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
return -ENODEV;
}
static inline int tpm_seal_trusted(u32 chip_num,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
return -ENODEV;
}
static inline int tpm_unseal_trusted(u32 chip_num,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
return -ENODEV;
}
#endif
#endif

1
kernel/.gitignore vendored
View file

@ -5,4 +5,3 @@ config_data.h
config_data.gz
timeconst.h
hz.bc
x509_certificate_list

View file

@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <keys/system_keyring.h>
#include <crypto/public_key.h>
#include "module-internal.h"

View file

@ -79,12 +79,13 @@ static int digsig_verify_rsa(struct key *key,
unsigned char *out1 = NULL;
const char *m;
MPI in = NULL, res = NULL, pkey[2];
uint8_t *p, *datap, *endp;
struct user_key_payload *ukp;
uint8_t *p, *datap;
const uint8_t *endp;
const struct user_key_payload *ukp;
struct pubkey_hdr *pkh;
down_read(&key->sem);
ukp = key->payload.data;
ukp = user_key_payload(key);
if (ukp->datalen < sizeof(*pkh))
goto err1;

View file

@ -318,7 +318,7 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) {
goto out;
}
ckey = ukey->payload.data;
ckey = ukey->payload.data[0];
err = ceph_crypto_key_clone(dst, ckey);
if (err)
goto out_key;

View file

@ -537,7 +537,7 @@ static int ceph_key_preparse(struct key_preparsed_payload *prep)
if (ret < 0)
goto err_ckey;
prep->payload[0] = ckey;
prep->payload.data[0] = ckey;
prep->quotalen = datalen;
return 0;
@ -549,14 +549,14 @@ static int ceph_key_preparse(struct key_preparsed_payload *prep)
static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
{
struct ceph_crypto_key *ckey = prep->payload[0];
struct ceph_crypto_key *ckey = prep->payload.data[0];
ceph_crypto_key_destroy(ckey);
kfree(ckey);
}
static void ceph_key_destroy(struct key *key)
{
struct ceph_crypto_key *ckey = key->payload.data;
struct ceph_crypto_key *ckey = key->payload.data[0];
ceph_crypto_key_destroy(ckey);
kfree(ckey);

View file

@ -122,7 +122,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
goto bad_option_value;
kdebug("dns error no. = %lu", derrno);
prep->type_data[0] = ERR_PTR(-derrno);
prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
continue;
}
@ -137,8 +137,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
/* don't cache the result if we're caching an error saying there's no
* result */
if (prep->type_data[0]) {
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
if (prep->payload.data[dns_key_error]) {
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
return 0;
}
@ -155,7 +155,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
memcpy(upayload->data, data, result_len);
upayload->data[result_len] = '\0';
prep->payload[0] = upayload;
prep->payload.data[dns_key_data] = upayload;
kleave(" = 0");
return 0;
}
@ -167,7 +167,7 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
{
pr_devel("==>%s()\n", __func__);
kfree(prep->payload[0]);
kfree(prep->payload.data[dns_key_data]);
}
/*
@ -223,10 +223,10 @@ static int dns_resolver_match_preparse(struct key_match_data *match_data)
*/
static void dns_resolver_describe(const struct key *key, struct seq_file *m)
{
int err = key->type_data.x[0];
seq_puts(m, key->description);
if (key_is_instantiated(key)) {
int err = PTR_ERR(key->payload.data[dns_key_error]);
if (err)
seq_printf(m, ": %d", err);
else
@ -241,8 +241,10 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
static long dns_resolver_read(const struct key *key,
char __user *buffer, size_t buflen)
{
if (key->type_data.x[0])
return key->type_data.x[0];
int err = PTR_ERR(key->payload.data[dns_key_error]);
if (err)
return err;
return user_read(key, buffer, buflen);
}

View file

@ -70,7 +70,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
const char *options, char **_result, time_t *_expiry)
{
struct key *rkey;
struct user_key_payload *upayload;
const struct user_key_payload *upayload;
const struct cred *saved_cred;
size_t typelen, desclen;
char *desc, *cp;
@ -137,12 +137,11 @@ int dns_query(const char *type, const char *name, size_t namelen,
goto put;
/* If the DNS server gave an error, return that to the caller */
ret = rkey->type_data.x[0];
ret = PTR_ERR(rkey->payload.data[dns_key_error]);
if (ret)
goto put;
upayload = rcu_dereference_protected(rkey->payload.data,
lockdep_is_held(&rkey->sem));
upayload = user_key_payload(rkey);
len = upayload->datalen;
ret = -ENOMEM;

View file

@ -22,6 +22,14 @@
#include <linux/kernel.h>
#include <linux/sched.h>
/*
* Layout of key payload words.
*/
enum {
dns_key_data,
dns_key_error,
};
/*
* dns_key.c
*/

View file

@ -305,7 +305,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
if (!key)
key = rx->key;
if (key && !key->payload.data)
if (key && !key->payload.data[0])
key = NULL; /* a no-security key */
bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);

View file

@ -148,10 +148,10 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
token->kad->ticket[6], token->kad->ticket[7]);
/* count the number of tokens attached */
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
/* attach the data */
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
*pptoken;
pptoken = &(*pptoken)->next)
continue;
@ -522,7 +522,7 @@ static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
goto inval;
/* attach the payload */
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
*pptoken;
pptoken = &(*pptoken)->next)
continue;
@ -764,10 +764,10 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
/* count the number of tokens attached */
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
/* attach the data */
pp = (struct rxrpc_key_token **)&prep->payload[0];
pp = (struct rxrpc_key_token **)&prep->payload.data[0];
while (*pp)
pp = &(*pp)->next;
*pp = token;
@ -814,7 +814,7 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
*/
static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
{
rxrpc_free_token_list(prep->payload[0]);
rxrpc_free_token_list(prep->payload.data[0]);
}
/*
@ -831,7 +831,7 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
if (prep->datalen != 8)
return -EINVAL;
memcpy(&prep->type_data, prep->data, 8);
memcpy(&prep->payload.data[2], prep->data, 8);
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(ci)) {
@ -842,7 +842,7 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
BUG();
prep->payload[0] = ci;
prep->payload.data[0] = ci;
_leave(" = 0");
return 0;
}
@ -852,8 +852,8 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
*/
static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
{
if (prep->payload[0])
crypto_free_blkcipher(prep->payload[0]);
if (prep->payload.data[0])
crypto_free_blkcipher(prep->payload.data[0]);
}
/*
@ -861,7 +861,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
*/
static void rxrpc_destroy(struct key *key)
{
rxrpc_free_token_list(key->payload.data);
rxrpc_free_token_list(key->payload.data[0]);
}
/*
@ -869,9 +869,9 @@ static void rxrpc_destroy(struct key *key)
*/
static void rxrpc_destroy_s(struct key *key)
{
if (key->payload.data) {
crypto_free_blkcipher(key->payload.data);
key->payload.data = NULL;
if (key->payload.data[0]) {
crypto_free_blkcipher(key->payload.data[0]);
key->payload.data[0] = NULL;
}
}
@ -1070,7 +1070,7 @@ static long rxrpc_read(const struct key *key,
size += 1 * 4; /* token count */
ntoks = 0;
for (token = key->payload.data; token; token = token->next) {
for (token = key->payload.data[0]; token; token = token->next) {
toksize = 4; /* sec index */
switch (token->security_index) {
@ -1163,7 +1163,7 @@ static long rxrpc_read(const struct key *key,
ENCODE(ntoks);
tok = 0;
for (token = key->payload.data; token; token = token->next) {
for (token = key->payload.data[0]; token; token = token->next) {
toksize = toksizes[tok++];
ENCODE(toksize);
oldxdr = xdr;

View file

@ -158,7 +158,7 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans,
service_id = htons(srx->srx_service);
}
key = rx->key;
if (key && !rx->key->payload.data)
if (key && !rx->key->payload.data[0])
key = NULL;
bundle = rxrpc_get_bundle(rx, trans, key, service_id,
GFP_KERNEL);

View file

@ -137,9 +137,9 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
if (ret < 0)
return ret;
if (!key->payload.data)
token = key->payload.data[0];
if (!token)
return -EKEYREJECTED;
token = key->payload.data;
sec = rxrpc_security_lookup(token->security_index);
if (!sec)

View file

@ -67,7 +67,7 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn)
_enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
token = conn->key->payload.data;
token = conn->key->payload.data[0];
conn->security_ix = token->security_index;
ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
@ -125,7 +125,7 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
if (!conn->key)
return;
token = conn->key->payload.data;
token = conn->key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
desc.tfm = conn->cipher;
@ -221,7 +221,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
rxkhdr.checksum = 0;
/* encrypt from the session key */
token = call->conn->key->payload.data;
token = call->conn->key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
desc.tfm = call->conn->cipher;
desc.info = iv.x;
@ -433,7 +433,7 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
skb_to_sgvec(skb, sg, 0, skb->len);
/* decrypt from the session key */
token = call->conn->key->payload.data;
token = call->conn->key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
desc.tfm = call->conn->cipher;
desc.info = iv.x;
@ -780,7 +780,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
if (conn->security_level < min_level)
goto protocol_error;
token = conn->key->payload.data;
token = conn->key->payload.data[0];
/* build the response packet */
memset(&resp, 0, sizeof(resp));
@ -848,12 +848,12 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
}
}
ASSERT(conn->server_key->payload.data != NULL);
ASSERT(conn->server_key->payload.data[0] != NULL);
ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
memcpy(&iv, &conn->server_key->type_data, sizeof(iv));
memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv));
desc.tfm = conn->server_key->payload.data;
desc.tfm = conn->server_key->payload.data[0];
desc.info = iv.x;
desc.flags = 0;

136
scripts/extract-module-sig.pl Executable file
View file

@ -0,0 +1,136 @@
#!/usr/bin/perl -w
#
# extract-mod-sig <part> <module-file>
#
# Reads the module file and writes out some or all of the signature
# section to stdout. Part is the bit to be written and is one of:
#
# -0: The unsigned module, no signature data at all
# -a: All of the signature data, including magic number
# -d: Just the descriptor values as a sequence of numbers
# -n: Just the signer's name
# -k: Just the key ID
# -s: Just the crypto signature or PKCS#7 message
#
use strict;
die "Format: $0 -[0adnks] module-file >out\n"
if ($#ARGV != 1);
my $part = $ARGV[0];
my $modfile = $ARGV[1];
my $magic_number = "~Module signature appended~\n";
#
# Read the module contents
#
open FD, "<$modfile" || die $modfile;
binmode(FD);
my @st = stat(FD);
die "$modfile" unless (@st);
my $buf = "";
my $len = sysread(FD, $buf, $st[7]);
die "$modfile" unless (defined($len));
die "Short read on $modfile\n" unless ($len == $st[7]);
close(FD) || die $modfile;
print STDERR "Read ", $len, " bytes from module file\n";
die "The file is too short to have a sig magic number and descriptor\n"
if ($len < 12 + length($magic_number));
#
# Check for the magic number and extract the information block
#
my $p = $len - length($magic_number);
my $raw_magic = substr($buf, $p);
die "Magic number not found at $len\n"
if ($raw_magic ne $magic_number);
print STDERR "Found magic number at $len\n";
$p -= 12;
my $raw_info = substr($buf, $p, 12);
my @info = unpack("CCCCCxxxN", $raw_info);
my ($algo, $hash, $id_type, $name_len, $kid_len, $sig_len) = @info;
if ($id_type == 0) {
print STDERR "Found PGP key identifier\n";
} elsif ($id_type == 1) {
print STDERR "Found X.509 cert identifier\n";
} elsif ($id_type == 2) {
print STDERR "Found PKCS#7/CMS encapsulation\n";
} else {
print STDERR "Found unsupported identifier type $id_type\n";
}
#
# Extract the three pieces of info data
#
die "Insufficient name+kid+sig data in file\n"
unless ($p >= $name_len + $kid_len + $sig_len);
$p -= $sig_len;
my $raw_sig = substr($buf, $p, $sig_len);
$p -= $kid_len;
my $raw_kid = substr($buf, $p, $kid_len);
$p -= $name_len;
my $raw_name = substr($buf, $p, $name_len);
my $module_len = $p;
if ($sig_len > 0) {
print STDERR "Found $sig_len bytes of signature [";
my $n = $sig_len > 16 ? 16 : $sig_len;
foreach my $i (unpack("C" x $n, substr($raw_sig, 0, $n))) {
printf STDERR "%02x", $i;
}
print STDERR "]\n";
}
if ($kid_len > 0) {
print STDERR "Found $kid_len bytes of key identifier [";
my $n = $kid_len > 16 ? 16 : $kid_len;
foreach my $i (unpack("C" x $n, substr($raw_kid, 0, $n))) {
printf STDERR "%02x", $i;
}
print STDERR "]\n";
}
if ($name_len > 0) {
print STDERR "Found $name_len bytes of signer's name [$raw_name]\n";
}
#
# Produce the requested output
#
if ($part eq "-0") {
# The unsigned module, no signature data at all
binmode(STDOUT);
print substr($buf, 0, $module_len);
} elsif ($part eq "-a") {
# All of the signature data, including magic number
binmode(STDOUT);
print substr($buf, $module_len);
} elsif ($part eq "-d") {
# Just the descriptor values as a sequence of numbers
print join(" ", @info), "\n";
} elsif ($part eq "-n") {
# Just the signer's name
print STDERR "No signer's name for PKCS#7 message type sig\n"
if ($id_type == 2);
binmode(STDOUT);
print $raw_name;
} elsif ($part eq "-k") {
# Just the key identifier
print STDERR "No key ID for PKCS#7 message type sig\n"
if ($id_type == 2);
binmode(STDOUT);
print $raw_kid;
} elsif ($part eq "-s") {
# Just the crypto signature or PKCS#7 message
binmode(STDOUT);
print $raw_sig;
}

144
scripts/extract-sys-certs.pl Executable file
View file

@ -0,0 +1,144 @@
#!/usr/bin/perl -w
#
use strict;
use Math::BigInt;
use Fcntl "SEEK_SET";
die "Format: $0 [-s <systemmap-file>] <vmlinux-file> <keyring-file>\n"
if ($#ARGV != 1 && $#ARGV != 3 ||
$#ARGV == 3 && $ARGV[0] ne "-s");
my $sysmap = "";
if ($#ARGV == 3) {
shift;
$sysmap = $ARGV[0];
shift;
}
my $vmlinux = $ARGV[0];
my $keyring = $ARGV[1];
#
# Parse the vmlinux section table
#
open FD, "objdump -h $vmlinux |" || die $vmlinux;
my @lines = <FD>;
close(FD) || die $vmlinux;
my @sections = ();
foreach my $line (@lines) {
chomp($line);
if ($line =~ /\s*([0-9]+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+2[*][*]([0-9]+)/
) {
my $seg = $1;
my $name = $2;
my $len = Math::BigInt->new("0x" . $3);
my $vma = Math::BigInt->new("0x" . $4);
my $lma = Math::BigInt->new("0x" . $5);
my $foff = Math::BigInt->new("0x" . $6);
my $align = 2 ** $7;
push @sections, { name => $name,
vma => $vma,
len => $len,
foff => $foff };
}
}
print "Have $#sections sections\n";
#
# Try and parse the vmlinux symbol table. If the vmlinux file has been created
# from a vmlinuz file with extract-vmlinux then the symbol table will be empty.
#
open FD, "nm $vmlinux 2>/dev/null |" || die $vmlinux;
@lines = <FD>;
close(FD) || die $vmlinux;
my %symbols = ();
my $nr_symbols = 0;
sub parse_symbols(@) {
foreach my $line (@_) {
chomp($line);
if ($line =~ /([0-9a-f]+)\s([a-zA-Z])\s(\S+)/
) {
my $addr = "0x" . $1;
my $type = $2;
my $name = $3;
$symbols{$name} = $addr;
$nr_symbols++;
}
}
}
parse_symbols(@lines);
if ($nr_symbols == 0 && $sysmap ne "") {
print "No symbols in vmlinux, trying $sysmap\n";
open FD, "<$sysmap" || die $sysmap;
@lines = <FD>;
close(FD) || die $sysmap;
parse_symbols(@lines);
}
die "No symbols available\n"
if ($nr_symbols == 0);
print "Have $nr_symbols symbols\n";
die "Can't find system certificate list"
unless (exists($symbols{"__cert_list_start"}) &&
exists($symbols{"__cert_list_end"}));
my $start = Math::BigInt->new($symbols{"__cert_list_start"});
my $end = Math::BigInt->new($symbols{"__cert_list_end"});
my $size = $end - $start;
printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
my $s = undef;
foreach my $sec (@sections) {
my $s_name = $sec->{name};
my $s_vma = $sec->{vma};
my $s_len = $sec->{len};
my $s_foff = $sec->{foff};
my $s_vend = $s_vma + $s_len;
next unless ($start >= $s_vma);
next if ($start >= $s_vend);
die "Cert object partially overflows section $s_name\n"
if ($end > $s_vend);
die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
if ($s);
$s = $sec;
}
die "Cert object not inside a section\n"
unless ($s);
print "Certificate list in section ", $s->{name}, "\n";
my $foff = $start - $s->{vma} + $s->{foff};
printf "Certificate list at file offset 0x%x\n", $foff;
open FD, "<$vmlinux" || die $vmlinux;
binmode(FD);
die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
my $buf = "";
my $len = sysread(FD, $buf, $size);
die "$vmlinux" if (!defined($len));
die "Short read on $vmlinux\n" if ($len != $size);
close(FD) || die $vmlinux;
open FD, ">$keyring" || die $keyring;
binmode(FD);
$len = syswrite(FD, $buf, $size);
die "$keyring" if (!defined($len));
die "Short write on $keyring\n" if ($len != $size);
close(FD) || die $keyring;

View file

@ -33,7 +33,7 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
config SECURITY_APPARMOR_HASH
bool "SHA1 hash of loaded profiles"
depends on SECURITY_APPARMOR
depends on CRYPTO
select CRYPTO
select CRYPTO_SHA1
default y

View file

@ -105,7 +105,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
rc,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate (%d): %s\n",

View file

@ -247,7 +247,7 @@ int evm_init_key(void)
return -ENOENT;
down_read(&evm_key->sem);
ekp = evm_key->payload.data;
ekp = evm_key->payload.data[0];
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
rc = -EINVAL;
goto out;

View file

@ -20,6 +20,16 @@
MODULE_LICENSE("GPL");
/*
* Layout of key payload words.
*/
enum {
big_key_data,
big_key_path,
big_key_path_2nd_part,
big_key_len,
};
/*
* If the data is under this limit, there's no point creating a shm file to
* hold it as the permanently resident metadata for the shmem fs will be at
@ -47,7 +57,7 @@ struct key_type key_type_big_key = {
*/
int big_key_preparse(struct key_preparsed_payload *prep)
{
struct path *path = (struct path *)&prep->payload;
struct path *path = (struct path *)&prep->payload.data[big_key_path];
struct file *file;
ssize_t written;
size_t datalen = prep->datalen;
@ -60,7 +70,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
/* Set an arbitrary quota */
prep->quotalen = 16;
prep->type_data[1] = (void *)(unsigned long)datalen;
prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
if (datalen > BIG_KEY_FILE_THRESHOLD) {
/* Create a shmem file to store the data in. This will permit the data
@ -94,7 +104,8 @@ int big_key_preparse(struct key_preparsed_payload *prep)
if (!data)
return -ENOMEM;
prep->payload[0] = memcpy(data, prep->data, prep->datalen);
prep->payload.data[big_key_data] = data;
memcpy(data, prep->data, prep->datalen);
}
return 0;
@ -110,10 +121,10 @@ int big_key_preparse(struct key_preparsed_payload *prep)
void big_key_free_preparse(struct key_preparsed_payload *prep)
{
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
struct path *path = (struct path *)&prep->payload;
struct path *path = (struct path *)&prep->payload.data[big_key_path];
path_put(path);
} else {
kfree(prep->payload[0]);
kfree(prep->payload.data[big_key_data]);
}
}
@ -123,11 +134,12 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
*/
void big_key_revoke(struct key *key)
{
struct path *path = (struct path *)&key->payload.data2;
struct path *path = (struct path *)&key->payload.data[big_key_path];
/* clear the quota */
key_payload_reserve(key, 0);
if (key_is_instantiated(key) && key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD)
if (key_is_instantiated(key) &&
(size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
vfs_truncate(path, 0);
}
@ -136,14 +148,16 @@ void big_key_revoke(struct key *key)
*/
void big_key_destroy(struct key *key)
{
if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
struct path *path = (struct path *)&key->payload.data2;
size_t datalen = (size_t)key->payload.data[big_key_len];
if (datalen) {
struct path *path = (struct path *)&key->payload.data[big_key_path];
path_put(path);
path->mnt = NULL;
path->dentry = NULL;
} else {
kfree(key->payload.data);
key->payload.data = NULL;
kfree(key->payload.data[big_key_data]);
key->payload.data[big_key_data] = NULL;
}
}
@ -152,12 +166,12 @@ void big_key_destroy(struct key *key)
*/
void big_key_describe(const struct key *key, struct seq_file *m)
{
unsigned long datalen = key->type_data.x[1];
size_t datalen = (size_t)key->payload.data[big_key_len];
seq_puts(m, key->description);
if (key_is_instantiated(key))
seq_printf(m, ": %lu [%s]",
seq_printf(m, ": %zu [%s]",
datalen,
datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
}
@ -168,14 +182,14 @@ void big_key_describe(const struct key *key, struct seq_file *m)
*/
long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
{
unsigned long datalen = key->type_data.x[1];
size_t datalen = (size_t)key->payload.data[big_key_len];
long ret;
if (!buffer || buflen < datalen)
return datalen;
if (datalen > BIG_KEY_FILE_THRESHOLD) {
struct path *path = (struct path *)&key->payload.data2;
struct path *path = (struct path *)&key->payload.data[big_key_path];
struct file *file;
loff_t pos;
@ -190,7 +204,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
ret = -EIO;
} else {
ret = datalen;
if (copy_to_user(buffer, key->payload.data, datalen) != 0)
if (copy_to_user(buffer, key->payload.data[big_key_data],
datalen) != 0)
ret = -EFAULT;
}

View file

@ -303,10 +303,10 @@ static char *datablob_format(struct encrypted_key_payload *epayload,
*
* Use a user provided key to encrypt/decrypt an encrypted-key.
*/
static struct key *request_user_key(const char *master_desc, u8 **master_key,
static struct key *request_user_key(const char *master_desc, const u8 **master_key,
size_t *master_keylen)
{
struct user_key_payload *upayload;
const struct user_key_payload *upayload;
struct key *ukey;
ukey = request_key(&key_type_user, master_desc, NULL);
@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key,
goto error;
down_read(&ukey->sem);
upayload = ukey->payload.data;
upayload = user_key_payload(ukey);
*master_key = upayload->data;
*master_keylen = upayload->datalen;
error:
@ -426,7 +426,7 @@ static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
}
static struct key *request_master_key(struct encrypted_key_payload *epayload,
u8 **master_key, size_t *master_keylen)
const u8 **master_key, size_t *master_keylen)
{
struct key *mkey = NULL;
@ -653,7 +653,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
{
struct key *mkey;
u8 derived_key[HASH_SIZE];
u8 *master_key;
const u8 *master_key;
u8 *hmac;
const char *hex_encoded_data;
unsigned int encrypted_datalen;
@ -837,7 +837,7 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
*/
static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
{
struct encrypted_key_payload *epayload = key->payload.data;
struct encrypted_key_payload *epayload = key->payload.data[0];
struct encrypted_key_payload *new_epayload;
char *buf;
char *new_master_desc = NULL;
@ -896,7 +896,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
{
struct encrypted_key_payload *epayload;
struct key *mkey;
u8 *master_key;
const u8 *master_key;
size_t master_keylen;
char derived_key[HASH_SIZE];
char *ascii_buf;
@ -957,13 +957,13 @@ static long encrypted_read(const struct key *key, char __user *buffer,
*/
static void encrypted_destroy(struct key *key)
{
struct encrypted_key_payload *epayload = key->payload.data;
struct encrypted_key_payload *epayload = key->payload.data[0];
if (!epayload)
return;
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
kfree(key->payload.data);
kfree(key->payload.data[0]);
}
struct key_type key_type_encrypted = {

View file

@ -5,10 +5,10 @@
#if defined(CONFIG_TRUSTED_KEYS) || \
(defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
extern struct key *request_trusted_key(const char *trusted_desc,
u8 **master_key, size_t *master_keylen);
const u8 **master_key, size_t *master_keylen);
#else
static inline struct key *request_trusted_key(const char *trusted_desc,
u8 **master_key,
const u8 **master_key,
size_t *master_keylen)
{
return ERR_PTR(-EOPNOTSUPP);

View file

@ -29,7 +29,7 @@
* data, trusted key type data is not visible decrypted from userspace.
*/
struct key *request_trusted_key(const char *trusted_desc,
u8 **master_key, size_t *master_keylen)
const u8 **master_key, size_t *master_keylen)
{
struct trusted_key_payload *tpayload;
struct key *tkey;
@ -39,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc,
goto error;
down_read(&tkey->sem);
tpayload = tkey->payload.data;
tpayload = tkey->payload.data[0];
*master_key = tpayload->key;
*master_keylen = tpayload->key_len;
error:

View file

@ -278,7 +278,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->index_key.desc_len = desclen;
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
if (!key->description)
if (!key->index_key.description)
goto no_memory_3;
atomic_set(&key->usage, 1);
@ -554,7 +554,7 @@ int key_reject_and_link(struct key *key,
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* mark the key as being negatively instantiated */
atomic_inc(&key->user->nikeys);
key->type_data.reject_error = -error;
key->reject_error = -error;
smp_wmb();
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
@ -1046,14 +1046,14 @@ int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
key->type_data.p[0] = prep->type_data[0];
key->type_data.p[1] = prep->type_data[1];
rcu_assign_keypointer(key, prep->payload[0]);
key->payload.data2[1] = prep->payload[1];
prep->type_data[0] = NULL;
prep->type_data[1] = NULL;
prep->payload[0] = NULL;
prep->payload[1] = NULL;
rcu_assign_keypointer(key, prep->payload.data[0]);
key->payload.data[1] = prep->payload.data[1];
key->payload.data[2] = prep->payload.data[2];
key->payload.data[3] = prep->payload.data[3];
prep->payload.data[0] = NULL;
prep->payload.data[1] = NULL;
prep->payload.data[2] = NULL;
prep->payload.data[3] = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;

View file

@ -67,7 +67,6 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
char type[32], *description;
void *payload;
long ret;
bool vm;
ret = -EINVAL;
if (plen > 1024 * 1024 - 1)
@ -98,14 +97,12 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
/* pull the payload in if one was supplied */
payload = NULL;
vm = false;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
if (!payload) {
if (plen <= PAGE_SIZE)
goto error2;
vm = true;
payload = vmalloc(plen);
if (!payload)
goto error2;
@ -138,10 +135,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
key_ref_put(keyring_ref);
error3:
if (!vm)
kfree(payload);
else
vfree(payload);
kvfree(payload);
error2:
kfree(description);
error:
@ -1033,7 +1027,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
if (!instkey)
goto error;
rka = instkey->payload.data;
rka = instkey->payload.data[0];
if (rka->target_key->serial != id)
goto error;
@ -1200,7 +1194,7 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
if (!instkey)
goto error;
rka = instkey->payload.data;
rka = instkey->payload.data[0];
if (rka->target_key->serial != id)
goto error;

View file

@ -118,7 +118,7 @@ static void keyring_publish_name(struct key *keyring)
if (!keyring_name_hash[bucket].next)
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
list_add_tail(&keyring->type_data.link,
list_add_tail(&keyring->name_link,
&keyring_name_hash[bucket]);
write_unlock(&keyring_name_lock);
@ -387,9 +387,9 @@ static void keyring_destroy(struct key *keyring)
if (keyring->description) {
write_lock(&keyring_name_lock);
if (keyring->type_data.link.next != NULL &&
!list_empty(&keyring->type_data.link))
list_del(&keyring->type_data.link);
if (keyring->name_link.next != NULL &&
!list_empty(&keyring->name_link))
list_del(&keyring->name_link);
write_unlock(&keyring_name_lock);
}
@ -572,7 +572,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
/* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
smp_rmb();
ctx->result = ERR_PTR(key->type_data.reject_error);
ctx->result = ERR_PTR(key->reject_error);
kleave(" = %d [neg]", ctx->skipped_ret);
goto skipped;
}
@ -990,7 +990,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
* that's readable and that hasn't been revoked */
list_for_each_entry(keyring,
&keyring_name_hash[bucket],
type_data.link
name_link
) {
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
continue;

View file

@ -457,7 +457,7 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
down_read(&cred->request_key_auth->sem);
if (key_validate(ctx->cred->request_key_auth) == 0) {
rka = ctx->cred->request_key_auth->payload.data;
rka = ctx->cred->request_key_auth->payload.data[0];
ctx->cred = rka->cred;
key_ref = search_process_keyrings(ctx);
@ -647,7 +647,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_ref = ERR_PTR(-EKEYREVOKED);
key = NULL;
} else {
rka = ctx.cred->request_key_auth->payload.data;
rka = ctx.cred->request_key_auth->payload.data[0];
key = rka->dest_keyring;
__key_get(key);
}

View file

@ -271,7 +271,7 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
if (cred->request_key_auth) {
authkey = cred->request_key_auth;
down_read(&authkey->sem);
rka = authkey->payload.data;
rka = authkey->payload.data[0];
if (!test_bit(KEY_FLAG_REVOKED,
&authkey->flags))
dest_keyring =
@ -596,7 +596,7 @@ int wait_for_key_construction(struct key *key, bool intr)
return -ERESTARTSYS;
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
smp_rmb();
return key->type_data.reject_error;
return key->reject_error;
}
return key_validate(key);
}

View file

@ -59,7 +59,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
static int request_key_auth_instantiate(struct key *key,
struct key_preparsed_payload *prep)
{
key->payload.data = (struct request_key_auth *)prep->data;
key->payload.data[0] = (struct request_key_auth *)prep->data;
return 0;
}
@ -69,7 +69,7 @@ static int request_key_auth_instantiate(struct key *key,
static void request_key_auth_describe(const struct key *key,
struct seq_file *m)
{
struct request_key_auth *rka = key->payload.data;
struct request_key_auth *rka = key->payload.data[0];
seq_puts(m, "key:");
seq_puts(m, key->description);
@ -84,7 +84,7 @@ static void request_key_auth_describe(const struct key *key,
static long request_key_auth_read(const struct key *key,
char __user *buffer, size_t buflen)
{
struct request_key_auth *rka = key->payload.data;
struct request_key_auth *rka = key->payload.data[0];
size_t datalen;
long ret;
@ -110,7 +110,7 @@ static long request_key_auth_read(const struct key *key,
*/
static void request_key_auth_revoke(struct key *key)
{
struct request_key_auth *rka = key->payload.data;
struct request_key_auth *rka = key->payload.data[0];
kenter("{%d}", key->serial);
@ -125,7 +125,7 @@ static void request_key_auth_revoke(struct key *key)
*/
static void request_key_auth_destroy(struct key *key)
{
struct request_key_auth *rka = key->payload.data;
struct request_key_auth *rka = key->payload.data[0];
kenter("{%d}", key->serial);
@ -179,7 +179,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
goto auth_key_revoked;
irka = cred->request_key_auth->payload.data;
irka = cred->request_key_auth->payload.data[0];
rka->cred = get_cred(irka->cred);
rka->pid = irka->pid;

View file

@ -862,12 +862,19 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p,
static struct trusted_key_options *trusted_options_alloc(void)
{
struct trusted_key_options *options;
int tpm2;
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
if (tpm2 < 0)
return NULL;
options = kzalloc(sizeof *options, GFP_KERNEL);
if (options) {
/* set any non-zero defaults */
options->keytype = SRK_keytype;
options->keyhandle = SRKHANDLE;
if (!tpm2)
options->keyhandle = SRKHANDLE;
}
return options;
}
@ -905,6 +912,11 @@ static int trusted_instantiate(struct key *key,
int ret = 0;
int key_cmd;
size_t key_len;
int tpm2;
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
if (tpm2 < 0)
return tpm2;
if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
@ -932,12 +944,20 @@ static int trusted_instantiate(struct key *key,
goto out;
}
if (!options->keyhandle) {
ret = -EINVAL;
goto out;
}
dump_payload(payload);
dump_options(options);
switch (key_cmd) {
case Opt_load:
ret = key_unseal(payload, options);
if (tpm2)
ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
else
ret = key_unseal(payload, options);
dump_payload(payload);
dump_options(options);
if (ret < 0)
@ -950,7 +970,10 @@ static int trusted_instantiate(struct key *key,
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
ret = key_seal(payload, options);
if (tpm2)
ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
else
ret = key_seal(payload, options);
if (ret < 0)
pr_info("trusted_key: key_seal failed (%d)\n", ret);
break;
@ -984,7 +1007,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
*/
static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
{
struct trusted_key_payload *p = key->payload.data;
struct trusted_key_payload *p = key->payload.data[0];
struct trusted_key_payload *new_p;
struct trusted_key_options *new_o;
size_t datalen = prep->datalen;
@ -1018,6 +1041,13 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
kfree(new_p);
goto out;
}
if (!new_o->keyhandle) {
ret = -EINVAL;
kfree(new_p);
goto out;
}
/* copy old key values, and reseal with new pcrs */
new_p->migratable = p->migratable;
new_p->key_len = p->key_len;
@ -1084,12 +1114,12 @@ static long trusted_read(const struct key *key, char __user *buffer,
*/
static void trusted_destroy(struct key *key)
{
struct trusted_key_payload *p = key->payload.data;
struct trusted_key_payload *p = key->payload.data[0];
if (!p)
return;
memset(p->key, 0, p->key_len);
kfree(key->payload.data);
kfree(key->payload.data[0]);
}
struct key_type key_type_trusted = {

View file

@ -2,7 +2,6 @@
#define __TRUSTED_KEY_H
/* implementation specific TPM constants */
#define MAX_PCRINFO_SIZE 64
#define MAX_BUF_SIZE 512
#define TPM_GETRANDOM_SIZE 14
#define TPM_OSAP_SIZE 36
@ -36,16 +35,6 @@ enum {
SRK_keytype = 4
};
struct trusted_key_options {
uint16_t keytype;
uint32_t keyhandle;
unsigned char keyauth[SHA1_DIGEST_SIZE];
unsigned char blobauth[SHA1_DIGEST_SIZE];
uint32_t pcrinfo_len;
unsigned char pcrinfo[MAX_PCRINFO_SIZE];
int pcrlock;
};
#define TPM_DEBUG 0
#if TPM_DEBUG

View file

@ -74,7 +74,7 @@ int user_preparse(struct key_preparsed_payload *prep)
/* attach the data */
prep->quotalen = datalen;
prep->payload[0] = upayload;
prep->payload.data[0] = upayload;
upayload->datalen = datalen;
memcpy(upayload->data, prep->data, datalen);
return 0;
@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(user_preparse);
*/
void user_free_preparse(struct key_preparsed_payload *prep)
{
kfree(prep->payload[0]);
kfree(prep->payload.data[0]);
}
EXPORT_SYMBOL_GPL(user_free_preparse);
@ -120,7 +120,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
if (ret == 0) {
/* attach the new data, displacing the old */
zap = key->payload.data;
zap = key->payload.data[0];
rcu_assign_keypointer(key, upayload);
key->expiry = 0;
}
@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(user_update);
*/
void user_revoke(struct key *key)
{
struct user_key_payload *upayload = key->payload.data;
struct user_key_payload *upayload = key->payload.data[0];
/* clear the quota */
key_payload_reserve(key, 0);
@ -158,7 +158,7 @@ EXPORT_SYMBOL(user_revoke);
*/
void user_destroy(struct key *key)
{
struct user_key_payload *upayload = key->payload.data;
struct user_key_payload *upayload = key->payload.data[0];
kfree(upayload);
}
@ -183,10 +183,10 @@ EXPORT_SYMBOL_GPL(user_describe);
*/
long user_read(const struct key *key, char __user *buffer, size_t buflen)
{
struct user_key_payload *upayload;
const struct user_key_payload *upayload;
long ret;
upayload = rcu_dereference_key(key);
upayload = user_key_payload(key);
ret = upayload->datalen;
/* we can return the data as is */

View file

@ -78,7 +78,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
int "NSA SELinux checkreqprot default value"
depends on SECURITY_SELINUX
range 0 1
default 1
default 0
help
This option sets the default value for the 'checkreqprot' flag
that determines whether SELinux checks the protection requested
@ -92,7 +92,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
'checkreqprot=' boot parameter. It may also be changed at runtime
via /selinux/checkreqprot if authorized by policy.
If you are unsure how to answer this question, answer 1.
If you are unsure how to answer this question, answer 0.
config SECURITY_SELINUX_POLICYDB_VERSION_MAX
bool "NSA SELinux maximum supported policy format version"

View file

@ -126,6 +126,7 @@ int selinux_enabled = 1;
#endif
static struct kmem_cache *sel_inode_cache;
static struct kmem_cache *file_security_cache;
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
@ -287,7 +288,7 @@ static int file_alloc_security(struct file *file)
struct file_security_struct *fsec;
u32 sid = current_sid();
fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
if (!fsec)
return -ENOMEM;
@ -302,7 +303,7 @@ static void file_free_security(struct file *file)
{
struct file_security_struct *fsec = file->f_security;
file->f_security = NULL;
kfree(fsec);
kmem_cache_free(file_security_cache, fsec);
}
static int superblock_alloc_security(struct super_block *sb)
@ -674,10 +675,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT)
continue;
rc = security_context_to_sid(mount_options[i],
strlen(mount_options[i]), &sid, GFP_KERNEL);
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, name, rc);
goto out;
@ -2617,15 +2617,12 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
for (i = 0; i < opts.num_mnt_opts; i++) {
u32 sid;
size_t len;
if (flags[i] == SBLABEL_MNT)
continue;
len = strlen(mount_options[i]);
rc = security_context_to_sid(mount_options[i], len, &sid,
GFP_KERNEL);
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, sb->s_type->name, rc);
goto out_free_opts;
@ -2946,7 +2943,8 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
&& !(ia_valid & ATTR_FILE))
av |= FILE__OPEN;
return dentry_has_perm(cred, dentry, av);
@ -3166,7 +3164,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
if (rc)
return rc;
@ -3238,7 +3236,7 @@ static void selinux_file_free_security(struct file *file)
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
*/
int ioctl_has_perm(const struct cred *cred, struct file *file,
static int ioctl_has_perm(const struct cred *cred, struct file *file,
u32 requested, u16 cmd)
{
struct common_audit_data ad;
@ -6093,6 +6091,9 @@ static __init int selinux_init(void)
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL);
file_security_cache = kmem_cache_create("selinux_file_security",
sizeof(struct file_security_struct),
0, SLAB_PANIC, NULL);
avc_init();
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));

View file

@ -166,6 +166,8 @@ int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid, gfp_t gfp);
int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp);
int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);

View file

@ -731,13 +731,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@ -819,13 +817,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf;
}
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@ -882,13 +878,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@ -940,7 +934,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2)
goto out;
length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
if (length)
goto out;
@ -1000,13 +994,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;

View file

@ -1218,13 +1218,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
/*
* Copy the user name, role name and type name into the context.
*/
sprintf(scontextp, "%s:%s:%s",
scontextp += sprintf(scontextp, "%s:%s:%s",
sym_name(&policydb, SYM_USERS, context->user - 1),
sym_name(&policydb, SYM_ROLES, context->role - 1),
sym_name(&policydb, SYM_TYPES, context->type - 1));
scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
mls_sid_to_context(context, &scontextp);
@ -1259,12 +1256,12 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
if (!scontext)
goto out;
scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
scontextp = kmemdup(initial_sid_to_string[sid],
*scontext_len, GFP_ATOMIC);
if (!scontextp) {
rc = -ENOMEM;
goto out;
}
strcpy(scontextp, initial_sid_to_string[sid]);
*scontext = scontextp;
goto out;
}
@ -1476,6 +1473,11 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
sid, SECSID_NULL, gfp, 0);
}
int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
{
return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
}
/**
* security_context_to_sid_default - Obtain a SID for a given security context,
* falling back to specified default if needed.
@ -2604,18 +2606,12 @@ int security_get_bools(int *len, char ***names, int **values)
goto err;
for (i = 0; i < *len; i++) {
size_t name_len;
(*values)[i] = policydb.bool_val_to_struct[i]->state;
name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
rc = -ENOMEM;
(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
(*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
if (!(*names)[i])
goto err;
strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
(*names)[i][name_len - 1] = 0;
}
rc = 0;
out:

View file

@ -115,6 +115,7 @@ struct task_smack {
struct smack_known *smk_forked; /* label when forked */
struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */
struct list_head smk_relabel; /* transit allowed labels */
};
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
@ -169,7 +170,7 @@ struct smk_port_label {
};
#endif /* SMACK_IPV6_PORT_LABELING */
struct smack_onlycap {
struct smack_known_list_elem {
struct list_head list;
struct smack_known *smk_label;
};
@ -301,6 +302,7 @@ struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
int smack_privileged(int cap);
void smk_destroy_label_list(struct list_head *list);
/*
* Shared data.

View file

@ -637,7 +637,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
int smack_privileged(int cap)
{
struct smack_known *skp = smk_of_current();
struct smack_onlycap *sop;
struct smack_known_list_elem *sklep;
/*
* All kernel tasks are privileged
@ -654,8 +654,8 @@ int smack_privileged(int cap)
return 1;
}
list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
if (sop->smk_label == skp) {
list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
if (sklep->smk_label == skp) {
rcu_read_unlock();
return 1;
}

View file

@ -52,7 +52,7 @@
#define SMK_SENDING 2
#ifdef SMACK_IPV6_PORT_LABELING
LIST_HEAD(smk_ipv6_port_list);
static LIST_HEAD(smk_ipv6_port_list);
#endif
static struct kmem_cache *smack_inode_cache;
int smack_enabled;
@ -326,6 +326,7 @@ static struct task_smack *new_task_smack(struct smack_known *task,
tsp->smk_task = task;
tsp->smk_forked = forked;
INIT_LIST_HEAD(&tsp->smk_rules);
INIT_LIST_HEAD(&tsp->smk_relabel);
mutex_init(&tsp->smk_rules_lock);
return tsp;
@ -360,6 +361,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
return rc;
}
/**
* smk_copy_relabel - copy smk_relabel labels list
* @nhead: new rules header pointer
* @ohead: old rules header pointer
* @gfp: type of the memory for the allocation
*
* Returns 0 on success, -ENOMEM on error
*/
static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
gfp_t gfp)
{
struct smack_known_list_elem *nklep;
struct smack_known_list_elem *oklep;
INIT_LIST_HEAD(nhead);
list_for_each_entry(oklep, ohead, list) {
nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
if (nklep == NULL) {
smk_destroy_label_list(nhead);
return -ENOMEM;
}
nklep->smk_label = oklep->smk_label;
list_add(&nklep->list, nhead);
}
return 0;
}
/**
* smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
* @mode - input mode in form of PTRACE_MODE_*
@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred)
return;
cred->security = NULL;
smk_destroy_label_list(&tsp->smk_relabel);
list_for_each_safe(l, n, &tsp->smk_rules) {
rp = list_entry(l, struct smack_rule, list);
list_del(&rp->list);
@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
if (rc != 0)
return rc;
rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
gfp);
if (rc != 0)
return rc;
new->security = new_tsp;
return 0;
}
@ -3354,6 +3391,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
isp->smk_inode = smk_of_current();
break;
case PIPEFS_MAGIC:
isp->smk_inode = smk_of_current();
break;
default:
isp->smk_inode = sbsp->smk_root;
break;
@ -3549,9 +3589,11 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
static int smack_setprocattr(struct task_struct *p, char *name,
void *value, size_t size)
{
struct task_smack *tsp;
struct task_smack *tsp = current_security();
struct cred *new;
struct smack_known *skp;
struct smack_known_list_elem *sklep;
int rc;
/*
* Changing another process' Smack value is too dangerous
@ -3560,7 +3602,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (p != current)
return -EPERM;
if (!smack_privileged(CAP_MAC_ADMIN))
if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
return -EPERM;
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
@ -3579,12 +3621,27 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (skp == &smack_known_web)
return -EPERM;
if (!smack_privileged(CAP_MAC_ADMIN)) {
rc = -EPERM;
list_for_each_entry(sklep, &tsp->smk_relabel, list)
if (sklep->smk_label == skp) {
rc = 0;
break;
}
if (rc)
return rc;
}
new = prepare_creds();
if (new == NULL)
return -ENOMEM;
tsp = new->security;
tsp->smk_task = skp;
/*
* process can change its label only once
*/
smk_destroy_label_list(&tsp->smk_relabel);
commit_creds(new);
return size;
@ -4708,8 +4765,6 @@ static __init int smack_init(void)
if (!security_module_enable("smack"))
return 0;
smack_enabled = 1;
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
if (!smack_inode_cache)
return -ENOMEM;
@ -4721,6 +4776,8 @@ static __init int smack_init(void)
return -ENOMEM;
}
smack_enabled = 1;
pr_info("Smack: Initializing.\n");
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
pr_info("Smack: Netfilter enabled.\n");

View file

@ -61,6 +61,7 @@ enum smk_inos {
#if IS_ENABLED(CONFIG_IPV6)
SMK_NET6ADDR = 23, /* single label IPv6 hosts */
#endif /* CONFIG_IPV6 */
SMK_RELABEL_SELF = 24, /* relabel possible without CAP_MAC_ADMIN */
};
/*
@ -1501,8 +1502,8 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
*/
if (smack[0] != '-') {
skp = smk_import_entry(smack, 0);
if (skp == NULL) {
rc = -EINVAL;
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto free_out;
}
} else {
@ -1914,10 +1915,10 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
static int onlycap_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_onlycap *sop =
list_entry_rcu(list, struct smack_onlycap, list);
struct smack_known_list_elem *sklep =
list_entry_rcu(list, struct smack_known_list_elem, list);
seq_puts(s, sop->smk_label->smk_known);
seq_puts(s, sklep->smk_label->smk_known);
seq_putc(s, ' ');
return 0;
@ -1973,6 +1974,54 @@ static void smk_list_swap_rcu(struct list_head *public,
}
}
/**
* smk_parse_label_list - parse list of Smack labels, separated by spaces
*
* @data: the string to parse
* @private: destination list
*
* Returns zero on success or error code, as appropriate
*/
static int smk_parse_label_list(char *data, struct list_head *list)
{
char *tok;
struct smack_known *skp;
struct smack_known_list_elem *sklep;
while ((tok = strsep(&data, " ")) != NULL) {
if (!*tok)
continue;
skp = smk_import_entry(tok, 0);
if (IS_ERR(skp))
return PTR_ERR(skp);
sklep = kzalloc(sizeof(*sklep), GFP_KERNEL);
if (sklep == NULL)
return -ENOMEM;
sklep->smk_label = skp;
list_add(&sklep->list, list);
}
return 0;
}
/**
* smk_destroy_label_list - destroy a list of smack_known_list_elem
* @head: header pointer of the list to destroy
*/
void smk_destroy_label_list(struct list_head *list)
{
struct smack_known_list_elem *sklep;
struct smack_known_list_elem *sklep2;
list_for_each_entry_safe(sklep, sklep2, list, list)
kfree(sklep);
INIT_LIST_HEAD(list);
}
/**
* smk_write_onlycap - write() for smackfs/onlycap
* @file: file pointer, not actually used
@ -1986,13 +2035,8 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data;
char *data_parse;
char *tok;
struct smack_known *skp;
struct smack_onlycap *sop;
struct smack_onlycap *sop2;
LIST_HEAD(list_tmp);
int rc = count;
int rc;
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
@ -2006,26 +2050,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
return -EFAULT;
}
data_parse = data;
while ((tok = strsep(&data_parse, " ")) != NULL) {
if (!*tok)
continue;
skp = smk_import_entry(tok, 0);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
break;
}
sop = kzalloc(sizeof(*sop), GFP_KERNEL);
if (sop == NULL) {
rc = -ENOMEM;
break;
}
sop->smk_label = skp;
list_add_rcu(&sop->list, &list_tmp);
}
rc = smk_parse_label_list(data, &list_tmp);
kfree(data);
/*
@ -2038,17 +2063,14 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
* But do so only on invalid label, not on system errors.
* The invalid label must be first to count as clearing attempt.
*/
if (rc == -EINVAL && list_empty(&list_tmp))
rc = count;
if (rc >= 0) {
if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
mutex_lock(&smack_onlycap_lock);
smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
mutex_unlock(&smack_onlycap_lock);
rc = count;
}
list_for_each_entry_safe(sop, sop2, &list_tmp, list)
kfree(sop);
smk_destroy_label_list(&list_tmp);
return rc;
}
@ -2698,6 +2720,113 @@ static const struct file_operations smk_syslog_ops = {
.llseek = default_llseek,
};
/*
* Seq_file read operations for /smack/relabel-self
*/
static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
{
struct task_smack *tsp = current_security();
return smk_seq_start(s, pos, &tsp->smk_relabel);
}
static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct task_smack *tsp = current_security();
return smk_seq_next(s, v, pos, &tsp->smk_relabel);
}
static int relabel_self_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_known_list_elem *sklep =
list_entry(list, struct smack_known_list_elem, list);
seq_puts(s, sklep->smk_label->smk_known);
seq_putc(s, ' ');
return 0;
}
static const struct seq_operations relabel_self_seq_ops = {
.start = relabel_self_seq_start,
.next = relabel_self_seq_next,
.show = relabel_self_seq_show,
.stop = smk_seq_stop,
};
/**
* smk_open_relabel_self - open() for /smack/relabel-self
* @inode: inode structure representing file
* @file: "relabel-self" file pointer
*
* Connect our relabel_self_seq_* operations with /smack/relabel-self
* file_operations
*/
static int smk_open_relabel_self(struct inode *inode, struct file *file)
{
return seq_open(file, &relabel_self_seq_ops);
}
/**
* smk_write_relabel_self - write() for /smack/relabel-self
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start - must be 0
*
*/
static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct task_smack *tsp = current_security();
char *data;
int rc;
LIST_HEAD(list_tmp);
/*
* Must have privilege.
*/
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
/*
* Enough data must be present.
*/
if (*ppos != 0)
return -EINVAL;
data = kzalloc(count + 1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
if (copy_from_user(data, buf, count) != 0) {
kfree(data);
return -EFAULT;
}
rc = smk_parse_label_list(data, &list_tmp);
kfree(data);
if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
smk_destroy_label_list(&tsp->smk_relabel);
list_splice(&list_tmp, &tsp->smk_relabel);
return count;
}
smk_destroy_label_list(&list_tmp);
return rc;
}
static const struct file_operations smk_relabel_self_ops = {
.open = smk_open_relabel_self,
.read = seq_read,
.llseek = seq_lseek,
.write = smk_write_relabel_self,
.release = seq_release,
};
/**
* smk_read_ptrace - read() for /smack/ptrace
@ -2824,6 +2953,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
[SMK_NET6ADDR] = {
"ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
#endif /* CONFIG_IPV6 */
[SMK_RELABEL_SELF] = {
"relabel-self", &smk_relabel_self_ops,
S_IRUGO|S_IWUGO},
/* last one */
{""}
};
@ -2892,7 +3024,7 @@ static int __init init_smk_fs(void)
int err;
int rc;
if (!security_module_enable("smack"))
if (smack_enabled == 0)
return 0;
err = smk_init_sysfs();