Commit 869cd649 authored by Breno Leitao's avatar Breno Leitao Committed by Jakub Kicinski
Browse files

netconsole: restore userdatum value on update_userdata() failure



userdatum_value_store() updates udm->value first and only then calls
update_userdata() to rebuild the on-the-wire payload. If
update_userdata() fails (e.g. -ENOMEM from kmalloc), the function
returns the error to userspace, but udm->value already holds the new
string while the live nt->userdata buffer still reflects the old one.

The next successful write to any sibling userdatum on the same target
will call update_userdata() again, which walks every entry and packs
the now-stale udm->value into the payload. The failed write is thus
silently activated later, with no indication to userspace that the
value it tried to set was rejected.

Snapshot the previous value before overwriting udm->value and restore
it if update_userdata() fails so the visible state and the active
payload stay consistent.

Fixes: eb83801a ("netconsole: Dynamic allocation of userdata buffer")
Signed-off-by: default avatarBreno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-4-59965f29d9cc@debian.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 92ceb7bf
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -1079,6 +1079,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
				     size_t count)
{
	struct userdatum *udm = to_userdatum(item);
	char old_value[MAX_EXTRADATA_VALUE_LEN];
	struct netconsole_target *nt;
	struct userdata *ud;
	ssize_t ret;
@@ -1088,6 +1089,8 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,

	mutex_lock(&netconsole_subsys.su_mutex);
	dynamic_netconsole_mutex_lock();
	/* Snapshot for rollback if update_userdata() fails below */
	strscpy(old_value, udm->value, sizeof(old_value));
	/* count is bounded above, so strscpy() cannot truncate here */
	strscpy(udm->value, buf, sizeof(udm->value));
	trim_newline(udm->value, sizeof(udm->value));
@@ -1095,8 +1098,11 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
	ud = to_userdata(item->ci_parent);
	nt = userdata_to_target(ud);
	ret = update_userdata(nt);
	if (ret < 0)
	if (ret < 0) {
		/* Restore the previous value so it matches the live payload */
		strscpy(udm->value, old_value, sizeof(udm->value));
		goto out_unlock;
	}
	ret = count;
out_unlock:
	dynamic_netconsole_mutex_unlock();