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>
This commit is contained in:
+19
-1
@@ -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
|
||||
},
|
||||
{
|
||||
|
||||
+18
-3
@@ -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)
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+28
-5
@@ -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;
|
||||
|
||||
for (len = 0; string[len] != '\0'; len++) {
|
||||
if (strchr(";,~\\()\'", string[len]))
|
||||
string[len] = '_';
|
||||
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;
|
||||
}
|
||||
|
||||
/* everything else is garbage */
|
||||
str[i] = '_';
|
||||
i++;
|
||||
replaced++;
|
||||
}
|
||||
|
||||
return replaced;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user