Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31998ef1 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Alasdair G Kergon
Browse files

dm: reject trailing characters in sccanf input



Device mapper uses sscanf to convert arguments to numbers. The problem is that
the way we use it ignores additional unmatched characters in the scanned string.

For example, this `if (sscanf(string, "%d", &number) == 1)' will match a number,
but also it will match number with some garbage appended, like "123abc".

As a result, device mapper accepts garbage after some numbers. For example
the command `dmsetup create vg1-new --table "0 16384 linear 254:1bla 34816bla"'
will pass without an error.

This patch fixes all sscanf uses in device mapper. It appends "%c" with
a pointer to a dummy character variable to every sscanf statement.

The construct `if (sscanf(string, "%d%c", &number, &dummy) == 1)' succeeds
only if string is a null-terminated number (optionally preceded by some
whitespace characters). If there is some character appended after the number,
sscanf matches "%c", writes the character to the dummy variable and returns 2.
We check the return value for 1 and consequently reject numbers with some
garbage appended.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Acked-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 0447568f
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -1415,6 +1415,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
	char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
	char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
	char *cipher_api = NULL;
	char *cipher_api = NULL;
	int cpu, ret = -EINVAL;
	int cpu, ret = -EINVAL;
	char dummy;


	/* Convert to crypto api definition? */
	/* Convert to crypto api definition? */
	if (strchr(cipher_in, '(')) {
	if (strchr(cipher_in, '(')) {
@@ -1436,7 +1437,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,


	if (!keycount)
	if (!keycount)
		cc->tfms_count = 1;
		cc->tfms_count = 1;
	else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 ||
	else if (sscanf(keycount, "%u%c", &cc->tfms_count, &dummy) != 1 ||
		 !is_power_of_2(cc->tfms_count)) {
		 !is_power_of_2(cc->tfms_count)) {
		ti->error = "Bad cipher key count specification";
		ti->error = "Bad cipher key count specification";
		return -EINVAL;
		return -EINVAL;
@@ -1581,6 +1582,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	int ret;
	int ret;
	struct dm_arg_set as;
	struct dm_arg_set as;
	const char *opt_string;
	const char *opt_string;
	char dummy;


	static struct dm_arg _args[] = {
	static struct dm_arg _args[] = {
		{0, 1, "Invalid number of feature args"},
		{0, 1, "Invalid number of feature args"},
@@ -1638,7 +1640,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	}
	}


	ret = -EINVAL;
	ret = -EINVAL;
	if (sscanf(argv[2], "%llu", &tmpll) != 1) {
	if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
		ti->error = "Invalid iv_offset sector";
		ti->error = "Invalid iv_offset sector";
		goto bad;
		goto bad;
	}
	}
@@ -1649,7 +1651,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
		goto bad;
		goto bad;
	}
	}


	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
	if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
		ti->error = "Invalid device sector";
		ti->error = "Invalid device sector";
		goto bad;
		goto bad;
	}
	}
+5 −4
Original line number Original line Diff line number Diff line
@@ -131,6 +131,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
{
	struct delay_c *dc;
	struct delay_c *dc;
	unsigned long long tmpll;
	unsigned long long tmpll;
	char dummy;


	if (argc != 3 && argc != 6) {
	if (argc != 3 && argc != 6) {
		ti->error = "requires exactly 3 or 6 arguments";
		ti->error = "requires exactly 3 or 6 arguments";
@@ -145,13 +146,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)


	dc->reads = dc->writes = 0;
	dc->reads = dc->writes = 0;


	if (sscanf(argv[1], "%llu", &tmpll) != 1) {
	if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
		ti->error = "Invalid device sector";
		ti->error = "Invalid device sector";
		goto bad;
		goto bad;
	}
	}
	dc->start_read = tmpll;
	dc->start_read = tmpll;


	if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
	if (sscanf(argv[2], "%u%c", &dc->read_delay, &dummy) != 1) {
		ti->error = "Invalid delay";
		ti->error = "Invalid delay";
		goto bad;
		goto bad;
	}
	}
@@ -166,13 +167,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	if (argc == 3)
	if (argc == 3)
		goto out;
		goto out;


	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
	if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
		ti->error = "Invalid write device sector";
		ti->error = "Invalid write device sector";
		goto bad_dev_read;
		goto bad_dev_read;
	}
	}
	dc->start_write = tmpll;
	dc->start_write = tmpll;


	if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
	if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
		ti->error = "Invalid write delay";
		ti->error = "Invalid write delay";
		goto bad_dev_read;
		goto bad_dev_read;
	}
	}
+2 −1
Original line number Original line Diff line number Diff line
@@ -160,6 +160,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	unsigned long long tmpll;
	unsigned long long tmpll;
	struct dm_arg_set as;
	struct dm_arg_set as;
	const char *devname;
	const char *devname;
	char dummy;


	as.argc = argc;
	as.argc = argc;
	as.argv = argv;
	as.argv = argv;
@@ -178,7 +179,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)


	devname = dm_shift_arg(&as);
	devname = dm_shift_arg(&as);


	if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
	if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
		ti->error = "Invalid device sector";
		ti->error = "Invalid device sector";
		goto bad;
		goto bad;
	}
	}
+3 −2
Original line number Original line Diff line number Diff line
@@ -880,6 +880,7 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
	struct hd_geometry geometry;
	struct hd_geometry geometry;
	unsigned long indata[4];
	unsigned long indata[4];
	char *geostr = (char *) param + param->data_start;
	char *geostr = (char *) param + param->data_start;
	char dummy;


	md = find_device(param);
	md = find_device(param);
	if (!md)
	if (!md)
@@ -891,8 +892,8 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
		goto out;
		goto out;
	}
	}


	x = sscanf(geostr, "%lu %lu %lu %lu", indata,
	x = sscanf(geostr, "%lu %lu %lu %lu%c", indata,
		   indata + 1, indata + 2, indata + 3);
		   indata + 1, indata + 2, indata + 3, &dummy);


	if (x != 4) {
	if (x != 4) {
		DMWARN("Unable to interpret geometry settings.");
		DMWARN("Unable to interpret geometry settings.");
+2 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
{
	struct linear_c *lc;
	struct linear_c *lc;
	unsigned long long tmp;
	unsigned long long tmp;
	char dummy;


	if (argc != 2) {
	if (argc != 2) {
		ti->error = "Invalid argument count";
		ti->error = "Invalid argument count";
@@ -41,7 +42,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	if (sscanf(argv[1], "%llu", &tmp) != 1) {
	if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
		ti->error = "dm-linear: Invalid device sector";
		ti->error = "dm-linear: Invalid device sector";
		goto bad;
		goto bad;
	}
	}
Loading