Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aed8673 authored by Logan Gunthorpe's avatar Logan Gunthorpe Committed by Sagi Grimberg
Browse files

nvmet: Fix use-after-free bug when a port is removed



When a port is removed through configfs, any connected controllers
are still active and can still send commands. This causes a
use-after-free bug which is detected by KASAN for any admin command
that dereferences req->port (like in nvmet_execute_identify_ctrl).

To fix this, disconnect all active controllers when a subsystem is
removed from a port. This ensures there are no active controllers
when the port is eventually removed.

Signed-off-by: default avatarLogan Gunthorpe <logang@deltatee.com>
Reviewed-by: default avatarSagi Grimberg <sagi@grimberg.me>
Reviewed-by: default avatarMax Gurtovoy <maxg@mellanox.com>
Reviewed-by : Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Signed-off-by: default avatarSagi Grimberg <sagi@grimberg.me>
parent fab7772b
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -675,6 +675,7 @@ static void nvmet_port_subsys_drop_link(struct config_item *parent,


found:
found:
	list_del(&p->entry);
	list_del(&p->entry);
	nvmet_port_del_ctrls(port, subsys);
	nvmet_port_disc_changed(port, subsys);
	nvmet_port_disc_changed(port, subsys);


	if (list_empty(&port->subsystems))
	if (list_empty(&port->subsystems))
+12 −0
Original line number Original line Diff line number Diff line
@@ -280,6 +280,18 @@ void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops)
}
}
EXPORT_SYMBOL_GPL(nvmet_unregister_transport);
EXPORT_SYMBOL_GPL(nvmet_unregister_transport);


void nvmet_port_del_ctrls(struct nvmet_port *port, struct nvmet_subsys *subsys)
{
	struct nvmet_ctrl *ctrl;

	mutex_lock(&subsys->lock);
	list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
		if (ctrl->port == port)
			ctrl->ops->delete_ctrl(ctrl);
	}
	mutex_unlock(&subsys->lock);
}

int nvmet_enable_port(struct nvmet_port *port)
int nvmet_enable_port(struct nvmet_port *port)
{
{
	const struct nvmet_fabrics_ops *ops;
	const struct nvmet_fabrics_ops *ops;
+3 −0
Original line number Original line Diff line number Diff line
@@ -418,6 +418,9 @@ void nvmet_port_send_ana_event(struct nvmet_port *port);
int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);
void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);


void nvmet_port_del_ctrls(struct nvmet_port *port,
			  struct nvmet_subsys *subsys);

int nvmet_enable_port(struct nvmet_port *port);
int nvmet_enable_port(struct nvmet_port *port);
void nvmet_disable_port(struct nvmet_port *port);
void nvmet_disable_port(struct nvmet_port *port);