diff options
| -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 | 176 | ||||
| -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 | 252 | ||||
| -rw-r--r-- | security/tomoyo/tomoyo.c | 5 | 
20 files changed, 447 insertions, 198 deletions
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 446859fcdca..ad6a73852f0 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 8a177e4b6e2..7a2d30c132e 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 0d2e82f9557..7c3b3dcbfbc 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 81b52015f66..0770d1d7936 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 8fe7ac3d095..37d5dcc10ea 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 (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 */ -	if (rc <= 0) -		goto out; +			usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); +		} -	/* 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 (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 1f5f71e14ab..5bb8e2ddd3b 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 720ebcf29fd..2168d15bc72 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 eb494f6a4c6..1bb071dca9a 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 032c366ef1c..4686491852a 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 873e086ce3a..249df3720be 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 5af44b59377..b7a10048a32 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 6783c3e6c88..1728d4e375d 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 3b3b7e6bf8d..6c491a63128 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 03f248b84e9..a3dce87d1ae 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 7171a957b93..feb2f42c5a0 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 99b36124f71..8ad30955e15 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 db14689a21e..2e397a88d41 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 fa64740abb5..d52c780bdb7 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 76a5dca4640..53a08b85bda 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 (sscanf(data, "%s %s %s", subject, object, access) == 3) -		rc = smk_fill_rule(subject, object, access, rule, import, 0); +	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); +	} -	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 a2ee362546a..f0b756e27fe 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;  |