udev: check formatting of attribute or value earlier

This commit is contained in:
Yu Watanabe
2019-06-03 08:35:33 +09:00
parent 1448820aad
commit d7aee41db3
4 changed files with 106 additions and 14 deletions
+35 -4
View File
@@ -149,7 +149,7 @@ static char format_type_to_char(FormatSubstitutionType t) {
return '\0';
}
static int get_subst_type(const char **str, FormatSubstitutionType *ret_type, char ret_attr[static UTIL_PATH_SIZE]) {
static int get_subst_type(const char **str, bool strict, FormatSubstitutionType *ret_type, char ret_attr[static UTIL_PATH_SIZE]) {
const char *p = *str, *q = NULL;
size_t i;
@@ -178,9 +178,11 @@ static int get_subst_type(const char **str, FormatSubstitutionType *ret_type, ch
q = p + 1;
break;
}
}
if (!q)
} else
return 0;
if (!q)
/* When 'strict' flag is set, then '$' and '%' must be escaped. */
return strict ? -EINVAL : 0;
if (q[0] == '{') {
const char *start, *end;
@@ -450,7 +452,7 @@ ssize_t udev_event_apply_format(UdevEvent *event,
char attr[UTIL_PATH_SIZE];
ssize_t subst_len;
r = get_subst_type(&s, &type, attr);
r = get_subst_type(&s, false, &type, attr);
if (r < 0)
return log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
if (r == 0) {
@@ -482,6 +484,35 @@ ssize_t udev_event_apply_format(UdevEvent *event,
return size;
}
int udev_check_format(const char *s) {
FormatSubstitutionType type;
char attr[UTIL_PATH_SIZE];
int r;
while (s[0] != '\0') {
r = get_subst_type(&s, true, &type, attr);
if (r < 0)
return r;
if (r == 0) {
s++;
continue;
}
if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr))
return -EINVAL;
if (type == FORMAT_SUBST_RESULT && !isempty(attr)) {
unsigned i;
r = safe_atou_optional_plus(attr, &i);
if (r < 0)
return r;
}
}
return 0;
}
static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
Spawn *spawn = userdata;
char buf[4096], *p;
+1
View File
@@ -51,6 +51,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
ssize_t udev_event_apply_format(UdevEvent *event,
const char *src, char *dest, size_t size,
bool replace_whitespace);
int udev_check_format(const char *s);
int udev_event_spawn(UdevEvent *event,
usec_t timeout_usec,
bool accept_failure,
+61 -10
View File
@@ -345,7 +345,13 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
r = rule_line_add_token(rule_line, is_match ? TK_M_DEVLINK : TK_A_DEVLINK, op, value, NULL);
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL);
} else
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL);
} else if (streq(key, "NAME")) {
if (attr)
return log_token_invalid_attr(rules, key);
@@ -363,6 +369,9 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (isempty(value))
return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL),
"Ignoring NAME=\"\", as udev will not delete any device nodes.");
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
} else
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL);
@@ -383,6 +392,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL),
"Invalid ENV attribute. '%s' cannot be set.", attr);
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr);
} else
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr);
@@ -394,7 +405,12 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
op = OP_ASSIGN;
}
r = rule_line_add_token(rule_line, is_match ? TK_M_TAG : TK_A_TAG, op, value, NULL);
if (!is_match) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL);
} else
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL);
} else if (streq(key, "SUBSYSTEM")) {
if (attr)
return log_token_invalid_attr(rules, key);
@@ -414,7 +430,9 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
} else if (streq(key, "ATTR")) {
if (isempty(attr))
return log_token_invalid_op(rules, key);
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) {
@@ -422,10 +440,18 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
op = OP_ASSIGN;
}
r = rule_line_add_token(rule_line, is_match ? TK_M_ATTR : TK_A_ATTR, op, value, attr);
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr);
} else
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr);
} else if (streq(key, "SYSCTL")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) {
@@ -433,7 +459,13 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
op = OP_ASSIGN;
}
r = rule_line_add_token(rule_line, is_match ? TK_M_SYSCTL : TK_A_SYSCTL, op, value, attr);
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr);
} else
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr);
} else if (streq(key, "KERNELS")) {
if (attr)
return log_token_invalid_attr(rules, key);
@@ -458,6 +490,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "ATTRS")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
if (!is_match)
return log_token_invalid_op(rules, key);
@@ -482,6 +516,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (r < 0)
return log_token_error_errno(rules, r, "Failed to parse mode '%s': %m", attr);
}
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
if (!is_match)
return log_token_invalid_op(rules, key);
@@ -489,6 +525,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "PROGRAM")) {
if (attr)
return log_token_invalid_attr(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (!is_match) {
@@ -503,6 +541,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "IMPORT")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (!is_match) {
@@ -603,9 +643,11 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
return log_token_error_errno(rules, r, "Failed to resolve user name '%s': %m", value);
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
else {
} else {
log_token_debug(rules, "Resolving user name is disabled, ignoring %s=%s", key, value);
return 0;
}
@@ -630,9 +672,11 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
return log_token_error_errno(rules, r, "Failed to resolve group name '%s': %m", value);
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL);
else {
} else {
log_token_debug(rules, "Resolving group name is disabled, ignoring %s=%s", key, value);
return 0;
}
@@ -650,11 +694,16 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (parse_mode(value, &mode) >= 0)
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
else
else {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL);
}
} else if (streq(key, "SECLABEL")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
if (is_match || op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (op == OP_ASSIGN_FINAL) {
@@ -666,6 +715,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "RUN")) {
if (is_match || op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
if (!attr || streq(attr, "program"))
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL);
else if (streq(attr, "builtin")) {
+9
View File
@@ -215,3 +215,12 @@ int udev_rules_apply_static_dev_perms(UdevRules *rules);
#define log_token_invalid_op(rules, key) _log_token_invalid(rules, key, "operator")
#define log_token_invalid_attr(rules, key) _log_token_invalid(rules, key, "attribute")
#define log_token_invalid_attr_format(rules, key, attr) \
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
"Invalid attribute \"%s\" for %s, ignoring, but please fix it.", \
attr, key)
#define log_token_invalid_value(rules, key, value) \
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
"Invalid value \"%s\" for %s, ignoring, but please fix it.", \
value, key)