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:
commit
1873499e13
89 changed files with 1748 additions and 492 deletions
Documentation
MAINTAINERSarch/powerpc/kernel
certs
crypto/asymmetric_keys
drivers/char/tpm
st33zp24
tpm-chip.ctpm-interface.ctpm.htpm2-cmd.ctpm_crb.ctpm_eventlog.ctpm_eventlog.htpm_i2c_atmel.ctpm_i2c_infineon.ctpm_i2c_nuvoton.ctpm_ibmvtpm.ctpm_of.ctpm_ppi.ctpm_tis.cfs
cifs
ecryptfs
ext4
f2fs
fscache
nfs
sysfs
include
crypto
keys
linux
kernel
lib
net
ceph
dns_resolver
rxrpc
scripts
security
apparmor
integrity
keys
big_key.c
encrypted-keys
key.ckeyctl.ckeyring.cprocess_keys.crequest_key.crequest_key_auth.ctrusted.ctrusted.huser_defined.cselinux
smack
|
@ -1,4 +1,4 @@
|
||||||
What: /sys/devices/pnp0/<bus-num>/ppi/
|
What: /sys/class/tpm/tpmX/ppi/
|
||||||
Date: August 2012
|
Date: August 2012
|
||||||
Kernel Version: 3.6
|
Kernel Version: 3.6
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
|
@ -8,9 +8,14 @@ Description:
|
||||||
folder makes sense. The folder path can be got by command
|
folder makes sense. The folder path can be got by command
|
||||||
'find /sys/ -name 'pcrs''. For the detail information of PPI,
|
'find /sys/ -name 'pcrs''. For the detail information of PPI,
|
||||||
please refer to the PPI specification from
|
please refer to the PPI specification from
|
||||||
|
|
||||||
http://www.trustedcomputinggroup.org/
|
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
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
@ -18,7 +23,7 @@ Description:
|
||||||
platform.
|
platform.
|
||||||
This file is readonly.
|
This file is readonly.
|
||||||
|
|
||||||
What: /sys/devices/pnp0/<bus-num>/ppi/request
|
What: /sys/class/tpm/tpmX/ppi/request
|
||||||
Date: August 2012
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
@ -28,7 +33,7 @@ Description:
|
||||||
integer value range from 1 to 160, and 0 means no request.
|
integer value range from 1 to 160, and 0 means no request.
|
||||||
This file can be read and written.
|
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
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
@ -37,7 +42,7 @@ Description:
|
||||||
: <response description>".
|
: <response description>".
|
||||||
This file is readonly.
|
This file is readonly.
|
||||||
|
|
||||||
What: /sys/devices/pnp0/<bus-num>/ppi/transition_action
|
What: /sys/class/tpm/tpmX/ppi/transition_action
|
||||||
Date: August 2012
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
@ -47,7 +52,7 @@ Description:
|
||||||
description>".
|
description>".
|
||||||
This file is readonly.
|
This file is readonly.
|
||||||
|
|
||||||
What: /sys/devices/pnp0/<bus-num>/ppi/tcg_operations
|
What: /sys/class/tpm/tpmX/ppi/tcg_operations
|
||||||
Date: August 2012
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
@ -58,7 +63,7 @@ Description:
|
||||||
This attribute is only supported by PPI version 1.2+.
|
This attribute is only supported by PPI version 1.2+.
|
||||||
This file is readonly.
|
This file is readonly.
|
||||||
|
|
||||||
What: /sys/devices/pnp0/<bus-num>/ppi/vs_operations
|
What: /sys/class/tpm/tpmX/ppi/vs_operations
|
||||||
Date: August 2012
|
Date: August 2012
|
||||||
Contact: xiaoyan.zhang@intel.com
|
Contact: xiaoyan.zhang@intel.com
|
||||||
Description:
|
Description:
|
||||||
|
|
|
@ -186,7 +186,7 @@ and looks like the following:
|
||||||
const struct public_key_signature *sig);
|
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 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.
|
the subtype. Currently, the name is only used for print statements.
|
||||||
|
@ -269,8 +269,7 @@ mandatory:
|
||||||
|
|
||||||
struct key_preparsed_payload {
|
struct key_preparsed_payload {
|
||||||
char *description;
|
char *description;
|
||||||
void *type_data[2];
|
void *payload[4];
|
||||||
void *payload;
|
|
||||||
const void *data;
|
const void *data;
|
||||||
size_t datalen;
|
size_t datalen;
|
||||||
size_t quotalen;
|
size_t quotalen;
|
||||||
|
@ -283,16 +282,18 @@ mandatory:
|
||||||
not theirs.
|
not theirs.
|
||||||
|
|
||||||
If the parser is happy with the blob, it should propose a description for
|
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
|
the key and attach it to ->description, ->payload[asym_subtype] should be
|
||||||
point to the subtype to be used, ->payload should be set to point to the
|
set to point to the subtype to be used, ->payload[asym_crypto] should be
|
||||||
initialised data for that subtype, ->type_data[1] should point to a hex
|
set to point to the initialised data for that subtype,
|
||||||
fingerprint and quotalen should be updated to indicate how much quota this
|
->payload[asym_key_ids] should point to one or more hex fingerprints and
|
||||||
key should account for.
|
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
|
When clearing up, the data attached to ->payload[asym_key_ids] and
|
||||||
will be kfree()'d and the data attached to ->payload will be passed to the
|
->description will be kfree()'d and the data attached to
|
||||||
subtype's ->destroy() method to be disposed of. A module reference for
|
->payload[asm_crypto] will be passed to the subtype's ->destroy() method
|
||||||
the subtype pointed to by ->type_data[0] will be put.
|
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
|
If the data format is not recognised, -EBADMSG should be returned. If it
|
||||||
|
|
|
@ -255,6 +255,16 @@ unconfined
|
||||||
the access permitted if it wouldn't be otherwise. Note that this
|
the access permitted if it wouldn't be otherwise. Note that this
|
||||||
is dangerous and can ruin the proper labeling of your system.
|
is dangerous and can ruin the proper labeling of your system.
|
||||||
It should never be used in production.
|
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
|
If you are using the smackload utility
|
||||||
you can add access rules in /etc/smack/accesses. They take the form:
|
you can add access rules in /etc/smack/accesses. They take the form:
|
||||||
|
|
|
@ -1049,12 +1049,12 @@ search a specific keyring, so using keyrings in this way is of limited utility.
|
||||||
NOTES ON ACCESSING PAYLOAD CONTENTS
|
NOTES ON ACCESSING PAYLOAD CONTENTS
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
The simplest payload is just a number in key->payload.value. In this case,
|
The simplest payload is just data stored in key->payload directly. In this
|
||||||
there's no need to indulge in RCU or locking when accessing the payload.
|
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
|
More complex payload contents must be allocated and pointers to them set in the
|
||||||
key->payload.data. One of the following ways must be selected to access the
|
key->payload.data[] array. One of the following ways must be selected to
|
||||||
data:
|
access the data:
|
||||||
|
|
||||||
(1) Unmodifiable key type.
|
(1) Unmodifiable key type.
|
||||||
|
|
||||||
|
@ -1092,6 +1092,13 @@ data:
|
||||||
the payload. key->datalen cannot be relied upon to be consistent with the
|
the payload. key->datalen cannot be relied upon to be consistent with the
|
||||||
payload just dereferenced if the key's semaphore is not held.
|
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
|
DEFINING A KEY TYPE
|
||||||
|
@ -1143,8 +1150,7 @@ The structure has a number of fields, some of which are mandatory:
|
||||||
|
|
||||||
struct key_preparsed_payload {
|
struct key_preparsed_payload {
|
||||||
char *description;
|
char *description;
|
||||||
void *type_data[2];
|
union key_payload payload;
|
||||||
void *payload;
|
|
||||||
const void *data;
|
const void *data;
|
||||||
size_t datalen;
|
size_t datalen;
|
||||||
size_t quotalen;
|
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
|
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 "".
|
key description if the caller of add_key() passes NULL or "".
|
||||||
|
|
||||||
The method can attach anything it likes to type_data[] and payload. These
|
The method can attach anything it likes to payload. This is merely passed
|
||||||
are merely passed along to the instantiate() or update() operations. If
|
along to the instantiate() or update() operations. If set, the expiry
|
||||||
set, the expiry time will be applied to the key if it is instantiated from
|
time will be applied to the key if it is instantiated from this data.
|
||||||
this data.
|
|
||||||
|
|
||||||
The method should return 0 if successful or a negative error code
|
The method should return 0 if successful or a negative error code
|
||||||
otherwise.
|
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);
|
(*) void (*free_preparse)(struct key_preparsed_payload *prep);
|
||||||
|
|
||||||
This method is only required if the preparse() method is provided,
|
This method is only required if the preparse() method is provided,
|
||||||
otherwise it is unused. It cleans up anything attached to the
|
otherwise it is unused. It cleans up anything attached to the description
|
||||||
description, type_data and payload fields of the key_preparsed_payload
|
and payload fields of the key_preparsed_payload struct as filled in by the
|
||||||
struct as filled in by the preparse() method. It will always be called
|
preparse() method. It will always be called after preparse() returns
|
||||||
after preparse() returns successfully, even if instantiate() or update()
|
successfully, even if instantiate() or update() succeed.
|
||||||
succeed.
|
|
||||||
|
|
||||||
|
|
||||||
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
|
(*) 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.
|
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);
|
(*) int (*update)(struct key *key, const void *data, size_t datalen);
|
||||||
|
|
||||||
|
|
|
@ -10738,6 +10738,7 @@ F: drivers/media/pci/tw68/
|
||||||
TPM DEVICE DRIVER
|
TPM DEVICE DRIVER
|
||||||
M: Peter Huewe <peterhuewe@gmx.de>
|
M: Peter Huewe <peterhuewe@gmx.de>
|
||||||
M: Marcel Selhorst <tpmdd@selhorst.net>
|
M: Marcel Selhorst <tpmdd@selhorst.net>
|
||||||
|
M: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
R: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
|
R: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
|
||||||
W: http://tpmdd.sourceforge.net
|
W: http://tpmdd.sourceforge.net
|
||||||
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||||
|
|
|
@ -1425,27 +1425,45 @@ static void __init prom_instantiate_sml(void)
|
||||||
{
|
{
|
||||||
phandle ibmvtpm_node;
|
phandle ibmvtpm_node;
|
||||||
ihandle ibmvtpm_inst;
|
ihandle ibmvtpm_inst;
|
||||||
u32 entry = 0, size = 0;
|
u32 entry = 0, size = 0, succ = 0;
|
||||||
u64 base;
|
u64 base;
|
||||||
|
__be32 val;
|
||||||
|
|
||||||
prom_debug("prom_instantiate_sml: start...\n");
|
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);
|
prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
|
||||||
if (!PHANDLE_VALID(ibmvtpm_node))
|
if (!PHANDLE_VALID(ibmvtpm_node))
|
||||||
return;
|
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)) {
|
if (!IHANDLE_VALID(ibmvtpm_inst)) {
|
||||||
prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
|
prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call_prom_ret("call-method", 2, 2, &size,
|
if (prom_getprop(ibmvtpm_node, "ibm,sml-efi-reformat-supported",
|
||||||
ADDR("sml-get-handover-size"),
|
&val, sizeof(val)) != PROM_ERROR) {
|
||||||
ibmvtpm_inst) != 0 || size == 0) {
|
if (call_prom_ret("call-method", 2, 2, &succ,
|
||||||
prom_printf("SML get handover size failed\n");
|
ADDR("reformat-sml-to-efi-alignment"),
|
||||||
return;
|
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);
|
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);
|
prom_printf("instantiating sml at 0x%x...", base);
|
||||||
|
|
||||||
|
memset((void *)base, 0, size);
|
||||||
|
|
||||||
if (call_prom_ret("call-method", 4, 2, &entry,
|
if (call_prom_ret("call-method", 4, 2, &entry,
|
||||||
ADDR("sml-handover"),
|
ADDR("sml-handover"),
|
||||||
ibmvtpm_inst, size, base) != 0 || entry == 0) {
|
ibmvtpm_inst, size, base) != 0 || entry == 0) {
|
||||||
|
@ -1464,9 +1484,9 @@ static void __init prom_instantiate_sml(void)
|
||||||
|
|
||||||
reserve_mem(base, size);
|
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));
|
&base, sizeof(base));
|
||||||
prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size",
|
prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size",
|
||||||
&size, sizeof(size));
|
&size, sizeof(size));
|
||||||
|
|
||||||
prom_debug("sml base = 0x%x\n", base);
|
prom_debug("sml base = 0x%x\n", base);
|
||||||
|
|
4
certs/.gitignore
vendored
Normal file
4
certs/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# Generated files
|
||||||
|
#
|
||||||
|
x509_certificate_list
|
|
@ -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,
|
extern int __asymmetric_key_hex_to_key_id(const char *id,
|
||||||
struct asymmetric_key_id *match_id,
|
struct asymmetric_key_id *match_id,
|
||||||
size_t hexlen);
|
size_t hexlen);
|
||||||
static inline
|
|
||||||
const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
|
|
||||||
{
|
|
||||||
return key->type_data.p[1];
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
int i;
|
||||||
|
|
||||||
pr_devel("==>%s()\n", __func__);
|
|
||||||
|
|
||||||
if (subtype) {
|
|
||||||
subtype->destroy(prep->payload[0]);
|
|
||||||
module_put(subtype->owner);
|
|
||||||
}
|
|
||||||
if (kids) {
|
if (kids) {
|
||||||
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
|
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
|
||||||
kfree(kids->id[i]);
|
kfree(kids->id[i]);
|
||||||
kfree(kids);
|
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);
|
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)
|
static void asymmetric_key_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(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) {
|
if (subtype) {
|
||||||
subtype->destroy(key->payload.data);
|
subtype->destroy(data);
|
||||||
module_put(subtype->owner);
|
module_put(subtype->owner);
|
||||||
key->type_data.p[0] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kids) {
|
asymmetric_key_free_kids(kids);
|
||||||
kfree(kids->id[0]);
|
|
||||||
kfree(kids->id[1]);
|
|
||||||
kfree(kids);
|
|
||||||
key->type_data.p[1] = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_type key_type_asymmetric = {
|
struct key_type key_type_asymmetric = {
|
||||||
|
|
|
@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(pkey_id_type_name);
|
||||||
static void public_key_describe(const struct key *asymmetric_key,
|
static void public_key_describe(const struct key *asymmetric_key,
|
||||||
struct seq_file *m)
|
struct seq_file *m)
|
||||||
{
|
{
|
||||||
struct public_key *key = asymmetric_key->payload.data;
|
struct public_key *key = asymmetric_key->payload.data[asym_crypto];
|
||||||
|
|
||||||
if (key)
|
if (key)
|
||||||
seq_printf(m, "%s.%s",
|
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,
|
static int public_key_verify_signature_2(const struct key *key,
|
||||||
const struct public_key_signature *sig)
|
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);
|
return public_key_verify_signature(pk, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ int verify_signature(const struct key *key,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
subtype = asymmetric_key_subtype(key);
|
subtype = asymmetric_key_subtype(key);
|
||||||
if (!subtype ||
|
if (!subtype ||
|
||||||
!key->payload.data)
|
!key->payload.data[0])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!subtype->verify_signature)
|
if (!subtype->verify_signature)
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <crypto/public_key.h>
|
#include <crypto/public_key.h>
|
||||||
|
#include <keys/asymmetric-type.h>
|
||||||
|
|
||||||
struct x509_certificate {
|
struct x509_certificate {
|
||||||
struct x509_certificate *next;
|
struct x509_certificate *next;
|
||||||
|
|
|
@ -267,7 +267,8 @@ static int x509_validate_trust(struct x509_certificate *cert,
|
||||||
if (!IS_ERR(key)) {
|
if (!IS_ERR(key)) {
|
||||||
if (!use_builtin_keys
|
if (!use_builtin_keys
|
||||||
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))
|
|| 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);
|
key_put(key);
|
||||||
}
|
}
|
||||||
return ret;
|
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 */
|
/* We're pinning the module by being linked against it */
|
||||||
__module_get(public_key_subtype.owner);
|
__module_get(public_key_subtype.owner);
|
||||||
prep->type_data[0] = &public_key_subtype;
|
prep->payload.data[asym_subtype] = &public_key_subtype;
|
||||||
prep->type_data[1] = kids;
|
prep->payload.data[asym_key_ids] = kids;
|
||||||
prep->payload[0] = cert->pub;
|
prep->payload.data[asym_crypto] = cert->pub;
|
||||||
prep->description = desc;
|
prep->description = desc;
|
||||||
prep->quotalen = 100;
|
prep->quotalen = 100;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
config TCG_TIS_ST33ZP24
|
config TCG_TIS_ST33ZP24
|
||||||
tristate "STMicroelectronics TPM Interface Specification 1.2 Interface"
|
tristate "STMicroelectronics TPM Interface Specification 1.2 Interface"
|
||||||
depends on GPIOLIB
|
depends on GPIOLIB || COMPILE_TEST
|
||||||
---help---
|
---help---
|
||||||
STMicroelectronics ST33ZP24 core driver. It implements the core
|
STMicroelectronics ST33ZP24 core driver. It implements the core
|
||||||
TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will
|
TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will
|
||||||
|
|
|
@ -258,7 +258,6 @@ static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend,
|
||||||
|
|
||||||
static struct i2c_driver st33zp24_i2c_driver = {
|
static struct i2c_driver st33zp24_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.name = TPM_ST33_I2C,
|
.name = TPM_ST33_I2C,
|
||||||
.pm = &st33zp24_i2c_ops,
|
.pm = &st33zp24_i2c_ops,
|
||||||
.of_match_table = of_match_ptr(of_st33zp24_i2c_match),
|
.of_match_table = of_match_ptr(of_st33zp24_i2c_match),
|
||||||
|
|
|
@ -119,6 +119,9 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
|
||||||
chip->dev.class = tpm_class;
|
chip->dev.class = tpm_class;
|
||||||
chip->dev.release = tpm_dev_release;
|
chip->dev.release = tpm_dev_release;
|
||||||
chip->dev.parent = chip->pdev;
|
chip->dev.parent = chip->pdev;
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
chip->dev.groups = chip->groups;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (chip->dev_num == 0)
|
if (chip->dev_num == 0)
|
||||||
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
|
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
|
||||||
|
@ -182,12 +185,6 @@ static int tpm1_chip_register(struct tpm_chip *chip)
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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);
|
chip->bios_dir = tpm_bios_log_setup(chip->devname);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -201,8 +198,6 @@ static void tpm1_chip_unregister(struct tpm_chip *chip)
|
||||||
if (chip->bios_dir)
|
if (chip->bios_dir)
|
||||||
tpm_bios_log_teardown(chip->bios_dir);
|
tpm_bios_log_teardown(chip->bios_dir);
|
||||||
|
|
||||||
tpm_remove_ppi(chip);
|
|
||||||
|
|
||||||
tpm_sysfs_del_device(chip);
|
tpm_sysfs_del_device(chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,10 +220,20 @@ int tpm_chip_register(struct tpm_chip *chip)
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
tpm_add_ppi(chip);
|
||||||
|
|
||||||
rc = tpm_dev_add_device(chip);
|
rc = tpm_dev_add_device(chip);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_err;
|
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. */
|
/* Make the chip available. */
|
||||||
spin_lock(&driver_lock);
|
spin_lock(&driver_lock);
|
||||||
list_add_rcu(&chip->list, &tpm_chip_list);
|
list_add_rcu(&chip->list, &tpm_chip_list);
|
||||||
|
@ -263,6 +268,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
|
||||||
spin_unlock(&driver_lock);
|
spin_unlock(&driver_lock);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
|
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||||
|
sysfs_remove_link(&chip->pdev->kobj, "ppi");
|
||||||
|
|
||||||
tpm1_chip_unregister(chip);
|
tpm1_chip_unregister(chip);
|
||||||
tpm_dev_del_device(chip);
|
tpm_dev_del_device(chip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,6 +665,30 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||||
return rc;
|
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
|
* tpm_pcr_read - read a pcr value
|
||||||
* @chip_num: tpm idx # or ANY
|
* @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);
|
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)
|
static int __init tpm_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2004 IBM Corporation
|
* Copyright (C) 2004 IBM Corporation
|
||||||
|
* Copyright (C) 2015 Intel Corporation
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Leendert van Doorn <leendert@watson.ibm.com>
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include <linux/tpm.h>
|
#include <linux/tpm.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
|
||||||
enum tpm_const {
|
enum tpm_const {
|
||||||
TPM_MINOR = 224, /* officially assigned */
|
TPM_MINOR = 224, /* officially assigned */
|
||||||
|
@ -88,6 +90,9 @@ enum tpm2_return_codes {
|
||||||
|
|
||||||
enum tpm2_algorithms {
|
enum tpm2_algorithms {
|
||||||
TPM2_ALG_SHA1 = 0x0004,
|
TPM2_ALG_SHA1 = 0x0004,
|
||||||
|
TPM2_ALG_KEYEDHASH = 0x0008,
|
||||||
|
TPM2_ALG_SHA256 = 0x000B,
|
||||||
|
TPM2_ALG_NULL = 0x0010
|
||||||
};
|
};
|
||||||
|
|
||||||
enum tpm2_command_codes {
|
enum tpm2_command_codes {
|
||||||
|
@ -95,6 +100,10 @@ enum tpm2_command_codes {
|
||||||
TPM2_CC_SELF_TEST = 0x0143,
|
TPM2_CC_SELF_TEST = 0x0143,
|
||||||
TPM2_CC_STARTUP = 0x0144,
|
TPM2_CC_STARTUP = 0x0144,
|
||||||
TPM2_CC_SHUTDOWN = 0x0145,
|
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_CAPABILITY = 0x017A,
|
||||||
TPM2_CC_GET_RANDOM = 0x017B,
|
TPM2_CC_GET_RANDOM = 0x017B,
|
||||||
TPM2_CC_PCR_READ = 0x017E,
|
TPM2_CC_PCR_READ = 0x017E,
|
||||||
|
@ -115,6 +124,13 @@ enum tpm2_startup_types {
|
||||||
TPM2_SU_STATE = 0x0001,
|
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_chip;
|
||||||
|
|
||||||
struct tpm_vendor_specific {
|
struct tpm_vendor_specific {
|
||||||
|
@ -151,8 +167,7 @@ struct tpm_vendor_specific {
|
||||||
|
|
||||||
enum tpm_chip_flags {
|
enum tpm_chip_flags {
|
||||||
TPM_CHIP_FLAG_REGISTERED = BIT(0),
|
TPM_CHIP_FLAG_REGISTERED = BIT(0),
|
||||||
TPM_CHIP_FLAG_PPI = BIT(1),
|
TPM_CHIP_FLAG_TPM2 = BIT(1),
|
||||||
TPM_CHIP_FLAG_TPM2 = BIT(2),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tpm_chip {
|
struct tpm_chip {
|
||||||
|
@ -175,6 +190,8 @@ struct tpm_chip {
|
||||||
struct dentry **bios_dir;
|
struct dentry **bios_dir;
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
const struct attribute_group *groups[2];
|
||||||
|
unsigned int groups_cnt;
|
||||||
acpi_handle acpi_dev_handle;
|
acpi_handle acpi_dev_handle;
|
||||||
char ppi_version[TPM_PPI_VERSION_LEN + 1];
|
char ppi_version[TPM_PPI_VERSION_LEN + 1];
|
||||||
#endif /* CONFIG_ACPI */
|
#endif /* CONFIG_ACPI */
|
||||||
|
@ -182,7 +199,7 @@ struct tpm_chip {
|
||||||
struct list_head list;
|
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)
|
static inline void tpm_chip_put(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +399,101 @@ struct tpm_cmd_t {
|
||||||
tpm_cmd_params params;
|
tpm_cmd_params params;
|
||||||
} __packed;
|
} __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 struct class *tpm_class;
|
||||||
extern dev_t tpm_devt;
|
extern dev_t tpm_devt;
|
||||||
extern const struct file_operations tpm_fops;
|
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);
|
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
extern int tpm_add_ppi(struct tpm_chip *chip);
|
extern void tpm_add_ppi(struct tpm_chip *chip);
|
||||||
extern void tpm_remove_ppi(struct tpm_chip *chip);
|
|
||||||
#else
|
#else
|
||||||
static inline int tpm_add_ppi(struct tpm_chip *chip)
|
static inline void tpm_add_ppi(struct tpm_chip *chip)
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void tpm_remove_ppi(struct tpm_chip *chip)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#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_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_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_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,
|
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
|
||||||
u32 *value, const char *desc);
|
u32 *value, const char *desc);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Intel Corporation
|
* Copyright (C) 2014, 2015 Intel Corporation
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
||||||
|
@ -16,6 +16,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
|
#include <keys/trusted-type.h>
|
||||||
|
|
||||||
|
enum tpm2_object_attributes {
|
||||||
|
TPM2_ATTR_USER_WITH_AUTH = BIT(6),
|
||||||
|
};
|
||||||
|
|
||||||
struct tpm2_startup_in {
|
struct tpm2_startup_in {
|
||||||
__be16 startup_type;
|
__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)
|
.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
|
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
|
||||||
* @chip: TPM chip to use.
|
* @chip: TPM chip to use.
|
||||||
|
|
|
@ -34,12 +34,6 @@ enum crb_defaults {
|
||||||
CRB_ACPI_START_INDEX = 1,
|
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_tpm2 {
|
||||||
struct acpi_table_header hdr;
|
struct acpi_table_header hdr;
|
||||||
u16 platform_class;
|
u16 platform_class;
|
||||||
|
@ -74,7 +68,8 @@ struct crb_control_area {
|
||||||
u32 int_enable;
|
u32 int_enable;
|
||||||
u32 int_sts;
|
u32 int_sts;
|
||||||
u32 cmd_size;
|
u32 cmd_size;
|
||||||
u64 cmd_pa;
|
u32 cmd_pa_low;
|
||||||
|
u32 cmd_pa_high;
|
||||||
u32 rsp_size;
|
u32 rsp_size;
|
||||||
u64 rsp_pa;
|
u64 rsp_pa;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
@ -220,12 +215,6 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||||
u64 pa;
|
u64 pa;
|
||||||
int rc;
|
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,
|
status = acpi_get_table(ACPI_SIG_TPM2, 1,
|
||||||
(struct acpi_table_header **) &buf);
|
(struct acpi_table_header **) &buf);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
|
@ -233,13 +222,15 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At least some versions of AMI BIOS have a bug that TPM2 table has
|
/* Should the FIFO driver handle this? */
|
||||||
* zero address for the control area and therefore we must fail.
|
if (buf->start_method == TPM2_START_FIFO)
|
||||||
*/
|
return -ENODEV;
|
||||||
if (!buf->control_area_pa) {
|
|
||||||
dev_err(dev, "TPM2 ACPI table has a zero address for the control area\n");
|
chip = tpmm_chip_alloc(dev, &tpm_crb);
|
||||||
return -EINVAL;
|
if (IS_ERR(chip))
|
||||||
}
|
return PTR_ERR(chip);
|
||||||
|
|
||||||
|
chip->flags = TPM_CHIP_FLAG_TPM2;
|
||||||
|
|
||||||
if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
|
if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
|
||||||
dev_err(dev, "TPM2 ACPI table has wrong size");
|
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
|
* report only ACPI start but in practice seems to require both
|
||||||
* ACPI start and CRB start.
|
* 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"))
|
!strcmp(acpi_device_hid(device), "MSFT0101"))
|
||||||
priv->flags |= CRB_FL_CRB_START;
|
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->flags |= CRB_FL_ACPI_START;
|
||||||
|
|
||||||
priv->cca = (struct crb_control_area __iomem *)
|
priv->cca = (struct crb_control_area __iomem *)
|
||||||
|
@ -273,8 +264,8 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
|
pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
|
||||||
pa = le64_to_cpu(pa);
|
(u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
|
||||||
priv->cmd = devm_ioremap_nocache(dev, pa,
|
priv->cmd = devm_ioremap_nocache(dev, pa,
|
||||||
ioread32(&priv->cca->cmd_size));
|
ioread32(&priv->cca->cmd_size));
|
||||||
if (!priv->cmd) {
|
if (!priv->cmd) {
|
||||||
|
|
|
@ -76,15 +76,25 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
|
||||||
void *addr = log->bios_event_log;
|
void *addr = log->bios_event_log;
|
||||||
void *limit = log->bios_event_log_end;
|
void *limit = log->bios_event_log_end;
|
||||||
struct tcpa_event *event;
|
struct tcpa_event *event;
|
||||||
|
u32 converted_event_size;
|
||||||
|
u32 converted_event_type;
|
||||||
|
|
||||||
|
|
||||||
/* read over *pos measurements */
|
/* read over *pos measurements */
|
||||||
for (i = 0; i < *pos; i++) {
|
for (i = 0; i < *pos; i++) {
|
||||||
event = addr;
|
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 ((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;
|
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;
|
event = addr;
|
||||||
|
|
||||||
if ((event->event_type == 0 && event->event_size == 0) ||
|
converted_event_size = do_endian_conversion(event->event_size);
|
||||||
((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
|
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 NULL;
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
|
@ -107,8 +121,12 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
|
||||||
struct tcpa_event *event = v;
|
struct tcpa_event *event = v;
|
||||||
struct tpm_bios_log *log = m->private;
|
struct tpm_bios_log *log = m->private;
|
||||||
void *limit = log->bios_event_log_end;
|
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 */
|
/* now check if current entry is valid */
|
||||||
if ((v + sizeof(struct tcpa_event)) >= limit)
|
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;
|
event = v;
|
||||||
|
|
||||||
if (event->event_type == 0 && event->event_size == 0)
|
converted_event_size = do_endian_conversion(event->event_size);
|
||||||
return NULL;
|
converted_event_type = do_endian_conversion(event->event_type);
|
||||||
|
|
||||||
if ((event->event_type == 0 && event->event_size == 0) ||
|
if (((converted_event_type == 0) && (converted_event_size == 0)) ||
|
||||||
((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
|
((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
(*pos)++;
|
(*pos)++;
|
||||||
|
@ -140,7 +158,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
||||||
int i, n_len = 0, d_len = 0;
|
int i, n_len = 0, d_len = 0;
|
||||||
struct tcpa_pc_event *pc_event;
|
struct tcpa_pc_event *pc_event;
|
||||||
|
|
||||||
switch(event->event_type) {
|
switch (do_endian_conversion(event->event_type)) {
|
||||||
case PREBOOT:
|
case PREBOOT:
|
||||||
case POST_CODE:
|
case POST_CODE:
|
||||||
case UNUSED:
|
case UNUSED:
|
||||||
|
@ -156,14 +174,16 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
||||||
case NONHOST_CODE:
|
case NONHOST_CODE:
|
||||||
case NONHOST_CONFIG:
|
case NONHOST_CONFIG:
|
||||||
case NONHOST_INFO:
|
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);
|
n_len = strlen(name);
|
||||||
break;
|
break;
|
||||||
case SEPARATOR:
|
case SEPARATOR:
|
||||||
case ACTION:
|
case ACTION:
|
||||||
if (MAX_TEXT_EVENT > event->event_size) {
|
if (MAX_TEXT_EVENT >
|
||||||
|
do_endian_conversion(event->event_size)) {
|
||||||
name = event_entry;
|
name = event_entry;
|
||||||
n_len = event->event_size;
|
n_len = do_endian_conversion(event->event_size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_TAG:
|
case EVENT_TAG:
|
||||||
|
@ -171,7 +191,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
||||||
|
|
||||||
/* ToDo Row data -> Base64 */
|
/* ToDo Row data -> Base64 */
|
||||||
|
|
||||||
switch (pc_event->event_id) {
|
switch (do_endian_conversion(pc_event->event_id)) {
|
||||||
case SMBIOS:
|
case SMBIOS:
|
||||||
case BIS_CERT:
|
case BIS_CERT:
|
||||||
case CMOS:
|
case CMOS:
|
||||||
|
@ -179,7 +199,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
||||||
case OPTION_ROM_EXEC:
|
case OPTION_ROM_EXEC:
|
||||||
case OPTION_ROM_CONFIG:
|
case OPTION_ROM_CONFIG:
|
||||||
case S_CRTM_VERSION:
|
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);
|
n_len = strlen(name);
|
||||||
break;
|
break;
|
||||||
/* hash data */
|
/* hash data */
|
||||||
|
@ -188,7 +209,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
||||||
case OPTION_ROM_MICROCODE:
|
case OPTION_ROM_MICROCODE:
|
||||||
case S_CRTM_CONTENTS:
|
case S_CRTM_CONTENTS:
|
||||||
case POST_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);
|
n_len = strlen(name);
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
d_len += sprintf(&data[2*i], "%02x",
|
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)
|
static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
struct tcpa_event *event = v;
|
struct tcpa_event *event = v;
|
||||||
char *data = v;
|
struct tcpa_event temp_event;
|
||||||
|
char *tempPtr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
|
memcpy(&temp_event, event, sizeof(struct tcpa_event));
|
||||||
seq_putc(m, data[i]);
|
|
||||||
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tpm_bios_measurements_release(struct inode *inode,
|
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;
|
char *eventname;
|
||||||
struct tcpa_event *event = v;
|
struct tcpa_event *event = v;
|
||||||
unsigned char *event_entry =
|
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);
|
eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
|
||||||
if (!eventname) {
|
if (!eventname) {
|
||||||
|
@ -247,13 +280,14 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
seq_printf(m, "%2d ", event->pcr_index);
|
/* 1st: PCR */
|
||||||
|
seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
|
||||||
|
|
||||||
/* 2nd: SHA1 */
|
/* 2nd: SHA1 */
|
||||||
seq_printf(m, "%20phN", event->pcr_value);
|
seq_printf(m, "%20phN", event->pcr_value);
|
||||||
|
|
||||||
/* 3rd: event type identifier */
|
/* 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);
|
len += get_event_name(eventname, event, event_entry);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
#define MAX_TEXT_EVENT 1000 /* Max event string length */
|
#define MAX_TEXT_EVENT 1000 /* Max event string length */
|
||||||
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
|
#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 {
|
enum bios_platform_class {
|
||||||
BIOS_CLIENT = 0x00,
|
BIOS_CLIENT = 0x00,
|
||||||
BIOS_SERVER = 0x01,
|
BIOS_SERVER = 0x01,
|
||||||
|
|
|
@ -217,7 +217,6 @@ static struct i2c_driver i2c_atmel_driver = {
|
||||||
.remove = i2c_atmel_remove,
|
.remove = i2c_atmel_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = I2C_DRIVER_NAME,
|
.name = I2C_DRIVER_NAME,
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.pm = &i2c_atmel_pm_ops,
|
.pm = &i2c_atmel_pm_ops,
|
||||||
.of_match_table = of_match_ptr(i2c_atmel_of_match),
|
.of_match_table = of_match_ptr(i2c_atmel_of_match),
|
||||||
},
|
},
|
||||||
|
|
|
@ -711,7 +711,6 @@ static struct i2c_driver tpm_tis_i2c_driver = {
|
||||||
.remove = tpm_tis_i2c_remove,
|
.remove = tpm_tis_i2c_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tpm_i2c_infineon",
|
.name = "tpm_i2c_infineon",
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.pm = &tpm_tis_i2c_ops,
|
.pm = &tpm_tis_i2c_ops,
|
||||||
.of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
|
.of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
|
||||||
},
|
},
|
||||||
|
|
|
@ -641,7 +641,6 @@ static struct i2c_driver i2c_nuvoton_driver = {
|
||||||
.remove = i2c_nuvoton_remove,
|
.remove = i2c_nuvoton_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = I2C_DRIVER_NAME,
|
.name = I2C_DRIVER_NAME,
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.pm = &i2c_nuvoton_pm_ops,
|
.pm = &i2c_nuvoton_pm_ops,
|
||||||
.of_match_table = of_match_ptr(i2c_nuvoton_of_match),
|
.of_match_table = of_match_ptr(i2c_nuvoton_of_match),
|
||||||
},
|
},
|
||||||
|
|
|
@ -491,7 +491,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
|
||||||
}
|
}
|
||||||
ibmvtpm->rtce_size = be16_to_cpu(crq->len);
|
ibmvtpm->rtce_size = be16_to_cpu(crq->len);
|
||||||
ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
|
ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
|
||||||
GFP_KERNEL);
|
GFP_ATOMIC);
|
||||||
if (!ibmvtpm->rtce_buf) {
|
if (!ibmvtpm->rtce_buf) {
|
||||||
dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
|
dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,14 +24,14 @@ int read_log(struct tpm_bios_log *log)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
const u32 *sizep;
|
const u32 *sizep;
|
||||||
const __be64 *basep;
|
const u64 *basep;
|
||||||
|
|
||||||
if (log->bios_event_log != NULL) {
|
if (log->bios_event_log != NULL) {
|
||||||
pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
|
pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
np = of_find_node_by_name(NULL, "ibm,vtpm");
|
np = of_find_node_by_name(NULL, "vtpm");
|
||||||
if (!np) {
|
if (!np) {
|
||||||
pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
|
pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -63,7 +63,7 @@ int read_log(struct tpm_bios_log *log)
|
||||||
|
|
||||||
log->bios_event_log_end = log->bios_event_log + *sizep;
|
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;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
static ssize_t tpm_show_ppi_version(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
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);
|
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;
|
ssize_t size = -EINVAL;
|
||||||
union acpi_object *obj;
|
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,
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
|
||||||
ACPI_TYPE_PACKAGE, NULL);
|
ACPI_TYPE_PACKAGE, NULL);
|
||||||
|
@ -100,7 +100,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
int func = TPM_PPI_FN_SUBREQ;
|
int func = TPM_PPI_FN_SUBREQ;
|
||||||
union acpi_object *obj, tmp;
|
union acpi_object *obj, tmp;
|
||||||
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &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
|
* 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.length = 0,
|
||||||
.buffer.pointer = NULL
|
.buffer.pointer = NULL
|
||||||
};
|
};
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||||
|
|
||||||
static char *info[] = {
|
static char *info[] = {
|
||||||
"None",
|
"None",
|
||||||
|
@ -197,7 +197,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
|
||||||
acpi_status status = -EINVAL;
|
acpi_status status = -EINVAL;
|
||||||
union acpi_object *obj, *ret_obj;
|
union acpi_object *obj, *ret_obj;
|
||||||
u64 req, res;
|
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,
|
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
|
||||||
ACPI_TYPE_PACKAGE, NULL);
|
ACPI_TYPE_PACKAGE, NULL);
|
||||||
|
@ -296,7 +296,7 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
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,
|
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
|
||||||
PPI_TPM_REQ_MAX);
|
PPI_TPM_REQ_MAX);
|
||||||
|
@ -306,7 +306,7 @@ static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
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,
|
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
|
||||||
PPI_VS_REQ_END);
|
PPI_VS_REQ_END);
|
||||||
|
@ -334,17 +334,16 @@ static struct attribute_group ppi_attr_grp = {
|
||||||
.attrs = ppi_attrs
|
.attrs = ppi_attrs
|
||||||
};
|
};
|
||||||
|
|
||||||
int tpm_add_ppi(struct tpm_chip *chip)
|
void tpm_add_ppi(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
union acpi_object *obj;
|
union acpi_object *obj;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!chip->acpi_dev_handle)
|
if (!chip->acpi_dev_handle)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||||
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
|
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
/* Cache PPI version string. */
|
/* Cache PPI version string. */
|
||||||
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
|
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);
|
ACPI_FREE(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
|
chip->groups[chip->groups_cnt++] = &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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2005, 2006 IBM Corporation
|
* Copyright (C) 2005, 2006 IBM Corporation
|
||||||
* Copyright (C) 2014 Intel Corporation
|
* Copyright (C) 2014, 2015 Intel Corporation
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Leendert van Doorn <leendert@watson.ibm.com>
|
* Leendert van Doorn <leendert@watson.ibm.com>
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
#include <acpi/actbl2.h>
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
|
|
||||||
enum tis_access {
|
enum tis_access {
|
||||||
|
@ -65,6 +66,17 @@ enum tis_defaults {
|
||||||
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
|
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
|
/* Some timeout values are needed before it is known whether the chip is
|
||||||
* TPM 1.0 or TPM 2.0.
|
* TPM 1.0 or TPM 2.0.
|
||||||
|
@ -91,26 +103,54 @@ struct priv_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
|
#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;
|
struct acpi_hardware_id *id;
|
||||||
|
|
||||||
if (!acpi)
|
list_for_each_entry(id, &dev->pnp.ids, list)
|
||||||
return 0;
|
if (!strcmp(hid, id->id))
|
||||||
|
|
||||||
list_for_each_entry(id, &acpi->pnp.ids, list) {
|
|
||||||
if (!strcmp("INTC0102", id->id))
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
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
|
#else
|
||||||
static inline int is_itpm(struct pnp_dev *dev)
|
static inline int is_itpm(struct acpi_device *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int is_fifo(struct acpi_device *dev)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Before we attempt to access the TPM we must see that the valid bit is set.
|
/* 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);
|
release_locality(chip, chip->vendor.locality, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
|
static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||||
resource_size_t start, resource_size_t len,
|
acpi_handle acpi_dev_handle)
|
||||||
unsigned int irq)
|
|
||||||
{
|
{
|
||||||
u32 vendor, intfcaps, intmask;
|
u32 vendor, intfcaps, intmask;
|
||||||
int rc, i, irq_s, irq_e, probe;
|
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;
|
chip->acpi_dev_handle = acpi_dev_handle;
|
||||||
#endif
|
#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)
|
if (!chip->vendor.iobase)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -707,7 +746,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
|
||||||
chip->vendor.iobase +
|
chip->vendor.iobase +
|
||||||
TPM_INT_ENABLE(chip->vendor.locality));
|
TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
if (interrupts)
|
if (interrupts)
|
||||||
chip->vendor.irq = irq;
|
chip->vendor.irq = tpm_info->irq;
|
||||||
if (interrupts && !chip->vendor.irq) {
|
if (interrupts && !chip->vendor.irq) {
|
||||||
irq_s =
|
irq_s =
|
||||||
ioread8(chip->vendor.iobase +
|
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,
|
static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
|
||||||
const struct pnp_device_id *pnp_id)
|
const struct pnp_device_id *pnp_id)
|
||||||
{
|
{
|
||||||
resource_size_t start, len;
|
struct tpm_info tpm_info = tis_default_info;
|
||||||
unsigned int irq = 0;
|
|
||||||
acpi_handle acpi_dev_handle = NULL;
|
acpi_handle acpi_dev_handle = NULL;
|
||||||
|
|
||||||
start = pnp_mem_start(pnp_dev, 0);
|
tpm_info.start = pnp_mem_start(pnp_dev, 0);
|
||||||
len = pnp_mem_len(pnp_dev, 0);
|
tpm_info.len = pnp_mem_len(pnp_dev, 0);
|
||||||
|
|
||||||
if (pnp_irq_valid(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
|
else
|
||||||
interrupts = false;
|
interrupts = false;
|
||||||
|
|
||||||
if (is_itpm(pnp_dev))
|
|
||||||
itpm = true;
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#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;
|
acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
|
||||||
|
}
|
||||||
#endif
|
#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[] = {
|
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)
|
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
||||||
|
|
||||||
tpm_chip_unregister(chip);
|
tpm_chip_unregister(chip);
|
||||||
tpm_tis_remove(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");
|
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
|
||||||
#endif
|
#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 = {
|
static struct platform_driver tis_drv = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tpm_tis",
|
.name = "tpm_tis",
|
||||||
|
@ -966,9 +1079,25 @@ static int __init init_tis(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
if (!force)
|
if (!force) {
|
||||||
return pnp_register_driver(&tis_pnp_driver);
|
rc = pnp_register_driver(&tis_pnp_driver);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
#endif
|
#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);
|
rc = platform_driver_register(&tis_drv);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
|
@ -978,7 +1107,7 @@ static int __init init_tis(void)
|
||||||
rc = PTR_ERR(pdev);
|
rc = PTR_ERR(pdev);
|
||||||
goto err_dev;
|
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)
|
if (rc)
|
||||||
goto err_init;
|
goto err_init;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -992,9 +1121,14 @@ err_dev:
|
||||||
static void __exit cleanup_tis(void)
|
static void __exit cleanup_tis(void)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
#ifdef CONFIG_PNP
|
#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
|
||||||
if (!force) {
|
if (!force) {
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
acpi_bus_unregister_driver(&tis_acpi_driver);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_PNP
|
||||||
pnp_unregister_driver(&tis_pnp_driver);
|
pnp_unregister_driver(&tis_pnp_driver);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,7 +42,7 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* attach the data */
|
/* attach the data */
|
||||||
key->payload.data = payload;
|
key->payload.data[0] = payload;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -52,7 +52,7 @@ error:
|
||||||
static void
|
static void
|
||||||
cifs_spnego_key_destroy(struct key *key)
|
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
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
if (cifsFYI && !IS_ERR(spnego_key)) {
|
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,
|
cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
|
||||||
msg->secblob_len + msg->sesskey_len));
|
msg->secblob_len + msg->sesskey_len));
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,16 +58,15 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||||
* dereference payload.data!
|
* dereference payload.data!
|
||||||
*/
|
*/
|
||||||
if (prep->datalen <= sizeof(key->payload)) {
|
if (prep->datalen <= sizeof(key->payload)) {
|
||||||
key->payload.value = 0;
|
key->payload.data[0] = NULL;
|
||||||
memcpy(&key->payload.value, prep->data, prep->datalen);
|
memcpy(&key->payload, prep->data, prep->datalen);
|
||||||
key->datalen = prep->datalen;
|
} else {
|
||||||
return 0;
|
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;
|
key->datalen = prep->datalen;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +75,7 @@ static inline void
|
||||||
cifs_idmap_key_destroy(struct key *key)
|
cifs_idmap_key_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
if (key->datalen > sizeof(key->payload))
|
if (key->datalen > sizeof(key->payload))
|
||||||
kfree(key->payload.data);
|
kfree(key->payload.data[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct key_type cifs_idmap_key_type = {
|
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.
|
* it could be.
|
||||||
*/
|
*/
|
||||||
ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
|
ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
|
||||||
(struct cifs_sid *)&sidkey->payload.value :
|
(struct cifs_sid *)&sidkey->payload :
|
||||||
(struct cifs_sid *)sidkey->payload.data;
|
(struct cifs_sid *)sidkey->payload.data[0];
|
||||||
|
|
||||||
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
|
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
|
||||||
if (ksid_size > sidkey->datalen) {
|
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) {
|
if (sidtype == SIDOWNER) {
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
uid_t id;
|
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);
|
uid = make_kuid(&init_user_ns, id);
|
||||||
if (uid_valid(uid))
|
if (uid_valid(uid))
|
||||||
fuid = uid;
|
fuid = uid;
|
||||||
} else {
|
} else {
|
||||||
kgid_t gid;
|
kgid_t gid;
|
||||||
gid_t id;
|
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);
|
gid = make_kgid(&init_user_ns, id);
|
||||||
if (gid_valid(gid))
|
if (gid_valid(gid))
|
||||||
fgid = gid;
|
fgid = gid;
|
||||||
|
|
|
@ -2325,13 +2325,14 @@ static int
|
||||||
cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
|
cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
char *desc, *delim, *payload;
|
const char *delim, *payload;
|
||||||
|
char *desc;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
struct TCP_Server_Info *server = ses->server;
|
struct TCP_Server_Info *server = ses->server;
|
||||||
struct sockaddr_in *sa;
|
struct sockaddr_in *sa;
|
||||||
struct sockaddr_in6 *sa6;
|
struct sockaddr_in6 *sa6;
|
||||||
struct user_key_payload *upayload;
|
const struct user_key_payload *upayload;
|
||||||
|
|
||||||
desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
|
desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
|
@ -2374,14 +2375,14 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
|
||||||
}
|
}
|
||||||
|
|
||||||
down_read(&key->sem);
|
down_read(&key->sem);
|
||||||
upayload = key->payload.data;
|
upayload = user_key_payload(key);
|
||||||
if (IS_ERR_OR_NULL(upayload)) {
|
if (IS_ERR_OR_NULL(upayload)) {
|
||||||
rc = upayload ? PTR_ERR(upayload) : -EINVAL;
|
rc = upayload ? PTR_ERR(upayload) : -EINVAL;
|
||||||
goto out_key_put;
|
goto out_key_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find first : in payload */
|
/* find first : in payload */
|
||||||
payload = (char *)upayload->data;
|
payload = upayload->data;
|
||||||
delim = strnchr(payload, upayload->datalen, ':');
|
delim = strnchr(payload, upayload->datalen, ':');
|
||||||
cifs_dbg(FYI, "payload=%s\n", payload);
|
cifs_dbg(FYI, "payload=%s\n", payload);
|
||||||
if (!delim) {
|
if (!delim) {
|
||||||
|
|
|
@ -988,7 +988,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = spnego_key->payload.data;
|
msg = spnego_key->payload.data[0];
|
||||||
/*
|
/*
|
||||||
* check version field to make sure that cifs.upcall is
|
* check version field to make sure that cifs.upcall is
|
||||||
* sending us a response in an expected form
|
* sending us a response in an expected form
|
||||||
|
|
|
@ -660,7 +660,7 @@ ssetup_ntlmssp_authenticate:
|
||||||
goto ssetup_exit;
|
goto ssetup_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = spnego_key->payload.data;
|
msg = spnego_key->payload.data[0];
|
||||||
/*
|
/*
|
||||||
* check version field to make sure that cifs.upcall is
|
* check version field to make sure that cifs.upcall is
|
||||||
* sending us a response in an expected form
|
* sending us a response in an expected form
|
||||||
|
|
|
@ -86,7 +86,7 @@ ecryptfs_get_encrypted_key_payload_data(struct key *key)
|
||||||
{
|
{
|
||||||
if (key->type == &key_type_encrypted)
|
if (key->type == &key_type_encrypted)
|
||||||
return (struct ecryptfs_auth_tok *)
|
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
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,7 @@ ecryptfs_get_key_payload_data(struct key *key)
|
||||||
|
|
||||||
auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
|
auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
|
||||||
if (!auth_tok)
|
if (!auth_tok)
|
||||||
return (struct ecryptfs_auth_tok *)
|
return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
|
||||||
(((struct user_key_payload *)key->payload.data)->data);
|
|
||||||
else
|
else
|
||||||
return auth_tok;
|
return auth_tok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ int _ext4_get_encryption_info(struct inode *inode)
|
||||||
struct key *keyring_key = NULL;
|
struct key *keyring_key = NULL;
|
||||||
struct ext4_encryption_key *master_key;
|
struct ext4_encryption_key *master_key;
|
||||||
struct ext4_encryption_context ctx;
|
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 ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||||
struct crypto_ablkcipher *ctfm;
|
struct crypto_ablkcipher *ctfm;
|
||||||
const char *cipher_str;
|
const char *cipher_str;
|
||||||
|
@ -209,7 +209,7 @@ retry:
|
||||||
}
|
}
|
||||||
crypt_info->ci_keyring_key = keyring_key;
|
crypt_info->ci_keyring_key = keyring_key;
|
||||||
BUG_ON(keyring_key->type != &key_type_logon);
|
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)) {
|
if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -122,7 +122,7 @@ int _f2fs_get_encryption_info(struct inode *inode)
|
||||||
struct key *keyring_key = NULL;
|
struct key *keyring_key = NULL;
|
||||||
struct f2fs_encryption_key *master_key;
|
struct f2fs_encryption_key *master_key;
|
||||||
struct f2fs_encryption_context ctx;
|
struct f2fs_encryption_context ctx;
|
||||||
struct user_key_payload *ukp;
|
const struct user_key_payload *ukp;
|
||||||
struct crypto_ablkcipher *ctfm;
|
struct crypto_ablkcipher *ctfm;
|
||||||
const char *cipher_str;
|
const char *cipher_str;
|
||||||
char raw_key[F2FS_MAX_KEY_SIZE];
|
char raw_key[F2FS_MAX_KEY_SIZE];
|
||||||
|
@ -199,7 +199,7 @@ retry:
|
||||||
}
|
}
|
||||||
crypt_info->ci_keyring_key = keyring_key;
|
crypt_info->ci_keyring_key = keyring_key;
|
||||||
BUG_ON(keyring_key->type != &key_type_logon);
|
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)) {
|
if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -316,7 +316,7 @@ static const struct seq_operations fscache_objlist_ops = {
|
||||||
static void fscache_objlist_config(struct fscache_objlist_data *data)
|
static void fscache_objlist_config(struct fscache_objlist_data *data)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KEYS
|
#ifdef CONFIG_KEYS
|
||||||
struct user_key_payload *confkey;
|
const struct user_key_payload *confkey;
|
||||||
unsigned long config;
|
unsigned long config;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
const char *buf;
|
const char *buf;
|
||||||
|
@ -329,7 +329,7 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
|
||||||
config = 0;
|
config = 0;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
confkey = key->payload.data;
|
confkey = user_key_payload(key);
|
||||||
buf = confkey->data;
|
buf = confkey->data;
|
||||||
|
|
||||||
for (len = confkey->datalen - 1; len >= 0; len--) {
|
for (len = confkey->datalen - 1; len >= 0; len--) {
|
||||||
|
|
|
@ -297,7 +297,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
|
||||||
{
|
{
|
||||||
const struct cred *saved_cred;
|
const struct cred *saved_cred;
|
||||||
struct key *rkey;
|
struct key *rkey;
|
||||||
struct user_key_payload *payload;
|
const struct user_key_payload *payload;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
saved_cred = override_creds(id_resolver_cache);
|
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)
|
if (ret < 0)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
|
|
||||||
payload = rcu_dereference(rkey->payload.rcudata);
|
payload = user_key_payload(rkey);
|
||||||
if (IS_ERR_OR_NULL(payload)) {
|
if (IS_ERR_OR_NULL(payload)) {
|
||||||
ret = PTR_ERR(payload);
|
ret = PTR_ERR(payload);
|
||||||
goto out_up;
|
goto out_up;
|
||||||
|
|
|
@ -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);
|
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);
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#define _LINUX_PUBLIC_KEY_H
|
#define _LINUX_PUBLIC_KEY_H
|
||||||
|
|
||||||
#include <linux/mpi.h>
|
#include <linux/mpi.h>
|
||||||
#include <keys/asymmetric-type.h>
|
|
||||||
#include <crypto/hash_info.h>
|
#include <crypto/hash_info.h>
|
||||||
|
|
||||||
enum pkey_algo {
|
enum pkey_algo {
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct asymmetric_key_subtype {
|
||||||
static inline
|
static inline
|
||||||
struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
|
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 */
|
#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */
|
||||||
|
|
|
@ -18,6 +18,16 @@
|
||||||
|
|
||||||
extern struct key_type key_type_asymmetric;
|
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
|
* Identifiers for an asymmetric key ID. We have three ways of looking up a
|
||||||
* key derived from an X.509 certificate:
|
* 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,
|
size_t len_1,
|
||||||
const void *val_2,
|
const void *val_2,
|
||||||
size_t len_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.
|
* The payload is at the discretion of the subtype.
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
|
|
||||||
#include <linux/key.h>
|
#include <linux/key.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
|
#include <linux/tpm.h>
|
||||||
|
|
||||||
#define MIN_KEY_SIZE 32
|
#define MIN_KEY_SIZE 32
|
||||||
#define MAX_KEY_SIZE 128
|
#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 trusted_key_payload {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
@ -26,6 +28,16 @@ struct trusted_key_payload {
|
||||||
unsigned char blob[MAX_BLOB_SIZE];
|
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;
|
extern struct key_type key_type_trusted;
|
||||||
|
|
||||||
#endif /* _KEYS_TRUSTED_TYPE_H */
|
#endif /* _KEYS_TRUSTED_TYPE_H */
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <linux/key.h>
|
#include <linux/key.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEYS
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* the payload for a key of type "user" or "logon"
|
* 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,
|
extern long user_read(const struct key *key,
|
||||||
char __user *buffer, size_t buflen);
|
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 */
|
#endif /* _KEYS_USER_TYPE_H */
|
||||||
|
|
|
@ -40,8 +40,7 @@ struct key_construction {
|
||||||
*/
|
*/
|
||||||
struct key_preparsed_payload {
|
struct key_preparsed_payload {
|
||||||
char *description; /* Proposed key description (or NULL) */
|
char *description; /* Proposed key description (or NULL) */
|
||||||
void *type_data[2]; /* Private key-type data */
|
union key_payload payload; /* Proposed payload */
|
||||||
void *payload[2]; /* Proposed payload */
|
|
||||||
const void *data; /* Raw data */
|
const void *data; /* Raw data */
|
||||||
size_t datalen; /* Raw datalen */
|
size_t datalen; /* Raw datalen */
|
||||||
size_t quotalen; /* Quota length for proposed payload */
|
size_t quotalen; /* Quota length for proposed payload */
|
||||||
|
|
|
@ -89,6 +89,11 @@ struct keyring_index_key {
|
||||||
size_t desc_len;
|
size_t desc_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union key_payload {
|
||||||
|
void __rcu *rcu_data0;
|
||||||
|
void *data[4];
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* key reference with possession attribute handling
|
* 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
|
/* key data
|
||||||
* - this is used to hold the data actually used in cryptography or
|
* - this is used to hold the data actually used in cryptography or
|
||||||
* whatever
|
* whatever
|
||||||
*/
|
*/
|
||||||
union {
|
union {
|
||||||
union {
|
union key_payload payload;
|
||||||
unsigned long value;
|
struct {
|
||||||
void __rcu *rcudata;
|
/* Keyring bits */
|
||||||
void *data;
|
struct list_head name_link;
|
||||||
void *data2[2];
|
struct assoc_array keys;
|
||||||
} payload;
|
};
|
||||||
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) \
|
#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)))
|
rwsem_is_locked(&((struct key *)(KEY))->sem)))
|
||||||
|
|
||||||
#define rcu_assign_keypointer(KEY, PAYLOAD) \
|
#define rcu_assign_keypointer(KEY, PAYLOAD) \
|
||||||
do { \
|
do { \
|
||||||
rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD)); \
|
rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
|
|
|
@ -268,6 +268,9 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
|
||||||
struct kobject *target, const char *link_name);
|
struct kobject *target, const char *link_name);
|
||||||
void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
|
void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
|
||||||
const char *link_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);
|
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,
|
static inline void sysfs_notify(struct kobject *kobj, const char *dir,
|
||||||
const char *attr)
|
const char *attr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#define TPM_ANY_NUM 0xFFFF
|
#define TPM_ANY_NUM 0xFFFF
|
||||||
|
|
||||||
struct tpm_chip;
|
struct tpm_chip;
|
||||||
|
struct trusted_key_payload;
|
||||||
|
struct trusted_key_options;
|
||||||
|
|
||||||
struct tpm_class_ops {
|
struct tpm_class_ops {
|
||||||
const u8 req_complete_mask;
|
const u8 req_complete_mask;
|
||||||
|
@ -46,11 +48,22 @@ struct tpm_class_ops {
|
||||||
|
|
||||||
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
|
#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_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_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_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_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
|
#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) {
|
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
|
||||||
return -ENODEV;
|
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) {
|
static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
|
||||||
return -ENODEV;
|
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
|
||||||
#endif
|
#endif
|
||||||
|
|
1
kernel/.gitignore
vendored
1
kernel/.gitignore
vendored
|
@ -5,4 +5,3 @@ config_data.h
|
||||||
config_data.gz
|
config_data.gz
|
||||||
timeconst.h
|
timeconst.h
|
||||||
hz.bc
|
hz.bc
|
||||||
x509_certificate_list
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
#include <keys/system_keyring.h>
|
#include <keys/system_keyring.h>
|
||||||
#include <crypto/public_key.h>
|
#include <crypto/public_key.h>
|
||||||
#include "module-internal.h"
|
#include "module-internal.h"
|
||||||
|
|
|
@ -79,12 +79,13 @@ static int digsig_verify_rsa(struct key *key,
|
||||||
unsigned char *out1 = NULL;
|
unsigned char *out1 = NULL;
|
||||||
const char *m;
|
const char *m;
|
||||||
MPI in = NULL, res = NULL, pkey[2];
|
MPI in = NULL, res = NULL, pkey[2];
|
||||||
uint8_t *p, *datap, *endp;
|
uint8_t *p, *datap;
|
||||||
struct user_key_payload *ukp;
|
const uint8_t *endp;
|
||||||
|
const struct user_key_payload *ukp;
|
||||||
struct pubkey_hdr *pkh;
|
struct pubkey_hdr *pkh;
|
||||||
|
|
||||||
down_read(&key->sem);
|
down_read(&key->sem);
|
||||||
ukp = key->payload.data;
|
ukp = user_key_payload(key);
|
||||||
|
|
||||||
if (ukp->datalen < sizeof(*pkh))
|
if (ukp->datalen < sizeof(*pkh))
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
|
@ -318,7 +318,7 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ckey = ukey->payload.data;
|
ckey = ukey->payload.data[0];
|
||||||
err = ceph_crypto_key_clone(dst, ckey);
|
err = ceph_crypto_key_clone(dst, ckey);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_key;
|
goto out_key;
|
||||||
|
|
|
@ -537,7 +537,7 @@ static int ceph_key_preparse(struct key_preparsed_payload *prep)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_ckey;
|
goto err_ckey;
|
||||||
|
|
||||||
prep->payload[0] = ckey;
|
prep->payload.data[0] = ckey;
|
||||||
prep->quotalen = datalen;
|
prep->quotalen = datalen;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -549,14 +549,14 @@ err:
|
||||||
|
|
||||||
static void ceph_key_free_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);
|
ceph_crypto_key_destroy(ckey);
|
||||||
kfree(ckey);
|
kfree(ckey);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ceph_key_destroy(struct key *key)
|
static void ceph_key_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct ceph_crypto_key *ckey = key->payload.data;
|
struct ceph_crypto_key *ckey = key->payload.data[0];
|
||||||
|
|
||||||
ceph_crypto_key_destroy(ckey);
|
ceph_crypto_key_destroy(ckey);
|
||||||
kfree(ckey);
|
kfree(ckey);
|
||||||
|
|
|
@ -122,7 +122,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
|
||||||
goto bad_option_value;
|
goto bad_option_value;
|
||||||
|
|
||||||
kdebug("dns error no. = %lu", derrno);
|
kdebug("dns error no. = %lu", derrno);
|
||||||
prep->type_data[0] = ERR_PTR(-derrno);
|
prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
|
||||||
continue;
|
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
|
/* don't cache the result if we're caching an error saying there's no
|
||||||
* result */
|
* result */
|
||||||
if (prep->type_data[0]) {
|
if (prep->payload.data[dns_key_error]) {
|
||||||
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
|
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
|
||||||
memcpy(upayload->data, data, result_len);
|
memcpy(upayload->data, data, result_len);
|
||||||
upayload->data[result_len] = '\0';
|
upayload->data[result_len] = '\0';
|
||||||
|
|
||||||
prep->payload[0] = upayload;
|
prep->payload.data[dns_key_data] = upayload;
|
||||||
kleave(" = 0");
|
kleave(" = 0");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
pr_devel("==>%s()\n", __func__);
|
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)
|
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);
|
seq_puts(m, key->description);
|
||||||
if (key_is_instantiated(key)) {
|
if (key_is_instantiated(key)) {
|
||||||
|
int err = PTR_ERR(key->payload.data[dns_key_error]);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
seq_printf(m, ": %d", err);
|
seq_printf(m, ": %d", err);
|
||||||
else
|
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,
|
static long dns_resolver_read(const struct key *key,
|
||||||
char __user *buffer, size_t buflen)
|
char __user *buffer, size_t buflen)
|
||||||
{
|
{
|
||||||
if (key->type_data.x[0])
|
int err = PTR_ERR(key->payload.data[dns_key_error]);
|
||||||
return key->type_data.x[0];
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
return user_read(key, buffer, buflen);
|
return user_read(key, buffer, buflen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
|
||||||
const char *options, char **_result, time_t *_expiry)
|
const char *options, char **_result, time_t *_expiry)
|
||||||
{
|
{
|
||||||
struct key *rkey;
|
struct key *rkey;
|
||||||
struct user_key_payload *upayload;
|
const struct user_key_payload *upayload;
|
||||||
const struct cred *saved_cred;
|
const struct cred *saved_cred;
|
||||||
size_t typelen, desclen;
|
size_t typelen, desclen;
|
||||||
char *desc, *cp;
|
char *desc, *cp;
|
||||||
|
@ -137,12 +137,11 @@ int dns_query(const char *type, const char *name, size_t namelen,
|
||||||
goto put;
|
goto put;
|
||||||
|
|
||||||
/* If the DNS server gave an error, return that to the caller */
|
/* 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)
|
if (ret)
|
||||||
goto put;
|
goto put;
|
||||||
|
|
||||||
upayload = rcu_dereference_protected(rkey->payload.data,
|
upayload = user_key_payload(rkey);
|
||||||
lockdep_is_held(&rkey->sem));
|
|
||||||
len = upayload->datalen;
|
len = upayload->datalen;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
|
|
@ -22,6 +22,14 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Layout of key payload words.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
dns_key_data,
|
||||||
|
dns_key_error,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dns_key.c
|
* dns_key.c
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -305,7 +305,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
|
||||||
|
|
||||||
if (!key)
|
if (!key)
|
||||||
key = rx->key;
|
key = rx->key;
|
||||||
if (key && !key->payload.data)
|
if (key && !key->payload.data[0])
|
||||||
key = NULL; /* a no-security key */
|
key = NULL; /* a no-security key */
|
||||||
|
|
||||||
bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
|
bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
|
||||||
|
|
|
@ -148,10 +148,10 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
|
||||||
token->kad->ticket[6], token->kad->ticket[7]);
|
token->kad->ticket[6], token->kad->ticket[7]);
|
||||||
|
|
||||||
/* count the number of tokens attached */
|
/* 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 */
|
/* 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 = &(*pptoken)->next)
|
pptoken = &(*pptoken)->next)
|
||||||
continue;
|
continue;
|
||||||
|
@ -522,7 +522,7 @@ static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
|
||||||
goto inval;
|
goto inval;
|
||||||
|
|
||||||
/* attach the payload */
|
/* 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 = &(*pptoken)->next)
|
pptoken = &(*pptoken)->next)
|
||||||
continue;
|
continue;
|
||||||
|
@ -764,10 +764,10 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
|
||||||
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
|
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
|
||||||
|
|
||||||
/* count the number of tokens attached */
|
/* 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 */
|
/* attach the data */
|
||||||
pp = (struct rxrpc_key_token **)&prep->payload[0];
|
pp = (struct rxrpc_key_token **)&prep->payload.data[0];
|
||||||
while (*pp)
|
while (*pp)
|
||||||
pp = &(*pp)->next;
|
pp = &(*pp)->next;
|
||||||
*pp = token;
|
*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)
|
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)
|
if (prep->datalen != 8)
|
||||||
return -EINVAL;
|
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);
|
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
|
||||||
if (IS_ERR(ci)) {
|
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)
|
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
prep->payload[0] = ci;
|
prep->payload.data[0] = ci;
|
||||||
_leave(" = 0");
|
_leave(" = 0");
|
||||||
return 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)
|
static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
if (prep->payload[0])
|
if (prep->payload.data[0])
|
||||||
crypto_free_blkcipher(prep->payload[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)
|
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)
|
static void rxrpc_destroy_s(struct key *key)
|
||||||
{
|
{
|
||||||
if (key->payload.data) {
|
if (key->payload.data[0]) {
|
||||||
crypto_free_blkcipher(key->payload.data);
|
crypto_free_blkcipher(key->payload.data[0]);
|
||||||
key->payload.data = NULL;
|
key->payload.data[0] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,7 +1070,7 @@ static long rxrpc_read(const struct key *key,
|
||||||
size += 1 * 4; /* token count */
|
size += 1 * 4; /* token count */
|
||||||
|
|
||||||
ntoks = 0;
|
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 */
|
toksize = 4; /* sec index */
|
||||||
|
|
||||||
switch (token->security_index) {
|
switch (token->security_index) {
|
||||||
|
@ -1163,7 +1163,7 @@ static long rxrpc_read(const struct key *key,
|
||||||
ENCODE(ntoks);
|
ENCODE(ntoks);
|
||||||
|
|
||||||
tok = 0;
|
tok = 0;
|
||||||
for (token = key->payload.data; token; token = token->next) {
|
for (token = key->payload.data[0]; token; token = token->next) {
|
||||||
toksize = toksizes[tok++];
|
toksize = toksizes[tok++];
|
||||||
ENCODE(toksize);
|
ENCODE(toksize);
|
||||||
oldxdr = xdr;
|
oldxdr = xdr;
|
||||||
|
|
|
@ -158,7 +158,7 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans,
|
||||||
service_id = htons(srx->srx_service);
|
service_id = htons(srx->srx_service);
|
||||||
}
|
}
|
||||||
key = rx->key;
|
key = rx->key;
|
||||||
if (key && !rx->key->payload.data)
|
if (key && !rx->key->payload.data[0])
|
||||||
key = NULL;
|
key = NULL;
|
||||||
bundle = rxrpc_get_bundle(rx, trans, key, service_id,
|
bundle = rxrpc_get_bundle(rx, trans, key, service_id,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
|
@ -137,9 +137,9 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!key->payload.data)
|
token = key->payload.data[0];
|
||||||
|
if (!token)
|
||||||
return -EKEYREJECTED;
|
return -EKEYREJECTED;
|
||||||
token = key->payload.data;
|
|
||||||
|
|
||||||
sec = rxrpc_security_lookup(token->security_index);
|
sec = rxrpc_security_lookup(token->security_index);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
|
|
|
@ -67,7 +67,7 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn)
|
||||||
|
|
||||||
_enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
|
_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;
|
conn->security_ix = token->security_index;
|
||||||
|
|
||||||
ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
|
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)
|
if (!conn->key)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
token = conn->key->payload.data;
|
token = conn->key->payload.data[0];
|
||||||
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||||
|
|
||||||
desc.tfm = conn->cipher;
|
desc.tfm = conn->cipher;
|
||||||
|
@ -221,7 +221,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
||||||
rxkhdr.checksum = 0;
|
rxkhdr.checksum = 0;
|
||||||
|
|
||||||
/* encrypt from the session key */
|
/* 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));
|
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||||
desc.tfm = call->conn->cipher;
|
desc.tfm = call->conn->cipher;
|
||||||
desc.info = iv.x;
|
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);
|
skb_to_sgvec(skb, sg, 0, skb->len);
|
||||||
|
|
||||||
/* decrypt from the session key */
|
/* 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));
|
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||||
desc.tfm = call->conn->cipher;
|
desc.tfm = call->conn->cipher;
|
||||||
desc.info = iv.x;
|
desc.info = iv.x;
|
||||||
|
@ -780,7 +780,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
|
||||||
if (conn->security_level < min_level)
|
if (conn->security_level < min_level)
|
||||||
goto protocol_error;
|
goto protocol_error;
|
||||||
|
|
||||||
token = conn->key->payload.data;
|
token = conn->key->payload.data[0];
|
||||||
|
|
||||||
/* build the response packet */
|
/* build the response packet */
|
||||||
memset(&resp, 0, sizeof(resp));
|
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);
|
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.info = iv.x;
|
||||||
desc.flags = 0;
|
desc.flags = 0;
|
||||||
|
|
||||||
|
|
136
scripts/extract-module-sig.pl
Executable file
136
scripts/extract-module-sig.pl
Executable 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
144
scripts/extract-sys-certs.pl
Executable 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;
|
|
@ -33,7 +33,7 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
|
||||||
config SECURITY_APPARMOR_HASH
|
config SECURITY_APPARMOR_HASH
|
||||||
bool "SHA1 hash of loaded profiles"
|
bool "SHA1 hash of loaded profiles"
|
||||||
depends on SECURITY_APPARMOR
|
depends on SECURITY_APPARMOR
|
||||||
depends on CRYPTO
|
select CRYPTO
|
||||||
select CRYPTO_SHA1
|
select CRYPTO_SHA1
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
|
||||||
rc,
|
rc,
|
||||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||||
KEY_USR_VIEW | KEY_USR_READ),
|
KEY_USR_VIEW | KEY_USR_READ),
|
||||||
KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
|
KEY_ALLOC_NOT_IN_QUOTA);
|
||||||
if (IS_ERR(key)) {
|
if (IS_ERR(key)) {
|
||||||
rc = PTR_ERR(key);
|
rc = PTR_ERR(key);
|
||||||
pr_err("Problem loading X.509 certificate (%d): %s\n",
|
pr_err("Problem loading X.509 certificate (%d): %s\n",
|
||||||
|
|
|
@ -247,7 +247,7 @@ int evm_init_key(void)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
down_read(&evm_key->sem);
|
down_read(&evm_key->sem);
|
||||||
ekp = evm_key->payload.data;
|
ekp = evm_key->payload.data[0];
|
||||||
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
|
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -20,6 +20,16 @@
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
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
|
* 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
|
* 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)
|
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;
|
struct file *file;
|
||||||
ssize_t written;
|
ssize_t written;
|
||||||
size_t datalen = prep->datalen;
|
size_t datalen = prep->datalen;
|
||||||
|
@ -60,7 +70,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
|
||||||
/* Set an arbitrary quota */
|
/* Set an arbitrary quota */
|
||||||
prep->quotalen = 16;
|
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) {
|
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||||
/* Create a shmem file to store the data in. This will permit the data
|
/* 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)
|
if (!data)
|
||||||
return -ENOMEM;
|
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;
|
return 0;
|
||||||
|
|
||||||
|
@ -110,10 +121,10 @@ error:
|
||||||
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
|
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);
|
path_put(path);
|
||||||
} else {
|
} 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)
|
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 */
|
/* clear the quota */
|
||||||
key_payload_reserve(key, 0);
|
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);
|
vfs_truncate(path, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,14 +148,16 @@ void big_key_revoke(struct key *key)
|
||||||
*/
|
*/
|
||||||
void big_key_destroy(struct key *key)
|
void big_key_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
|
size_t datalen = (size_t)key->payload.data[big_key_len];
|
||||||
struct path *path = (struct path *)&key->payload.data2;
|
|
||||||
|
if (datalen) {
|
||||||
|
struct path *path = (struct path *)&key->payload.data[big_key_path];
|
||||||
path_put(path);
|
path_put(path);
|
||||||
path->mnt = NULL;
|
path->mnt = NULL;
|
||||||
path->dentry = NULL;
|
path->dentry = NULL;
|
||||||
} else {
|
} else {
|
||||||
kfree(key->payload.data);
|
kfree(key->payload.data[big_key_data]);
|
||||||
key->payload.data = NULL;
|
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)
|
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);
|
seq_puts(m, key->description);
|
||||||
|
|
||||||
if (key_is_instantiated(key))
|
if (key_is_instantiated(key))
|
||||||
seq_printf(m, ": %lu [%s]",
|
seq_printf(m, ": %zu [%s]",
|
||||||
datalen,
|
datalen,
|
||||||
datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
|
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)
|
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;
|
long ret;
|
||||||
|
|
||||||
if (!buffer || buflen < datalen)
|
if (!buffer || buflen < datalen)
|
||||||
return datalen;
|
return datalen;
|
||||||
|
|
||||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
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;
|
struct file *file;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
|
|
||||||
|
@ -190,7 +204,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
} else {
|
} else {
|
||||||
ret = datalen;
|
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;
|
ret = -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,10 +303,10 @@ out:
|
||||||
*
|
*
|
||||||
* Use a user provided key to encrypt/decrypt an encrypted-key.
|
* 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)
|
size_t *master_keylen)
|
||||||
{
|
{
|
||||||
struct user_key_payload *upayload;
|
const struct user_key_payload *upayload;
|
||||||
struct key *ukey;
|
struct key *ukey;
|
||||||
|
|
||||||
ukey = request_key(&key_type_user, master_desc, NULL);
|
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;
|
goto error;
|
||||||
|
|
||||||
down_read(&ukey->sem);
|
down_read(&ukey->sem);
|
||||||
upayload = ukey->payload.data;
|
upayload = user_key_payload(ukey);
|
||||||
*master_key = upayload->data;
|
*master_key = upayload->data;
|
||||||
*master_keylen = upayload->datalen;
|
*master_keylen = upayload->datalen;
|
||||||
error:
|
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,
|
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;
|
struct key *mkey = NULL;
|
||||||
|
|
||||||
|
@ -653,7 +653,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
|
||||||
{
|
{
|
||||||
struct key *mkey;
|
struct key *mkey;
|
||||||
u8 derived_key[HASH_SIZE];
|
u8 derived_key[HASH_SIZE];
|
||||||
u8 *master_key;
|
const u8 *master_key;
|
||||||
u8 *hmac;
|
u8 *hmac;
|
||||||
const char *hex_encoded_data;
|
const char *hex_encoded_data;
|
||||||
unsigned int encrypted_datalen;
|
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)
|
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;
|
struct encrypted_key_payload *new_epayload;
|
||||||
char *buf;
|
char *buf;
|
||||||
char *new_master_desc = NULL;
|
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 encrypted_key_payload *epayload;
|
||||||
struct key *mkey;
|
struct key *mkey;
|
||||||
u8 *master_key;
|
const u8 *master_key;
|
||||||
size_t master_keylen;
|
size_t master_keylen;
|
||||||
char derived_key[HASH_SIZE];
|
char derived_key[HASH_SIZE];
|
||||||
char *ascii_buf;
|
char *ascii_buf;
|
||||||
|
@ -957,13 +957,13 @@ out:
|
||||||
*/
|
*/
|
||||||
static void encrypted_destroy(struct key *key)
|
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)
|
if (!epayload)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
|
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
|
||||||
kfree(key->payload.data);
|
kfree(key->payload.data[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_type key_type_encrypted = {
|
struct key_type key_type_encrypted = {
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
#if defined(CONFIG_TRUSTED_KEYS) || \
|
#if defined(CONFIG_TRUSTED_KEYS) || \
|
||||||
(defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
|
(defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
|
||||||
extern struct key *request_trusted_key(const char *trusted_desc,
|
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
|
#else
|
||||||
static inline struct key *request_trusted_key(const char *trusted_desc,
|
static inline struct key *request_trusted_key(const char *trusted_desc,
|
||||||
u8 **master_key,
|
const u8 **master_key,
|
||||||
size_t *master_keylen)
|
size_t *master_keylen)
|
||||||
{
|
{
|
||||||
return ERR_PTR(-EOPNOTSUPP);
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
* data, trusted key type data is not visible decrypted from userspace.
|
* data, trusted key type data is not visible decrypted from userspace.
|
||||||
*/
|
*/
|
||||||
struct key *request_trusted_key(const char *trusted_desc,
|
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 trusted_key_payload *tpayload;
|
||||||
struct key *tkey;
|
struct key *tkey;
|
||||||
|
@ -39,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
down_read(&tkey->sem);
|
down_read(&tkey->sem);
|
||||||
tpayload = tkey->payload.data;
|
tpayload = tkey->payload.data[0];
|
||||||
*master_key = tpayload->key;
|
*master_key = tpayload->key;
|
||||||
*master_keylen = tpayload->key_len;
|
*master_keylen = tpayload->key_len;
|
||||||
error:
|
error:
|
||||||
|
|
|
@ -278,7 +278,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
|
||||||
|
|
||||||
key->index_key.desc_len = desclen;
|
key->index_key.desc_len = desclen;
|
||||||
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
|
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
|
||||||
if (!key->description)
|
if (!key->index_key.description)
|
||||||
goto no_memory_3;
|
goto no_memory_3;
|
||||||
|
|
||||||
atomic_set(&key->usage, 1);
|
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)) {
|
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
|
||||||
/* mark the key as being negatively instantiated */
|
/* mark the key as being negatively instantiated */
|
||||||
atomic_inc(&key->user->nikeys);
|
atomic_inc(&key->user->nikeys);
|
||||||
key->type_data.reject_error = -error;
|
key->reject_error = -error;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
||||||
set_bit(KEY_FLAG_INSTANTIATED, &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);
|
ret = key_payload_reserve(key, prep->quotalen);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
key->type_data.p[0] = prep->type_data[0];
|
rcu_assign_keypointer(key, prep->payload.data[0]);
|
||||||
key->type_data.p[1] = prep->type_data[1];
|
key->payload.data[1] = prep->payload.data[1];
|
||||||
rcu_assign_keypointer(key, prep->payload[0]);
|
key->payload.data[2] = prep->payload.data[2];
|
||||||
key->payload.data2[1] = prep->payload[1];
|
key->payload.data[3] = prep->payload.data[3];
|
||||||
prep->type_data[0] = NULL;
|
prep->payload.data[0] = NULL;
|
||||||
prep->type_data[1] = NULL;
|
prep->payload.data[1] = NULL;
|
||||||
prep->payload[0] = NULL;
|
prep->payload.data[2] = NULL;
|
||||||
prep->payload[1] = NULL;
|
prep->payload.data[3] = NULL;
|
||||||
}
|
}
|
||||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -67,7 +67,6 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||||
char type[32], *description;
|
char type[32], *description;
|
||||||
void *payload;
|
void *payload;
|
||||||
long ret;
|
long ret;
|
||||||
bool vm;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (plen > 1024 * 1024 - 1)
|
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 */
|
/* pull the payload in if one was supplied */
|
||||||
payload = NULL;
|
payload = NULL;
|
||||||
|
|
||||||
vm = false;
|
|
||||||
if (_payload) {
|
if (_payload) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
|
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
if (plen <= PAGE_SIZE)
|
if (plen <= PAGE_SIZE)
|
||||||
goto error2;
|
goto error2;
|
||||||
vm = true;
|
|
||||||
payload = vmalloc(plen);
|
payload = vmalloc(plen);
|
||||||
if (!payload)
|
if (!payload)
|
||||||
goto error2;
|
goto error2;
|
||||||
|
@ -138,10 +135,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||||
|
|
||||||
key_ref_put(keyring_ref);
|
key_ref_put(keyring_ref);
|
||||||
error3:
|
error3:
|
||||||
if (!vm)
|
kvfree(payload);
|
||||||
kfree(payload);
|
|
||||||
else
|
|
||||||
vfree(payload);
|
|
||||||
error2:
|
error2:
|
||||||
kfree(description);
|
kfree(description);
|
||||||
error:
|
error:
|
||||||
|
@ -1033,7 +1027,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
|
||||||
if (!instkey)
|
if (!instkey)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
rka = instkey->payload.data;
|
rka = instkey->payload.data[0];
|
||||||
if (rka->target_key->serial != id)
|
if (rka->target_key->serial != id)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1200,7 +1194,7 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
|
||||||
if (!instkey)
|
if (!instkey)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
rka = instkey->payload.data;
|
rka = instkey->payload.data[0];
|
||||||
if (rka->target_key->serial != id)
|
if (rka->target_key->serial != id)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ static void keyring_publish_name(struct key *keyring)
|
||||||
if (!keyring_name_hash[bucket].next)
|
if (!keyring_name_hash[bucket].next)
|
||||||
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
|
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
|
||||||
|
|
||||||
list_add_tail(&keyring->type_data.link,
|
list_add_tail(&keyring->name_link,
|
||||||
&keyring_name_hash[bucket]);
|
&keyring_name_hash[bucket]);
|
||||||
|
|
||||||
write_unlock(&keyring_name_lock);
|
write_unlock(&keyring_name_lock);
|
||||||
|
@ -387,9 +387,9 @@ static void keyring_destroy(struct key *keyring)
|
||||||
if (keyring->description) {
|
if (keyring->description) {
|
||||||
write_lock(&keyring_name_lock);
|
write_lock(&keyring_name_lock);
|
||||||
|
|
||||||
if (keyring->type_data.link.next != NULL &&
|
if (keyring->name_link.next != NULL &&
|
||||||
!list_empty(&keyring->type_data.link))
|
!list_empty(&keyring->name_link))
|
||||||
list_del(&keyring->type_data.link);
|
list_del(&keyring->name_link);
|
||||||
|
|
||||||
write_unlock(&keyring_name_lock);
|
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 */
|
/* we set a different error code if we pass a negative key */
|
||||||
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
|
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
ctx->result = ERR_PTR(key->type_data.reject_error);
|
ctx->result = ERR_PTR(key->reject_error);
|
||||||
kleave(" = %d [neg]", ctx->skipped_ret);
|
kleave(" = %d [neg]", ctx->skipped_ret);
|
||||||
goto skipped;
|
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 */
|
* that's readable and that hasn't been revoked */
|
||||||
list_for_each_entry(keyring,
|
list_for_each_entry(keyring,
|
||||||
&keyring_name_hash[bucket],
|
&keyring_name_hash[bucket],
|
||||||
type_data.link
|
name_link
|
||||||
) {
|
) {
|
||||||
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
|
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -457,7 +457,7 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
|
||||||
down_read(&cred->request_key_auth->sem);
|
down_read(&cred->request_key_auth->sem);
|
||||||
|
|
||||||
if (key_validate(ctx->cred->request_key_auth) == 0) {
|
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;
|
ctx->cred = rka->cred;
|
||||||
key_ref = search_process_keyrings(ctx);
|
key_ref = search_process_keyrings(ctx);
|
||||||
|
@ -647,7 +647,7 @@ try_again:
|
||||||
key_ref = ERR_PTR(-EKEYREVOKED);
|
key_ref = ERR_PTR(-EKEYREVOKED);
|
||||||
key = NULL;
|
key = NULL;
|
||||||
} else {
|
} else {
|
||||||
rka = ctx.cred->request_key_auth->payload.data;
|
rka = ctx.cred->request_key_auth->payload.data[0];
|
||||||
key = rka->dest_keyring;
|
key = rka->dest_keyring;
|
||||||
__key_get(key);
|
__key_get(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,7 +271,7 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
|
||||||
if (cred->request_key_auth) {
|
if (cred->request_key_auth) {
|
||||||
authkey = cred->request_key_auth;
|
authkey = cred->request_key_auth;
|
||||||
down_read(&authkey->sem);
|
down_read(&authkey->sem);
|
||||||
rka = authkey->payload.data;
|
rka = authkey->payload.data[0];
|
||||||
if (!test_bit(KEY_FLAG_REVOKED,
|
if (!test_bit(KEY_FLAG_REVOKED,
|
||||||
&authkey->flags))
|
&authkey->flags))
|
||||||
dest_keyring =
|
dest_keyring =
|
||||||
|
@ -596,7 +596,7 @@ int wait_for_key_construction(struct key *key, bool intr)
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
|
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
return key->type_data.reject_error;
|
return key->reject_error;
|
||||||
}
|
}
|
||||||
return key_validate(key);
|
return key_validate(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
static int request_key_auth_instantiate(struct key *key,
|
||||||
struct key_preparsed_payload *prep)
|
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;
|
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,
|
static void request_key_auth_describe(const struct key *key,
|
||||||
struct seq_file *m)
|
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:");
|
||||||
seq_puts(m, key->description);
|
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,
|
static long request_key_auth_read(const struct key *key,
|
||||||
char __user *buffer, size_t buflen)
|
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;
|
size_t datalen;
|
||||||
long ret;
|
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)
|
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);
|
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)
|
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);
|
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))
|
if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
|
||||||
goto auth_key_revoked;
|
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->cred = get_cred(irka->cred);
|
||||||
rka->pid = irka->pid;
|
rka->pid = irka->pid;
|
||||||
|
|
||||||
|
|
|
@ -862,12 +862,19 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p,
|
||||||
static struct trusted_key_options *trusted_options_alloc(void)
|
static struct trusted_key_options *trusted_options_alloc(void)
|
||||||
{
|
{
|
||||||
struct trusted_key_options *options;
|
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);
|
options = kzalloc(sizeof *options, GFP_KERNEL);
|
||||||
if (options) {
|
if (options) {
|
||||||
/* set any non-zero defaults */
|
/* set any non-zero defaults */
|
||||||
options->keytype = SRK_keytype;
|
options->keytype = SRK_keytype;
|
||||||
options->keyhandle = SRKHANDLE;
|
|
||||||
|
if (!tpm2)
|
||||||
|
options->keyhandle = SRKHANDLE;
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
@ -905,6 +912,11 @@ static int trusted_instantiate(struct key *key,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int key_cmd;
|
int key_cmd;
|
||||||
size_t key_len;
|
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)
|
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -932,12 +944,20 @@ static int trusted_instantiate(struct key *key,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options->keyhandle) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
dump_payload(payload);
|
dump_payload(payload);
|
||||||
dump_options(options);
|
dump_options(options);
|
||||||
|
|
||||||
switch (key_cmd) {
|
switch (key_cmd) {
|
||||||
case Opt_load:
|
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_payload(payload);
|
||||||
dump_options(options);
|
dump_options(options);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -950,7 +970,10 @@ static int trusted_instantiate(struct key *key,
|
||||||
pr_info("trusted_key: key_create failed (%d)\n", ret);
|
pr_info("trusted_key: key_create failed (%d)\n", ret);
|
||||||
goto out;
|
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)
|
if (ret < 0)
|
||||||
pr_info("trusted_key: key_seal failed (%d)\n", ret);
|
pr_info("trusted_key: key_seal failed (%d)\n", ret);
|
||||||
break;
|
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)
|
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_payload *new_p;
|
||||||
struct trusted_key_options *new_o;
|
struct trusted_key_options *new_o;
|
||||||
size_t datalen = prep->datalen;
|
size_t datalen = prep->datalen;
|
||||||
|
@ -1018,6 +1041,13 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
kfree(new_p);
|
kfree(new_p);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!new_o->keyhandle) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
kfree(new_p);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* copy old key values, and reseal with new pcrs */
|
/* copy old key values, and reseal with new pcrs */
|
||||||
new_p->migratable = p->migratable;
|
new_p->migratable = p->migratable;
|
||||||
new_p->key_len = p->key_len;
|
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)
|
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)
|
if (!p)
|
||||||
return;
|
return;
|
||||||
memset(p->key, 0, p->key_len);
|
memset(p->key, 0, p->key_len);
|
||||||
kfree(key->payload.data);
|
kfree(key->payload.data[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_type key_type_trusted = {
|
struct key_type key_type_trusted = {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define __TRUSTED_KEY_H
|
#define __TRUSTED_KEY_H
|
||||||
|
|
||||||
/* implementation specific TPM constants */
|
/* implementation specific TPM constants */
|
||||||
#define MAX_PCRINFO_SIZE 64
|
|
||||||
#define MAX_BUF_SIZE 512
|
#define MAX_BUF_SIZE 512
|
||||||
#define TPM_GETRANDOM_SIZE 14
|
#define TPM_GETRANDOM_SIZE 14
|
||||||
#define TPM_OSAP_SIZE 36
|
#define TPM_OSAP_SIZE 36
|
||||||
|
@ -36,16 +35,6 @@ enum {
|
||||||
SRK_keytype = 4
|
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
|
#define TPM_DEBUG 0
|
||||||
|
|
||||||
#if TPM_DEBUG
|
#if TPM_DEBUG
|
||||||
|
|
|
@ -74,7 +74,7 @@ int user_preparse(struct key_preparsed_payload *prep)
|
||||||
|
|
||||||
/* attach the data */
|
/* attach the data */
|
||||||
prep->quotalen = datalen;
|
prep->quotalen = datalen;
|
||||||
prep->payload[0] = upayload;
|
prep->payload.data[0] = upayload;
|
||||||
upayload->datalen = datalen;
|
upayload->datalen = datalen;
|
||||||
memcpy(upayload->data, prep->data, datalen);
|
memcpy(upayload->data, prep->data, datalen);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(user_preparse);
|
||||||
*/
|
*/
|
||||||
void user_free_preparse(struct key_preparsed_payload *prep)
|
void user_free_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
kfree(prep->payload[0]);
|
kfree(prep->payload.data[0]);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(user_free_preparse);
|
EXPORT_SYMBOL_GPL(user_free_preparse);
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/* attach the new data, displacing the old */
|
/* attach the new data, displacing the old */
|
||||||
zap = key->payload.data;
|
zap = key->payload.data[0];
|
||||||
rcu_assign_keypointer(key, upayload);
|
rcu_assign_keypointer(key, upayload);
|
||||||
key->expiry = 0;
|
key->expiry = 0;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(user_update);
|
||||||
*/
|
*/
|
||||||
void user_revoke(struct key *key)
|
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 */
|
/* clear the quota */
|
||||||
key_payload_reserve(key, 0);
|
key_payload_reserve(key, 0);
|
||||||
|
@ -158,7 +158,7 @@ EXPORT_SYMBOL(user_revoke);
|
||||||
*/
|
*/
|
||||||
void user_destroy(struct key *key)
|
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);
|
kfree(upayload);
|
||||||
}
|
}
|
||||||
|
@ -183,10 +183,10 @@ EXPORT_SYMBOL_GPL(user_describe);
|
||||||
*/
|
*/
|
||||||
long user_read(const struct key *key, char __user *buffer, size_t buflen)
|
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;
|
long ret;
|
||||||
|
|
||||||
upayload = rcu_dereference_key(key);
|
upayload = user_key_payload(key);
|
||||||
ret = upayload->datalen;
|
ret = upayload->datalen;
|
||||||
|
|
||||||
/* we can return the data as is */
|
/* we can return the data as is */
|
||||||
|
|
|
@ -78,7 +78,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
|
||||||
int "NSA SELinux checkreqprot default value"
|
int "NSA SELinux checkreqprot default value"
|
||||||
depends on SECURITY_SELINUX
|
depends on SECURITY_SELINUX
|
||||||
range 0 1
|
range 0 1
|
||||||
default 1
|
default 0
|
||||||
help
|
help
|
||||||
This option sets the default value for the 'checkreqprot' flag
|
This option sets the default value for the 'checkreqprot' flag
|
||||||
that determines whether SELinux checks the protection requested
|
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
|
'checkreqprot=' boot parameter. It may also be changed at runtime
|
||||||
via /selinux/checkreqprot if authorized by policy.
|
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
|
config SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||||
bool "NSA SELinux maximum supported policy format version"
|
bool "NSA SELinux maximum supported policy format version"
|
||||||
|
|
|
@ -126,6 +126,7 @@ int selinux_enabled = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct kmem_cache *sel_inode_cache;
|
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
|
* 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;
|
struct file_security_struct *fsec;
|
||||||
u32 sid = current_sid();
|
u32 sid = current_sid();
|
||||||
|
|
||||||
fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
|
fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
|
||||||
if (!fsec)
|
if (!fsec)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -302,7 +303,7 @@ static void file_free_security(struct file *file)
|
||||||
{
|
{
|
||||||
struct file_security_struct *fsec = file->f_security;
|
struct file_security_struct *fsec = file->f_security;
|
||||||
file->f_security = NULL;
|
file->f_security = NULL;
|
||||||
kfree(fsec);
|
kmem_cache_free(file_security_cache, fsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int superblock_alloc_security(struct super_block *sb)
|
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)
|
if (flags[i] == SBLABEL_MNT)
|
||||||
continue;
|
continue;
|
||||||
rc = security_context_to_sid(mount_options[i],
|
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
|
||||||
strlen(mount_options[i]), &sid, GFP_KERNEL);
|
|
||||||
if (rc) {
|
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",
|
"(%s) failed for (dev %s, type %s) errno=%d\n",
|
||||||
mount_options[i], sb->s_id, name, rc);
|
mount_options[i], sb->s_id, name, rc);
|
||||||
goto out;
|
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++) {
|
for (i = 0; i < opts.num_mnt_opts; i++) {
|
||||||
u32 sid;
|
u32 sid;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (flags[i] == SBLABEL_MNT)
|
if (flags[i] == SBLABEL_MNT)
|
||||||
continue;
|
continue;
|
||||||
len = strlen(mount_options[i]);
|
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
|
||||||
rc = security_context_to_sid(mount_options[i], len, &sid,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (rc) {
|
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",
|
"(%s) failed for (dev %s, type %s) errno=%d\n",
|
||||||
mount_options[i], sb->s_id, sb->s_type->name, rc);
|
mount_options[i], sb->s_id, sb->s_type->name, rc);
|
||||||
goto out_free_opts;
|
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))
|
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
|
||||||
return dentry_has_perm(cred, dentry, FILE__SETATTR);
|
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;
|
av |= FILE__OPEN;
|
||||||
|
|
||||||
return dentry_has_perm(cred, dentry, av);
|
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)
|
if (!value || !size)
|
||||||
return -EACCES;
|
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)
|
if (rc)
|
||||||
return 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
|
* Check whether a task has the ioctl permission and cmd
|
||||||
* operation to an inode.
|
* 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)
|
u32 requested, u16 cmd)
|
||||||
{
|
{
|
||||||
struct common_audit_data ad;
|
struct common_audit_data ad;
|
||||||
|
@ -6093,6 +6091,9 @@ static __init int selinux_init(void)
|
||||||
sel_inode_cache = kmem_cache_create("selinux_inode_security",
|
sel_inode_cache = kmem_cache_create("selinux_inode_security",
|
||||||
sizeof(struct inode_security_struct),
|
sizeof(struct inode_security_struct),
|
||||||
0, SLAB_PANIC, NULL);
|
0, SLAB_PANIC, NULL);
|
||||||
|
file_security_cache = kmem_cache_create("selinux_file_security",
|
||||||
|
sizeof(struct file_security_struct),
|
||||||
|
0, SLAB_PANIC, NULL);
|
||||||
avc_init();
|
avc_init();
|
||||||
|
|
||||||
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
|
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
|
||||||
|
|
|
@ -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,
|
int security_context_to_sid(const char *scontext, u32 scontext_len,
|
||||||
u32 *out_sid, gfp_t gfp);
|
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,
|
int security_context_to_sid_default(const char *scontext, u32 scontext_len,
|
||||||
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
|
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
|
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
|
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -819,13 +817,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
|
||||||
objname = namebuf;
|
objname = namebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
|
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
|
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
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)
|
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
|
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
|
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
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)
|
if (sscanf(buf, "%s %s", con, user) != 2)
|
||||||
goto out;
|
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)
|
if (length)
|
||||||
goto out;
|
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)
|
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
|
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
|
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (length)
|
if (length)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* 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_USERS, context->user - 1),
|
||||||
sym_name(&policydb, SYM_ROLES, context->role - 1),
|
sym_name(&policydb, SYM_ROLES, context->role - 1),
|
||||||
sym_name(&policydb, SYM_TYPES, context->type - 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);
|
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;
|
*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
|
||||||
if (!scontext)
|
if (!scontext)
|
||||||
goto out;
|
goto out;
|
||||||
scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
|
scontextp = kmemdup(initial_sid_to_string[sid],
|
||||||
|
*scontext_len, GFP_ATOMIC);
|
||||||
if (!scontextp) {
|
if (!scontextp) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
strcpy(scontextp, initial_sid_to_string[sid]);
|
|
||||||
*scontext = scontextp;
|
*scontext = scontextp;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1476,6 +1473,11 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
|
||||||
sid, SECSID_NULL, gfp, 0);
|
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,
|
* security_context_to_sid_default - Obtain a SID for a given security context,
|
||||||
* falling back to specified default if needed.
|
* falling back to specified default if needed.
|
||||||
|
@ -2604,18 +2606,12 @@ int security_get_bools(int *len, char ***names, int **values)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
for (i = 0; i < *len; i++) {
|
for (i = 0; i < *len; i++) {
|
||||||
size_t name_len;
|
|
||||||
|
|
||||||
(*values)[i] = policydb.bool_val_to_struct[i]->state;
|
(*values)[i] = policydb.bool_val_to_struct[i]->state;
|
||||||
name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
|
|
||||||
|
|
||||||
rc = -ENOMEM;
|
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])
|
if (!(*names)[i])
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
|
|
||||||
(*names)[i][name_len - 1] = 0;
|
|
||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -115,6 +115,7 @@ struct task_smack {
|
||||||
struct smack_known *smk_forked; /* label when forked */
|
struct smack_known *smk_forked; /* label when forked */
|
||||||
struct list_head smk_rules; /* per task access rules */
|
struct list_head smk_rules; /* per task access rules */
|
||||||
struct mutex smk_rules_lock; /* lock for the 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 */
|
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
|
||||||
|
@ -169,7 +170,7 @@ struct smk_port_label {
|
||||||
};
|
};
|
||||||
#endif /* SMACK_IPV6_PORT_LABELING */
|
#endif /* SMACK_IPV6_PORT_LABELING */
|
||||||
|
|
||||||
struct smack_onlycap {
|
struct smack_known_list_elem {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct smack_known *smk_label;
|
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);
|
void smk_insert_entry(struct smack_known *skp);
|
||||||
struct smack_known *smk_find_entry(const char *);
|
struct smack_known *smk_find_entry(const char *);
|
||||||
int smack_privileged(int cap);
|
int smack_privileged(int cap);
|
||||||
|
void smk_destroy_label_list(struct list_head *list);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared data.
|
* Shared data.
|
||||||
|
|
|
@ -637,7 +637,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
|
||||||
int smack_privileged(int cap)
|
int smack_privileged(int cap)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = smk_of_current();
|
struct smack_known *skp = smk_of_current();
|
||||||
struct smack_onlycap *sop;
|
struct smack_known_list_elem *sklep;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All kernel tasks are privileged
|
* All kernel tasks are privileged
|
||||||
|
@ -654,8 +654,8 @@ int smack_privileged(int cap)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
|
list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
|
||||||
if (sop->smk_label == skp) {
|
if (sklep->smk_label == skp) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
#define SMK_SENDING 2
|
#define SMK_SENDING 2
|
||||||
|
|
||||||
#ifdef SMACK_IPV6_PORT_LABELING
|
#ifdef SMACK_IPV6_PORT_LABELING
|
||||||
LIST_HEAD(smk_ipv6_port_list);
|
static LIST_HEAD(smk_ipv6_port_list);
|
||||||
#endif
|
#endif
|
||||||
static struct kmem_cache *smack_inode_cache;
|
static struct kmem_cache *smack_inode_cache;
|
||||||
int smack_enabled;
|
int smack_enabled;
|
||||||
|
@ -326,6 +326,7 @@ static struct task_smack *new_task_smack(struct smack_known *task,
|
||||||
tsp->smk_task = task;
|
tsp->smk_task = task;
|
||||||
tsp->smk_forked = forked;
|
tsp->smk_forked = forked;
|
||||||
INIT_LIST_HEAD(&tsp->smk_rules);
|
INIT_LIST_HEAD(&tsp->smk_rules);
|
||||||
|
INIT_LIST_HEAD(&tsp->smk_relabel);
|
||||||
mutex_init(&tsp->smk_rules_lock);
|
mutex_init(&tsp->smk_rules_lock);
|
||||||
|
|
||||||
return tsp;
|
return tsp;
|
||||||
|
@ -360,6 +361,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
|
||||||
return rc;
|
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_*
|
* smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
|
||||||
* @mode - input mode in form of PTRACE_MODE_*
|
* @mode - input mode in form of PTRACE_MODE_*
|
||||||
|
@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred)
|
||||||
return;
|
return;
|
||||||
cred->security = NULL;
|
cred->security = NULL;
|
||||||
|
|
||||||
|
smk_destroy_label_list(&tsp->smk_relabel);
|
||||||
|
|
||||||
list_for_each_safe(l, n, &tsp->smk_rules) {
|
list_for_each_safe(l, n, &tsp->smk_rules) {
|
||||||
rp = list_entry(l, struct smack_rule, list);
|
rp = list_entry(l, struct smack_rule, list);
|
||||||
list_del(&rp->list);
|
list_del(&rp->list);
|
||||||
|
@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
|
||||||
|
gfp);
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
new->security = new_tsp;
|
new->security = new_tsp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3354,6 +3391,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
*/
|
*/
|
||||||
isp->smk_inode = smk_of_current();
|
isp->smk_inode = smk_of_current();
|
||||||
break;
|
break;
|
||||||
|
case PIPEFS_MAGIC:
|
||||||
|
isp->smk_inode = smk_of_current();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
isp->smk_inode = sbsp->smk_root;
|
isp->smk_inode = sbsp->smk_root;
|
||||||
break;
|
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,
|
static int smack_setprocattr(struct task_struct *p, char *name,
|
||||||
void *value, size_t size)
|
void *value, size_t size)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp;
|
struct task_smack *tsp = current_security();
|
||||||
struct cred *new;
|
struct cred *new;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
struct smack_known_list_elem *sklep;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Changing another process' Smack value is too dangerous
|
* 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)
|
if (p != current)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
|
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)
|
if (skp == &smack_known_web)
|
||||||
return -EPERM;
|
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();
|
new = prepare_creds();
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
tsp = new->security;
|
tsp = new->security;
|
||||||
tsp->smk_task = skp;
|
tsp->smk_task = skp;
|
||||||
|
/*
|
||||||
|
* process can change its label only once
|
||||||
|
*/
|
||||||
|
smk_destroy_label_list(&tsp->smk_relabel);
|
||||||
|
|
||||||
commit_creds(new);
|
commit_creds(new);
|
||||||
return size;
|
return size;
|
||||||
|
@ -4708,8 +4765,6 @@ static __init int smack_init(void)
|
||||||
if (!security_module_enable("smack"))
|
if (!security_module_enable("smack"))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
smack_enabled = 1;
|
|
||||||
|
|
||||||
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
|
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
|
||||||
if (!smack_inode_cache)
|
if (!smack_inode_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -4721,6 +4776,8 @@ static __init int smack_init(void)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
smack_enabled = 1;
|
||||||
|
|
||||||
pr_info("Smack: Initializing.\n");
|
pr_info("Smack: Initializing.\n");
|
||||||
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
|
||||||
pr_info("Smack: Netfilter enabled.\n");
|
pr_info("Smack: Netfilter enabled.\n");
|
||||||
|
|
|
@ -61,6 +61,7 @@ enum smk_inos {
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
SMK_NET6ADDR = 23, /* single label IPv6 hosts */
|
SMK_NET6ADDR = 23, /* single label IPv6 hosts */
|
||||||
#endif /* CONFIG_IPV6 */
|
#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] != '-') {
|
if (smack[0] != '-') {
|
||||||
skp = smk_import_entry(smack, 0);
|
skp = smk_import_entry(smack, 0);
|
||||||
if (skp == NULL) {
|
if (IS_ERR(skp)) {
|
||||||
rc = -EINVAL;
|
rc = PTR_ERR(skp);
|
||||||
goto free_out;
|
goto free_out;
|
||||||
}
|
}
|
||||||
} else {
|
} 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)
|
static int onlycap_seq_show(struct seq_file *s, void *v)
|
||||||
{
|
{
|
||||||
struct list_head *list = v;
|
struct list_head *list = v;
|
||||||
struct smack_onlycap *sop =
|
struct smack_known_list_elem *sklep =
|
||||||
list_entry_rcu(list, struct smack_onlycap, list);
|
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, ' ');
|
seq_putc(s, ' ');
|
||||||
|
|
||||||
return 0;
|
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
|
* smk_write_onlycap - write() for smackfs/onlycap
|
||||||
* @file: file pointer, not actually used
|
* @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)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
char *data_parse;
|
|
||||||
char *tok;
|
|
||||||
struct smack_known *skp;
|
|
||||||
struct smack_onlycap *sop;
|
|
||||||
struct smack_onlycap *sop2;
|
|
||||||
LIST_HEAD(list_tmp);
|
LIST_HEAD(list_tmp);
|
||||||
int rc = count;
|
int rc;
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
@ -2006,26 +2050,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_parse = data;
|
rc = smk_parse_label_list(data, &list_tmp);
|
||||||
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);
|
|
||||||
}
|
|
||||||
kfree(data);
|
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.
|
* But do so only on invalid label, not on system errors.
|
||||||
* The invalid label must be first to count as clearing attempt.
|
* The invalid label must be first to count as clearing attempt.
|
||||||
*/
|
*/
|
||||||
if (rc == -EINVAL && list_empty(&list_tmp))
|
if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
|
||||||
rc = count;
|
|
||||||
|
|
||||||
if (rc >= 0) {
|
|
||||||
mutex_lock(&smack_onlycap_lock);
|
mutex_lock(&smack_onlycap_lock);
|
||||||
smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
|
smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
|
||||||
mutex_unlock(&smack_onlycap_lock);
|
mutex_unlock(&smack_onlycap_lock);
|
||||||
|
rc = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(sop, sop2, &list_tmp, list)
|
smk_destroy_label_list(&list_tmp);
|
||||||
kfree(sop);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -2698,6 +2720,113 @@ static const struct file_operations smk_syslog_ops = {
|
||||||
.llseek = default_llseek,
|
.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
|
* 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] = {
|
[SMK_NET6ADDR] = {
|
||||||
"ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
|
"ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
|
||||||
#endif /* CONFIG_IPV6 */
|
#endif /* CONFIG_IPV6 */
|
||||||
|
[SMK_RELABEL_SELF] = {
|
||||||
|
"relabel-self", &smk_relabel_self_ops,
|
||||||
|
S_IRUGO|S_IWUGO},
|
||||||
/* last one */
|
/* last one */
|
||||||
{""}
|
{""}
|
||||||
};
|
};
|
||||||
|
@ -2892,7 +3024,7 @@ static int __init init_smk_fs(void)
|
||||||
int err;
|
int err;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!security_module_enable("smack"))
|
if (smack_enabled == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = smk_init_sysfs();
|
err = smk_init_sysfs();
|
||||||
|
|
Loading…
Add table
Reference in a new issue