summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Forshee <seth.forshee@canonical.com>2019-11-07 10:08:24 -0600
committerStefan Bader <stefan.bader@canonical.com>2019-11-12 18:47:02 +0100
commitef81780548d20a786cc77ed4203fca146fd81ce3 (patch)
tree168121e81b83b3f5532e1eb931f08ef810dc9f0b
parent15d0f167f58224307f71e6056c3d63abf3099555 (diff)
UBUNTU: SAUCE: shiftfs: Restore vm_file value when lower fs mmap fails
BugLink: https://bugs.launchpad.net/bugs/1850994 shiftfs_mmap() overwrites vma->vm_file before calling the lower filesystem mmap but does not restore the original value on failure. This means it is giving a pointer to the lower fs file back to the caller with no reference, which is a bad practice. However, it does not lead to any issues with upstream kernels as no caller accesses vma->vm_file after call_mmap(). With the aufs patches applied the story is different. Whereas mmap_region() previously fput a local variable containing the file it assigned to vm_file, it now calls vma_fput() which will fput vm_file, for which it has no reference, and the reference for the original vm_file is not put. Fix this by restoring vma->vm_file to the original value when the mmap call into the lower fs fails. CVE-2019-15794 Reported-by: Jann Horn <jannh@google.com> Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> Acked-by: Tyler Hicks <tyhicks@canonical.com> Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
-rw-r--r--fs/shiftfs.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/shiftfs.c b/fs/shiftfs.c
index 279fc64..cea42fc 100644
--- a/fs/shiftfs.c
+++ b/fs/shiftfs.c
@@ -1296,10 +1296,17 @@ static int shiftfs_mmap(struct file *file, struct vm_area_struct *vma)
shiftfs_file_accessed(file);
- if (ret)
- fput(realfile); /* Drop refcount from new vm_file value */
- else
- fput(file); /* Drop refcount from previous vm_file value */
+ if (ret) {
+ /*
+ * Drop refcount from new vm_file value and restore original
+ * vm_file value
+ */
+ vma->vm_file = file;
+ fput(realfile);
+ } else {
+ /* Drop refcount from previous vm_file value */
+ fput(file);
+ }
return ret;
}