Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull general security subsystem updates from James Morris: "TPM (from Jarkko): - essential clean up for tpm_crb so that ARM64 and x86 versions do not distract each other as much as before - /dev/tpm0 rejects now too short writes (shorter buffer than specified in the command header - use DMA-safe buffer in tpm_tis_spi - otherwise mostly minor fixes. Smack: - base support for overlafs Capabilities: - BPRM_FCAPS fixes, from Richard Guy Briggs: The audit subsystem is adding a BPRM_FCAPS record when auditing setuid application execution (SYSCALL execve). This is not expected as it was supposed to be limited to when the file system actually had capabilities in an extended attribute. It lists all capabilities making the event really ugly to parse what is happening. The PATH record correctly records the setuid bit and owner. Suppress the BPRM_FCAPS record on set*id. TOMOYO: - Y2038 timestamping fixes" * 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (28 commits) MAINTAINERS: update the IMA, EVM, trusted-keys, encrypted-keys entries Smack: Base support for overlayfs MAINTAINERS: remove David Safford as maintainer for encrypted+trusted keys tomoyo: fix timestamping for y2038 capabilities: audit log other surprising conditions capabilities: fix logic for effective root or real root capabilities: invert logic for clarity capabilities: remove a layer of conditional logic capabilities: move audit log decision to function capabilities: use intuitive names for id changes capabilities: use root_priveleged inline to clarify logic capabilities: rename has_cap to has_fcap capabilities: intuitive names for cap gain status capabilities: factor out cap_bprm_set_creds privileged root tpm, tpm_tis: use ARRAY_SIZE() to define TPM_HID_USR_IDX tpm: fix duplicate inline declaration specifier tpm: fix type of a local variables in tpm_tis_spi.c tpm: fix type of a local variable in tpm2_map_command() tpm: fix type of a local variable in tpm2_get_cc_attrs_tbl() tpm-dev-common: Reject too short writes ...
This commit is contained in:
commit
55b3a0cb5a
13
MAINTAINERS
13
MAINTAINERS
@ -5219,8 +5219,7 @@ F: fs/ext4/
|
||||
|
||||
Extended Verification Module (EVM)
|
||||
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
||||
L: linux-ima-devel@lists.sourceforge.net
|
||||
L: linux-security-module@vger.kernel.org
|
||||
L: linux-integrity@vger.kernel.org
|
||||
S: Supported
|
||||
F: security/integrity/evm/
|
||||
|
||||
@ -6847,9 +6846,7 @@ L: linux-crypto@vger.kernel.org
|
||||
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
|
||||
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
||||
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
|
||||
L: linux-ima-devel@lists.sourceforge.net
|
||||
L: linux-ima-user@lists.sourceforge.net
|
||||
L: linux-security-module@vger.kernel.org
|
||||
L: linux-integrity@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
|
||||
S: Supported
|
||||
F: security/integrity/ima/
|
||||
@ -7632,8 +7629,7 @@ F: kernel/kexec*
|
||||
|
||||
KEYS-ENCRYPTED
|
||||
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
||||
M: David Safford <safford@us.ibm.com>
|
||||
L: linux-security-module@vger.kernel.org
|
||||
L: linux-integrity@vger.kernel.org
|
||||
L: keyrings@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/security/keys/trusted-encrypted.rst
|
||||
@ -7641,9 +7637,8 @@ F: include/keys/encrypted-type.h
|
||||
F: security/keys/encrypted-keys/
|
||||
|
||||
KEYS-TRUSTED
|
||||
M: David Safford <safford@us.ibm.com>
|
||||
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
||||
L: linux-security-module@vger.kernel.org
|
||||
L: linux-integrity@vger.kernel.org
|
||||
L: keyrings@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/security/keys/trusted-encrypted.rst
|
||||
|
@ -110,6 +110,12 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (in_size < 6 ||
|
||||
in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) {
|
||||
mutex_unlock(&priv->buffer_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* atomic tpm command send and result receive. We only hold the ops
|
||||
* lock during this period so that the tpm can be unregistered even if
|
||||
* the char dev is held open.
|
||||
|
@ -20,44 +20,48 @@
|
||||
#include <linux/device.h>
|
||||
#include "tpm.h"
|
||||
|
||||
#define READ_PUBEK_RESULT_SIZE 314
|
||||
struct tpm_readpubek_out {
|
||||
u8 algorithm[4];
|
||||
u8 encscheme[2];
|
||||
u8 sigscheme[2];
|
||||
__be32 paramsize;
|
||||
u8 parameters[12];
|
||||
__be32 keysize;
|
||||
u8 modulus[256];
|
||||
u8 checksum[20];
|
||||
} __packed;
|
||||
|
||||
#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
|
||||
#define TPM_ORD_READPUBEK 124
|
||||
static const struct tpm_input_header tpm_readpubek_header = {
|
||||
.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
|
||||
.length = cpu_to_be32(30),
|
||||
.ordinal = cpu_to_be32(TPM_ORD_READPUBEK)
|
||||
};
|
||||
|
||||
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
u8 *data;
|
||||
struct tpm_cmd_t tpm_cmd;
|
||||
ssize_t err;
|
||||
int i, rc;
|
||||
struct tpm_buf tpm_buf;
|
||||
struct tpm_readpubek_out *out;
|
||||
ssize_t rc;
|
||||
int i;
|
||||
char *str = buf;
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
char anti_replay[20];
|
||||
|
||||
memset(&tpm_cmd, 0, sizeof(tpm_cmd));
|
||||
memset(&anti_replay, 0, sizeof(anti_replay));
|
||||
|
||||
tpm_cmd.header.in = tpm_readpubek_header;
|
||||
err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
|
||||
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
|
||||
"attempting to read the PUBEK");
|
||||
if (err)
|
||||
goto out;
|
||||
rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
ignore header 10 bytes
|
||||
algorithm 32 bits (1 == RSA )
|
||||
encscheme 16 bits
|
||||
sigscheme 16 bits
|
||||
parameters (RSA 12->bytes: keybit, #primes, expbit)
|
||||
keylenbytes 32 bits
|
||||
256 byte modulus
|
||||
ignore checksum 20 bytes
|
||||
*/
|
||||
data = tpm_cmd.params.readpubek_out_buffer;
|
||||
tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE,
|
||||
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
|
||||
"attempting to read the PUBEK");
|
||||
if (rc) {
|
||||
tpm_buf_destroy(&tpm_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
|
||||
str +=
|
||||
sprintf(str,
|
||||
"Algorithm: %02X %02X %02X %02X\n"
|
||||
@ -68,21 +72,26 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
|
||||
"%02X %02X %02X %02X\n"
|
||||
"Modulus length: %d\n"
|
||||
"Modulus:\n",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5],
|
||||
data[6], data[7],
|
||||
data[12], data[13], data[14], data[15],
|
||||
data[16], data[17], data[18], data[19],
|
||||
data[20], data[21], data[22], data[23],
|
||||
be32_to_cpu(*((__be32 *) (data + 24))));
|
||||
out->algorithm[0], out->algorithm[1], out->algorithm[2],
|
||||
out->algorithm[3],
|
||||
out->encscheme[0], out->encscheme[1],
|
||||
out->sigscheme[0], out->sigscheme[1],
|
||||
out->parameters[0], out->parameters[1],
|
||||
out->parameters[2], out->parameters[3],
|
||||
out->parameters[4], out->parameters[5],
|
||||
out->parameters[6], out->parameters[7],
|
||||
out->parameters[8], out->parameters[9],
|
||||
out->parameters[10], out->parameters[11],
|
||||
be32_to_cpu(out->keysize));
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
str += sprintf(str, "%02X ", data[i + 28]);
|
||||
str += sprintf(str, "%02X ", out->modulus[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
str += sprintf(str, "\n");
|
||||
}
|
||||
out:
|
||||
|
||||
rc = str - buf;
|
||||
tpm_buf_destroy(&tpm_buf);
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RO(pubek);
|
||||
|
@ -345,17 +345,6 @@ enum tpm_sub_capabilities {
|
||||
TPM_CAP_PROP_TIS_DURATION = 0x120,
|
||||
};
|
||||
|
||||
struct tpm_readpubek_params_out {
|
||||
u8 algorithm[4];
|
||||
u8 encscheme[2];
|
||||
u8 sigscheme[2];
|
||||
__be32 paramsize;
|
||||
u8 parameters[12]; /*assuming RSA*/
|
||||
__be32 keysize;
|
||||
u8 modulus[256];
|
||||
u8 checksum[20];
|
||||
} __packed;
|
||||
|
||||
typedef union {
|
||||
struct tpm_input_header in;
|
||||
struct tpm_output_header out;
|
||||
@ -385,8 +374,6 @@ struct tpm_getrandom_in {
|
||||
} __packed;
|
||||
|
||||
typedef union {
|
||||
struct tpm_readpubek_params_out readpubek_out;
|
||||
u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
|
||||
struct tpm_pcrread_in pcrread_in;
|
||||
struct tpm_pcrread_out pcrread_out;
|
||||
struct tpm_getrandom_in getrandom_in;
|
||||
@ -557,7 +544,7 @@ static inline void tpm_add_ppi(struct tpm_chip *chip)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline inline u32 tpm2_rc_value(u32 rc)
|
||||
static inline u32 tpm2_rc_value(u32 rc)
|
||||
{
|
||||
return (rc & BIT(7)) ? rc & 0xff : rc;
|
||||
}
|
||||
|
@ -834,72 +834,43 @@ static const struct tpm_input_header tpm2_selftest_header = {
|
||||
};
|
||||
|
||||
/**
|
||||
* tpm2_continue_selftest() - start a self test
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
* @full: test all commands instead of testing only those that were not
|
||||
* previously tested.
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd with exception of RC_TESTING.
|
||||
*/
|
||||
static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
|
||||
{
|
||||
int rc;
|
||||
struct tpm2_cmd cmd;
|
||||
|
||||
cmd.header.in = tpm2_selftest_header;
|
||||
cmd.params.selftest_in.full_test = full;
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
|
||||
"continue selftest");
|
||||
|
||||
/* At least some prototype chips seem to give RC_TESTING error
|
||||
* immediately. This is a workaround for that.
|
||||
*/
|
||||
if (rc == TPM2_RC_TESTING) {
|
||||
dev_warn(&chip->dev, "Got RC_TESTING, ignoring\n");
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm2_do_selftest() - run a full self test
|
||||
* tpm2_do_selftest() - ensure that all self tests have passed
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd.
|
||||
*
|
||||
* During the self test TPM2 commands return with the error code RC_TESTING.
|
||||
* Waiting is done by issuing PCR read until it executes successfully.
|
||||
* The TPM can either run all self tests synchronously and then return
|
||||
* RC_SUCCESS once all tests were successful. Or it can choose to run the tests
|
||||
* asynchronously and return RC_TESTING immediately while the self tests still
|
||||
* execute in the background. This function handles both cases and waits until
|
||||
* all tests have completed.
|
||||
*/
|
||||
static int tpm2_do_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
unsigned int loops;
|
||||
unsigned int delay_msec = 100;
|
||||
unsigned long duration;
|
||||
int i;
|
||||
unsigned int delay_msec = 20;
|
||||
long duration;
|
||||
struct tpm2_cmd cmd;
|
||||
|
||||
duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
|
||||
duration = jiffies_to_msecs(
|
||||
tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
|
||||
|
||||
loops = jiffies_to_msecs(duration) / delay_msec;
|
||||
while (duration > 0) {
|
||||
cmd.header.in = tpm2_selftest_header;
|
||||
cmd.params.selftest_in.full_test = 0;
|
||||
|
||||
rc = tpm2_start_selftest(chip, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < loops; i++) {
|
||||
/* Attempt to read a PCR value */
|
||||
rc = tpm2_pcr_read(chip, 0, NULL);
|
||||
if (rc < 0)
|
||||
break;
|
||||
rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
|
||||
0, 0, "continue selftest");
|
||||
|
||||
if (rc != TPM2_RC_TESTING)
|
||||
break;
|
||||
|
||||
tpm_msleep(delay_msec);
|
||||
duration -= delay_msec;
|
||||
|
||||
/* wait longer the next round */
|
||||
delay_msec *= 2;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -1009,7 +980,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
u32 nr_commands;
|
||||
u32 *attrs;
|
||||
__be32 *attrs;
|
||||
u32 cc;
|
||||
int i;
|
||||
int rc;
|
||||
@ -1049,7 +1020,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
|
||||
|
||||
chip->nr_commands = nr_commands;
|
||||
|
||||
attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9];
|
||||
attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
|
||||
for (i = 0; i < nr_commands; i++, attrs++) {
|
||||
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
|
||||
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
|
||||
|
@ -242,7 +242,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
|
||||
struct tpm_space *space = &chip->work_space;
|
||||
unsigned int nr_handles;
|
||||
u32 attrs;
|
||||
u32 *handle;
|
||||
__be32 *handle;
|
||||
int i;
|
||||
|
||||
i = tpm2_find_cc(chip, cc);
|
||||
@ -252,7 +252,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
|
||||
attrs = chip->cc_attrs_tbl[i];
|
||||
nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
|
||||
|
||||
handle = (u32 *)&cmd[TPM_HEADER_SIZE];
|
||||
handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
|
||||
for (i = 0; i < nr_handles; i++, handle++) {
|
||||
if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
|
||||
if (!tpm2_map_to_phandle(space, handle))
|
||||
|
@ -92,14 +92,9 @@ enum crb_status {
|
||||
CRB_DRV_STS_COMPLETE = BIT(0),
|
||||
};
|
||||
|
||||
enum crb_flags {
|
||||
CRB_FL_ACPI_START = BIT(0),
|
||||
CRB_FL_CRB_START = BIT(1),
|
||||
CRB_FL_CRB_SMC_START = BIT(2),
|
||||
};
|
||||
|
||||
struct crb_priv {
|
||||
unsigned int flags;
|
||||
u32 sm;
|
||||
const char *hid;
|
||||
void __iomem *iobase;
|
||||
struct crb_regs_head __iomem *regs_h;
|
||||
struct crb_regs_tail __iomem *regs_t;
|
||||
@ -128,14 +123,16 @@ struct tpm2_crb_smc {
|
||||
* Anyhow, we do not wait here as a consequent CMD_READY request
|
||||
* will be handled correctly even if idle was not completed.
|
||||
*
|
||||
* The function does nothing for devices with ACPI-start method.
|
||||
* The function does nothing for devices with ACPI-start method
|
||||
* or SMC-start method.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
|
||||
{
|
||||
if ((priv->flags & CRB_FL_ACPI_START) ||
|
||||
(priv->flags & CRB_FL_CRB_SMC_START))
|
||||
if ((priv->sm == ACPI_TPM2_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
|
||||
return 0;
|
||||
|
||||
iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
|
||||
@ -174,14 +171,16 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
|
||||
* The device should respond within TIMEOUT_C.
|
||||
*
|
||||
* The function does nothing for devices with ACPI-start method
|
||||
* or SMC-start method.
|
||||
*
|
||||
* Return: 0 on success -ETIME on timeout;
|
||||
*/
|
||||
static int __maybe_unused crb_cmd_ready(struct device *dev,
|
||||
struct crb_priv *priv)
|
||||
{
|
||||
if ((priv->flags & CRB_FL_ACPI_START) ||
|
||||
(priv->flags & CRB_FL_CRB_SMC_START))
|
||||
if ((priv->sm == ACPI_TPM2_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
|
||||
return 0;
|
||||
|
||||
iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
|
||||
@ -325,13 +324,20 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
/* Make sure that cmd is populated before issuing start. */
|
||||
wmb();
|
||||
|
||||
if (priv->flags & CRB_FL_CRB_START)
|
||||
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
|
||||
* report only ACPI start but in practice seems to require both
|
||||
* CRB start, hence invoking CRB start method if hid == MSFT0101.
|
||||
*/
|
||||
if ((priv->sm == ACPI_TPM2_COMMAND_BUFFER) ||
|
||||
(priv->sm == ACPI_TPM2_MEMORY_MAPPED) ||
|
||||
(!strcmp(priv->hid, "MSFT0101")))
|
||||
iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
|
||||
|
||||
if (priv->flags & CRB_FL_ACPI_START)
|
||||
if ((priv->sm == ACPI_TPM2_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD))
|
||||
rc = crb_do_acpi_start(chip);
|
||||
|
||||
if (priv->flags & CRB_FL_CRB_SMC_START) {
|
||||
if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
|
||||
iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
|
||||
rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
|
||||
}
|
||||
@ -345,7 +351,9 @@ static void crb_cancel(struct tpm_chip *chip)
|
||||
|
||||
iowrite32(CRB_CANCEL_INVOKE, &priv->regs_t->ctrl_cancel);
|
||||
|
||||
if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
|
||||
if (((priv->sm == ACPI_TPM2_START_METHOD) ||
|
||||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)) &&
|
||||
crb_do_acpi_start(chip))
|
||||
dev_err(&chip->dev, "ACPI Start failed\n");
|
||||
}
|
||||
|
||||
@ -458,7 +466,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
|
||||
* the control area, as one nice sane region except for some older
|
||||
* stuff that puts the control area outside the ACPI IO region.
|
||||
*/
|
||||
if (!(priv->flags & CRB_FL_ACPI_START)) {
|
||||
if ((priv->sm == ACPI_TPM2_COMMAND_BUFFER) ||
|
||||
(priv->sm == ACPI_TPM2_MEMORY_MAPPED)) {
|
||||
if (buf->control_address == io_res.start +
|
||||
sizeof(*priv->regs_h))
|
||||
priv->regs_h = priv->iobase;
|
||||
@ -552,18 +561,6 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
|
||||
* report only ACPI start but in practice seems to require both
|
||||
* ACPI start and CRB start.
|
||||
*/
|
||||
if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED ||
|
||||
!strcmp(acpi_device_hid(device), "MSFT0101"))
|
||||
priv->flags |= CRB_FL_CRB_START;
|
||||
|
||||
if (sm == ACPI_TPM2_START_METHOD ||
|
||||
sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
|
||||
priv->flags |= CRB_FL_ACPI_START;
|
||||
|
||||
if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
|
||||
if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
|
||||
dev_err(dev,
|
||||
@ -574,9 +571,11 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||
}
|
||||
crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
|
||||
priv->smc_func_id = crb_smc->smc_func_id;
|
||||
priv->flags |= CRB_FL_CRB_SMC_START;
|
||||
}
|
||||
|
||||
priv->sm = sm;
|
||||
priv->hid = acpi_device_hid(device);
|
||||
|
||||
rc = crb_map_io(device, priv, buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "tpm.h"
|
||||
#include "tpm_tis_core.h"
|
||||
|
||||
@ -223,7 +224,7 @@ static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
}
|
||||
|
||||
static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *value)
|
||||
const u8 *value)
|
||||
{
|
||||
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||
|
||||
@ -365,7 +366,7 @@ static struct pnp_driver tis_pnp_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
|
||||
#define TIS_HID_USR_IDX (ARRAY_SIZE(tpm_pnp_tbl) - 2)
|
||||
module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
|
||||
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
|
||||
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
|
||||
|
@ -252,7 +252,7 @@ out:
|
||||
* tpm.c can skip polling for the data to be available as the interrupt is
|
||||
* waited for here
|
||||
*/
|
||||
static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
int rc, status, burstcnt;
|
||||
@ -343,7 +343,7 @@ static void disable_interrupts(struct tpm_chip *chip)
|
||||
* tpm.c can skip polling for the data to be available as the interrupt is
|
||||
* waited for here
|
||||
*/
|
||||
static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
int rc;
|
||||
@ -445,7 +445,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
int rc = 0;
|
||||
u8 cmd_getticks[] = {
|
||||
static const u8 cmd_getticks[] = {
|
||||
0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
|
||||
0x00, 0x00, 0x00, 0xf1
|
||||
};
|
||||
|
@ -98,7 +98,7 @@ struct tpm_tis_phy_ops {
|
||||
int (*read_bytes)(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *result);
|
||||
int (*write_bytes)(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *value);
|
||||
const u8 *value);
|
||||
int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
|
||||
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
|
||||
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
|
||||
@ -128,7 +128,7 @@ static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr,
|
||||
}
|
||||
|
||||
static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *value)
|
||||
u16 len, const u8 *value)
|
||||
{
|
||||
return data->phy_ops->write_bytes(data, addr, len, value);
|
||||
}
|
||||
|
@ -46,9 +46,7 @@
|
||||
struct tpm_tis_spi_phy {
|
||||
struct tpm_tis_data priv;
|
||||
struct spi_device *spi_device;
|
||||
|
||||
u8 tx_buf[4];
|
||||
u8 rx_buf[4];
|
||||
u8 *iobuf;
|
||||
};
|
||||
|
||||
static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data)
|
||||
@ -57,7 +55,7 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *buffer, u8 direction)
|
||||
u8 *in, const u8 *out)
|
||||
{
|
||||
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
|
||||
int ret = 0;
|
||||
@ -71,14 +69,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
while (len) {
|
||||
transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
|
||||
|
||||
phy->tx_buf[0] = direction | (transfer_len - 1);
|
||||
phy->tx_buf[1] = 0xd4;
|
||||
phy->tx_buf[2] = addr >> 8;
|
||||
phy->tx_buf[3] = addr;
|
||||
phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
|
||||
phy->iobuf[1] = 0xd4;
|
||||
phy->iobuf[2] = addr >> 8;
|
||||
phy->iobuf[3] = addr;
|
||||
|
||||
memset(&spi_xfer, 0, sizeof(spi_xfer));
|
||||
spi_xfer.tx_buf = phy->tx_buf;
|
||||
spi_xfer.rx_buf = phy->rx_buf;
|
||||
spi_xfer.tx_buf = phy->iobuf;
|
||||
spi_xfer.rx_buf = phy->iobuf;
|
||||
spi_xfer.len = 4;
|
||||
spi_xfer.cs_change = 1;
|
||||
|
||||
@ -88,9 +86,9 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if ((phy->rx_buf[3] & 0x01) == 0) {
|
||||
if ((phy->iobuf[3] & 0x01) == 0) {
|
||||
// handle SPI wait states
|
||||
phy->tx_buf[0] = 0;
|
||||
phy->iobuf[0] = 0;
|
||||
|
||||
for (i = 0; i < TPM_RETRY; i++) {
|
||||
spi_xfer.len = 1;
|
||||
@ -99,7 +97,7 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
if (phy->rx_buf[0] & 0x01)
|
||||
if (phy->iobuf[0] & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -113,12 +111,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
spi_xfer.len = transfer_len;
|
||||
spi_xfer.delay_usecs = 5;
|
||||
|
||||
if (direction) {
|
||||
if (in) {
|
||||
spi_xfer.tx_buf = NULL;
|
||||
spi_xfer.rx_buf = buffer;
|
||||
} else {
|
||||
spi_xfer.tx_buf = buffer;
|
||||
} else if (out) {
|
||||
spi_xfer.rx_buf = NULL;
|
||||
memcpy(phy->iobuf, out, transfer_len);
|
||||
out += transfer_len;
|
||||
}
|
||||
|
||||
spi_message_init(&m);
|
||||
@ -127,8 +125,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (in) {
|
||||
memcpy(in, phy->iobuf, transfer_len);
|
||||
in += transfer_len;
|
||||
}
|
||||
|
||||
len -= transfer_len;
|
||||
buffer += transfer_len;
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -139,40 +141,51 @@ exit:
|
||||
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *result)
|
||||
{
|
||||
return tpm_tis_spi_transfer(data, addr, len, result, 0x80);
|
||||
return tpm_tis_spi_transfer(data, addr, len, result, NULL);
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *value)
|
||||
u16 len, const u8 *value)
|
||||
{
|
||||
return tpm_tis_spi_transfer(data, addr, len, value, 0);
|
||||
return tpm_tis_spi_transfer(data, addr, len, NULL, value);
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
|
||||
{
|
||||
__le16 result_le;
|
||||
int rc;
|
||||
|
||||
rc = data->phy_ops->read_bytes(data, addr, sizeof(u16), (u8 *)result);
|
||||
rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
|
||||
(u8 *)&result_le);
|
||||
if (!rc)
|
||||
*result = le16_to_cpu(*result);
|
||||
*result = le16_to_cpu(result_le);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
|
||||
{
|
||||
__le32 result_le;
|
||||
int rc;
|
||||
|
||||
rc = data->phy_ops->read_bytes(data, addr, sizeof(u32), (u8 *)result);
|
||||
rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
|
||||
(u8 *)&result_le);
|
||||
if (!rc)
|
||||
*result = le32_to_cpu(*result);
|
||||
*result = le32_to_cpu(result_le);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
|
||||
{
|
||||
value = cpu_to_le32(value);
|
||||
return data->phy_ops->write_bytes(data, addr, sizeof(u32),
|
||||
(u8 *)&value);
|
||||
__le32 value_le;
|
||||
int rc;
|
||||
|
||||
value_le = cpu_to_le32(value);
|
||||
rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
|
||||
(u8 *)&value_le);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct tpm_tis_phy_ops tpm_spi_phy_ops = {
|
||||
@ -194,6 +207,10 @@ static int tpm_tis_spi_probe(struct spi_device *dev)
|
||||
|
||||
phy->spi_device = dev;
|
||||
|
||||
phy->iobuf = devm_kmalloc(&dev->dev, MAX_SPI_FRAMESIZE, GFP_KERNEL);
|
||||
if (!phy->iobuf)
|
||||
return -ENOMEM;
|
||||
|
||||
return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops,
|
||||
NULL);
|
||||
}
|
||||
|
@ -536,7 +536,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
|
||||
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||||
struct linux_binprm *bprm,
|
||||
bool *effective,
|
||||
bool *has_cap)
|
||||
bool *has_fcap)
|
||||
{
|
||||
struct cred *new = bprm->cred;
|
||||
unsigned i;
|
||||
@ -546,7 +546,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||||
*effective = true;
|
||||
|
||||
if (caps->magic_etc & VFS_CAP_REVISION_MASK)
|
||||
*has_cap = true;
|
||||
*has_fcap = true;
|
||||
|
||||
CAP_FOR_EACH_U32(i) {
|
||||
__u32 permitted = caps->permitted.cap[i];
|
||||
@ -653,7 +653,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
|
||||
* its xattrs and, if present, apply them to the proposed credentials being
|
||||
* constructed by execve().
|
||||
*/
|
||||
static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
|
||||
static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap)
|
||||
{
|
||||
int rc = 0;
|
||||
struct cpu_vfs_cap_data vcaps;
|
||||
@ -684,7 +684,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
|
||||
rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap);
|
||||
if (rc == -EINVAL)
|
||||
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
|
||||
__func__, rc, bprm->filename);
|
||||
@ -696,6 +696,115 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool root_privileged(void) { return !issecure(SECURE_NOROOT); }
|
||||
|
||||
static inline bool __is_real(kuid_t uid, struct cred *cred)
|
||||
{ return uid_eq(cred->uid, uid); }
|
||||
|
||||
static inline bool __is_eff(kuid_t uid, struct cred *cred)
|
||||
{ return uid_eq(cred->euid, uid); }
|
||||
|
||||
static inline bool __is_suid(kuid_t uid, struct cred *cred)
|
||||
{ return !__is_real(uid, cred) && __is_eff(uid, cred); }
|
||||
|
||||
/*
|
||||
* handle_privileged_root - Handle case of privileged root
|
||||
* @bprm: The execution parameters, including the proposed creds
|
||||
* @has_fcap: Are any file capabilities set?
|
||||
* @effective: Do we have effective root privilege?
|
||||
* @root_uid: This namespace' root UID WRT initial USER namespace
|
||||
*
|
||||
* Handle the case where root is privileged and hasn't been neutered by
|
||||
* SECURE_NOROOT. If file capabilities are set, they won't be combined with
|
||||
* set UID root and nothing is changed. If we are root, cap_permitted is
|
||||
* updated. If we have become set UID root, the effective bit is set.
|
||||
*/
|
||||
static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
|
||||
bool *effective, kuid_t root_uid)
|
||||
{
|
||||
const struct cred *old = current_cred();
|
||||
struct cred *new = bprm->cred;
|
||||
|
||||
if (!root_privileged())
|
||||
return;
|
||||
/*
|
||||
* If the legacy file capability is set, then don't set privs
|
||||
* for a setuid root binary run by a non-root user. Do set it
|
||||
* for a root user just to cause least surprise to an admin.
|
||||
*/
|
||||
if (has_fcap && __is_suid(root_uid, new)) {
|
||||
warn_setuid_and_fcaps_mixed(bprm->filename);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* To support inheritance of root-permissions and suid-root
|
||||
* executables under compatibility mode, we override the
|
||||
* capability sets for the file.
|
||||
*/
|
||||
if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
|
||||
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
||||
new->cap_permitted = cap_combine(old->cap_bset,
|
||||
old->cap_inheritable);
|
||||
}
|
||||
/*
|
||||
* If only the real uid is 0, we do not set the effective bit.
|
||||
*/
|
||||
if (__is_eff(root_uid, new))
|
||||
*effective = true;
|
||||
}
|
||||
|
||||
#define __cap_gained(field, target, source) \
|
||||
!cap_issubset(target->cap_##field, source->cap_##field)
|
||||
#define __cap_grew(target, source, cred) \
|
||||
!cap_issubset(cred->cap_##target, cred->cap_##source)
|
||||
#define __cap_full(field, cred) \
|
||||
cap_issubset(CAP_FULL_SET, cred->cap_##field)
|
||||
|
||||
static inline bool __is_setuid(struct cred *new, const struct cred *old)
|
||||
{ return !uid_eq(new->euid, old->uid); }
|
||||
|
||||
static inline bool __is_setgid(struct cred *new, const struct cred *old)
|
||||
{ return !gid_eq(new->egid, old->gid); }
|
||||
|
||||
/*
|
||||
* 1) Audit candidate if current->cap_effective is set
|
||||
*
|
||||
* We do not bother to audit if 3 things are true:
|
||||
* 1) cap_effective has all caps
|
||||
* 2) we became root *OR* are were already root
|
||||
* 3) root is supposed to have all caps (SECURE_NOROOT)
|
||||
* Since this is just a normal root execing a process.
|
||||
*
|
||||
* Number 1 above might fail if you don't have a full bset, but I think
|
||||
* that is interesting information to audit.
|
||||
*
|
||||
* A number of other conditions require logging:
|
||||
* 2) something prevented setuid root getting all caps
|
||||
* 3) non-setuid root gets fcaps
|
||||
* 4) non-setuid root gets ambient
|
||||
*/
|
||||
static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old,
|
||||
kuid_t root, bool has_fcap)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if ((__cap_grew(effective, ambient, new) &&
|
||||
!(__cap_full(effective, new) &&
|
||||
(__is_eff(root, new) || __is_real(root, new)) &&
|
||||
root_privileged())) ||
|
||||
(root_privileged() &&
|
||||
__is_suid(root, new) &&
|
||||
!__cap_full(effective, new)) ||
|
||||
(!__is_setuid(new, old) &&
|
||||
((has_fcap &&
|
||||
__cap_gained(permitted, new, old)) ||
|
||||
__cap_gained(ambient, new, old))))
|
||||
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cap_bprm_set_creds - Set up the proposed credentials for execve().
|
||||
* @bprm: The execution parameters, including the proposed creds
|
||||
@ -708,61 +817,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
const struct cred *old = current_cred();
|
||||
struct cred *new = bprm->cred;
|
||||
bool effective, has_cap = false, is_setid;
|
||||
bool effective = false, has_fcap = false, is_setid;
|
||||
int ret;
|
||||
kuid_t root_uid;
|
||||
|
||||
if (WARN_ON(!cap_ambient_invariant_ok(old)))
|
||||
return -EPERM;
|
||||
|
||||
effective = false;
|
||||
ret = get_file_caps(bprm, &effective, &has_cap);
|
||||
ret = get_file_caps(bprm, &effective, &has_fcap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
root_uid = make_kuid(new->user_ns, 0);
|
||||
|
||||
if (!issecure(SECURE_NOROOT)) {
|
||||
/*
|
||||
* If the legacy file capability is set, then don't set privs
|
||||
* for a setuid root binary run by a non-root user. Do set it
|
||||
* for a root user just to cause least surprise to an admin.
|
||||
*/
|
||||
if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
|
||||
warn_setuid_and_fcaps_mixed(bprm->filename);
|
||||
goto skip;
|
||||
}
|
||||
/*
|
||||
* To support inheritance of root-permissions and suid-root
|
||||
* executables under compatibility mode, we override the
|
||||
* capability sets for the file.
|
||||
*
|
||||
* If only the real uid is 0, we do not set the effective bit.
|
||||
*/
|
||||
if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
|
||||
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
||||
new->cap_permitted = cap_combine(old->cap_bset,
|
||||
old->cap_inheritable);
|
||||
}
|
||||
if (uid_eq(new->euid, root_uid))
|
||||
effective = true;
|
||||
}
|
||||
skip:
|
||||
handle_privileged_root(bprm, has_fcap, &effective, root_uid);
|
||||
|
||||
/* if we have fs caps, clear dangerous personality flags */
|
||||
if (!cap_issubset(new->cap_permitted, old->cap_permitted))
|
||||
if (__cap_gained(permitted, new, old))
|
||||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||||
|
||||
|
||||
/* Don't let someone trace a set[ug]id/setpcap binary with the revised
|
||||
* credentials unless they have the appropriate permit.
|
||||
*
|
||||
* In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
|
||||
*/
|
||||
is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid);
|
||||
is_setid = __is_setuid(new, old) || __is_setgid(new, old);
|
||||
|
||||
if ((is_setid ||
|
||||
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
|
||||
if ((is_setid || __cap_gained(permitted, new, old)) &&
|
||||
((bprm->unsafe & ~LSM_UNSAFE_PTRACE) ||
|
||||
!ptracer_capable(current, new->user_ns))) {
|
||||
/* downgrade; they get no more than they had, and maybe less */
|
||||
@ -779,7 +860,7 @@ skip:
|
||||
new->sgid = new->fsgid = new->egid;
|
||||
|
||||
/* File caps or setid cancels ambient. */
|
||||
if (has_cap || is_setid)
|
||||
if (has_fcap || is_setid)
|
||||
cap_clear(new->cap_ambient);
|
||||
|
||||
/*
|
||||
@ -800,26 +881,10 @@ skip:
|
||||
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* Audit candidate if current->cap_effective is set
|
||||
*
|
||||
* We do not bother to audit if 3 things are true:
|
||||
* 1) cap_effective has all caps
|
||||
* 2) we are root
|
||||
* 3) root is supposed to have all caps (SECURE_NOROOT)
|
||||
* Since this is just a normal root execing a process.
|
||||
*
|
||||
* Number 1 above might fail if you don't have a full bset, but I think
|
||||
* that is interesting information to audit.
|
||||
*/
|
||||
if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
|
||||
if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
|
||||
!uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
|
||||
issecure(SECURE_NOROOT)) {
|
||||
ret = audit_log_bprm_fcaps(bprm, new, old);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (nonroot_raised_pE(new, old, root_uid, has_fcap)) {
|
||||
ret = audit_log_bprm_fcaps(bprm, new, old);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
||||
@ -829,13 +894,11 @@ skip:
|
||||
|
||||
/* Check for privilege-elevated exec. */
|
||||
bprm->cap_elevated = 0;
|
||||
if (is_setid) {
|
||||
if (is_setid ||
|
||||
(!__is_real(root_uid, new) &&
|
||||
(effective ||
|
||||
__cap_grew(permitted, ambient, new))))
|
||||
bprm->cap_elevated = 1;
|
||||
} else if (!uid_eq(new->uid, root_uid)) {
|
||||
if (effective ||
|
||||
!cap_issubset(new->cap_permitted, new->cap_ambient))
|
||||
bprm->cap_elevated = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4600,6 +4600,82 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
|
||||
{
|
||||
|
||||
struct task_smack *tsp;
|
||||
struct smack_known *skp;
|
||||
struct inode_smack *isp;
|
||||
struct cred *new_creds = *new;
|
||||
|
||||
if (new_creds == NULL) {
|
||||
new_creds = prepare_creds();
|
||||
if (new_creds == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tsp = new_creds->security;
|
||||
|
||||
/*
|
||||
* Get label from overlay inode and set it in create_sid
|
||||
*/
|
||||
isp = d_inode(dentry->d_parent)->i_security;
|
||||
skp = isp->smk_inode;
|
||||
tsp->smk_task = skp;
|
||||
*new = new_creds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smack_inode_copy_up_xattr(const char *name)
|
||||
{
|
||||
/*
|
||||
* Return 1 if this is the smack access Smack attribute.
|
||||
*/
|
||||
if (strcmp(name, XATTR_NAME_SMACK) == 0)
|
||||
return 1;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||
struct qstr *name,
|
||||
const struct cred *old,
|
||||
struct cred *new)
|
||||
{
|
||||
struct task_smack *otsp = old->security;
|
||||
struct task_smack *ntsp = new->security;
|
||||
struct inode_smack *isp;
|
||||
int may;
|
||||
|
||||
/*
|
||||
* Use the process credential unless all of
|
||||
* the transmuting criteria are met
|
||||
*/
|
||||
ntsp->smk_task = otsp->smk_task;
|
||||
|
||||
/*
|
||||
* the attribute of the containing directory
|
||||
*/
|
||||
isp = d_inode(dentry->d_parent)->i_security;
|
||||
|
||||
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
|
||||
rcu_read_lock();
|
||||
may = smk_access_entry(otsp->smk_task->smk_known,
|
||||
isp->smk_inode->smk_known,
|
||||
&otsp->smk_task->smk_rules);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* If the directory is transmuting and the rule
|
||||
* providing access is transmuting use the containing
|
||||
* directory label instead of the process label.
|
||||
*/
|
||||
if (may > 0 && (may & MAY_TRANSMUTE))
|
||||
ntsp->smk_task = isp->smk_inode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
|
||||
@ -4735,6 +4811,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
|
||||
LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
|
||||
LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
|
||||
LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up),
|
||||
LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr),
|
||||
LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as),
|
||||
};
|
||||
|
||||
|
||||
|
@ -157,7 +157,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
tomoyo_convert_time(get_seconds(), &stamp);
|
||||
tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
|
||||
|
||||
pos = snprintf(buffer, tomoyo_buffer_len - 1,
|
||||
"#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
|
||||
|
@ -2257,7 +2257,7 @@ static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
|
||||
/* Timestamp counter for last updated. */
|
||||
static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
|
||||
/* Counter for number of updates. */
|
||||
static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
|
||||
static time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
|
||||
|
||||
/**
|
||||
* tomoyo_update_stat - Update statistic counters.
|
||||
@ -2272,7 +2272,7 @@ void tomoyo_update_stat(const u8 index)
|
||||
* I don't use atomic operations because race condition is not fatal.
|
||||
*/
|
||||
tomoyo_stat_updated[index]++;
|
||||
tomoyo_stat_modified[index] = get_seconds();
|
||||
tomoyo_stat_modified[index] = ktime_get_real_seconds();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1037,7 +1037,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
|
||||
bool (*check_entry) (struct tomoyo_request_info *,
|
||||
const struct tomoyo_acl_info *));
|
||||
void tomoyo_check_profile(void);
|
||||
void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
|
||||
void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp);
|
||||
void tomoyo_del_condition(struct list_head *element);
|
||||
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
|
||||
void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
|
||||
|
@ -87,38 +87,17 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
|
||||
* @stamp: Pointer to "struct tomoyo_time".
|
||||
*
|
||||
* Returns nothing.
|
||||
*
|
||||
* This function does not handle Y2038 problem.
|
||||
*/
|
||||
void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp)
|
||||
void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
|
||||
{
|
||||
static const u16 tomoyo_eom[2][12] = {
|
||||
{ 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
{ 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
u16 y;
|
||||
u8 m;
|
||||
bool r;
|
||||
stamp->sec = time % 60;
|
||||
time /= 60;
|
||||
stamp->min = time % 60;
|
||||
time /= 60;
|
||||
stamp->hour = time % 24;
|
||||
time /= 24;
|
||||
for (y = 1970; ; y++) {
|
||||
const unsigned short days = (y & 3) ? 365 : 366;
|
||||
if (time < days)
|
||||
break;
|
||||
time -= days;
|
||||
}
|
||||
r = (y & 3) == 0;
|
||||
for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++)
|
||||
;
|
||||
if (m)
|
||||
time -= tomoyo_eom[r][m - 1];
|
||||
stamp->year = y;
|
||||
stamp->month = ++m;
|
||||
stamp->day = ++time;
|
||||
struct tm tm;
|
||||
time64_to_tm(time64, 0, &tm);
|
||||
stamp->sec = tm.tm_sec;
|
||||
stamp->min = tm.tm_min;
|
||||
stamp->hour = tm.tm_hour;
|
||||
stamp->day = tm.tm_mday;
|
||||
stamp->month = tm.tm_mon + 1;
|
||||
stamp->year = tm.tm_year + 1900;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user