Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem update from James Morris: "Just some minor updates across the subsystem" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: ima: eliminate passing d_name.name to process_measurement() TPM: Retry SaveState command in suspend path tpm/tpm_i2c_infineon: Add small comment about return value of __i2c_transfer tpm/tpm_i2c_infineon.c: Add OF attributes type and name to the of_device_id table entries tpm_i2c_stm_st33: Remove duplicate inclusion of header files tpm: Add support for new Infineon I2C TPM (SLB 9645 TT 1.2 I2C) char/tpm: Convert struct i2c_msg initialization to C99 format drivers/char/tpm/tpm_ppi: use strlcpy instead of strncpy tpm/tpm_i2c_stm_st33: formatting and white space changes Smack: include magic.h in smackfs.c selinux: make security_sb_clone_mnt_opts return an error on context mismatch seccomp: allow BPF_XOR based ALU instructions. Fix NULL pointer dereference in smack_inode_unlink() and smack_inode_rmdir() Smack: add support for modification of existing rules smack: SMACK_MAGIC to include/uapi/linux/magic.h Smack: add missing support for transmute bit in smack_str_from_perm() Smack: prevent revoke-subject from failing when unseen label is written to it tomoyo: use DEFINE_SRCU() to define tomoyo_ss tomoyo: use DEFINE_SRCU() to define tomoyo_ss
This commit is contained in:
commit
2e1deaad1e
|
@ -35,6 +35,8 @@ fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
|
||||||
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
|
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
|
||||||
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
|
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
|
||||||
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
|
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
|
||||||
|
infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
|
||||||
|
infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
|
||||||
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
|
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
|
||||||
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
|
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
|
||||||
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
|
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
|
||||||
|
|
|
@ -117,6 +117,17 @@ access2
|
||||||
ambient
|
ambient
|
||||||
This contains the Smack label applied to unlabeled network
|
This contains the Smack label applied to unlabeled network
|
||||||
packets.
|
packets.
|
||||||
|
change-rule
|
||||||
|
This interface allows modification of existing access control rules.
|
||||||
|
The format accepted on write is:
|
||||||
|
"%s %s %s %s"
|
||||||
|
where the first string is the subject label, the second the
|
||||||
|
object label, the third the access to allow and the fourth the
|
||||||
|
access to deny. The access strings may contain only the characters
|
||||||
|
"rwxat-". If a rule for a given subject and object exists it will be
|
||||||
|
modified by enabling the permissions in the third string and disabling
|
||||||
|
those in the fourth string. If there is no such rule it will be
|
||||||
|
created using the access specified in the third and the fourth strings.
|
||||||
cipso
|
cipso
|
||||||
This interface allows a specific CIPSO header to be assigned
|
This interface allows a specific CIPSO header to be assigned
|
||||||
to a Smack label. The format accepted on write is:
|
to a Smack label. The format accepted on write is:
|
||||||
|
|
|
@ -1337,7 +1337,7 @@ int tpm_pm_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||||
struct tpm_cmd_t cmd;
|
struct tpm_cmd_t cmd;
|
||||||
int rc;
|
int rc, try;
|
||||||
|
|
||||||
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
|
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
|
||||||
|
|
||||||
|
@ -1355,9 +1355,32 @@ int tpm_pm_suspend(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now do the actual savestate */
|
/* now do the actual savestate */
|
||||||
cmd.header.in = savestate_header;
|
for (try = 0; try < TPM_RETRY; try++) {
|
||||||
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
|
cmd.header.in = savestate_header;
|
||||||
"sending savestate before suspend");
|
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the TPM indicates that it is too busy to respond to
|
||||||
|
* this command then retry before giving up. It can take
|
||||||
|
* several seconds for this TPM to be ready.
|
||||||
|
*
|
||||||
|
* This can happen if the TPM has already been sent the
|
||||||
|
* SaveState command before the driver has loaded. TCG 1.2
|
||||||
|
* specification states that any communication after SaveState
|
||||||
|
* may cause the TPM to invalidate previously saved state.
|
||||||
|
*/
|
||||||
|
if (rc != TPM_WARN_RETRY)
|
||||||
|
break;
|
||||||
|
msleep(TPM_TIMEOUT_RETRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
dev_err(chip->dev,
|
||||||
|
"Error (%d) sending savestate before suspend\n", rc);
|
||||||
|
else if (try > 0)
|
||||||
|
dev_warn(chip->dev, "TPM savestate took %dms\n",
|
||||||
|
try * TPM_TIMEOUT_RETRY);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_pm_suspend);
|
EXPORT_SYMBOL_GPL(tpm_pm_suspend);
|
||||||
|
|
|
@ -32,10 +32,12 @@ enum tpm_const {
|
||||||
TPM_MINOR = 224, /* officially assigned */
|
TPM_MINOR = 224, /* officially assigned */
|
||||||
TPM_BUFSIZE = 4096,
|
TPM_BUFSIZE = 4096,
|
||||||
TPM_NUM_DEVICES = 256,
|
TPM_NUM_DEVICES = 256,
|
||||||
|
TPM_RETRY = 50, /* 5 seconds */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum tpm_timeout {
|
enum tpm_timeout {
|
||||||
TPM_TIMEOUT = 5, /* msecs */
|
TPM_TIMEOUT = 5, /* msecs */
|
||||||
|
TPM_TIMEOUT_RETRY = 100 /* msecs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TPM addresses */
|
/* TPM addresses */
|
||||||
|
@ -44,6 +46,7 @@ enum tpm_addr {
|
||||||
TPM_ADDR = 0x4E,
|
TPM_ADDR = 0x4E,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TPM_WARN_RETRY 0x800
|
||||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||||
#define TPM_ERR_DEACTIVATED 0x6
|
#define TPM_ERR_DEACTIVATED 0x6
|
||||||
#define TPM_ERR_DISABLED 0x7
|
#define TPM_ERR_DISABLED 0x7
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Infineon Technologies
|
* Copyright (C) 2012,2013 Infineon Technologies
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Peter Huewe <peter.huewe@infineon.com>
|
* Peter Huewe <peter.huewe@infineon.com>
|
||||||
|
@ -56,13 +56,21 @@
|
||||||
#define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000)
|
#define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000)
|
||||||
|
|
||||||
/* expected value for DIDVID register */
|
/* expected value for DIDVID register */
|
||||||
#define TPM_TIS_I2C_DID_VID 0x000b15d1L
|
#define TPM_TIS_I2C_DID_VID_9635 0xd1150b00L
|
||||||
|
#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
|
||||||
|
|
||||||
|
enum i2c_chip_type {
|
||||||
|
SLB9635,
|
||||||
|
SLB9645,
|
||||||
|
UNKNOWN,
|
||||||
|
};
|
||||||
|
|
||||||
/* Structure to store I2C TPM specific stuff */
|
/* Structure to store I2C TPM specific stuff */
|
||||||
struct tpm_inf_dev {
|
struct tpm_inf_dev {
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */
|
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
|
enum i2c_chip_type chip_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tpm_inf_dev tpm_dev;
|
static struct tpm_inf_dev tpm_dev;
|
||||||
|
@ -90,10 +98,20 @@ static struct i2c_driver tpm_tis_i2c_driver;
|
||||||
static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
|
static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr };
|
struct i2c_msg msg1 = {
|
||||||
struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer };
|
.addr = tpm_dev.client->addr,
|
||||||
|
.len = 1,
|
||||||
|
.buf = &addr
|
||||||
|
};
|
||||||
|
struct i2c_msg msg2 = {
|
||||||
|
.addr = tpm_dev.client->addr,
|
||||||
|
.flags = I2C_M_RD,
|
||||||
|
.len = len,
|
||||||
|
.buf = buffer
|
||||||
|
};
|
||||||
|
struct i2c_msg msgs[] = {msg1, msg2};
|
||||||
|
|
||||||
int rc;
|
int rc = 0;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
/* Lock the adapter for the duration of the whole sequence. */
|
/* Lock the adapter for the duration of the whole sequence. */
|
||||||
|
@ -101,30 +119,53 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
i2c_lock_adapter(tpm_dev.client->adapter);
|
i2c_lock_adapter(tpm_dev.client->adapter);
|
||||||
|
|
||||||
for (count = 0; count < MAX_COUNT; count++) {
|
if (tpm_dev.chip_type == SLB9645) {
|
||||||
rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
|
/* use a combined read for newer chips
|
||||||
if (rc > 0)
|
* unfortunately the smbus functions are not suitable due to
|
||||||
break; /* break here to skip sleep */
|
* the 32 byte limit of the smbus.
|
||||||
|
* retries should usually not be needed, but are kept just to
|
||||||
|
* be on the safe side.
|
||||||
|
*/
|
||||||
|
for (count = 0; count < MAX_COUNT; count++) {
|
||||||
|
rc = __i2c_transfer(tpm_dev.client->adapter, msgs, 2);
|
||||||
|
if (rc > 0)
|
||||||
|
break; /* break here to skip sleep */
|
||||||
|
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* slb9635 protocol should work in all cases */
|
||||||
|
for (count = 0; count < MAX_COUNT; count++) {
|
||||||
|
rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
|
||||||
|
if (rc > 0)
|
||||||
|
break; /* break here to skip sleep */
|
||||||
|
|
||||||
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* After the TPM has successfully received the register address it needs
|
|
||||||
* some time, thus we're sleeping here again, before retrieving the data
|
|
||||||
*/
|
|
||||||
for (count = 0; count < MAX_COUNT; count++) {
|
|
||||||
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
|
||||||
rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
|
|
||||||
if (rc > 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
/* After the TPM has successfully received the register address
|
||||||
|
* it needs some time, thus we're sleeping here again, before
|
||||||
|
* retrieving the data
|
||||||
|
*/
|
||||||
|
for (count = 0; count < MAX_COUNT; count++) {
|
||||||
|
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
||||||
|
rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
|
||||||
|
if (rc > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
i2c_unlock_adapter(tpm_dev.client->adapter);
|
i2c_unlock_adapter(tpm_dev.client->adapter);
|
||||||
|
/* take care of 'guard time' */
|
||||||
|
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
||||||
|
|
||||||
|
/* __i2c_transfer returns the number of successfully transferred
|
||||||
|
* messages.
|
||||||
|
* So rc should be greater than 0 here otherwise we have an error.
|
||||||
|
*/
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -138,7 +179,11 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
|
||||||
int rc = -EIO;
|
int rc = -EIO;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf };
|
struct i2c_msg msg1 = {
|
||||||
|
.addr = tpm_dev.client->addr,
|
||||||
|
.len = len + 1,
|
||||||
|
.buf = tpm_dev.buf
|
||||||
|
};
|
||||||
|
|
||||||
if (len > TPM_BUFSIZE)
|
if (len > TPM_BUFSIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -154,16 +199,24 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
|
||||||
/*
|
/*
|
||||||
* NOTE: We have to use these special mechanisms here and unfortunately
|
* NOTE: We have to use these special mechanisms here and unfortunately
|
||||||
* cannot rely on the standard behavior of i2c_transfer.
|
* cannot rely on the standard behavior of i2c_transfer.
|
||||||
|
* Even for newer chips the smbus functions are not
|
||||||
|
* suitable due to the 32 byte limit of the smbus.
|
||||||
*/
|
*/
|
||||||
for (count = 0; count < max_count; count++) {
|
for (count = 0; count < max_count; count++) {
|
||||||
rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
|
rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
usleep_range(sleep_low, sleep_hi);
|
usleep_range(sleep_low, sleep_hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_unlock_adapter(tpm_dev.client->adapter);
|
i2c_unlock_adapter(tpm_dev.client->adapter);
|
||||||
|
/* take care of 'guard time' */
|
||||||
|
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
|
||||||
|
|
||||||
|
/* __i2c_transfer returns the number of successfully transferred
|
||||||
|
* messages.
|
||||||
|
* So rc should be greater than 0 here otherwise we have an error.
|
||||||
|
*/
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -283,11 +336,18 @@ static int request_locality(struct tpm_chip *chip, int loc)
|
||||||
static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
|
static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
/* NOTE: since I2C read may fail, return 0 in this case --> time-out */
|
/* NOTE: since I2C read may fail, return 0 in this case --> time-out */
|
||||||
u8 buf;
|
u8 buf = 0xFF;
|
||||||
if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
|
u8 i = 0;
|
||||||
return 0;
|
|
||||||
else
|
do {
|
||||||
return buf;
|
if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
/* if locallity is set STS should not be 0xFF */
|
||||||
|
} while ((buf == 0xFF) && i < 10);
|
||||||
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tpm_tis_i2c_ready(struct tpm_chip *chip)
|
static void tpm_tis_i2c_ready(struct tpm_chip *chip)
|
||||||
|
@ -328,7 +388,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||||
|
|
||||||
/* check current status */
|
/* check current status */
|
||||||
*status = tpm_tis_i2c_status(chip);
|
*status = tpm_tis_i2c_status(chip);
|
||||||
if ((*status & mask) == mask)
|
if ((*status != 0xFF) && (*status & mask) == mask)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
stop = jiffies + timeout;
|
stop = jiffies + timeout;
|
||||||
|
@ -372,7 +432,6 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
/* avoid endless loop in case of broken HW */
|
/* avoid endless loop in case of broken HW */
|
||||||
if (retries > MAX_COUNT_LONG)
|
if (retries > MAX_COUNT_LONG)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +539,6 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write last byte */
|
/* write last byte */
|
||||||
|
@ -568,6 +626,7 @@ static int tpm_tis_i2c_init(struct device *dev)
|
||||||
|
|
||||||
chip = tpm_register_hardware(dev, &tpm_tis_i2c);
|
chip = tpm_register_hardware(dev, &tpm_tis_i2c);
|
||||||
if (!chip) {
|
if (!chip) {
|
||||||
|
dev_err(dev, "could not register hardware\n");
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
@ -582,20 +641,24 @@ static int tpm_tis_i2c_init(struct device *dev)
|
||||||
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
||||||
|
|
||||||
if (request_locality(chip, 0) != 0) {
|
if (request_locality(chip, 0) != 0) {
|
||||||
|
dev_err(dev, "could not request locality\n");
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto out_vendor;
|
goto out_vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read four bytes from DID_VID register */
|
/* read four bytes from DID_VID register */
|
||||||
if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) {
|
if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) {
|
||||||
|
dev_err(dev, "could not read vendor id\n");
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto out_release;
|
goto out_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create DID_VID register value, after swapping to little-endian */
|
if (vendor == TPM_TIS_I2C_DID_VID_9645) {
|
||||||
vendor = be32_to_cpu((__be32) vendor);
|
tpm_dev.chip_type = SLB9645;
|
||||||
|
} else if (vendor == TPM_TIS_I2C_DID_VID_9635) {
|
||||||
if (vendor != TPM_TIS_I2C_DID_VID) {
|
tpm_dev.chip_type = SLB9635;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "vendor id did not match! ID was %08x\n", vendor);
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto out_release;
|
goto out_release;
|
||||||
}
|
}
|
||||||
|
@ -631,22 +694,53 @@ out_err:
|
||||||
|
|
||||||
static const struct i2c_device_id tpm_tis_i2c_table[] = {
|
static const struct i2c_device_id tpm_tis_i2c_table[] = {
|
||||||
{"tpm_i2c_infineon", 0},
|
{"tpm_i2c_infineon", 0},
|
||||||
|
{"slb9635tt", 0},
|
||||||
|
{"slb9645tt", 1},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
|
MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id tpm_tis_i2c_of_match[] = {
|
||||||
|
{
|
||||||
|
.name = "tpm_i2c_infineon",
|
||||||
|
.type = "tpm",
|
||||||
|
.compatible = "infineon,tpm_i2c_infineon",
|
||||||
|
.data = (void *)0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "slb9635tt",
|
||||||
|
.type = "tpm",
|
||||||
|
.compatible = "infineon,slb9635tt",
|
||||||
|
.data = (void *)0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "slb9645tt",
|
||||||
|
.type = "tpm",
|
||||||
|
.compatible = "infineon,slb9645tt",
|
||||||
|
.data = (void *)1
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume);
|
static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume);
|
||||||
|
|
||||||
static int tpm_tis_i2c_probe(struct i2c_client *client,
|
static int tpm_tis_i2c_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
if (tpm_dev.client != NULL)
|
struct device *dev = &(client->dev);
|
||||||
|
|
||||||
|
if (tpm_dev.client != NULL) {
|
||||||
|
dev_err(dev, "This driver only supports one client at a time\n");
|
||||||
return -EBUSY; /* We only support one client */
|
return -EBUSY; /* We only support one client */
|
||||||
|
}
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||||
dev_err(&client->dev,
|
dev_err(dev, "no algorithms associated to the i2c bus\n");
|
||||||
"no algorithms associated to the i2c bus\n");
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +776,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct i2c_driver tpm_tis_i2c_driver = {
|
static struct i2c_driver tpm_tis_i2c_driver = {
|
||||||
|
|
||||||
.id_table = tpm_tis_i2c_table,
|
.id_table = tpm_tis_i2c_table,
|
||||||
.probe = tpm_tis_i2c_probe,
|
.probe = tpm_tis_i2c_probe,
|
||||||
.remove = tpm_tis_i2c_remove,
|
.remove = tpm_tis_i2c_remove,
|
||||||
|
@ -690,11 +783,12 @@ static struct i2c_driver tpm_tis_i2c_driver = {
|
||||||
.name = "tpm_i2c_infineon",
|
.name = "tpm_i2c_infineon",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pm = &tpm_tis_i2c_ops,
|
.pm = &tpm_tis_i2c_ops,
|
||||||
|
.of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module_i2c_driver(tpm_tis_i2c_driver);
|
module_i2c_driver(tpm_tis_i2c_driver);
|
||||||
MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>");
|
MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>");
|
||||||
MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver");
|
MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver");
|
||||||
MODULE_VERSION("2.1.5");
|
MODULE_VERSION("2.2.0");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -50,7 +49,6 @@
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sched.h>
|
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_i2c_stm_st33.h"
|
#include "tpm_i2c_stm_st33.h"
|
||||||
|
@ -178,7 +176,7 @@ static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct st33zp24_platform_data *pin_infos;
|
struct st33zp24_platform_data *pin_infos;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
pin_infos = client->dev.platform_data;
|
pin_infos = client->dev.platform_data;
|
||||||
|
|
||||||
status = wait_for_completion_interruptible_timeout(
|
status = wait_for_completion_interruptible_timeout(
|
||||||
|
@ -197,12 +195,12 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
|
||||||
int status = 2;
|
int status = 2;
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
status = _wait_for_interrupt_serirq_timeout(chip, timeout);
|
status = _wait_for_interrupt_serirq_timeout(chip, timeout);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
status = -EBUSY;
|
status = -EBUSY;
|
||||||
} else{
|
} else {
|
||||||
clear_interruption(client);
|
clear_interruption(client);
|
||||||
if (condition)
|
if (condition)
|
||||||
status = 1;
|
status = 1;
|
||||||
|
@ -219,7 +217,7 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u8 data;
|
u8 data;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
data = TPM_STS_COMMAND_READY;
|
data = TPM_STS_COMMAND_READY;
|
||||||
I2C_WRITE_DATA(client, TPM_STS, &data, 1);
|
I2C_WRITE_DATA(client, TPM_STS, &data, 1);
|
||||||
|
@ -236,7 +234,7 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u8 data;
|
u8 data;
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
I2C_READ_DATA(client, TPM_STS, &data, 1);
|
I2C_READ_DATA(client, TPM_STS, &data, 1);
|
||||||
return data;
|
return data;
|
||||||
|
@ -254,7 +252,7 @@ static int check_locality(struct tpm_chip *chip)
|
||||||
u8 data;
|
u8 data;
|
||||||
u8 status;
|
u8 status;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1);
|
status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1);
|
||||||
if (status && (data &
|
if (status && (data &
|
||||||
|
@ -278,7 +276,7 @@ static int request_locality(struct tpm_chip *chip)
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u8 data;
|
u8 data;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
if (check_locality(chip) == chip->vendor.locality)
|
if (check_locality(chip) == chip->vendor.locality)
|
||||||
return chip->vendor.locality;
|
return chip->vendor.locality;
|
||||||
|
@ -294,7 +292,7 @@ static int request_locality(struct tpm_chip *chip)
|
||||||
chip->vendor.timeout_a);
|
chip->vendor.timeout_a);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
return chip->vendor.locality;
|
return chip->vendor.locality;
|
||||||
} else{
|
} else {
|
||||||
stop = jiffies + chip->vendor.timeout_a;
|
stop = jiffies + chip->vendor.timeout_a;
|
||||||
do {
|
do {
|
||||||
if (check_locality(chip) >= 0)
|
if (check_locality(chip) >= 0)
|
||||||
|
@ -316,7 +314,7 @@ static void release_locality(struct tpm_chip *chip)
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u8 data;
|
u8 data;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
data = TPM_ACCESS_ACTIVE_LOCALITY;
|
data = TPM_ACCESS_ACTIVE_LOCALITY;
|
||||||
|
|
||||||
I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
|
I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
|
||||||
|
@ -333,7 +331,7 @@ static int get_burstcount(struct tpm_chip *chip)
|
||||||
int burstcnt, status;
|
int burstcnt, status;
|
||||||
u8 tpm_reg, temp;
|
u8 tpm_reg, temp;
|
||||||
|
|
||||||
struct i2c_client *client = (struct i2c_client *) TPM_VPRIV(chip);
|
struct i2c_client *client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
stop = jiffies + chip->vendor.timeout_d;
|
stop = jiffies + chip->vendor.timeout_d;
|
||||||
do {
|
do {
|
||||||
|
@ -379,7 +377,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||||
mask), timeout);
|
mask), timeout);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
return 0;
|
return 0;
|
||||||
} else{
|
} else {
|
||||||
stop = jiffies + timeout;
|
stop = jiffies + timeout;
|
||||||
do {
|
do {
|
||||||
msleep(TPM_TIMEOUT);
|
msleep(TPM_TIMEOUT);
|
||||||
|
@ -403,7 +401,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
int size = 0, burstcnt, len;
|
int size = 0, burstcnt, len;
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
|
|
||||||
while (size < count &&
|
while (size < count &&
|
||||||
wait_for_stat(chip,
|
wait_for_stat(chip,
|
||||||
|
@ -433,7 +431,7 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
|
||||||
|
|
||||||
disable_irq_nosync(irq);
|
disable_irq_nosync(irq);
|
||||||
|
|
||||||
client = (struct i2c_client *) TPM_VPRIV(chip);
|
client = (struct i2c_client *)TPM_VPRIV(chip);
|
||||||
pin_infos = client->dev.platform_data;
|
pin_infos = client->dev.platform_data;
|
||||||
|
|
||||||
complete(&pin_infos->irq_detection);
|
complete(&pin_infos->irq_detection);
|
||||||
|
@ -453,8 +451,7 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
|
||||||
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
u32 status,
|
u32 status, burstcnt = 0, i, size;
|
||||||
burstcnt = 0, i, size;
|
|
||||||
int ret;
|
int ret;
|
||||||
u8 data;
|
u8 data;
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
@ -483,7 +480,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0 ; i < len - 1 ;) {
|
for (i = 0; i < len - 1;) {
|
||||||
burstcnt = get_burstcount(chip);
|
burstcnt = get_burstcount(chip);
|
||||||
size = min_t(int, len - i - 1, burstcnt);
|
size = min_t(int, len - i - 1, burstcnt);
|
||||||
ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
|
ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
|
||||||
|
@ -547,7 +544,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = be32_to_cpu(*(__be32 *) (buf + 2));
|
expected = be32_to_cpu(*(__be32 *)(buf + 2));
|
||||||
if (expected > count) {
|
if (expected > count) {
|
||||||
size = -EIO;
|
size = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -569,7 +566,7 @@ out:
|
||||||
|
|
||||||
static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
{
|
{
|
||||||
return (status == TPM_STS_COMMAND_READY);
|
return (status == TPM_STS_COMMAND_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations tpm_st33_i2c_fops = {
|
static const struct file_operations tpm_st33_i2c_fops = {
|
||||||
|
@ -617,7 +614,7 @@ static struct tpm_vendor_specific st_i2c_tpm = {
|
||||||
.miscdev = {.fops = &tpm_st33_i2c_fops,},
|
.miscdev = {.fops = &tpm_st33_i2c_fops,},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int interrupts ;
|
static int interrupts;
|
||||||
module_param(interrupts, int, 0444);
|
module_param(interrupts, int, 0444);
|
||||||
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
||||||
|
|
||||||
|
@ -714,7 +711,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
"TPM SERIRQ management", chip);
|
"TPM SERIRQ management", chip);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
|
dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
|
||||||
gpio_to_irq(platform_data->io_serirq));
|
gpio_to_irq(platform_data->io_serirq));
|
||||||
goto _irq_set;
|
goto _irq_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +751,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
dev_info(chip->dev, "TPM I2C Initialized\n");
|
dev_info(chip->dev, "TPM I2C Initialized\n");
|
||||||
return 0;
|
return 0;
|
||||||
_irq_set:
|
_irq_set:
|
||||||
free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip);
|
free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
|
||||||
_gpio_init2:
|
_gpio_init2:
|
||||||
if (interrupts)
|
if (interrupts)
|
||||||
gpio_free(platform_data->io_serirq);
|
gpio_free(platform_data->io_serirq);
|
||||||
|
@ -784,7 +781,7 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
|
struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
|
||||||
struct st33zp24_platform_data *pin_infos =
|
struct st33zp24_platform_data *pin_infos =
|
||||||
((struct i2c_client *) TPM_VPRIV(chip))->dev.platform_data;
|
((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
|
||||||
|
|
||||||
if (pin_infos != NULL) {
|
if (pin_infos != NULL) {
|
||||||
free_irq(pin_infos->io_serirq, chip);
|
free_irq(pin_infos->io_serirq, chip);
|
||||||
|
@ -823,9 +820,9 @@ static int tpm_st33_i2c_pm_suspend(struct device *dev)
|
||||||
struct st33zp24_platform_data *pin_infos = dev->platform_data;
|
struct st33zp24_platform_data *pin_infos = dev->platform_data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (power_mgt)
|
if (power_mgt) {
|
||||||
gpio_set_value(pin_infos->io_lpcpd, 0);
|
gpio_set_value(pin_infos->io_lpcpd, 0);
|
||||||
else{
|
} else {
|
||||||
if (chip->data_buffer == NULL)
|
if (chip->data_buffer == NULL)
|
||||||
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
|
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
|
||||||
ret = tpm_pm_suspend(dev);
|
ret = tpm_pm_suspend(dev);
|
||||||
|
@ -851,12 +848,12 @@ static int tpm_st33_i2c_pm_resume(struct device *dev)
|
||||||
(chip->vendor.status(chip) &
|
(chip->vendor.status(chip) &
|
||||||
TPM_STS_VALID) == TPM_STS_VALID,
|
TPM_STS_VALID) == TPM_STS_VALID,
|
||||||
chip->vendor.timeout_b);
|
chip->vendor.timeout_b);
|
||||||
} else{
|
} else {
|
||||||
if (chip->data_buffer == NULL)
|
if (chip->data_buffer == NULL)
|
||||||
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
|
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
|
||||||
ret = tpm_pm_resume(dev);
|
ret = tpm_pm_resume(dev);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
tpm_do_selftest(chip);
|
tpm_do_selftest(chip);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} /* tpm_st33_i2c_pm_resume() */
|
} /* tpm_st33_i2c_pm_resume() */
|
||||||
|
@ -867,7 +864,8 @@ static const struct i2c_device_id tpm_st33_i2c_id[] = {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
|
MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
|
||||||
static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, tpm_st33_i2c_pm_resume);
|
static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend,
|
||||||
|
tpm_st33_i2c_pm_resume);
|
||||||
static struct i2c_driver tpm_st33_i2c_driver = {
|
static struct i2c_driver tpm_st33_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
|
|
@ -158,9 +158,9 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||||
ACPI_TYPE_STRING);
|
ACPI_TYPE_STRING);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
strncpy(version,
|
strlcpy(version,
|
||||||
((union acpi_object *)output.pointer)->string.pointer,
|
((union acpi_object *)output.pointer)->string.pointer,
|
||||||
PPI_VERSION_LEN);
|
PPI_VERSION_LEN + 1);
|
||||||
kfree(output.pointer);
|
kfree(output.pointer);
|
||||||
output.length = ACPI_ALLOCATE_BUFFER;
|
output.length = ACPI_ALLOCATE_BUFFER;
|
||||||
output.pointer = NULL;
|
output.pointer = NULL;
|
||||||
|
@ -237,9 +237,9 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
|
||||||
ACPI_TYPE_STRING);
|
ACPI_TYPE_STRING);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
strncpy(version,
|
strlcpy(version,
|
||||||
((union acpi_object *)output.pointer)->string.pointer,
|
((union acpi_object *)output.pointer)->string.pointer,
|
||||||
PPI_VERSION_LEN);
|
PPI_VERSION_LEN + 1);
|
||||||
/*
|
/*
|
||||||
* PPI spec defines params[3].type as empty package, but some platforms
|
* PPI spec defines params[3].type as empty package, but some platforms
|
||||||
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
|
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
|
||||||
|
@ -351,7 +351,7 @@ cleanup:
|
||||||
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
||||||
{
|
{
|
||||||
char *str = buf;
|
char *str = buf;
|
||||||
char version[PPI_VERSION_LEN];
|
char version[PPI_VERSION_LEN + 1];
|
||||||
acpi_handle handle;
|
acpi_handle handle;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
struct acpi_object_list input;
|
struct acpi_object_list input;
|
||||||
|
@ -381,9 +381,9 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
strncpy(version,
|
strlcpy(version,
|
||||||
((union acpi_object *)output.pointer)->string.pointer,
|
((union acpi_object *)output.pointer)->string.pointer,
|
||||||
PPI_VERSION_LEN);
|
PPI_VERSION_LEN + 1);
|
||||||
kfree(output.pointer);
|
kfree(output.pointer);
|
||||||
output.length = ACPI_ALLOCATE_BUFFER;
|
output.length = ACPI_ALLOCATE_BUFFER;
|
||||||
output.pointer = NULL;
|
output.pointer = NULL;
|
||||||
|
|
|
@ -2385,10 +2385,9 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
|
||||||
struct nfs_mount_info *mount_info)
|
struct nfs_mount_info *mount_info)
|
||||||
{
|
{
|
||||||
/* clone any lsm security options from the parent to the new sb */
|
/* clone any lsm security options from the parent to the new sb */
|
||||||
security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
|
|
||||||
if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
|
if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
|
||||||
return -ESTALE;
|
return -ESTALE;
|
||||||
return 0;
|
return security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
|
EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
|
||||||
|
|
||||||
|
|
|
@ -1440,7 +1440,7 @@ struct security_operations {
|
||||||
struct path *new_path);
|
struct path *new_path);
|
||||||
int (*sb_set_mnt_opts) (struct super_block *sb,
|
int (*sb_set_mnt_opts) (struct super_block *sb,
|
||||||
struct security_mnt_opts *opts);
|
struct security_mnt_opts *opts);
|
||||||
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
|
int (*sb_clone_mnt_opts) (const struct super_block *oldsb,
|
||||||
struct super_block *newsb);
|
struct super_block *newsb);
|
||||||
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
|
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
|
||||||
|
|
||||||
|
@ -1726,7 +1726,7 @@ int security_sb_mount(const char *dev_name, struct path *path,
|
||||||
int security_sb_umount(struct vfsmount *mnt, int flags);
|
int security_sb_umount(struct vfsmount *mnt, int flags);
|
||||||
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
|
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
|
||||||
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
|
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
|
||||||
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
struct super_block *newsb);
|
struct super_block *newsb);
|
||||||
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
|
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
|
||||||
|
|
||||||
|
@ -2016,9 +2016,11 @@ static inline int security_sb_set_mnt_opts(struct super_block *sb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
struct super_block *newsb)
|
struct super_block *newsb)
|
||||||
{ }
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
|
static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define DEBUGFS_MAGIC 0x64626720
|
#define DEBUGFS_MAGIC 0x64626720
|
||||||
#define SECURITYFS_MAGIC 0x73636673
|
#define SECURITYFS_MAGIC 0x73636673
|
||||||
#define SELINUX_MAGIC 0xf97cff8c
|
#define SELINUX_MAGIC 0xf97cff8c
|
||||||
|
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
|
||||||
#define RAMFS_MAGIC 0x858458f6 /* some random number */
|
#define RAMFS_MAGIC 0x858458f6 /* some random number */
|
||||||
#define TMPFS_MAGIC 0x01021994
|
#define TMPFS_MAGIC 0x01021994
|
||||||
#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */
|
#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */
|
||||||
|
|
|
@ -160,6 +160,8 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
|
||||||
case BPF_S_ALU_AND_X:
|
case BPF_S_ALU_AND_X:
|
||||||
case BPF_S_ALU_OR_K:
|
case BPF_S_ALU_OR_K:
|
||||||
case BPF_S_ALU_OR_X:
|
case BPF_S_ALU_OR_X:
|
||||||
|
case BPF_S_ALU_XOR_K:
|
||||||
|
case BPF_S_ALU_XOR_X:
|
||||||
case BPF_S_ALU_LSH_K:
|
case BPF_S_ALU_LSH_K:
|
||||||
case BPF_S_ALU_LSH_X:
|
case BPF_S_ALU_LSH_X:
|
||||||
case BPF_S_ALU_RSH_K:
|
case BPF_S_ALU_RSH_K:
|
||||||
|
|
|
@ -98,9 +98,10 @@ static int cap_sb_set_mnt_opts(struct super_block *sb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cap_sb_clone_mnt_opts(const struct super_block *oldsb,
|
static int cap_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
struct super_block *newsb)
|
struct super_block *newsb)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
|
static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
|
||||||
|
|
|
@ -189,11 +189,9 @@ static int process_measurement(struct file *file, const char *filename,
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
goto out_digsig;
|
goto out_digsig;
|
||||||
|
|
||||||
if (function != BPRM_CHECK)
|
pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename;
|
||||||
pathname = ima_d_path(&file->f_path, &pathbuf);
|
|
||||||
|
|
||||||
if (!pathname)
|
if (!pathname)
|
||||||
pathname = filename;
|
pathname = (const char *)file->f_dentry->d_name.name;
|
||||||
|
|
||||||
if (action & IMA_MEASURE)
|
if (action & IMA_MEASURE)
|
||||||
ima_store_measurement(iint, file, pathname);
|
ima_store_measurement(iint, file, pathname);
|
||||||
|
@ -226,8 +224,7 @@ out:
|
||||||
int ima_file_mmap(struct file *file, unsigned long prot)
|
int ima_file_mmap(struct file *file, unsigned long prot)
|
||||||
{
|
{
|
||||||
if (file && (prot & PROT_EXEC))
|
if (file && (prot & PROT_EXEC))
|
||||||
return process_measurement(file, file->f_dentry->d_name.name,
|
return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
|
||||||
MAY_EXEC, MMAP_CHECK);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +262,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
|
||||||
int ima_file_check(struct file *file, int mask)
|
int ima_file_check(struct file *file, int mask)
|
||||||
{
|
{
|
||||||
ima_rdwr_violation_check(file);
|
ima_rdwr_violation_check(file);
|
||||||
return process_measurement(file, file->f_dentry->d_name.name,
|
return process_measurement(file, NULL,
|
||||||
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
||||||
FILE_CHECK);
|
FILE_CHECK);
|
||||||
}
|
}
|
||||||
|
@ -290,8 +287,7 @@ int ima_module_check(struct file *file)
|
||||||
#endif
|
#endif
|
||||||
return 0; /* We rely on module signature checking */
|
return 0; /* We rely on module signature checking */
|
||||||
}
|
}
|
||||||
return process_measurement(file, file->f_dentry->d_name.name,
|
return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
|
||||||
MAY_EXEC, MODULE_CHECK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init init_ima(void)
|
static int __init init_ima(void)
|
||||||
|
|
|
@ -299,10 +299,10 @@ int security_sb_set_mnt_opts(struct super_block *sb,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(security_sb_set_mnt_opts);
|
EXPORT_SYMBOL(security_sb_set_mnt_opts);
|
||||||
|
|
||||||
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
struct super_block *newsb)
|
struct super_block *newsb)
|
||||||
{
|
{
|
||||||
security_ops->sb_clone_mnt_opts(oldsb, newsb);
|
return security_ops->sb_clone_mnt_opts(oldsb, newsb);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(security_sb_clone_mnt_opts);
|
EXPORT_SYMBOL(security_sb_clone_mnt_opts);
|
||||||
|
|
||||||
|
|
|
@ -751,7 +751,37 @@ out_double_mount:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
static int selinux_cmp_sb_context(const struct super_block *oldsb,
|
||||||
|
const struct super_block *newsb)
|
||||||
|
{
|
||||||
|
struct superblock_security_struct *old = oldsb->s_security;
|
||||||
|
struct superblock_security_struct *new = newsb->s_security;
|
||||||
|
char oldflags = old->flags & SE_MNTMASK;
|
||||||
|
char newflags = new->flags & SE_MNTMASK;
|
||||||
|
|
||||||
|
if (oldflags != newflags)
|
||||||
|
goto mismatch;
|
||||||
|
if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
|
||||||
|
goto mismatch;
|
||||||
|
if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
|
||||||
|
goto mismatch;
|
||||||
|
if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
|
||||||
|
goto mismatch;
|
||||||
|
if (oldflags & ROOTCONTEXT_MNT) {
|
||||||
|
struct inode_security_struct *oldroot = oldsb->s_root->d_inode->i_security;
|
||||||
|
struct inode_security_struct *newroot = newsb->s_root->d_inode->i_security;
|
||||||
|
if (oldroot->sid != newroot->sid)
|
||||||
|
goto mismatch;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
mismatch:
|
||||||
|
printk(KERN_WARNING "SELinux: mount invalid. Same superblock, "
|
||||||
|
"different security settings for (dev %s, "
|
||||||
|
"type %s)\n", newsb->s_id, newsb->s_type->name);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
struct super_block *newsb)
|
struct super_block *newsb)
|
||||||
{
|
{
|
||||||
const struct superblock_security_struct *oldsbsec = oldsb->s_security;
|
const struct superblock_security_struct *oldsbsec = oldsb->s_security;
|
||||||
|
@ -766,14 +796,14 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
* mount options. thus we can safely deal with this superblock later
|
* mount options. thus we can safely deal with this superblock later
|
||||||
*/
|
*/
|
||||||
if (!ss_initialized)
|
if (!ss_initialized)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/* how can we clone if the old one wasn't set up?? */
|
/* how can we clone if the old one wasn't set up?? */
|
||||||
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
|
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
|
||||||
|
|
||||||
/* if fs is reusing a sb, just let its options stand... */
|
/* if fs is reusing a sb, make sure that the contexts match */
|
||||||
if (newsbsec->flags & SE_SBINITIALIZED)
|
if (newsbsec->flags & SE_SBINITIALIZED)
|
||||||
return;
|
return selinux_cmp_sb_context(oldsb, newsb);
|
||||||
|
|
||||||
mutex_lock(&newsbsec->lock);
|
mutex_lock(&newsbsec->lock);
|
||||||
|
|
||||||
|
@ -806,6 +836,7 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||||
|
|
||||||
sb_finish_set_opts(newsb);
|
sb_finish_set_opts(newsb);
|
||||||
mutex_unlock(&newsbsec->lock);
|
mutex_unlock(&newsbsec->lock);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_parse_opts_str(char *options,
|
static int selinux_parse_opts_str(char *options,
|
||||||
|
|
|
@ -148,11 +148,6 @@ struct smack_known {
|
||||||
#define SMACK_UNLABELED_SOCKET 0
|
#define SMACK_UNLABELED_SOCKET 0
|
||||||
#define SMACK_CIPSO_SOCKET 1
|
#define SMACK_CIPSO_SOCKET 1
|
||||||
|
|
||||||
/*
|
|
||||||
* smackfs magic number
|
|
||||||
*/
|
|
||||||
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CIPSO defaults.
|
* CIPSO defaults.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -252,6 +252,8 @@ static inline void smack_str_from_perm(char *string, int access)
|
||||||
string[i++] = 'x';
|
string[i++] = 'x';
|
||||||
if (access & MAY_APPEND)
|
if (access & MAY_APPEND)
|
||||||
string[i++] = 'a';
|
string[i++] = 'a';
|
||||||
|
if (access & MAY_TRANSMUTE)
|
||||||
|
string[i++] = 't';
|
||||||
string[i] = '\0';
|
string[i] = '\0';
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -654,7 +654,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
/*
|
/*
|
||||||
* You also need write access to the containing directory
|
* You also need write access to the containing directory
|
||||||
*/
|
*/
|
||||||
smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
|
||||||
smk_ad_setfield_u_fs_inode(&ad, dir);
|
smk_ad_setfield_u_fs_inode(&ad, dir);
|
||||||
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
|
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
|
||||||
}
|
}
|
||||||
|
@ -685,7 +685,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
/*
|
/*
|
||||||
* You also need write access to the containing directory
|
* You also need write access to the containing directory
|
||||||
*/
|
*/
|
||||||
smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
|
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
|
||||||
smk_ad_setfield_u_fs_inode(&ad, dir);
|
smk_ad_setfield_u_fs_inode(&ad, dir);
|
||||||
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
|
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
#include "smack.h"
|
#include "smack.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -50,12 +51,12 @@ enum smk_inos {
|
||||||
SMK_ACCESS2 = 16, /* make an access check with long labels */
|
SMK_ACCESS2 = 16, /* make an access check with long labels */
|
||||||
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
|
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
|
||||||
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
||||||
|
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List locks
|
* List locks
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(smack_list_lock);
|
|
||||||
static DEFINE_MUTEX(smack_cipso_lock);
|
static DEFINE_MUTEX(smack_cipso_lock);
|
||||||
static DEFINE_MUTEX(smack_ambient_lock);
|
static DEFINE_MUTEX(smack_ambient_lock);
|
||||||
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
||||||
|
@ -110,6 +111,13 @@ struct smack_master_list {
|
||||||
|
|
||||||
LIST_HEAD(smack_rule_list);
|
LIST_HEAD(smack_rule_list);
|
||||||
|
|
||||||
|
struct smack_parsed_rule {
|
||||||
|
char *smk_subject;
|
||||||
|
char *smk_object;
|
||||||
|
int smk_access1;
|
||||||
|
int smk_access2;
|
||||||
|
};
|
||||||
|
|
||||||
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
||||||
|
|
||||||
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
|
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
|
||||||
|
@ -167,25 +175,28 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
|
||||||
#define SMK_NETLBLADDRMIN 9
|
#define SMK_NETLBLADDRMIN 9
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_set_access - add a rule to the rule list
|
* smk_set_access - add a rule to the rule list or replace an old rule
|
||||||
* @srp: the new rule to add
|
* @srp: the rule to add or replace
|
||||||
* @rule_list: the list of rules
|
* @rule_list: the list of rules
|
||||||
* @rule_lock: the rule list lock
|
* @rule_lock: the rule list lock
|
||||||
|
* @global: if non-zero, indicates a global rule
|
||||||
*
|
*
|
||||||
* Looks through the current subject/object/access list for
|
* Looks through the current subject/object/access list for
|
||||||
* the subject/object pair and replaces the access that was
|
* the subject/object pair and replaces the access that was
|
||||||
* there. If the pair isn't found add it with the specified
|
* there. If the pair isn't found add it with the specified
|
||||||
* access.
|
* access.
|
||||||
*
|
*
|
||||||
* Returns 1 if a rule was found to exist already, 0 if it is new
|
|
||||||
* Returns 0 if nothing goes wrong or -ENOMEM if it fails
|
* Returns 0 if nothing goes wrong or -ENOMEM if it fails
|
||||||
* during the allocation of the new pair to add.
|
* during the allocation of the new pair to add.
|
||||||
*/
|
*/
|
||||||
static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
|
static int smk_set_access(struct smack_parsed_rule *srp,
|
||||||
struct mutex *rule_lock)
|
struct list_head *rule_list,
|
||||||
|
struct mutex *rule_lock, int global)
|
||||||
{
|
{
|
||||||
struct smack_rule *sp;
|
struct smack_rule *sp;
|
||||||
|
struct smack_master_list *smlp;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
mutex_lock(rule_lock);
|
mutex_lock(rule_lock);
|
||||||
|
|
||||||
|
@ -197,23 +208,89 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
|
||||||
if (sp->smk_object == srp->smk_object &&
|
if (sp->smk_object == srp->smk_object &&
|
||||||
sp->smk_subject == srp->smk_subject) {
|
sp->smk_subject == srp->smk_subject) {
|
||||||
found = 1;
|
found = 1;
|
||||||
sp->smk_access = srp->smk_access;
|
sp->smk_access |= srp->smk_access1;
|
||||||
|
sp->smk_access &= ~srp->smk_access2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found == 0)
|
|
||||||
list_add_rcu(&srp->list, rule_list);
|
|
||||||
|
|
||||||
|
if (found == 0) {
|
||||||
|
sp = kzalloc(sizeof(*sp), GFP_KERNEL);
|
||||||
|
if (sp == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp->smk_subject = srp->smk_subject;
|
||||||
|
sp->smk_object = srp->smk_object;
|
||||||
|
sp->smk_access = srp->smk_access1 & ~srp->smk_access2;
|
||||||
|
|
||||||
|
list_add_rcu(&sp->list, rule_list);
|
||||||
|
/*
|
||||||
|
* If this is a global as opposed to self and a new rule
|
||||||
|
* it needs to get added for reporting.
|
||||||
|
*/
|
||||||
|
if (global) {
|
||||||
|
smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
|
||||||
|
if (smlp != NULL) {
|
||||||
|
smlp->smk_rule = sp;
|
||||||
|
list_add_rcu(&smlp->list, &smack_rule_list);
|
||||||
|
} else
|
||||||
|
rc = -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
mutex_unlock(rule_lock);
|
mutex_unlock(rule_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return found;
|
/**
|
||||||
|
* smk_perm_from_str - parse smack accesses from a text string
|
||||||
|
* @string: a text string that contains a Smack accesses code
|
||||||
|
*
|
||||||
|
* Returns an integer with respective bits set for specified accesses.
|
||||||
|
*/
|
||||||
|
static int smk_perm_from_str(const char *string)
|
||||||
|
{
|
||||||
|
int perm = 0;
|
||||||
|
const char *cp;
|
||||||
|
|
||||||
|
for (cp = string; ; cp++)
|
||||||
|
switch (*cp) {
|
||||||
|
case '-':
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
perm |= MAY_READ;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
case 'W':
|
||||||
|
perm |= MAY_WRITE;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
perm |= MAY_EXEC;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
perm |= MAY_APPEND;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
perm |= MAY_TRANSMUTE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return perm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_fill_rule - Fill Smack rule from strings
|
* smk_fill_rule - Fill Smack rule from strings
|
||||||
* @subject: subject label string
|
* @subject: subject label string
|
||||||
* @object: object label string
|
* @object: object label string
|
||||||
* @access: access string
|
* @access1: access string
|
||||||
|
* @access2: string with permissions to be removed
|
||||||
* @rule: Smack rule
|
* @rule: Smack rule
|
||||||
* @import: if non-zero, import labels
|
* @import: if non-zero, import labels
|
||||||
* @len: label length limit
|
* @len: label length limit
|
||||||
|
@ -221,8 +298,9 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
|
||||||
* Returns 0 on success, -1 on failure
|
* Returns 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
static int smk_fill_rule(const char *subject, const char *object,
|
static int smk_fill_rule(const char *subject, const char *object,
|
||||||
const char *access, struct smack_rule *rule,
|
const char *access1, const char *access2,
|
||||||
int import, int len)
|
struct smack_parsed_rule *rule, int import,
|
||||||
|
int len)
|
||||||
{
|
{
|
||||||
const char *cp;
|
const char *cp;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
@ -255,36 +333,11 @@ static int smk_fill_rule(const char *subject, const char *object,
|
||||||
rule->smk_object = skp->smk_known;
|
rule->smk_object = skp->smk_known;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule->smk_access = 0;
|
rule->smk_access1 = smk_perm_from_str(access1);
|
||||||
|
if (access2)
|
||||||
for (cp = access; *cp != '\0'; cp++) {
|
rule->smk_access2 = smk_perm_from_str(access2);
|
||||||
switch (*cp) {
|
else
|
||||||
case '-':
|
rule->smk_access2 = ~rule->smk_access1;
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
case 'R':
|
|
||||||
rule->smk_access |= MAY_READ;
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
case 'W':
|
|
||||||
rule->smk_access |= MAY_WRITE;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
rule->smk_access |= MAY_EXEC;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
case 'A':
|
|
||||||
rule->smk_access |= MAY_APPEND;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
case 'T':
|
|
||||||
rule->smk_access |= MAY_TRANSMUTE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -297,30 +350,33 @@ static int smk_fill_rule(const char *subject, const char *object,
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on errors.
|
* Returns 0 on success, -1 on errors.
|
||||||
*/
|
*/
|
||||||
static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
|
static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
|
||||||
|
int import)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = smk_fill_rule(data, data + SMK_LABELLEN,
|
rc = smk_fill_rule(data, data + SMK_LABELLEN,
|
||||||
data + SMK_LABELLEN + SMK_LABELLEN, rule, import,
|
data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule,
|
||||||
SMK_LABELLEN);
|
import, SMK_LABELLEN);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_parse_long_rule - parse Smack rule from rule string
|
* smk_parse_long_rule - parse Smack rule from rule string
|
||||||
* @data: string to be parsed, null terminated
|
* @data: string to be parsed, null terminated
|
||||||
* @rule: Smack rule
|
* @rule: Will be filled with Smack parsed rule
|
||||||
* @import: if non-zero, import labels
|
* @import: if non-zero, import labels
|
||||||
|
* @change: if non-zero, data is from /smack/change-rule
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure
|
* Returns 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
|
static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
|
||||||
int import)
|
int import, int change)
|
||||||
{
|
{
|
||||||
char *subject;
|
char *subject;
|
||||||
char *object;
|
char *object;
|
||||||
char *access;
|
char *access1;
|
||||||
|
char *access2;
|
||||||
int datalen;
|
int datalen;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
|
@ -334,14 +390,27 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
|
||||||
object = kzalloc(datalen, GFP_KERNEL);
|
object = kzalloc(datalen, GFP_KERNEL);
|
||||||
if (object == NULL)
|
if (object == NULL)
|
||||||
goto free_out_s;
|
goto free_out_s;
|
||||||
access = kzalloc(datalen, GFP_KERNEL);
|
access1 = kzalloc(datalen, GFP_KERNEL);
|
||||||
if (access == NULL)
|
if (access1 == NULL)
|
||||||
goto free_out_o;
|
goto free_out_o;
|
||||||
|
access2 = kzalloc(datalen, GFP_KERNEL);
|
||||||
|
if (access2 == NULL)
|
||||||
|
goto free_out_a;
|
||||||
|
|
||||||
if (sscanf(data, "%s %s %s", subject, object, access) == 3)
|
if (change) {
|
||||||
rc = smk_fill_rule(subject, object, access, rule, import, 0);
|
if (sscanf(data, "%s %s %s %s",
|
||||||
|
subject, object, access1, access2) == 4)
|
||||||
|
rc = smk_fill_rule(subject, object, access1, access2,
|
||||||
|
rule, import, 0);
|
||||||
|
} else {
|
||||||
|
if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
|
||||||
|
rc = smk_fill_rule(subject, object, access1, NULL,
|
||||||
|
rule, import, 0);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(access);
|
kfree(access2);
|
||||||
|
free_out_a:
|
||||||
|
kfree(access1);
|
||||||
free_out_o:
|
free_out_o:
|
||||||
kfree(object);
|
kfree(object);
|
||||||
free_out_s:
|
free_out_s:
|
||||||
|
@ -351,6 +420,7 @@ free_out_s:
|
||||||
|
|
||||||
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
||||||
#define SMK_LONG_FMT 1 /* Variable long label format */
|
#define SMK_LONG_FMT 1 /* Variable long label format */
|
||||||
|
#define SMK_CHANGE_FMT 2 /* Rule modification format */
|
||||||
/**
|
/**
|
||||||
* smk_write_rules_list - write() for any /smack rule file
|
* smk_write_rules_list - write() for any /smack rule file
|
||||||
* @file: file pointer, not actually used
|
* @file: file pointer, not actually used
|
||||||
|
@ -359,22 +429,24 @@ free_out_s:
|
||||||
* @ppos: where to start - must be 0
|
* @ppos: where to start - must be 0
|
||||||
* @rule_list: the list of rules to write to
|
* @rule_list: the list of rules to write to
|
||||||
* @rule_lock: lock for the rule list
|
* @rule_lock: lock for the rule list
|
||||||
* @format: /smack/load or /smack/load2 format.
|
* @format: /smack/load or /smack/load2 or /smack/change-rule format.
|
||||||
*
|
*
|
||||||
* Get one smack access rule from above.
|
* Get one smack access rule from above.
|
||||||
* The format for SMK_LONG_FMT is:
|
* The format for SMK_LONG_FMT is:
|
||||||
* "subject<whitespace>object<whitespace>access[<whitespace>...]"
|
* "subject<whitespace>object<whitespace>access[<whitespace>...]"
|
||||||
* The format for SMK_FIXED24_FMT is exactly:
|
* The format for SMK_FIXED24_FMT is exactly:
|
||||||
* "subject object rwxat"
|
* "subject object rwxat"
|
||||||
|
* The format for SMK_CHANGE_FMT is:
|
||||||
|
* "subject<whitespace>object<whitespace>
|
||||||
|
* acc_enable<whitespace>acc_disable[<whitespace>...]"
|
||||||
*/
|
*/
|
||||||
static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
||||||
size_t count, loff_t *ppos,
|
size_t count, loff_t *ppos,
|
||||||
struct list_head *rule_list,
|
struct list_head *rule_list,
|
||||||
struct mutex *rule_lock, int format)
|
struct mutex *rule_lock, int format)
|
||||||
{
|
{
|
||||||
struct smack_master_list *smlp;
|
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
struct smack_rule *rule;
|
struct smack_parsed_rule *rule;
|
||||||
char *data;
|
char *data;
|
||||||
int datalen;
|
int datalen;
|
||||||
int rc = -EINVAL;
|
int rc = -EINVAL;
|
||||||
|
@ -417,7 +489,11 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
||||||
* Be sure the data string is terminated.
|
* Be sure the data string is terminated.
|
||||||
*/
|
*/
|
||||||
data[count] = '\0';
|
data[count] = '\0';
|
||||||
if (smk_parse_long_rule(data, rule, 1))
|
if (smk_parse_long_rule(data, rule, 1, 0))
|
||||||
|
goto out_free_rule;
|
||||||
|
} else if (format == SMK_CHANGE_FMT) {
|
||||||
|
data[count] = '\0';
|
||||||
|
if (smk_parse_long_rule(data, rule, 1, 1))
|
||||||
goto out_free_rule;
|
goto out_free_rule;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -437,22 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
||||||
rule_lock = &skp->smk_rules_lock;
|
rule_lock = &skp->smk_rules_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = count;
|
rc = smk_set_access(rule, rule_list, rule_lock, load);
|
||||||
/*
|
if (rc == 0) {
|
||||||
* If this is a global as opposed to self and a new rule
|
rc = count;
|
||||||
* it needs to get added for reporting.
|
|
||||||
* smk_set_access returns true if there was already a rule
|
|
||||||
* for the subject/object pair, and false if it was new.
|
|
||||||
*/
|
|
||||||
if (!smk_set_access(rule, rule_list, rule_lock)) {
|
|
||||||
if (load) {
|
|
||||||
smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
|
|
||||||
if (smlp != NULL) {
|
|
||||||
smlp->smk_rule = rule;
|
|
||||||
list_add_rcu(&smlp->list, &smack_rule_list);
|
|
||||||
} else
|
|
||||||
rc = -ENOMEM;
|
|
||||||
}
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1774,7 +1837,7 @@ static const struct file_operations smk_load_self_ops = {
|
||||||
static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
||||||
size_t count, loff_t *ppos, int format)
|
size_t count, loff_t *ppos, int format)
|
||||||
{
|
{
|
||||||
struct smack_rule rule;
|
struct smack_parsed_rule rule;
|
||||||
char *data;
|
char *data;
|
||||||
char *cod;
|
char *cod;
|
||||||
int res;
|
int res;
|
||||||
|
@ -1796,14 +1859,14 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
memcpy(cod, data, count);
|
memcpy(cod, data, count);
|
||||||
cod[count] = '\0';
|
cod[count] = '\0';
|
||||||
res = smk_parse_long_rule(cod, &rule, 0);
|
res = smk_parse_long_rule(cod, &rule, 0, 0);
|
||||||
kfree(cod);
|
kfree(cod);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
|
res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1,
|
||||||
NULL);
|
NULL);
|
||||||
data[0] = res == 0 ? '1' : '0';
|
data[0] = res == 0 ? '1' : '0';
|
||||||
data[1] = '\0';
|
data[1] = '\0';
|
||||||
|
@ -2035,10 +2098,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
skp = smk_find_entry(cp);
|
skp = smk_find_entry(cp);
|
||||||
if (skp == NULL) {
|
if (skp == NULL)
|
||||||
rc = -EINVAL;
|
|
||||||
goto free_out;
|
goto free_out;
|
||||||
}
|
|
||||||
|
|
||||||
rule_list = &skp->smk_rules;
|
rule_list = &skp->smk_rules;
|
||||||
rule_lock = &skp->smk_rules_lock;
|
rule_lock = &skp->smk_rules_lock;
|
||||||
|
@ -2076,6 +2137,33 @@ static int smk_init_sysfs(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_write_change_rule - write() for /smack/change-rule
|
||||||
|
* @file: file pointer
|
||||||
|
* @buf: data from user space
|
||||||
|
* @count: bytes sent
|
||||||
|
* @ppos: where to start - must be 0
|
||||||
|
*/
|
||||||
|
static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Must have privilege.
|
||||||
|
*/
|
||||||
|
if (!capable(CAP_MAC_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
|
||||||
|
SMK_CHANGE_FMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations smk_change_rule_ops = {
|
||||||
|
.write = smk_write_change_rule,
|
||||||
|
.read = simple_transaction_read,
|
||||||
|
.release = simple_transaction_release,
|
||||||
|
.llseek = generic_file_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_fill_super - fill the /smackfs superblock
|
* smk_fill_super - fill the /smackfs superblock
|
||||||
* @sb: the empty superblock
|
* @sb: the empty superblock
|
||||||
|
@ -2125,6 +2213,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
[SMK_REVOKE_SUBJ] = {
|
[SMK_REVOKE_SUBJ] = {
|
||||||
"revoke-subject", &smk_revoke_subj_ops,
|
"revoke-subject", &smk_revoke_subj_ops,
|
||||||
S_IRUGO|S_IWUSR},
|
S_IRUGO|S_IWUSR},
|
||||||
|
[SMK_CHANGE_RULE] = {
|
||||||
|
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
||||||
/* last one */
|
/* last one */
|
||||||
{""}
|
{""}
|
||||||
};
|
};
|
||||||
|
|
|
@ -536,7 +536,7 @@ static struct security_operations tomoyo_security_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Lock for GC. */
|
/* Lock for GC. */
|
||||||
struct srcu_struct tomoyo_ss;
|
DEFINE_SRCU(tomoyo_ss);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_init - Register TOMOYO Linux as a LSM module.
|
* tomoyo_init - Register TOMOYO Linux as a LSM module.
|
||||||
|
@ -550,8 +550,7 @@ static int __init tomoyo_init(void)
|
||||||
if (!security_module_enable(&tomoyo_security_ops))
|
if (!security_module_enable(&tomoyo_security_ops))
|
||||||
return 0;
|
return 0;
|
||||||
/* register ourselves with the security framework */
|
/* register ourselves with the security framework */
|
||||||
if (register_security(&tomoyo_security_ops) ||
|
if (register_security(&tomoyo_security_ops))
|
||||||
init_srcu_struct(&tomoyo_ss))
|
|
||||||
panic("Failure registering TOMOYO Linux");
|
panic("Failure registering TOMOYO Linux");
|
||||||
printk(KERN_INFO "TOMOYO Linux initialized\n");
|
printk(KERN_INFO "TOMOYO Linux initialized\n");
|
||||||
cred->security = &tomoyo_kernel_domain;
|
cred->security = &tomoyo_kernel_domain;
|
||||||
|
|
Loading…
Reference in New Issue