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:
Linus Torvalds 2013-04-30 16:27:51 -07:00
commit 2e1deaad1e
20 changed files with 447 additions and 198 deletions

View File

@ -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

View File

@ -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:

View File

@ -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 */
for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header; cmd.header.in = savestate_header;
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
"sending savestate before suspend");
/*
* 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);

View File

@ -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

View File

@ -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,6 +119,21 @@ 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);
if (tpm_dev.chip_type == SLB9645) {
/* use a combined read for newer chips
* unfortunately the smbus functions are not suitable due to
* 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++) { 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)
@ -112,19 +145,27 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
if (rc <= 0) if (rc <= 0)
goto out; goto out;
/* After the TPM has successfully received the register address it needs /* After the TPM has successfully received the register address
* some time, thus we're sleeping here again, before retrieving the data * it needs some time, thus we're sleeping here again, before
* retrieving the data
*/ */
for (count = 0; count < MAX_COUNT; count++) { for (count = 0; count < MAX_COUNT; count++) {
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
if (rc > 0) if (rc > 0)
break; 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,10 +336,17 @@ 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;
u8 i = 0;
do {
if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
return 0; return 0;
else
i++;
/* if locallity is set STS should not be 0xFF */
} while ((buf == 0xFF) && i < 10);
return buf; return buf;
} }
@ -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");

View File

@ -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;
@ -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");
@ -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,7 +848,7 @@ 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);
@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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)
{ {

View File

@ -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 */

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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.
*/ */

View File

@ -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';
} }
/** /**

View File

@ -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);
} }

View File

@ -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 = smk_set_access(rule, rule_list, rule_lock, load);
if (rc == 0) {
rc = count; rc = count;
/*
* If this is a global as opposed to self and a new rule
* 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 */
{""} {""}
}; };

View File

@ -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;