Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

debugfs: full_proxy_open(): free proxy on ->open() failure

Debugfs' full_proxy_open(), the ->open() installed at all inodes created
through debugfs_create_file(),
- grabs a reference to the original struct file_operations instance passed
to debugfs_create_file(),
- dynamically allocates a proxy struct file_operations instance wrapping
the original
- and installs this at the file's ->f_op.

Afterwards, it calls the original ->open() and passes its return value back
to the VFS layer.

Now, if that return value indicates failure, the VFS layer won't ever call
->release() and thus, neither the reference to the original file_operations
nor the memory for the proxy file_operations will get released, i.e. both
are leaked.

Upon failure of the original fops' ->open(), undo the proxy installation.
That is:
- Set the struct file ->f_op to what it had been when full_proxy_open()
was entered.
- Drop the reference to the original file_operations.
- Free the memory holding the proxy file_operations.

Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private
data")
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nicolai Stange and committed by
Greg Kroah-Hartman
b10e3e90 df4565f9

+4 -2
+4 -2
fs/debugfs/file.c
··· 262 262 263 263 if (real_fops->open) { 264 264 r = real_fops->open(inode, filp); 265 - 266 - if (filp->f_op != proxy_fops) { 265 + if (r) { 266 + replace_fops(filp, d_inode(dentry)->i_fop); 267 + goto free_proxy; 268 + } else if (filp->f_op != proxy_fops) { 267 269 /* No protection against file removal anymore. */ 268 270 WARN(1, "debugfs file owner replaced proxy fops: %pd", 269 271 dentry);