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

Commit 50774d31 authored by Harsh Agarwal's avatar Harsh Agarwal
Browse files

usb: gadget: f_ipc: Fix race between ipc_free_inst and ipc_close



There is a possibility of race condition when we unregister the
gadget f_ipc.As part of this, ipc_free_inst and ipc_close gets
executed in parallel threads. The race condition may arise
depending on when the ipc_dev is freed in ipc_free_inst, which in
turn could lead to use-after-free in ipc_close.

Fix this by moving the allocation and de-allocation of ipc_dev in
ipc_init and ipc_exit.

Change-Id: I30bf28258a8da6d2c9cd2f4eae7f38025b49ee0d
Signed-off-by: default avatarHarsh Agarwal <harshq@codeaurora.org>
parent 48fec5f5
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -794,10 +794,6 @@ static int ipc_set_inst_name(struct usb_function_instance *fi,
	if (name_len > MAX_INST_NAME_LEN)
		return -ENAMETOOLONG;

	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
	if (!ipc_dev)
		return -ENOMEM;

	spin_lock_init(&ipc_dev->lock);
	init_waitqueue_head(&ipc_dev->state_wq);
	init_completion(&ipc_dev->read_done);
@@ -813,7 +809,6 @@ static void ipc_free_inst(struct usb_function_instance *f)
{
	struct ipc_opts *opts = container_of(f, struct ipc_opts, func_inst);

	kfree(opts->ctxt);
	kfree(opts);
}

@@ -844,9 +839,17 @@ static int __init ipc_init(void)
{
	int ret;

	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
	if (!ipc_dev)
		return -ENOMEM;

	ret = usb_function_register(&ipcusb_func);
	if (ret)
	if (ret) {
		kfree(ipc_dev);
		ipc_dev = NULL;
		pr_err("%s: failed to register ipc %d\n", __func__, ret);
		return ret;
	}

	fipc_debugfs_init();

@@ -857,6 +860,8 @@ static void __exit ipc_exit(void)
{
	fipc_debugfs_remove();
	usb_function_unregister(&ipcusb_func);
	kfree(ipc_dev);
	ipc_dev = NULL;
}

module_init(ipc_init);