From 764ce7f2ab526c084f005186e0dcbabe59070247 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 28 Aug 2005 15:55:58 +0200 Subject: [PATCH] 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 --- test/udev-test.pl | 20 +++++++++++++++++++- udev_rules.c | 21 ++++++++++++++++++--- udev_utils.h | 2 +- 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 c32cfe7ee..e7c00e29e 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -1324,7 +1324,25 @@ EOF devpath => "/block/sda/sda1", exp_name => "sane", rules => < "untrusted string sanitize (don't replace utf8)", + subsys => "block", + devpath => "/block/sda/sda1", + exp_name => "uber", + rules => < "untrusted string sanitize (replace invalid utf8)", + subsys => "block", + devpath => "/block/sda/sda1", + exp_name => "replaced", + rules => < 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 a07d8d2b7..ad415641d 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 a30181e76..bb5677d46 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; } -- 2.30.2