chiark / gitweb /
start to enforce plain ascii or valid utf8
authorKay Sievers <kay.sievers@suse.de>
Sun, 28 Aug 2005 13:55:58 +0000 (15:55 +0200)
committerKay Sievers <kay.sievers@suse.de>
Sun, 28 Aug 2005 13:55:58 +0000 (15:55 +0200)
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>
test/udev-test.pl
udev_rules.c
udev_utils.h
udev_utils_string.c

index c32cfe7eeb0f253c232783cd7d7f0c6ce63a12ad..e7c00e29e6e08e0bd855fd746a70071dafb4a512 100755 (executable)
@@ -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
        },
        {
index 41a7291d7976747788ac31013805dcd86b8d0e0e..c1482c34b50be4a126927760c693c652361be29b 100644 (file)
@@ -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)
index a07d8d2b7cecb6f152ef34f2631604b14dd4d68c..ad415641d8cb68065e41468468696d6e94c42b19 100644 (file)
@@ -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);
index a30181e760d5592625fd83831a5a4a0f2bb27f3b..bb5677d46ebbcc5395d904b5918a815b40be53fc 100644 (file)
@@ -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;
 }