In case of e.g. arp_ping (or nsna_ping) link watch used
when adding a port dynamically (i.e. through PortAdd DBus
method for instance) teamd crashes on lw_psr_port_removed()
ops call, when there was no previous corresponding
lw_ap_port_added() call.
That happens when teamd_link_watch_arp_ping object
port_priv's .init call did not happen due to some preceding
error, whereas .fini is called immediately following the error
flow of port_obj_create().
Calls:
port_priv_change_handler_func()
port_obj_create()
teamd_event_port_added()
port_priv_init_all() <- some initial .init fails here, before
port_prov's init. lw_ap_port_added()
remains uncalled and psr_ppriv->ops
unset (NULL).
port_obj_destroy()
port_priv_fini_all() <- segfault, due to uninitialized ops.
First step fix would be to check for initialization of
psr_ppriv->ops, indicating that corresponding .init call
has happened before.
Signed-off-by: Pawel Wieczorkiewicz <pwieczorkiewicz(a)suse.de>
---
teamd/teamd_lw_psr.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/teamd/teamd_lw_psr.c b/teamd/teamd_lw_psr.c
index c0772db..ca1eadf 100644
--- a/teamd/teamd_lw_psr.c
+++ b/teamd/teamd_lw_psr.c
@@ -39,6 +39,9 @@ static int lw_psr_callback_periodic(struct teamd_context *ctx, int
events, void
bool link_up = common_ppriv->link_up;
int err;
+ if (!psr_ppriv->ops)
+ return -EINVAL;
+
if (psr_ppriv->reply_received) {
link_up = true;
psr_ppriv->missed = 0;
@@ -65,6 +68,9 @@ static int lw_psr_callback_socket(struct teamd_context *ctx, int events,
void *p
{
struct lw_psr_port_priv *psr_ppriv = priv;
+ if (!psr_ppriv->ops)
+ return -EINVAL;
+
return psr_ppriv->ops->receive(psr_ppriv);
}
@@ -120,6 +126,9 @@ int lw_psr_port_added(struct teamd_context *ctx, struct teamd_port
*tdport,
struct lw_psr_port_priv *psr_ppriv = priv;
int err;
+ if (!psr_ppriv->ops)
+ return -EINVAL;
+
err = lw_psr_load_options(ctx, tdport, psr_ppriv);
if (err) {
teamd_log_err("Failed to load options.");
@@ -182,6 +191,9 @@ void lw_psr_port_removed(struct teamd_context *ctx, struct teamd_port
*tdport,
{
struct lw_psr_port_priv *psr_ppriv = priv;
+ if (!psr_ppriv->ops)
+ return;
+
teamd_loop_callback_del(ctx, LW_PERIODIC_CB_NAME, psr_ppriv);
teamd_loop_callback_del(ctx, LW_SOCKET_CB_NAME, psr_ppriv);
psr_ppriv->ops->sock_close(psr_ppriv);
--
2.1.4
Show replies by thread