Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 30 Apr 2013 23:27:51 +0000 (16:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 30 Apr 2013 23:27:51 +0000 (16:27 -0700)
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

20 files changed:
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/security/Smack.txt
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_i2c_stm_st33.c
drivers/char/tpm/tpm_ppi.c
fs/nfs/super.c
include/linux/security.h
include/uapi/linux/magic.h
kernel/seccomp.c
security/capability.c
security/integrity/ima/ima_main.c
security/security.c
security/selinux/hooks.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/tomoyo.c

index 446859f..ad6a738 100644 (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,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
index 8a177e4..7a2d30c 100644 (file)
@@ -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:
index 0d2e82f..7c3b3dc 100644 (file)
@@ -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);
index 81b5201..0770d1d 100644 (file)
@@ -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
index 8fe7ac3..37d5dcc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Infineon Technologies
+ * Copyright (C) 2012,2013 Infineon Technologies
  *
  * Authors:
  * Peter Huewe <peter.huewe@infineon.com>
 #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");
index 1f5f71e..5bb8e2d 100644 (file)
@@ -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,
index 720ebcf..2168d15 100644 (file)
@@ -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;
index eb494f6..1bb071d 100644 (file)
@@ -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);
 
index 032c366..4686491 100644 (file)
@@ -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)
 {
index 873e086..249df37 100644 (file)
@@ -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 */
index 5af44b5..b7a1004 100644 (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_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:
index 6783c3e..1728d4e 100644 (file)
@@ -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)
index 3b3b7e6..6c491a6 100644 (file)
@@ -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)
index 03f248b..a3dce87 100644 (file)
@@ -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);
 
index 7171a95..feb2f42 100644 (file)
@@ -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,
index 99b3612..8ad3095 100644 (file)
@@ -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 */
index db14689..2e397a8 100644 (file)
@@ -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';
 }
 /**
index fa64740..d52c780 100644 (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
                 */
-               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);
        }
index 76a5dca..53a08b8 100644 (file)
@@ -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 */
                        {""}
        };
index a2ee362..f0b756e 100644 (file)
@@ -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;