binder: prevent UAF for binderfs devices II

This is a necessary follow up to the first fix I proposed and we merged
in 2669b8b0c79 ("binder: prevent UAF for binderfs devices"). I have been
overly optimistic that the simple fix I proposed would work. But alas,
ihold() + iput() won't work since the inodes won't survive the
destruction of the superblock.
So all we get with my prior fix is a different race with a tinier
race-window but it doesn't solve the issue. Fwiw, the problem lies with
generic_shutdown_super(). It even has this cozy Al-style comment:

if (!list_empty(&sb->s_inodes)) {
printk("VFS: Busy inodes after unmount of %s. "
"Self-destruct in 5 seconds. Have a nice day...\n",
sb->s_id);
}

On binder_release(), binder_defer_work(proc, BINDER_DEFERRED_RELEASE) is
called which punts the actual cleanup operation to a workqueue. At some
point, binder_deferred_func() will be called which will end up calling
binder_deferred_release() which will retrieve and cleanup the
binder_context attach to this struct binder_proc.

If we trace back where this binder_context is attached to binder_proc we
see that it is set in binder_open() and is taken from the struct
binder_device it is associated with. This obviously assumes that the
struct binder_device that context is attached to is _never_ freed. While
that might be true for devtmpfs binder devices it is most certainly
wrong for binderfs binder devices.

So, assume binder_open() is called on a binderfs binder devices. We now
stash away the struct binder_context associated with that struct
binder_devices:
proc->context = &binder_dev->context;
/* binderfs stashes devices in i_private */
if (is_binderfs_device(nodp)) {
binder_dev = nodp->i_private;
info = nodp->i_sb->s_fs_info;
binder_binderfs_dir_entry_proc = info->proc_log_dir;
} else {
.
.
.
proc->context = &binder_dev->context;

Now let's assume that the binderfs instance for that binder devices is
shutdown via umount() and/or the mount namespace associated with it goes
away. As long as there is still an fd open for that binderfs binder
device things are fine. But let's assume we now close the last fd for
that binderfs binder device. Now binder_release() is called and punts to
the workqueue. Assume that the workqueue has quite a bit of stuff to do
and doesn't get to cleaning up the struct binder_proc and the associated
struct binder_context with it for that binderfs binder device right
away. In the meantime, the VFS is killing the super block and is
ultimately calling sb->evict_inode() which means it will call
binderfs_evict_inode() which does:

static void binderfs_evict_inode(struct inode *inode)
{
struct binder_device *device = inode->i_private;
struct binderfs_info *info = BINDERFS_I(inode);

clear_inode(inode);

if (!S_ISCHR(inode->i_mode) || !device)
return;

mutex_lock(&binderfs_minors_mutex);
--info->device_count;
ida_free(&binderfs_minors, device->miscdev.minor);
mutex_unlock(&binderfs_minors_mutex);

kfree(device->context.name);
kfree(device);
}

thereby freeing the struct binder_device including struct
binder_context.

Now the workqueue finally has time to get around to cleaning up struct
binder_proc and is now trying to access the associate struct
binder_context. Since it's already freed it will OOPs.

Fix this by introducing a refounct on binder devices.

This is an alternative fix to 51d8a7eca677 ("binder: prevent UAF read in
print_binder_transaction_log_entry()").

Fixes: 3ad20fe393b3 ("binder: implement binderfs")
Fixes: 2669b8b0c798 ("binder: prevent UAF for binderfs devices")
Fixes: 03e2e07e3814 ("binder: Make transaction_log available in binderfs")
Related : 51d8a7eca677 ("binder: prevent UAF read in print_binder_transaction_log_entry()")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Acked-by: Todd Kjos <tkjos@google.com>
Link: https://lore.kernel.org/r/20200303164340.670054-1-christian.brauner@ubuntu.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Christian Brauner and committed by Greg Kroah-Hartman f0fe2c0f 37911636

Changed files
+16 -18
drivers
+9 -3
drivers/android/binder.c
··· 5221 5221 proc->default_priority = task_nice(current); 5222 5222 /* binderfs stashes devices in i_private */ 5223 5223 if (is_binderfs_device(nodp)) { 5224 - binder_dev = binderfs_device_get(nodp->i_private); 5224 + binder_dev = nodp->i_private; 5225 5225 info = nodp->i_sb->s_fs_info; 5226 5226 binder_binderfs_dir_entry_proc = info->proc_log_dir; 5227 5227 } else { 5228 5228 binder_dev = container_of(filp->private_data, 5229 5229 struct binder_device, miscdev); 5230 5230 } 5231 + refcount_inc(&binder_dev->ref); 5231 5232 proc->context = &binder_dev->context; 5232 5233 binder_alloc_init(&proc->alloc); 5233 5234 ··· 5423 5422 context->binder_context_mgr_node = NULL; 5424 5423 } 5425 5424 mutex_unlock(&context->context_mgr_node_lock); 5425 + device = container_of(proc->context, struct binder_device, context); 5426 + if (refcount_dec_and_test(&device->ref)) { 5427 + kfree(context->name); 5428 + kfree(device); 5429 + } 5430 + proc->context = NULL; 5426 5431 binder_inner_proc_lock(proc); 5427 5432 /* 5428 5433 * Make sure proc stays alive after we ··· 5492 5485 outgoing_refs, active_transactions); 5493 5486 5494 5487 binder_proc_dec_tmpref(proc); 5495 - device = container_of(proc->context, struct binder_device, context); 5496 - binderfs_device_put(device); 5497 5488 } 5498 5489 5499 5490 static void binder_deferred_func(struct work_struct *work) ··· 6085 6080 binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; 6086 6081 binder_device->miscdev.name = name; 6087 6082 6083 + refcount_set(&binder_device->ref, 1); 6088 6084 binder_device->context.binder_context_mgr_uid = INVALID_UID; 6089 6085 binder_device->context.name = name; 6090 6086 mutex_init(&binder_device->context.context_mgr_node_lock);
+2 -13
drivers/android/binder_internal.h
··· 8 8 #include <linux/list.h> 9 9 #include <linux/miscdevice.h> 10 10 #include <linux/mutex.h> 11 + #include <linux/refcount.h> 11 12 #include <linux/stddef.h> 12 13 #include <linux/types.h> 13 14 #include <linux/uidgid.h> ··· 34 33 struct miscdevice miscdev; 35 34 struct binder_context context; 36 35 struct inode *binderfs_inode; 36 + refcount_t ref; 37 37 }; 38 - 39 - static inline struct binder_device *binderfs_device_get(struct binder_device *dev) 40 - { 41 - if (dev->binderfs_inode) 42 - ihold(dev->binderfs_inode); 43 - return dev; 44 - } 45 - 46 - static inline void binderfs_device_put(struct binder_device *dev) 47 - { 48 - if (dev->binderfs_inode) 49 - iput(dev->binderfs_inode); 50 - } 51 38 52 39 /** 53 40 * binderfs_mount_opts - mount options for binderfs
+5 -2
drivers/android/binderfs.c
··· 154 154 if (!name) 155 155 goto err; 156 156 157 + refcount_set(&device->ref, 1); 157 158 device->binderfs_inode = inode; 158 159 device->context.binder_context_mgr_uid = INVALID_UID; 159 160 device->context.name = name; ··· 258 257 ida_free(&binderfs_minors, device->miscdev.minor); 259 258 mutex_unlock(&binderfs_minors_mutex); 260 259 261 - kfree(device->context.name); 262 - kfree(device); 260 + if (refcount_dec_and_test(&device->ref)) { 261 + kfree(device->context.name); 262 + kfree(device); 263 + } 263 264 } 264 265 265 266 /**