Skip to content

Commit 31998ef

Browse files
Mikulas Patockakergon
authored andcommitted
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: Mikulas Patocka <[email protected]> Acked-by: Mike Snitzer <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent 0447568 commit 31998ef

File tree

13 files changed

+44
-25
lines changed

13 files changed

+44
-25
lines changed

drivers/md/dm-crypt.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
14151415
char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
14161416
char *cipher_api = NULL;
14171417
int cpu, ret = -EINVAL;
1418+
char dummy;
14181419

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

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

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

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

1652-
if (sscanf(argv[4], "%llu", &tmpll) != 1) {
1654+
if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
16531655
ti->error = "Invalid device sector";
16541656
goto bad;
16551657
}

drivers/md/dm-delay.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
131131
{
132132
struct delay_c *dc;
133133
unsigned long long tmpll;
134+
char dummy;
134135

135136
if (argc != 3 && argc != 6) {
136137
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)
145146

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

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

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

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

175-
if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
176+
if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
176177
ti->error = "Invalid write delay";
177178
goto bad_dev_read;
178179
}

drivers/md/dm-flakey.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
160160
unsigned long long tmpll;
161161
struct dm_arg_set as;
162162
const char *devname;
163+
char dummy;
163164

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

179180
devname = dm_shift_arg(&as);
180181

181-
if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
182+
if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
182183
ti->error = "Invalid device sector";
183184
goto bad;
184185
}

drivers/md/dm-ioctl.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
880880
struct hd_geometry geometry;
881881
unsigned long indata[4];
882882
char *geostr = (char *) param + param->data_start;
883+
char dummy;
883884

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

894-
x = sscanf(geostr, "%lu %lu %lu %lu", indata,
895-
indata + 1, indata + 2, indata + 3);
895+
x = sscanf(geostr, "%lu %lu %lu %lu%c", indata,
896+
indata + 1, indata + 2, indata + 3, &dummy);
896897

897898
if (x != 4) {
898899
DMWARN("Unable to interpret geometry settings.");

drivers/md/dm-linear.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
2929
{
3030
struct linear_c *lc;
3131
unsigned long long tmp;
32+
char dummy;
3233

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

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

drivers/md/dm-log.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
369369
unsigned int region_count;
370370
size_t bitset_size, buf_size;
371371
int r;
372+
char dummy;
372373

373374
if (argc < 1 || argc > 2) {
374375
DMWARN("wrong number of arguments to dirty region log");
@@ -387,7 +388,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
387388
}
388389
}
389390

390-
if (sscanf(argv[0], "%u", &region_size) != 1 ||
391+
if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
391392
!_check_region_size(ti, region_size)) {
392393
DMWARN("invalid region size %s", argv[0]);
393394
return -EINVAL;

drivers/md/dm-mpath.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,8 +1070,9 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
10701070
struct priority_group *pg;
10711071
unsigned pgnum;
10721072
unsigned long flags;
1073+
char dummy;
10731074

1074-
if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
1075+
if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
10751076
(pgnum > m->nr_priority_groups)) {
10761077
DMWARN("invalid PG number supplied to switch_pg_num");
10771078
return -EINVAL;
@@ -1101,8 +1102,9 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
11011102
{
11021103
struct priority_group *pg;
11031104
unsigned pgnum;
1105+
char dummy;
11041106

1105-
if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
1107+
if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
11061108
(pgnum > m->nr_priority_groups)) {
11071109
DMWARN("invalid PG number supplied to bypass_pg");
11081110
return -EINVAL;

drivers/md/dm-queue-length.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
112112
struct selector *s = ps->context;
113113
struct path_info *pi;
114114
unsigned repeat_count = QL_MIN_IO;
115+
char dummy;
115116

116117
/*
117118
* Arguments: [<repeat_count>]
@@ -123,7 +124,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
123124
return -EINVAL;
124125
}
125126

126-
if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
127+
if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
127128
*error = "queue-length ps: invalid repeat count";
128129
return -EINVAL;
129130
}

drivers/md/dm-raid1.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -924,8 +924,9 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
924924
unsigned int mirror, char **argv)
925925
{
926926
unsigned long long offset;
927+
char dummy;
927928

928-
if (sscanf(argv[1], "%llu", &offset) != 1) {
929+
if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) {
929930
ti->error = "Invalid offset";
930931
return -EINVAL;
931932
}
@@ -953,13 +954,14 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
953954
{
954955
unsigned param_count;
955956
struct dm_dirty_log *dl;
957+
char dummy;
956958

957959
if (argc < 2) {
958960
ti->error = "Insufficient mirror log arguments";
959961
return NULL;
960962
}
961963

962-
if (sscanf(argv[1], "%u", &param_count) != 1) {
964+
if (sscanf(argv[1], "%u%c", &param_count, &dummy) != 1) {
963965
ti->error = "Invalid mirror log argument count";
964966
return NULL;
965967
}
@@ -986,13 +988,14 @@ static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
986988
{
987989
unsigned num_features;
988990
struct dm_target *ti = ms->ti;
991+
char dummy;
989992

990993
*args_used = 0;
991994

992995
if (!argc)
993996
return 0;
994997

995-
if (sscanf(argv[0], "%u", &num_features) != 1) {
998+
if (sscanf(argv[0], "%u%c", &num_features, &dummy) != 1) {
996999
ti->error = "Invalid number of features";
9971000
return -EINVAL;
9981001
}
@@ -1036,6 +1039,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
10361039
unsigned int nr_mirrors, m, args_used;
10371040
struct mirror_set *ms;
10381041
struct dm_dirty_log *dl;
1042+
char dummy;
10391043

10401044
dl = create_dirty_log(ti, argc, argv, &args_used);
10411045
if (!dl)
@@ -1044,7 +1048,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
10441048
argv += args_used;
10451049
argc -= args_used;
10461050

1047-
if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
1051+
if (!argc || sscanf(argv[0], "%u%c", &nr_mirrors, &dummy) != 1 ||
10481052
nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
10491053
ti->error = "Invalid number of mirrors";
10501054
dm_dirty_log_destroy(dl);

drivers/md/dm-round-robin.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,15 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
114114
struct selector *s = (struct selector *) ps->context;
115115
struct path_info *pi;
116116
unsigned repeat_count = RR_MIN_IO;
117+
char dummy;
117118

118119
if (argc > 1) {
119120
*error = "round-robin ps: incorrect number of arguments";
120121
return -EINVAL;
121122
}
122123

123124
/* First path argument is number of I/Os before switching path */
124-
if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
125+
if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
125126
*error = "round-robin ps: invalid repeat count";
126127
return -EINVAL;
127128
}

drivers/md/dm-service-time.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
110110
struct path_info *pi;
111111
unsigned repeat_count = ST_MIN_IO;
112112
unsigned relative_throughput = 1;
113+
char dummy;
113114

114115
/*
115116
* Arguments: [<repeat_count> [<relative_throughput>]]
@@ -128,13 +129,13 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
128129
return -EINVAL;
129130
}
130131

131-
if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
132+
if (argc && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
132133
*error = "service-time ps: invalid repeat count";
133134
return -EINVAL;
134135
}
135136

136137
if ((argc == 2) &&
137-
(sscanf(argv[1], "%u", &relative_throughput) != 1 ||
138+
(sscanf(argv[1], "%u%c", &relative_throughput, &dummy) != 1 ||
138139
relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
139140
*error = "service-time ps: invalid relative_throughput value";
140141
return -EINVAL;

drivers/md/dm-stripe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
7575
unsigned int stripe, char **argv)
7676
{
7777
unsigned long long start;
78+
char dummy;
7879

79-
if (sscanf(argv[1], "%llu", &start) != 1)
80+
if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
8081
return -EINVAL;
8182

8283
if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),

drivers/md/dm-table.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,10 +463,11 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
463463
struct dm_dev_internal *dd;
464464
unsigned int major, minor;
465465
struct dm_table *t = ti->table;
466+
char dummy;
466467

467468
BUG_ON(!t);
468469

469-
if (sscanf(path, "%u:%u", &major, &minor) == 2) {
470+
if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
470471
/* Extract the major/minor numbers */
471472
dev = MKDEV(major, minor);
472473
if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -841,9 +842,10 @@ static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
841842
unsigned *value, char **error, unsigned grouped)
842843
{
843844
const char *arg_str = dm_shift_arg(arg_set);
845+
char dummy;
844846

845847
if (!arg_str ||
846-
(sscanf(arg_str, "%u", value) != 1) ||
848+
(sscanf(arg_str, "%u%c", value, &dummy) != 1) ||
847849
(*value < arg->min) ||
848850
(*value > arg->max) ||
849851
(grouped && arg_set->argc < *value)) {

0 commit comments

Comments
 (0)