summaryrefslogtreecommitdiff
path: root/lib/hashtable.c
diff options
context:
space:
mode:
authorChristoph Niedermaier <cniedermaier@dh-electronics.com>2024-12-07 00:04:19 +0100
committerFabio Estevam <festevam@gmail.com>2024-12-07 09:07:45 -0300
commit86f58ea539e35b47235dff0dd77ec20fe8894469 (patch)
tree80caf2023734b0baeac12803e3f95052abeaa1b6 /lib/hashtable.c
parent489b965564ad73c7a2e8f8743908347775c5df3b (diff)
lib: hashtable: Prevent recursive calling of callback functions
In case there are two variables which each implement env callback that performs env_set() on the other variable, the callbacks will call each other recursively until the stack runs out. Prevent such a recursion from happening. Example which triggers this behavior: static int on_foo(...) { env_set("bar", 0); ... } static int on_bar(...) { env_set("foo", 0); ... } U_BOOT_ENV_CALLBACK(foo, on_foo); U_BOOT_ENV_CALLBACK(bar, on_bar); Signed-off-by: Christoph Niedermaier <cniedermaier@dh-electronics.com> Suggested-by: Marek Vasut <marex@denx.de>
Diffstat (limited to 'lib/hashtable.c')
-rw-r--r--lib/hashtable.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/lib/hashtable.c b/lib/hashtable.c
index e8a59e2dcac..75c263b5053 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -221,11 +221,32 @@ static int
do_callback(const struct env_entry *e, const char *name, const char *value,
enum env_op op, int flags)
{
+ int ret = 0;
+
#ifndef CONFIG_XPL_BUILD
- if (e->callback)
- return e->callback(name, value, op, flags);
+ static bool in_callback;
+
+ if (!e->callback || in_callback)
+ return 0;
+
+ /*
+ * In case there are two variables which each implement env callback
+ * that performs env_set() on the other variable, the callbacks will
+ * call each other recursively until the stack runs out. Prevent such
+ * a recursion from happening.
+ *
+ * Example which triggers this behavior:
+ * static int on_foo(...) { env_set("bar", 0); ... }
+ * static int on_bar(...) { env_set("foo", 0); ... }
+ * U_BOOT_ENV_CALLBACK(foo, on_foo);
+ * U_BOOT_ENV_CALLBACK(bar, on_bar);
+ */
+ in_callback = true;
+ ret = e->callback(name, value, op, flags);
+ in_callback = false;
#endif
- return 0;
+
+ return ret;
}
/*