summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@suse.de>2005-08-28 15:55:58 +0200
committerKay Sievers <kay.sievers@suse.de>2005-08-28 15:55:58 +0200
commit764ce7f2ab526c084f005186e0dcbabe59070247 (patch)
tree411a1246ee2a77271d2dab8a6480e5e7388694ac
parent5b13ecb830cdec338b514b9ed8c2c559c2f05223 (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-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;
}