Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netconsole: Acquire su_mutex before navigating configs hierarchy

There is a race between operations that iterate over the userdata
cg_children list and concurrent add/remove of userdata items through
configfs. The update_userdata() function iterates over the
nt->userdata_group.cg_children list, and count_extradata_entries() also
iterates over this same list to count nodes.

Quoting from Documentation/filesystems/configfs.rst:
> A subsystem can navigate the cg_children list and the ci_parent pointer
> to see the tree created by the subsystem. This can race with configfs'
> management of the hierarchy, so configfs uses the subsystem mutex to
> protect modifications. Whenever a subsystem wants to navigate the
> hierarchy, it must do so under the protection of the subsystem
> mutex.

Without proper locking, if a userdata item is added or removed
concurrently while these functions are iterating, the list can be
accessed in an inconsistent state. For example, the list_for_each() loop
can reach a node that is being removed from the list by list_del_init()
which sets the nodes' .next pointer to point to itself, so the loop will
never end (or reach the WARN_ON_ONCE in update_userdata() ).

Fix this by holding the configfs subsystem mutex (su_mutex) during all
operations that iterate over cg_children.
This includes:
- userdatum_value_store() which calls update_userdata() to iterate over
cg_children
- All sysdata_*_enabled_store() functions which call
count_extradata_entries() to iterate over cg_children

The su_mutex must be acquired before dynamic_netconsole_mutex to avoid
potential lock ordering issues, as configfs operations may already hold
su_mutex when calling into our code.

Fixes: df03f830d099 ("net: netconsole: cache userdata formatted string in netconsole_target")
Signed-off-by: Gustavo Luiz Duarte <gustavold@gmail.com>
Link: https://patch.msgid.link/20251029-netconsole-fix-warn-v1-1-0d0dd4622f48@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Gustavo Luiz Duarte and committed by
Jakub Kicinski
d7d2fcf7 c211f5d7

+10
+10
drivers/net/netconsole.c
··· 936 936 if (count > MAX_EXTRADATA_VALUE_LEN) 937 937 return -EMSGSIZE; 938 938 939 + mutex_lock(&netconsole_subsys.su_mutex); 939 940 mutex_lock(&dynamic_netconsole_mutex); 940 941 941 942 ret = strscpy(udm->value, buf, sizeof(udm->value)); ··· 950 949 ret = count; 951 950 out_unlock: 952 951 mutex_unlock(&dynamic_netconsole_mutex); 952 + mutex_unlock(&netconsole_subsys.su_mutex); 953 953 return ret; 954 954 } 955 955 ··· 976 974 if (ret) 977 975 return ret; 978 976 977 + mutex_lock(&netconsole_subsys.su_mutex); 979 978 mutex_lock(&dynamic_netconsole_mutex); 980 979 curr = !!(nt->sysdata_fields & SYSDATA_MSGID); 981 980 if (msgid_enabled == curr) ··· 997 994 ret = strnlen(buf, count); 998 995 unlock: 999 996 mutex_unlock(&dynamic_netconsole_mutex); 997 + mutex_unlock(&netconsole_subsys.su_mutex); 1000 998 return ret; 1001 999 } 1002 1000 ··· 1012 1008 if (ret) 1013 1009 return ret; 1014 1010 1011 + mutex_lock(&netconsole_subsys.su_mutex); 1015 1012 mutex_lock(&dynamic_netconsole_mutex); 1016 1013 curr = !!(nt->sysdata_fields & SYSDATA_RELEASE); 1017 1014 if (release_enabled == curr) ··· 1033 1028 ret = strnlen(buf, count); 1034 1029 unlock: 1035 1030 mutex_unlock(&dynamic_netconsole_mutex); 1031 + mutex_unlock(&netconsole_subsys.su_mutex); 1036 1032 return ret; 1037 1033 } 1038 1034 ··· 1048 1042 if (ret) 1049 1043 return ret; 1050 1044 1045 + mutex_lock(&netconsole_subsys.su_mutex); 1051 1046 mutex_lock(&dynamic_netconsole_mutex); 1052 1047 curr = !!(nt->sysdata_fields & SYSDATA_TASKNAME); 1053 1048 if (taskname_enabled == curr) ··· 1069 1062 ret = strnlen(buf, count); 1070 1063 unlock: 1071 1064 mutex_unlock(&dynamic_netconsole_mutex); 1065 + mutex_unlock(&netconsole_subsys.su_mutex); 1072 1066 return ret; 1073 1067 } 1074 1068 ··· 1085 1077 if (ret) 1086 1078 return ret; 1087 1079 1080 + mutex_lock(&netconsole_subsys.su_mutex); 1088 1081 mutex_lock(&dynamic_netconsole_mutex); 1089 1082 curr = !!(nt->sysdata_fields & SYSDATA_CPU_NR); 1090 1083 if (cpu_nr_enabled == curr) ··· 1114 1105 ret = strnlen(buf, count); 1115 1106 unlock: 1116 1107 mutex_unlock(&dynamic_netconsole_mutex); 1108 + mutex_unlock(&netconsole_subsys.su_mutex); 1117 1109 return ret; 1118 1110 } 1119 1111