From a58d37bce0d21cf7fbd589384c619e465ef2f927 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Mon, 24 Jun 2019 16:41:48 +0200 Subject: ocxl: Fix concurrent AFU open and device removal If an ocxl device is unbound through sysfs at the same time its AFU is being opened by a user process, the open code may dereference freed stuctures, which can lead to kernel oops messages. You'd have to hit a tiny time window, but it's possible. It's fairly easy to test by making the time window bigger artificially. Fix it with a combination of 2 changes: - when an AFU device is found in the IDR by looking for the device minor number, we should hold a reference on the device until after the context is allocated. A reference on the AFU structure is kept when the context is allocated, so we can release the reference on the device after the context allocation. - with the fix above, there's still another even tinier window, between the time the AFU device is found in the IDR and the reference on the device is taken. We can fix this one by removing the IDR entry earlier, when the device setup is removed, instead of waiting for the 'release' device callback. With proper locking around the IDR. Fixes: 75ca758adbaf ("ocxl: Create a clear delineation between ocxl backend & frontend") Cc: stable@vger.kernel.org # v5.2+ Signed-off-by: Frederic Barrat Reviewed-by: Greg Kurz Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190624144148.32022-1-fbarrat@linux.ibm.com --- drivers/misc/ocxl/file.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 2870c25da166..4d1b44de1492 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -18,18 +18,15 @@ static struct class *ocxl_class; static struct mutex minors_idr_lock; static struct idr minors_idr; -static struct ocxl_file_info *find_file_info(dev_t devno) +static struct ocxl_file_info *find_and_get_file_info(dev_t devno) { struct ocxl_file_info *info; - /* - * We don't declare an RCU critical section here, as our AFU - * is protected by a reference counter on the device. By the time the - * info reference is removed from the idr, the ref count of - * the device is already at 0, so no user API will access that AFU and - * this function can't return it. - */ + mutex_lock(&minors_idr_lock); info = idr_find(&minors_idr, MINOR(devno)); + if (info) + get_device(&info->dev); + mutex_unlock(&minors_idr_lock); return info; } @@ -58,14 +55,16 @@ static int afu_open(struct inode *inode, struct file *file) pr_debug("%s for device %x\n", __func__, inode->i_rdev); - info = find_file_info(inode->i_rdev); + info = find_and_get_file_info(inode->i_rdev); if (!info) return -ENODEV; rc = ocxl_context_alloc(&ctx, info->afu, inode->i_mapping); - if (rc) + if (rc) { + put_device(&info->dev); return rc; - + } + put_device(&info->dev); file->private_data = ctx; return 0; } @@ -487,7 +486,6 @@ static void info_release(struct device *dev) { struct ocxl_file_info *info = container_of(dev, struct ocxl_file_info, dev); - free_minor(info); ocxl_afu_put(info->afu); kfree(info); } @@ -577,6 +575,7 @@ void ocxl_file_unregister_afu(struct ocxl_afu *afu) ocxl_file_make_invisible(info); ocxl_sysfs_unregister_afu(info); + free_minor(info); device_unregister(&info->dev); } -- cgit From 913e73c77d48aeeb50c16450a653dca9c71ae2e2 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Mon, 9 Dec 2019 11:55:13 +0100 Subject: ocxl: Fix potential memory leak on context creation If we couldn't fully init a context, we were leaking memory. Fixes: b9721d275cc2 ("ocxl: Allow external drivers to use OpenCAPI contexts") Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Reviewed-by: Greg Kurz Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191209105513.8566-1-fbarrat@linux.ibm.com --- drivers/misc/ocxl/context.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c index 994563a078eb..de8a66b9d76b 100644 --- a/drivers/misc/ocxl/context.c +++ b/drivers/misc/ocxl/context.c @@ -10,18 +10,17 @@ int ocxl_context_alloc(struct ocxl_context **context, struct ocxl_afu *afu, int pasid; struct ocxl_context *ctx; - *context = kzalloc(sizeof(struct ocxl_context), GFP_KERNEL); - if (!*context) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) return -ENOMEM; - ctx = *context; - ctx->afu = afu; mutex_lock(&afu->contexts_lock); pasid = idr_alloc(&afu->contexts_idr, ctx, afu->pasid_base, afu->pasid_base + afu->pasid_max, GFP_KERNEL); if (pasid < 0) { mutex_unlock(&afu->contexts_lock); + kfree(ctx); return pasid; } afu->pasid_count++; @@ -43,6 +42,7 @@ int ocxl_context_alloc(struct ocxl_context **context, struct ocxl_afu *afu, * duration of the life of the context */ ocxl_afu_get(afu); + *context = ctx; return 0; } EXPORT_SYMBOL_GPL(ocxl_context_alloc); -- cgit