diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 16:27:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 16:27:51 -0700 |
commit | 2e1deaad1e48453cea782854ab87df3f78c121c2 (patch) | |
tree | da0fe592dcc9ef6b0c4cd104a67af3c1d9e4c5d5 | |
parent | 50528fabeb25f9883e2845f5147f5e00a1c57cf7 (diff) | |
parent | b7ae9f064bec903bd4a9f257a35da4d1e9bbcc99 (diff) |
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
-rw-r--r-- | Documentation/devicetree/bindings/i2c/trivial-devices.txt | 2 | ||||
-rw-r--r-- | Documentation/security/Smack.txt | 11 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.c | 31 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 180 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_stm_st33.c | 64 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ppi.c | 14 | ||||
-rw-r--r-- | fs/nfs/super.c | 3 | ||||
-rw-r--r-- | include/linux/security.h | 10 | ||||
-rw-r--r-- | include/uapi/linux/magic.h | 1 | ||||
-rw-r--r-- | kernel/seccomp.c | 2 | ||||
-rw-r--r-- | security/capability.c | 3 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 14 | ||||
-rw-r--r-- | security/security.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 39 | ||||
-rw-r--r-- | security/smack/smack.h | 5 | ||||
-rw-r--r-- | security/smack/smack_access.c | 2 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 4 | ||||
-rw-r--r-- | security/smack/smackfs.c | 254 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 5 |
20 files changed, 450 insertions, 201 deletions
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 446859fcdca4..ad6a73852f08 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -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,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller 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,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 diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index 8a177e4b6e21..7a2d30c132e3 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt @@ -117,6 +117,17 @@ access2 ambient This contains the Smack label applied to unlabeled network 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 This interface allows a specific CIPSO header to be assigned to a Smack label. The format accepted on write is: diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 0d2e82f95577..7c3b3dcbfbc8 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1337,7 +1337,7 @@ int tpm_pm_suspend(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_cmd_t cmd; - int rc; + int rc, try; u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; @@ -1355,9 +1355,32 @@ int tpm_pm_suspend(struct device *dev) } /* now do the actual savestate */ - cmd.header.in = savestate_header; - rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, - "sending savestate before suspend"); + for (try = 0; try < TPM_RETRY; try++) { + cmd.header.in = savestate_header; + 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; } EXPORT_SYMBOL_GPL(tpm_pm_suspend); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 81b52015f669..0770d1d79366 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -32,10 +32,12 @@ enum tpm_const { TPM_MINOR = 224, /* officially assigned */ TPM_BUFSIZE = 4096, TPM_NUM_DEVICES = 256, + TPM_RETRY = 50, /* 5 seconds */ }; enum tpm_timeout { TPM_TIMEOUT = 5, /* msecs */ + TPM_TIMEOUT_RETRY = 100 /* msecs */ }; /* TPM addresses */ @@ -44,6 +46,7 @@ enum tpm_addr { TPM_ADDR = 0x4E, }; +#define TPM_WARN_RETRY 0x800 #define TPM_WARN_DOING_SELFTEST 0x802 #define TPM_ERR_DEACTIVATED 0x6 #define TPM_ERR_DISABLED 0x7 diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 8fe7ac3d095b..37d5dcc10ea7 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Infineon Technologies + * Copyright (C) 2012,2013 Infineon Technologies * * Authors: * Peter Huewe <peter.huewe@infineon.com> @@ -56,13 +56,21 @@ #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) /* 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 */ struct tpm_inf_dev { struct i2c_client *client; u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ struct tpm_chip *chip; + enum i2c_chip_type chip_type; }; 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) { - struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr }; - struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer }; + struct i2c_msg msg1 = { + .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; /* 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; i2c_lock_adapter(tpm_dev.client->adapter); - 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); - } - - if (rc <= 0) - 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; + 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++) { + 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); + } + if (rc <= 0) + 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; + } } out: 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) return -EIO; @@ -138,7 +179,11 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, int rc = -EIO; 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) 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 * 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++) { rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); if (rc > 0) break; - usleep_range(sleep_low, sleep_hi); } 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) 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) { /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ - u8 buf; - if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) - return 0; - else - return buf; + u8 buf = 0xFF; + u8 i = 0; + + do { + 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) @@ -328,7 +388,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, /* check current status */ *status = tpm_tis_i2c_status(chip); - if ((*status & mask) == mask) + if ((*status != 0xFF) && (*status & mask) == mask) return 0; 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 */ if (retries > MAX_COUNT_LONG) return -EIO; - } return size; } @@ -480,7 +539,6 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) rc = -EIO; goto out_err; } - } /* write last byte */ @@ -568,6 +626,7 @@ static int tpm_tis_i2c_init(struct device *dev) chip = tpm_register_hardware(dev, &tpm_tis_i2c); if (!chip) { + dev_err(dev, "could not register hardware\n"); rc = -ENODEV; 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); if (request_locality(chip, 0) != 0) { + dev_err(dev, "could not request locality\n"); rc = -ENODEV; goto out_vendor; } /* read four bytes from DID_VID register */ if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { + dev_err(dev, "could not read vendor id\n"); rc = -EIO; goto out_release; } - /* create DID_VID register value, after swapping to little-endian */ - vendor = be32_to_cpu((__be32) vendor); - - if (vendor != TPM_TIS_I2C_DID_VID) { + if (vendor == TPM_TIS_I2C_DID_VID_9645) { + tpm_dev.chip_type = SLB9645; + } else if (vendor == TPM_TIS_I2C_DID_VID_9635) { + tpm_dev.chip_type = SLB9635; + } else { + dev_err(dev, "vendor id did not match! ID was %08x\n", vendor); rc = -ENODEV; goto out_release; } @@ -631,22 +694,53 @@ out_err: static const struct i2c_device_id tpm_tis_i2c_table[] = { {"tpm_i2c_infineon", 0}, + {"slb9635tt", 0}, + {"slb9645tt", 1}, {}, }; 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 int tpm_tis_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { 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 */ + } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, - "no algorithms associated to the i2c bus\n"); + dev_err(dev, "no algorithms associated to the i2c bus\n"); return -ENODEV; } @@ -682,7 +776,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client) } static struct i2c_driver tpm_tis_i2c_driver = { - .id_table = tpm_tis_i2c_table, .probe = tpm_tis_i2c_probe, .remove = tpm_tis_i2c_remove, @@ -690,11 +783,12 @@ static struct i2c_driver tpm_tis_i2c_driver = { .name = "tpm_i2c_infineon", .owner = THIS_MODULE, .pm = &tpm_tis_i2c_ops, + .of_match_table = of_match_ptr(tpm_tis_i2c_of_match), }, }; module_i2c_driver(tpm_tis_i2c_driver); MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); -MODULE_VERSION("2.1.5"); +MODULE_VERSION("2.2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 1f5f71e14abe..5bb8e2ddd3b3 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -36,7 +36,6 @@ #include <linux/i2c.h> #include <linux/fs.h> #include <linux/miscdevice.h> -#include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/init.h> @@ -50,7 +49,6 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/slab.h> -#include <linux/sched.h> #include "tpm.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 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; 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; 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); if (!status) { status = -EBUSY; - } else{ + } else { clear_interruption(client); if (condition) status = 1; @@ -219,7 +217,7 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) struct i2c_client *client; u8 data; - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); data = TPM_STS_COMMAND_READY; 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; u8 data; - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); I2C_READ_DATA(client, TPM_STS, &data, 1); return data; @@ -254,7 +252,7 @@ static int check_locality(struct tpm_chip *chip) u8 data; 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); if (status && (data & @@ -278,7 +276,7 @@ static int request_locality(struct tpm_chip *chip) struct i2c_client *client; u8 data; - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; @@ -294,7 +292,7 @@ static int request_locality(struct tpm_chip *chip) chip->vendor.timeout_a); if (rc > 0) return chip->vendor.locality; - } else{ + } else { stop = jiffies + chip->vendor.timeout_a; do { if (check_locality(chip) >= 0) @@ -316,7 +314,7 @@ static void release_locality(struct tpm_chip *chip) struct i2c_client *client; u8 data; - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); data = TPM_ACCESS_ACTIVE_LOCALITY; I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); @@ -333,7 +331,7 @@ static int get_burstcount(struct tpm_chip *chip) int burstcnt, status; 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; do { @@ -379,7 +377,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, mask), timeout); if (rc > 0) return 0; - } else{ + } else { stop = jiffies + timeout; do { 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; struct i2c_client *client; - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); while (size < count && wait_for_stat(chip, @@ -433,7 +431,7 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) disable_irq_nosync(irq); - client = (struct i2c_client *) TPM_VPRIV(chip); + client = (struct i2c_client *)TPM_VPRIV(chip); pin_infos = client->dev.platform_data; 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, size_t len) { - u32 status, - burstcnt = 0, i, size; + u32 status, burstcnt = 0, i, size; int ret; u8 data; 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); size = min_t(int, len - i - 1, burstcnt); 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; } - expected = be32_to_cpu(*(__be32 *) (buf + 2)); + expected = be32_to_cpu(*(__be32 *)(buf + 2)); if (expected > count) { size = -EIO; goto out; @@ -569,7 +566,7 @@ out: 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 = { @@ -617,7 +614,7 @@ static struct tpm_vendor_specific st_i2c_tpm = { .miscdev = {.fops = &tpm_st33_i2c_fops,}, }; -static int interrupts ; +static int interrupts; module_param(interrupts, int, 0444); 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); if (err < 0) { 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; } @@ -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"); return 0; _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: if (interrupts) 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 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) { 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; int ret = 0; - if (power_mgt) + if (power_mgt) { gpio_set_value(pin_infos->io_lpcpd, 0); - else{ + } else { if (chip->data_buffer == NULL) chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; ret = tpm_pm_suspend(dev); @@ -851,12 +848,12 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) (chip->vendor.status(chip) & TPM_STS_VALID) == TPM_STS_VALID, chip->vendor.timeout_b); - } else{ - if (chip->data_buffer == NULL) - chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; - ret = tpm_pm_resume(dev); - if (!ret) - tpm_do_selftest(chip); + } else { + if (chip->data_buffer == NULL) + chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; + ret = tpm_pm_resume(dev); + if (!ret) + tpm_do_selftest(chip); } return ret; } /* 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); -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 = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 720ebcf29fdf..2168d15bc728 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -158,9 +158,9 @@ static ssize_t tpm_store_ppi_request(struct device *dev, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; - strncpy(version, + strlcpy(version, ((union acpi_object *)output.pointer)->string.pointer, - PPI_VERSION_LEN); + PPI_VERSION_LEN + 1); kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; @@ -237,9 +237,9 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, ACPI_TYPE_STRING); if (ACPI_FAILURE(status)) return -ENOMEM; - strncpy(version, + strlcpy(version, ((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 * (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) { char *str = buf; - char version[PPI_VERSION_LEN]; + char version[PPI_VERSION_LEN + 1]; acpi_handle handle; acpi_status status; 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)) return -ENOMEM; - strncpy(version, + strlcpy(version, ((union acpi_object *)output.pointer)->string.pointer, - PPI_VERSION_LEN); + PPI_VERSION_LEN + 1); kfree(output.pointer); output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index eb494f6a4c6b..1bb071dca9ab 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2385,10 +2385,9 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, struct nfs_mount_info *mount_info) { /* 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) return -ESTALE; - return 0; + return security_sb_clone_mnt_opts(mount_info->cloned->sb, s); } EXPORT_SYMBOL_GPL(nfs_clone_sb_security); diff --git a/include/linux/security.h b/include/linux/security.h index 032c366ef1c6..4686491852a7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1440,7 +1440,7 @@ struct security_operations { struct path *new_path); int (*sb_set_mnt_opts) (struct super_block *sb, 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); 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_pivotroot(struct path *old_path, struct path *new_path); 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); 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; } -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) -{ } +{ + return 0; +} static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) { diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 873e086ce3a1..249df3720be2 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -11,6 +11,7 @@ #define DEBUGFS_MAGIC 0x64626720 #define SECURITYFS_MAGIC 0x73636673 #define SELINUX_MAGIC 0xf97cff8c +#define SMACK_MAGIC 0x43415d53 /* "SMAC" */ #define RAMFS_MAGIC 0x858458f6 /* some random number */ #define TMPFS_MAGIC 0x01021994 #define HUGETLBFS_MAGIC 0x958458f6 /* some random number */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 5af44b593770..b7a10048a32c 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -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_OR_K: 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_X: case BPF_S_ALU_RSH_K: diff --git a/security/capability.c b/security/capability.c index 6783c3e6c88e..1728d4e375db 100644 --- a/security/capability.c +++ b/security/capability.c @@ -98,9 +98,10 @@ static int cap_sb_set_mnt_opts(struct super_block *sb, 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) { + return 0; } static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3b3b7e6bf8da..6c491a63128e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -189,11 +189,9 @@ static int process_measurement(struct file *file, const char *filename, if (rc != 0) goto out_digsig; - if (function != BPRM_CHECK) - pathname = ima_d_path(&file->f_path, &pathbuf); - + pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename; if (!pathname) - pathname = filename; + pathname = (const char *)file->f_dentry->d_name.name; if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname); @@ -226,8 +224,7 @@ out: int ima_file_mmap(struct file *file, unsigned long prot) { if (file && (prot & PROT_EXEC)) - return process_measurement(file, file->f_dentry->d_name.name, - MAY_EXEC, MMAP_CHECK); + return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK); return 0; } @@ -265,7 +262,7 @@ int ima_bprm_check(struct linux_binprm *bprm) int ima_file_check(struct file *file, int mask) { 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), FILE_CHECK); } @@ -290,8 +287,7 @@ int ima_module_check(struct file *file) #endif return 0; /* We rely on module signature checking */ } - return process_measurement(file, file->f_dentry->d_name.name, - MAY_EXEC, MODULE_CHECK); + return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); } static int __init init_ima(void) diff --git a/security/security.c b/security/security.c index 03f248b84e9f..a3dce87d1aef 100644 --- a/security/security.c +++ b/security/security.c @@ -299,10 +299,10 @@ int security_sb_set_mnt_opts(struct super_block *sb, } 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) { - security_ops->sb_clone_mnt_opts(oldsb, newsb); + return security_ops->sb_clone_mnt_opts(oldsb, newsb); } EXPORT_SYMBOL(security_sb_clone_mnt_opts); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7171a957b933..feb2f42c5a07 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -751,7 +751,37 @@ out_double_mount: 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) { 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 */ if (!ss_initialized) - return; + return 0; /* how can we clone if the old one wasn't set up?? */ 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) - return; + return selinux_cmp_sb_context(oldsb, newsb); 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); mutex_unlock(&newsbsec->lock); + return 0; } static int selinux_parse_opts_str(char *options, diff --git a/security/smack/smack.h b/security/smack/smack.h index 99b36124f712..8ad30955e15d 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -149,11 +149,6 @@ struct smack_known { #define SMACK_CIPSO_SOCKET 1 /* - * smackfs magic number - */ -#define SMACK_MAGIC 0x43415d53 /* "SMAC" */ - -/* * CIPSO defaults. */ #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index db14689a21e0..2e397a88d410 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -252,6 +252,8 @@ static inline void smack_str_from_perm(char *string, int access) string[i++] = 'x'; if (access & MAY_APPEND) string[i++] = 'a'; + if (access & MAY_TRANSMUTE) + string[i++] = 't'; string[i] = '\0'; } /** diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index fa64740abb59..d52c780bdb78 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -654,7 +654,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) /* * 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); 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 */ - 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); rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); } diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 76a5dca46404..53a08b85bda4 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -26,6 +26,7 @@ #include <linux/seq_file.h> #include <linux/ctype.h> #include <linux/audit.h> +#include <linux/magic.h> #include "smack.h" /* @@ -50,12 +51,12 @@ enum smk_inos { SMK_ACCESS2 = 16, /* make an access check with long labels */ SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ + SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ }; /* * List locks */ -static DEFINE_MUTEX(smack_list_lock); static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_ambient_lock); static DEFINE_MUTEX(smk_netlbladdr_lock); @@ -110,6 +111,13 @@ struct smack_master_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; 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 /** - * smk_set_access - add a rule to the rule list - * @srp: the new rule to add + * smk_set_access - add a rule to the rule list or replace an old rule + * @srp: the rule to add or replace * @rule_list: the list of rules * @rule_lock: the rule list lock + * @global: if non-zero, indicates a global rule * * Looks through the current subject/object/access list for * the subject/object pair and replaces the access that was * there. If the pair isn't found add it with the specified * 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 * during the allocation of the new pair to add. */ -static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, - struct mutex *rule_lock) +static int smk_set_access(struct smack_parsed_rule *srp, + struct list_head *rule_list, + struct mutex *rule_lock, int global) { struct smack_rule *sp; + struct smack_master_list *smlp; int found = 0; + int rc = 0; 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 && sp->smk_subject == srp->smk_subject) { found = 1; - sp->smk_access = srp->smk_access; + sp->smk_access |= srp->smk_access1; + sp->smk_access &= ~srp->smk_access2; 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); + return rc; +} + +/** + * 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; - return found; + 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 * @subject: subject label string * @object: object label string - * @access: access string + * @access1: access string + * @access2: string with permissions to be removed * @rule: Smack rule * @import: if non-zero, import labels * @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 */ static int smk_fill_rule(const char *subject, const char *object, - const char *access, struct smack_rule *rule, - int import, int len) + const char *access1, const char *access2, + struct smack_parsed_rule *rule, int import, + int len) { const char *cp; 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_access = 0; - - for (cp = access; *cp != '\0'; cp++) { - switch (*cp) { - case '-': - 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; - } - } + rule->smk_access1 = smk_perm_from_str(access1); + if (access2) + rule->smk_access2 = smk_perm_from_str(access2); + else + rule->smk_access2 = ~rule->smk_access1; return 0; } @@ -297,30 +350,33 @@ static int smk_fill_rule(const char *subject, const char *object, * * 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; rc = smk_fill_rule(data, data + SMK_LABELLEN, - data + SMK_LABELLEN + SMK_LABELLEN, rule, import, - SMK_LABELLEN); + data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule, + import, SMK_LABELLEN); return rc; } /** * smk_parse_long_rule - parse Smack rule from rule string * @data: string to be parsed, null terminated - * @rule: Smack rule + * @rule: Will be filled with Smack parsed rule * @import: if non-zero, import labels + * @change: if non-zero, data is from /smack/change-rule * * Returns 0 on success, -1 on failure */ -static int smk_parse_long_rule(const char *data, struct smack_rule *rule, - int import) +static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, + int import, int change) { char *subject; char *object; - char *access; + char *access1; + char *access2; int datalen; 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); if (object == NULL) goto free_out_s; - access = kzalloc(datalen, GFP_KERNEL); - if (access == NULL) + access1 = kzalloc(datalen, GFP_KERNEL); + if (access1 == NULL) goto free_out_o; + access2 = kzalloc(datalen, GFP_KERNEL); + if (access2 == NULL) + goto free_out_a; + + if (change) { + 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); + } - if (sscanf(data, "%s %s %s", subject, object, access) == 3) - rc = smk_fill_rule(subject, object, access, rule, import, 0); - - kfree(access); + kfree(access2); +free_out_a: + kfree(access1); free_out_o: kfree(object); free_out_s: @@ -351,6 +420,7 @@ free_out_s: #define SMK_FIXED24_FMT 0 /* Fixed 24byte 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 * @file: file pointer, not actually used @@ -359,22 +429,24 @@ free_out_s: * @ppos: where to start - must be 0 * @rule_list: the list of rules to write to * @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. * The format for SMK_LONG_FMT is: * "subject<whitespace>object<whitespace>access[<whitespace>...]" * The format for SMK_FIXED24_FMT is exactly: * "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, size_t count, loff_t *ppos, struct list_head *rule_list, struct mutex *rule_lock, int format) { - struct smack_master_list *smlp; struct smack_known *skp; - struct smack_rule *rule; + struct smack_parsed_rule *rule; char *data; int datalen; 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. */ 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; } 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; } - 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; - } + rc = smk_set_access(rule, rule_list, rule_lock, load); + if (rc == 0) { + rc = count; 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, size_t count, loff_t *ppos, int format) { - struct smack_rule rule; + struct smack_parsed_rule rule; char *data; char *cod; int res; @@ -1796,14 +1859,14 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, return -ENOMEM; memcpy(cod, data, count); cod[count] = '\0'; - res = smk_parse_long_rule(cod, &rule, 0); + res = smk_parse_long_rule(cod, &rule, 0, 0); kfree(cod); } if (res) 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); data[0] = res == 0 ? '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); - if (skp == NULL) { - rc = -EINVAL; + if (skp == NULL) goto free_out; - } rule_list = &skp->smk_rules; rule_lock = &skp->smk_rules_lock; @@ -2077,6 +2138,33 @@ static int smk_init_sysfs(void) } /** + * 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 * @sb: the empty superblock * @data: unused @@ -2125,6 +2213,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) [SMK_REVOKE_SUBJ] = { "revoke-subject", &smk_revoke_subj_ops, S_IRUGO|S_IWUSR}, + [SMK_CHANGE_RULE] = { + "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, /* last one */ {""} }; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index a2ee362546ab..f0b756e27fed 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -536,7 +536,7 @@ static struct security_operations tomoyo_security_ops = { }; /* Lock for GC. */ -struct srcu_struct tomoyo_ss; +DEFINE_SRCU(tomoyo_ss); /** * 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)) return 0; /* register ourselves with the security framework */ - if (register_security(&tomoyo_security_ops) || - init_srcu_struct(&tomoyo_ss)) + if (register_security(&tomoyo_security_ops)) panic("Failure registering TOMOYO Linux"); printk(KERN_INFO "TOMOYO Linux initialized\n"); cred->security = &tomoyo_kernel_domain; |