diff --git a/src/udp/udp.c b/src/udp/udp.c
index 5168b3ffd..590cccf08 100644
--- a/src/udp/udp.c
+++ b/src/udp/udp.c
@@ -22,6 +22,7 @@
 #include <re_mem.h>
 #include <re_mbuf.h>
 #include <re_list.h>
+#include <re_thread.h>
 #include <re_net.h>
 #include <re_main.h>
 #include <re_sa.h>
@@ -74,6 +75,7 @@ struct udp_sock {
 	QOS_FLOWID qos_id;   /**< QOS IPv4 flow id            */
 	QOS_FLOWID qos_id6;  /**< QOS IPv6 flow id            */
 #endif
+	mtx_t *lock;         /**< A lock for helpers          */
 };
 
 /** Defines a UDP helper */
@@ -120,7 +122,10 @@ static void udp_destructor(void *data)
 {
 	struct udp_sock *us = data;
 
+	mtx_lock(us->lock);
 	list_flush(&us->helpers);
+	mtx_unlock(us->lock);
+	mem_deref(us->lock);
 
 #ifdef WIN32
 	if (us->qos && us->qos_id)
@@ -185,6 +190,7 @@ static void udp_read(struct udp_sock *us, re_sock_t fd)
 	(void)mbuf_resize(mb, mb->end);
 
 	/* call helpers */
+	mtx_lock(us->lock);
 	le = us->helpers.head;
 	while (le) {
 		struct udp_helper *uh = le->data;
@@ -200,6 +206,7 @@ static void udp_read(struct udp_sock *us, re_sock_t fd)
 	us->rh(&src, mb, us->arg);
 
  out:
+	mtx_unlock(us->lock);
 	mem_deref(mb);
 }
 
@@ -250,6 +257,10 @@ int udp_listen(struct udp_sock **usp, const struct sa *local,
 	if (!us)
 		return ENOMEM;
 
+	err = mutex_alloc(&us->lock);
+	if (err)
+		goto out;
+
 	list_init(&us->helpers);
 
 	us->fd  = RE_BAD_SOCK;
@@ -382,6 +393,10 @@ int udp_alloc_sockless(struct udp_sock **usp,
 	if (!us)
 		return ENOMEM;
 
+	int err = mutex_alloc(&us->lock);
+	if (err)
+		goto out;
+
 	list_init(&us->helpers);
 
 	us->fd    = RE_BAD_SOCK;
@@ -391,9 +406,13 @@ int udp_alloc_sockless(struct udp_sock **usp,
 	us->arg   = arg;
 	us->rxsz  = UDP_RXSZ_DEFAULT;
 
-	*usp = us;
+out:
+	if (err)
+		mem_deref(us);
+	else
+		*usp = us;
 
-	return 0;
+	return err;
 }
 
 
@@ -407,6 +426,10 @@ int udp_alloc_fd(struct udp_sock **usp, re_sock_t fd,
 	if (!us)
 		return ENOMEM;
 
+	int err = mutex_alloc(&us->lock);
+	if (err)
+		goto out;
+
 	list_init(&us->helpers);
 
 	us->fd   = fd;
@@ -415,7 +438,11 @@ int udp_alloc_fd(struct udp_sock **usp, re_sock_t fd,
 	us->arg  = arg;
 	us->rxsz = UDP_RXSZ_DEFAULT;
 
-	*usp = us;
+out:
+	if (err)
+		mem_deref(us);
+	else
+		*usp = us;
 
 	return 0;
 }
@@ -442,6 +469,10 @@ int udp_open(struct udp_sock **usp, int af)
 	if (!us)
 		return ENOMEM;
 
+	err = mutex_alloc(&us->lock);
+	if (err)
+		goto out;
+
 	us->fd  = RE_BAD_SOCK;
 	us->fd6 = RE_BAD_SOCK;
 
@@ -879,6 +910,7 @@ int udp_register_helper(struct udp_helper **uhp, struct udp_sock *us,
 	if (!uh)
 		return ENOMEM;
 
+	mtx_lock(us->lock);
 	list_append(&us->helpers, &uh->le, uh);
 
 	uh->layer = layer;
@@ -891,6 +923,7 @@ int udp_register_helper(struct udp_helper **uhp, struct udp_sock *us,
 	if (uhp)
 		*uhp = uh;
 
+	mtx_unlock(us->lock);
 	return 0;
 }
 
@@ -957,19 +990,24 @@ void udp_recv_helper(struct udp_sock *us, const struct sa *src,
 struct udp_helper *udp_helper_find(const struct udp_sock *us, int layer)
 {
 	struct le *le;
+	struct udp_helper *uhf = NULL;
 
 	if (!us)
 		return NULL;
 
+	mtx_lock(us->lock);
 	for (le = us->helpers.head; le; le = le->next) {
 
 		struct udp_helper *uh = le->data;
 
-		if (layer == uh->layer)
-			return uh;
+		if (layer == uh->layer) {
+			uhf = uh;
+			break;
+		}
 	}
 
-	return NULL;
+	mtx_unlock(us->lock);
+	return uhf;
 }
 
 
@@ -1005,11 +1043,13 @@ void udp_recv_packet(struct udp_sock *us, const struct sa *src,
 		     struct mbuf *mb)
 {
 	struct sa hsrc;
+	struct le *le;
 
 	if (!us || !src || !mb)
 		return;
 
-	struct le *le = us->helpers.head;
+	mtx_lock(us->lock);
+	le = us->helpers.head;
 	while (le) {
 		struct udp_helper *uh = le->data;
 		bool hdld;
@@ -1023,8 +1063,10 @@ void udp_recv_packet(struct udp_sock *us, const struct sa *src,
 
 		hdld = uh->recvh(&hsrc, mb, uh->arg);
 		if (hdld)
-			return;
+			goto out;
 	}
 
 	us->rh(src, mb, us->arg);
+out:
+	mtx_unlock(us->lock);
 }