diff options
author | Kay Sievers <kay.sievers@suse.de> | 2005-08-28 15:55:58 +0200 |
---|---|---|
committer | Kay Sievers <kay.sievers@suse.de> | 2005-08-28 15:55:58 +0200 |
commit | 764ce7f2ab526c084f005186e0dcbabe59070247 (patch) | |
tree | 411a1246ee2a77271d2dab8a6480e5e7388694ac | |
parent | 5b13ecb830cdec338b514b9ed8c2c559c2f05223 (diff) |
start to enforce plain ascii or valid utf8
No device node or symlink can have other characters as plain
readable ascii or valid utf8. The /dev/disk/by-label/* symlinks
can no longer contain weird stuff read from untrusted sources.
Signed-off-by: Kay Sievers <kay.sievers@suse.de>
-rwxr-xr-x | test/udev-test.pl | 20 | ||||
-rw-r--r-- | udev_rules.c | 21 | ||||
-rw-r--r-- | udev_utils.h | 2 | ||||
-rw-r--r-- | udev_utils_string.c | 33 |
4 files changed, 66 insertions, 10 deletions
diff --git a/test/udev-test.pl b/test/udev-test.pl index c32cfe7eeb..e7c00e29e6 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -1324,7 +1324,25 @@ EOF devpath => "/block/sda/sda1", exp_name => "sane", rules => <<EOF -BUS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/sbin/badprogram)", RESULT="name_ _/sbin/badprogram_", NAME="sane" +BUS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/sbin/badprogram)", RESULT=="name_ _/sbin/badprogram_", NAME="sane" +EOF + }, + { + desc => "untrusted string sanitize (don't replace utf8)", + subsys => "block", + devpath => "/block/sda/sda1", + exp_name => "uber", + rules => <<EOF +BUS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", NAME="uber" +EOF + }, + { + desc => "untrusted string sanitize (replace invalid utf8)", + subsys => "block", + devpath => "/block/sda/sda1", + exp_name => "replaced", + rules => <<EOF +BUS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="[?][?]garbage", NAME="replaced" EOF }, { diff --git a/udev_rules.c b/udev_rules.c index 41a7291d79..c1482c34b5 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -362,6 +362,7 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, char *head, *tail, *pos, *cpos, *attr, *rest; int len; int i; + int count; unsigned int next_free_number; struct sysfs_class_device *class_dev_parent; enum subst_type { @@ -544,7 +545,9 @@ found: i = strlen(temp2); while (i > 0 && isspace(temp2[i-1])) temp2[--i] = '\0'; - replace_untrusted_chars(temp2); + count = replace_untrusted_chars(temp2); + if (count) + info("%i untrusted character(s) replaced" , count); strlcat(string, temp2, maxsize); dbg("substitute sysfs value '%s'", temp2); break; @@ -812,9 +815,13 @@ try_parent: if (rule->program.operation != KEY_OP_NOMATCH) goto exit; } else { + int count; + dbg("PROGRAM matches"); remove_trailing_char(result, '\n'); - replace_untrusted_chars(result); + count = replace_untrusted_chars(result); + if (count) + info("%i untrusted character(s) replaced" , count); dbg("result is '%s'", result); strlcpy(udev->program_result, result, sizeof(udev->program_result)); dbg("PROGRAM returned successful"); @@ -960,6 +967,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s if (!udev->symlink_final && rule->symlink.operation != KEY_OP_UNSET) { char temp[PATH_SIZE]; char *pos, *next; + int count; if (rule->symlink.operation == KEY_OP_ASSIGN_FINAL) udev->symlink_final = 1; @@ -969,7 +977,10 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s } strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp)); apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); - dbg("rule applied, added symlink '%s'", temp); + count = replace_untrusted_chars(temp); + if (count) + info("%i untrusted character(s) replaced" , count); + dbg("rule applied, added symlink(s) '%s'", temp); /* add multiple symlinks separated by spaces */ pos = temp; @@ -993,9 +1004,13 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s /* set name, later rules with name set will be ignored */ if (rule->name.operation != KEY_OP_UNSET) { + int count; name_set = 1; strlcpy(udev->name, key_val(rule, &rule->name), sizeof(udev->name)); apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); + count = replace_untrusted_chars(udev->name); + if (count) + info("%i untrusted character(s) replaced", count); info("rule applied, '%s' becomes '%s'", udev->kernel_name, udev->name); if (udev->type != DEV_NET) diff --git a/udev_utils.h b/udev_utils.h index a07d8d2b7c..ad415641d8 100644 --- a/udev_utils.h +++ b/udev_utils.h @@ -42,9 +42,9 @@ extern int add_matching_files(struct list_head *name_list, const char *dirname, /* udev_utils_string.c */ extern int strcmp_pattern(const char *p, const char *s); extern int string_is_true(const char *str); -extern void replace_untrusted_chars(char *string); extern void remove_trailing_char(char *path, char c); extern int utf8_encoded_valid_unichar(const char *str); +extern int replace_untrusted_chars(char *str); /* udev_utils_file.c */ extern int create_path(const char *path); diff --git a/udev_utils_string.c b/udev_utils_string.c index a30181e760..bb5677d46e 100644 --- a/udev_utils_string.c +++ b/udev_utils_string.c @@ -232,12 +232,35 @@ int utf8_encoded_valid_unichar(const char *str) return len; } -void replace_untrusted_chars(char *string) +/* replace everything but whitelisted plain ascii and valid utf8 */ +int replace_untrusted_chars(char *str) { - size_t len; + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') { + int len; + + /* valid printable ascii char */ + if ((str[i] >= '0' && str[i] <= '9') || + (str[i] >= 'A' && str[i] <= 'Z') || + (str[i] >= 'a' && str[i] <= 'z') || + strchr(" #$%+-./:=?@_", str[i])) { + i++; + continue; + } + /* valid utf8 is accepted */ + len = utf8_encoded_valid_unichar(&str[i]); + if (len > 1) { + i += len; + continue; + } - for (len = 0; string[len] != '\0'; len++) { - if (strchr(";,~\\()\'", string[len])) - string[len] = '_'; + /* everything else is garbage */ + str[i] = '_'; + i++; + replaced++; } + + return replaced; } |