mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
udev-rules: use sd_device_set_sysattr_value() to write sysfs attribute
Then, we can avoid that files outside of sysfs are written by udev ATTR key. This also makes - logs failure in udev_resolve_subsys_kernel(), - failure in sd_device_get_syspath() critical, as that should not happen, - cache the value to be write when running on test mode, to make it shown by OPTIONS="dump" or obtained by ATTR match token.
This commit is contained in:
@@ -2960,50 +2960,85 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_ATTR: {
|
case TK_A_ATTR: {
|
||||||
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
||||||
const char *val, *key_name = token->data;
|
const char *key = token->data;
|
||||||
|
|
||||||
|
/* First, try to resolve "[<SUBSYSTEM>/<KERNEL>]<attribute>" format. */
|
||||||
|
r = udev_resolve_subsys_kernel(key, buf, sizeof(buf), false);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) {
|
||||||
|
log_event_warning_errno(event, token, r, "Failed to resolve sysfs attribute \"%s\", ignoring: %m", key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
/* If not, make the path to sysfs attribute absolute, to make '*' resolvable by attr_subst_subdir(). */
|
||||||
|
const char *syspath;
|
||||||
|
r = sd_device_get_syspath(dev, &syspath);
|
||||||
|
if (r < 0)
|
||||||
|
return log_event_error_errno(event, token, r, "Failed to get syspath: %m");
|
||||||
|
|
||||||
if (udev_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 &&
|
|
||||||
sd_device_get_syspath(dev, &val) >= 0) {
|
|
||||||
bool truncated;
|
bool truncated;
|
||||||
strscpyl_full(buf, sizeof(buf), &truncated, val, "/", key_name, NULL);
|
strscpyl_full(buf, sizeof(buf), &truncated, syspath, "/", key, NULL);
|
||||||
if (truncated) {
|
if (truncated) {
|
||||||
log_event_warning(event, token,
|
log_event_warning(event, token,
|
||||||
"The path to the attribute \"%s/%s\" is too long, refusing to set the attribute.",
|
"The path to the attribute \"%s/%s\" is too long, refusing to set the attribute.",
|
||||||
val, key_name);
|
syspath, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve '*' in the path. */
|
||||||
|
r = attr_subst_subdir(buf);
|
||||||
|
if (r < 0) {
|
||||||
|
log_event_error_errno(event, token, r, "Could not find file matches \"%s\", ignoring: %m", buf);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = attr_subst_subdir(buf);
|
/* Then, make the path relative again. This also checks if the path being inside of the sysfs. */
|
||||||
|
_cleanup_free_ char *resolved = NULL;
|
||||||
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
r = device_chase(dev, buf, /* flags = */ 0, &resolved, &fd);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_event_error_errno(event, token, r, "Could not find file matches \"%s\", ignoring: %m", buf);
|
log_event_error_errno(event, token, r, "Could not chase sysfs attribute \"%s\", ignoring: %m", buf);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply formatting to the value. */
|
||||||
if (!apply_format_value(event, token, value, sizeof(value), "attribute value"))
|
if (!apply_format_value(event, token, value, sizeof(value), "attribute value"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
||||||
log_event_debug(event, token, "Writing \"%s\" to sysfs attribute \"%s\".", value, buf);
|
log_event_debug(event, token, "Writing \"%s\" to sysfs attribute \"%s\".", value, resolved);
|
||||||
r = write_string_file(buf, value,
|
r = sd_device_set_sysattr_value(dev, resolved, value);
|
||||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE |
|
|
||||||
WRITE_STRING_FILE_DISABLE_BUFFER |
|
|
||||||
WRITE_STRING_FILE_AVOID_NEWLINE |
|
|
||||||
WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_event_error_errno(event, token, r, "Failed to write \"%s\" to sysfs attribute \"%s\", ignoring: %m", value, buf);
|
log_event_error_errno(event, token, r, "Failed to write \"%s\" to sysfs attribute \"%s\", ignoring: %m", value, resolved);
|
||||||
else {
|
else {
|
||||||
event_cache_written_sysattr(event, buf, value);
|
event_cache_written_sysattr(event, resolved, value);
|
||||||
log_event_done(event, token);
|
log_event_done(event, token);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_event_debug(event, token, "Running in test mode, skipping writing \"%s\" to sysfs attribute \"%s\".", value, buf);
|
log_event_debug(event, token, "Running in test mode, skipping writing \"%s\" to sysfs attribute \"%s\".", value, resolved);
|
||||||
|
|
||||||
r = verify_regular_at(AT_FDCWD, buf, /* follow = */ false);
|
/* We assume the attribute is writable if the path points to a regular file, and cache
|
||||||
|
* the value to make it shown by OPTIONS="dump" or obtained by later ATTR match token. */
|
||||||
|
r = fd_verify_regular(fd);
|
||||||
if (r < 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
|
if (r < 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
|
||||||
log_event_error_errno(event, token, r, "Failed to verify sysfs attribute \"%s\" is a regular file: %m", buf);
|
log_event_error_errno(event, token, r, "Failed to verify sysfs attribute \"%s\" is a regular file: %m", resolved);
|
||||||
else
|
else {
|
||||||
event_cache_written_sysattr(event, buf, value);
|
event_cache_written_sysattr(event, resolved, value);
|
||||||
|
|
||||||
|
_cleanup_free_ char *copied = strdup(value);
|
||||||
|
if (!copied)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = device_cache_sysattr_value(dev, resolved, value, /* error = */ 0);
|
||||||
|
if (r < 0)
|
||||||
|
log_event_warning_errno(event, token, r, "Failed to cache sysfs attribute \"%s\", ignoring: %m", resolved);
|
||||||
|
else if (r > 0) {
|
||||||
|
TAKE_PTR(resolved);
|
||||||
|
TAKE_PTR(copied);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user