summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/udev-test.pl20
-rw-r--r--udev_rules.c21
-rw-r--r--udev_utils.h2
-rw-r--r--udev_utils_string.c33
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;
}