diff options
author | Nicolai Stange <nicstange@gmail.com> | 2016-05-24 14:08:53 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-15 14:56:35 +0300 |
commit | b10e3e90485e32e4cea9e35d2295ee7bffaeff73 (patch) | |
tree | 99aeebe65cb41e45077f9bc6f3f500214dbe742a | |
parent | df4565f9ebdc4d6dc50edc6e8fed08004e328332 (diff) | |
download | linux-b10e3e90485e32e4cea9e35d2295ee7bffaeff73.tar.xz |
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>
-rw-r--r-- | fs/debugfs/file.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 9c1c9a01b7e5..d1ec80331414 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -262,8 +262,10 @@ static int full_proxy_open(struct inode *inode, struct file *filp) if (real_fops->open) { r = real_fops->open(inode, filp); - - if (filp->f_op != proxy_fops) { + if (r) { + replace_fops(filp, d_inode(dentry)->i_fop); + goto free_proxy; + } else if (filp->f_op != proxy_fops) { /* No protection against file removal anymore. */ WARN(1, "debugfs file owner replaced proxy fops: %pd", dentry); |