Commit 55b3a0cb authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents dee02770 34d8751f
...@@ -5219,8 +5219,7 @@ F: fs/ext4/ ...@@ -5219,8 +5219,7 @@ F: fs/ext4/
Extended Verification Module (EVM) Extended Verification Module (EVM)
M: Mimi Zohar <zohar@linux.vnet.ibm.com> M: Mimi Zohar <zohar@linux.vnet.ibm.com>
L: linux-ima-devel@lists.sourceforge.net L: linux-integrity@vger.kernel.org
L: linux-security-module@vger.kernel.org
S: Supported S: Supported
F: security/integrity/evm/ F: security/integrity/evm/
...@@ -6847,9 +6846,7 @@ L: linux-crypto@vger.kernel.org ...@@ -6847,9 +6846,7 @@ L: linux-crypto@vger.kernel.org
INTEGRITY MEASUREMENT ARCHITECTURE (IMA) INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@linux.vnet.ibm.com> M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com> M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
L: linux-ima-devel@lists.sourceforge.net L: linux-integrity@vger.kernel.org
L: linux-ima-user@lists.sourceforge.net
L: linux-security-module@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
S: Supported S: Supported
F: security/integrity/ima/ F: security/integrity/ima/
...@@ -7632,8 +7629,7 @@ F: kernel/kexec* ...@@ -7632,8 +7629,7 @@ F: kernel/kexec*
KEYS-ENCRYPTED KEYS-ENCRYPTED
M: Mimi Zohar <zohar@linux.vnet.ibm.com> M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: David Safford <safford@us.ibm.com> L: linux-integrity@vger.kernel.org
L: linux-security-module@vger.kernel.org
L: keyrings@vger.kernel.org L: keyrings@vger.kernel.org
S: Supported S: Supported
F: Documentation/security/keys/trusted-encrypted.rst F: Documentation/security/keys/trusted-encrypted.rst
...@@ -7641,9 +7637,8 @@ F: include/keys/encrypted-type.h ...@@ -7641,9 +7637,8 @@ F: include/keys/encrypted-type.h
F: security/keys/encrypted-keys/ F: security/keys/encrypted-keys/
KEYS-TRUSTED KEYS-TRUSTED
M: David Safford <safford@us.ibm.com>
M: Mimi Zohar <zohar@linux.vnet.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 L: keyrings@vger.kernel.org
S: Supported S: Supported
F: Documentation/security/keys/trusted-encrypted.rst F: Documentation/security/keys/trusted-encrypted.rst
......
...@@ -110,6 +110,12 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -110,6 +110,12 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
return -EFAULT; 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 /* 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 * lock during this period so that the tpm can be unregistered even if
* the char dev is held open. * the char dev is held open.
......
...@@ -20,44 +20,48 @@ ...@@ -20,44 +20,48 @@
#include <linux/device.h> #include <linux/device.h>
#include "tpm.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 READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
#define TPM_ORD_READPUBEK 124 #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, static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
u8 *data; struct tpm_buf tpm_buf;
struct tpm_cmd_t tpm_cmd; struct tpm_readpubek_out *out;
ssize_t err; ssize_t rc;
int i, rc; int i;
char *str = buf; char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev); 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; rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE, if (rc)
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, return rc;
"attempting to read the PUBEK");
if (err) tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
goto out;
rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE,
/* READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
ignore header 10 bytes "attempting to read the PUBEK");
algorithm 32 bits (1 == RSA ) if (rc) {
encscheme 16 bits tpm_buf_destroy(&tpm_buf);
sigscheme 16 bits return 0;
parameters (RSA 12->bytes: keybit, #primes, expbit) }
keylenbytes 32 bits
256 byte modulus out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
ignore checksum 20 bytes
*/
data = tpm_cmd.params.readpubek_out_buffer;
str += str +=
sprintf(str, sprintf(str,
"Algorithm: %02X %02X %02X %02X\n" "Algorithm: %02X %02X %02X %02X\n"
...@@ -68,21 +72,26 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ...@@ -68,21 +72,26 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
"%02X %02X %02X %02X\n" "%02X %02X %02X %02X\n"
"Modulus length: %d\n" "Modulus length: %d\n"
"Modulus:\n", "Modulus:\n",
data[0], data[1], data[2], data[3], out->algorithm[0], out->algorithm[1], out->algorithm[2],
data[4], data[5], out->algorithm[3],
data[6], data[7], out->encscheme[0], out->encscheme[1],
data[12], data[13], data[14], data[15], out->sigscheme[0], out->sigscheme[1],
data[16], data[17], data[18], data[19], out->parameters[0], out->parameters[1],
data[20], data[21], data[22], data[23], out->parameters[2], out->parameters[3],
be32_to_cpu(*((__be32 *) (data + 24)))); 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++) { 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) if ((i + 1) % 16 == 0)
str += sprintf(str, "\n"); str += sprintf(str, "\n");
} }
out:
rc = str - buf; rc = str - buf;
tpm_buf_destroy(&tpm_buf);
return rc; return rc;
} }
static DEVICE_ATTR_RO(pubek); static DEVICE_ATTR_RO(pubek);
......
...@@ -345,17 +345,6 @@ enum tpm_sub_capabilities { ...@@ -345,17 +345,6 @@ enum tpm_sub_capabilities {
TPM_CAP_PROP_TIS_DURATION = 0x120, 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 { typedef union {
struct tpm_input_header in; struct tpm_input_header in;
struct tpm_output_header out; struct tpm_output_header out;
...@@ -385,8 +374,6 @@ struct tpm_getrandom_in { ...@@ -385,8 +374,6 @@ struct tpm_getrandom_in {
} __packed; } __packed;
typedef union { 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_in pcrread_in;
struct tpm_pcrread_out pcrread_out; struct tpm_pcrread_out pcrread_out;
struct tpm_getrandom_in getrandom_in; struct tpm_getrandom_in getrandom_in;
...@@ -557,7 +544,7 @@ static inline void tpm_add_ppi(struct tpm_chip *chip) ...@@ -557,7 +544,7 @@ static inline void tpm_add_ppi(struct tpm_chip *chip)
} }
#endif #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; return (rc & BIT(7)) ? rc & 0xff : rc;
} }
......
...@@ -834,72 +834,43 @@ static const struct tpm_input_header tpm2_selftest_header = { ...@@ -834,72 +834,43 @@ static const struct tpm_input_header tpm2_selftest_header = {
}; };
/** /**
* tpm2_continue_selftest() - start a self test * tpm2_do_selftest() - ensure that all self tests have passed
*
* @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
* *
* @chip: TPM chip to use * @chip: TPM chip to use
* *
* Return: Same as with tpm_transmit_cmd. * Return: Same as with tpm_transmit_cmd.
* *
* During the self test TPM2 commands return with the error code RC_TESTING. * The TPM can either run all self tests synchronously and then return
* Waiting is done by issuing PCR read until it executes successfully. * 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) static int tpm2_do_selftest(struct tpm_chip *chip)
{ {
int rc; int rc;
unsigned int loops; unsigned int delay_msec = 20;
unsigned int delay_msec = 100; long duration;
unsigned long duration; struct tpm2_cmd cmd;
int i;
duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
loops = jiffies_to_msecs(duration) / delay_msec; duration = jiffies_to_msecs(
tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
rc = tpm2_start_selftest(chip, true); while (duration > 0) {
if (rc) cmd.header.in = tpm2_selftest_header;
return rc; cmd.params.selftest_in.full_test = 0;
for (i = 0; i < loops; i++) { rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
/* Attempt to read a PCR value */ 0, 0, "continue selftest");
rc = tpm2_pcr_read(chip, 0, NULL);
if (rc < 0)
break;
if (rc != TPM2_RC_TESTING) if (rc != TPM2_RC_TESTING)
break; break;
tpm_msleep(delay_msec); tpm_msleep(delay_msec);
duration -= delay_msec;
/* wait longer the next round */
delay_msec *= 2;
} }
return rc; return rc;
...@@ -1009,7 +980,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) ...@@ -1009,7 +980,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{ {
struct tpm_buf buf; struct tpm_buf buf;
u32 nr_commands; u32 nr_commands;
u32 *attrs; __be32 *attrs;
u32 cc; u32 cc;
int i; int i;
int rc; int rc;
...@@ -1049,7 +1020,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) ...@@ -1049,7 +1020,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
chip->nr_commands = nr_commands; 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++) { for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs); chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF; cc = chip->cc_attrs_tbl[i] & 0xFFFF;
......
...@@ -242,7 +242,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) ...@@ -242,7 +242,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
struct tpm_space *space = &chip->work_space; struct tpm_space *space = &chip->work_space;
unsigned int nr_handles; unsigned int nr_handles;
u32 attrs; u32 attrs;
u32 *handle; __be32 *handle;
int i; int i;
i = tpm2_find_cc(chip, cc); i = tpm2_find_cc(chip, cc);
...@@ -252,7 +252,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) ...@@ -252,7 +252,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
attrs = chip->cc_attrs_tbl[i]; attrs = chip->cc_attrs_tbl[i];
nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); 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++) { for (i = 0; i < nr_handles; i++, handle++) {
if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) { if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
if (!tpm2_map_to_phandle(space, handle)) if (!tpm2_map_to_phandle(space, handle))
......
...@@ -92,14 +92,9 @@ enum crb_status { ...@@ -92,14 +92,9 @@ enum crb_status {
CRB_DRV_STS_COMPLETE = BIT(0), 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 { struct crb_priv {
unsigned int flags; u32 sm;
const char *hid;
void __iomem *iobase; void __iomem *iobase;
struct crb_regs_head __iomem *regs_h; struct crb_regs_head __iomem *regs_h;
struct crb_regs_tail __iomem *regs_t; struct crb_regs_tail __iomem *regs_t;
...@@ -128,14 +123,16 @@ struct tpm2_crb_smc { ...@@ -128,14 +123,16 @@ struct tpm2_crb_smc {
* Anyhow, we do not wait here as a consequent CMD_READY request * Anyhow, we do not wait here as a consequent CMD_READY request
* will be handled correctly even if idle was not completed. * 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 * Return: 0 always
*/ */
static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
{ {
if ((priv->flags & CRB_FL_ACPI_START) || if ((priv->sm == ACPI_TPM2_START_METHOD) ||
(priv->flags & CRB_FL_CRB_SMC_START)) (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
return 0; return 0;
iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); 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, ...@@ -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 device should respond within TIMEOUT_C.
* *
* 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 on success -ETIME on timeout; * Return: 0 on success -ETIME on timeout;
*/ */
static int __maybe_unused crb_cmd_ready(struct device *dev, static int __maybe_unused crb_cmd_ready(struct device *dev,
struct crb_priv *priv) struct crb_priv *priv)
{ {
if ((priv->flags & CRB_FL_ACPI_START) || if ((priv->sm == ACPI_TPM2_START_METHOD) ||
(priv->flags & CRB_FL_CRB_SMC_START)) (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
return 0; return 0;
iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req); 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) ...@@ -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. */ /* Make sure that cmd is populated before issuing start. */
wmb(); 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); 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); 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); iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
} }
...@@ -345,7 +351,9 @@ static void crb_cancel(struct tpm_chip *chip) ...@@ -345,7 +351,9 @@ static void crb_cancel(struct tpm_chip *chip)
iowrite32(CRB_CANCEL_INVOKE, &priv->regs_t->ctrl_cancel); 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"); 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, ...@@ -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 * the control area, as one nice sane region except for some older
* stuff that puts the control area outside the ACPI IO region. * 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 + if (buf->control_address == io_res.start +
sizeof(*priv->regs_h)) sizeof(*priv->regs_h))
priv->regs_h = priv->iobase; priv->regs_h = priv->iobase;
...@@ -552,18 +561,6 @@ static int crb_acpi_add(struct acpi_device *device) ...@@ -552,18 +561,6 @@ static int crb_acpi_add(struct acpi_device *device)
if (!priv) if (!priv)
return -ENOMEM; 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 (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) { if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
dev_err(dev, dev_err(dev,
...@@ -574,9 +571,11 @@ static int crb_acpi_add(struct acpi_device *device) ...@@ -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)); crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
priv->smc_func_id = crb_smc->smc_func_id; 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); rc = crb_map_io(device, priv, buf);
if (rc) if (rc)
return rc; return rc;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/kernel.h>
#include "tpm.h" #include "tpm.h"
#include "tpm_tis_core.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, ...@@ -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, 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); struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
...@@ -365,7 +366,7 @@ static struct pnp_driver tis_pnp_driver = { ...@@ -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, module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
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");
......
...@@ -252,7 +252,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -252,7 +252,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
* tpm.c can skip polling for the data to be available as the interrupt is * tpm.c can skip polling for the data to be available as the interrupt is
* waited for here * 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); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt; int rc, status, burstcnt;
...@@ -343,7 +343,7 @@ static void disable_interrupts(struct tpm_chip *chip) ...@@ -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 * tpm.c can skip polling for the data to be available as the interrupt is
* waited for here * 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); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc; int rc;
...@@ -445,7 +445,7 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -445,7 +445,7 @@ static int probe_itpm(struct tpm_chip *chip)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc = 0; int rc = 0;
u8 cmd_getticks[] = { static const u8 cmd_getticks[] = {
0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
0x00, 0x00, 0x00, 0xf1 0x00, 0x00, 0x00, 0xf1
}; };
......
...@@ -98,7 +98,7 @@ struct tpm_tis_phy_ops { ...@@ -98,7 +98,7 @@ struct tpm_tis_phy_ops {
int (*read_bytes)(struct tpm_tis_data *data, u32 addr, u16 len, int (*read_bytes)(struct tpm_tis_data *data, u32 addr, u16 len,
u8 *result); u8 *result);
int (*write_bytes)(struct tpm_tis_data *data, u32 addr, u16 len, 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 (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result); int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src); 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, ...@@ -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, 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); return data->phy_ops->write_bytes(data, addr, len, value);
} }
......
...@@ -46,9 +46,7 @@ ...@@ -46,9 +46,7 @@
struct tpm_tis_spi_phy { struct tpm_tis_spi_phy {
struct tpm_tis_data priv; struct tpm_tis_data priv;
struct spi_device *spi_device; struct spi_device *spi_device;
u8 *iobuf;
u8 tx_buf[4];
u8 rx_buf[4];
}; };
static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data) 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 ...@@ -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, 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); struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
int ret = 0; int ret = 0;
...@@ -71,14 +69,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -71,14 +69,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
while (len) { while (len) {
transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
phy->tx_buf[0] = direction | (transfer_len - 1); phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
phy->tx_buf[1] = 0xd4; phy->iobuf[1] = 0xd4;
phy->tx_buf[2] = addr >> 8; phy->iobuf[2] = addr >> 8;
phy->tx_buf[3] = addr; phy->iobuf[3] = addr;
memset(&spi_xfer, 0, sizeof(spi_xfer)); memset(&spi_xfer, 0, sizeof(spi_xfer));
spi_xfer.tx_buf = phy->tx_buf; spi_xfer.tx_buf = phy->iobuf;
spi_xfer.rx_buf = phy->rx_buf; spi_xfer.rx_buf = phy->iobuf;
spi_xfer.len = 4; spi_xfer.len = 4;
spi_xfer.cs_change = 1; spi_xfer.cs_change = 1;
...@@ -88,9 +86,9 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -88,9 +86,9 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
if (ret < 0) if (ret < 0)
goto exit; goto exit;
if ((phy->rx_buf[3] & 0x01) == 0) { if ((phy->iobuf[3] & 0x01) == 0) {
// handle SPI wait states // handle SPI wait states
phy->tx_buf[0] = 0; phy->iobuf[0] = 0;
for (i = 0; i < TPM_RETRY; i++) { for (i = 0; i < TPM_RETRY; i++) {
spi_xfer.len = 1; spi_xfer.len = 1;
...@@ -99,7 +97,7 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -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); ret = spi_sync_locked(phy->spi_device, &m);
if (ret < 0) if (ret < 0)
goto exit; goto exit;
if (phy->rx_buf[0] & 0x01) if (phy->iobuf[0] & 0x01)
break; break;
} }
...@@ -113,12 +111,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -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.len = transfer_len;
spi_xfer.delay_usecs = 5; spi_xfer.delay_usecs = 5;
if (direction) { if (in) {
spi_xfer.tx_buf = NULL; spi_xfer.tx_buf = NULL;
spi_xfer.rx_buf = buffer; } else if (out) {
} else {
spi_xfer.tx_buf = buffer;
spi_xfer.rx_buf = NULL; spi_xfer.rx_buf = NULL;
memcpy(phy->iobuf, out, transfer_len);
out += transfer_len;
} }
spi_message_init(&m); spi_message_init(&m);
...@@ -127,8 +125,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -127,8 +125,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
if (ret < 0) if (ret < 0)
goto exit; goto exit;
if (in) {
memcpy(in, phy->iobuf, transfer_len);
in += transfer_len;
}
len -= transfer_len; len -= transfer_len;
buffer += transfer_len;
} }
exit: exit:
...@@ -139,40 +141,51 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -139,40 +141,51 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
u16 len, u8 *result) 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, 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) static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
{ {
__le16 result_le;
int rc; 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) if (!rc)
*result = le16_to_cpu(*result); *result = le16_to_cpu(result_le);
return rc; return rc;
} }
static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result) static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
{ {
__le32 result_le;
int rc; 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) if (!rc)
*result = le32_to_cpu(*result); *result = le32_to_cpu(result_le);
return rc; return rc;
} }
static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value) static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
{ {
value = cpu_to_le32(value); __le32 value_le;
return data->phy_ops->write_bytes(data, addr, sizeof(u32), int rc;
(u8 *)&value);
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 = { 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) ...@@ -194,6 +207,10 @@ static int tpm_tis_spi_probe(struct spi_device *dev)
phy->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, return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops,
NULL); NULL);
} }
......
...@@ -536,7 +536,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) ...@@ -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, static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
struct linux_binprm *bprm, struct linux_binprm *bprm,
bool *effective, bool *effective,
bool *has_cap) bool *has_fcap)
{ {
struct cred *new = bprm->cred; struct cred *new = bprm->cred;
unsigned i; unsigned i;
...@@ -546,7 +546,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, ...@@ -546,7 +546,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
*effective = true; *effective = true;
if (caps->magic_etc & VFS_CAP_REVISION_MASK) if (caps->magic_etc & VFS_CAP_REVISION_MASK)
*has_cap = true; *has_fcap = true;
CAP_FOR_EACH_U32(i) { CAP_FOR_EACH_U32(i) {
__u32 permitted = caps->permitted.cap[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 ...@@ -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 * its xattrs and, if present, apply them to the proposed credentials being
* constructed by execve(). * 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; int rc = 0;
struct cpu_vfs_cap_data vcaps; struct cpu_vfs_cap_data vcaps;
...@@ -684,7 +684,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c ...@@ -684,7 +684,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
goto out; 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) if (rc == -EINVAL)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
__func__, rc, bprm->filename); __func__, rc, bprm->filename);
...@@ -696,6 +696,115 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c ...@@ -696,6 +696,115 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
return rc; 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(). * cap_bprm_set_creds - Set up the proposed credentials for execve().
* @bprm: The execution parameters, including the proposed creds * @bprm: The execution parameters, including the proposed creds
...@@ -708,61 +817,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -708,61 +817,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
{ {
const struct cred *old = current_cred(); const struct cred *old = current_cred();
struct cred *new = bprm->cred; struct cred *new = bprm->cred;
bool effective, has_cap = false, is_setid; bool effective = false, has_fcap = false, is_setid;
int ret; int ret;
kuid_t root_uid; kuid_t root_uid;
if (WARN_ON(!cap_ambient_invariant_ok(old))) if (WARN_ON(!cap_ambient_invariant_ok(old)))
return -EPERM; return -EPERM;
effective = false; ret = get_file_caps(bprm, &effective, &has_fcap);
ret = get_file_caps(bprm, &effective, &has_cap);
if (ret < 0) if (ret < 0)
return ret; return ret;
root_uid = make_kuid(new->user_ns, 0); root_uid = make_kuid(new->user_ns, 0);
if (!issecure(SECURE_NOROOT)) { handle_privileged_root(bprm, has_fcap, &effective, root_uid);
/*
* 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:
/* if we have fs caps, clear dangerous personality flags */ /* 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; bprm->per_clear |= PER_CLEAR_ON_SETID;
/* Don't let someone trace a set[ug]id/setpcap binary with the revised /* Don't let someone trace a set[ug]id/setpcap binary with the revised
* credentials unless they have the appropriate permit. * credentials unless they have the appropriate permit.
* *
* In addition, if NO_NEW_PRIVS, then ensure we get no new privs. * 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 || if ((is_setid || __cap_gained(permitted, new, old)) &&
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
((bprm->unsafe & ~LSM_UNSAFE_PTRACE) || ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) ||
!ptracer_capable(current, new->user_ns))) { !ptracer_capable(current, new->user_ns))) {
/* downgrade; they get no more than they had, and maybe less */ /* downgrade; they get no more than they had, and maybe less */
...@@ -779,7 +860,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -779,7 +860,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
new->sgid = new->fsgid = new->egid; new->sgid = new->fsgid = new->egid;
/* File caps or setid cancels ambient. */ /* File caps or setid cancels ambient. */
if (has_cap || is_setid) if (has_fcap || is_setid)
cap_clear(new->cap_ambient); cap_clear(new->cap_ambient);
/* /*
...@@ -800,26 +881,10 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -800,26 +881,10 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
if (WARN_ON(!cap_ambient_invariant_ok(new))) if (WARN_ON(!cap_ambient_invariant_ok(new)))
return -EPERM; return -EPERM;
/* if (nonroot_raised_pE(new, old, root_uid, has_fcap)) {
* Audit candidate if current->cap_effective is set ret = audit_log_bprm_fcaps(bprm, new, old);
* if (ret < 0)
* We do not bother to audit if 3 things are true: return ret;
* 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;
}
} }
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
...@@ -829,13 +894,11 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -829,13 +894,11 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
/* Check for privilege-elevated exec. */ /* Check for privilege-elevated exec. */
bprm->cap_elevated = 0; 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; 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; return 0;
} }
......
...@@ -4600,6 +4600,82 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) ...@@ -4600,6 +4600,82 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
return 0; 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 = { 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_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
...@@ -4735,6 +4811,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { ...@@ -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_notifysecctx, smack_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx), 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) ...@@ -157,7 +157,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
if (!buffer) if (!buffer)
return NULL; return NULL;
tomoyo_convert_time(get_seconds(), &stamp); tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
pos = snprintf(buffer, tomoyo_buffer_len - 1, pos = snprintf(buffer, tomoyo_buffer_len - 1,
"#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " "#%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] = { ...@@ -2257,7 +2257,7 @@ static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
/* Timestamp counter for last updated. */ /* Timestamp counter for last updated. */
static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
/* Counter for number of updates. */ /* 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. * tomoyo_update_stat - Update statistic counters.
...@@ -2272,7 +2272,7 @@ void tomoyo_update_stat(const u8 index) ...@@ -2272,7 +2272,7 @@ void tomoyo_update_stat(const u8 index)
* I don't use atomic operations because race condition is not fatal. * I don't use atomic operations because race condition is not fatal.
*/ */
tomoyo_stat_updated[index]++; 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, ...@@ -1037,7 +1037,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
bool (*check_entry) (struct tomoyo_request_info *, bool (*check_entry) (struct tomoyo_request_info *,
const struct tomoyo_acl_info *)); const struct tomoyo_acl_info *));
void tomoyo_check_profile(void); 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_del_condition(struct list_head *element);
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
void tomoyo_get_attributes(struct tomoyo_obj_info *obj); void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
......
...@@ -87,38 +87,17 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { ...@@ -87,38 +87,17 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
* @stamp: Pointer to "struct tomoyo_time". * @stamp: Pointer to "struct tomoyo_time".
* *
* Returns nothing. * 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] = { struct tm tm;
{ 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, time64_to_tm(time64, 0, &tm);
{ 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } stamp->sec = tm.tm_sec;
}; stamp->min = tm.tm_min;
u16 y; stamp->hour = tm.tm_hour;
u8 m; stamp->day = tm.tm_mday;
bool r; stamp->month = tm.tm_mon + 1;
stamp->sec = time % 60; stamp->year = tm.tm_year + 1900;
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;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment