Skip to content

Commit d57431c

Browse files
fs/ntfs3: Do copy_to_user out of run_lock
In order not to call copy_to_user (from fiemap_fill_next_extent) we allocate memory in the kernel, fill it and copy it to user memory after up_read(run_lock). Reported-by: [email protected] Signed-off-by: Konstantin Komarov <[email protected]>
1 parent eb95678 commit d57431c

File tree

1 file changed

+72
-3
lines changed

1 file changed

+72
-3
lines changed

fs/ntfs3/frecord.c

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,47 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
18981898
return REPARSE_LINK;
18991899
}
19001900

1901+
/*
1902+
* fiemap_fill_next_extent_k - a copy of fiemap_fill_next_extent
1903+
* but it accepts kernel address for fi_extents_start
1904+
*/
1905+
static int fiemap_fill_next_extent_k(struct fiemap_extent_info *fieinfo,
1906+
u64 logical, u64 phys, u64 len, u32 flags)
1907+
{
1908+
struct fiemap_extent extent;
1909+
struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
1910+
1911+
/* only count the extents */
1912+
if (fieinfo->fi_extents_max == 0) {
1913+
fieinfo->fi_extents_mapped++;
1914+
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
1915+
}
1916+
1917+
if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
1918+
return 1;
1919+
1920+
if (flags & FIEMAP_EXTENT_DELALLOC)
1921+
flags |= FIEMAP_EXTENT_UNKNOWN;
1922+
if (flags & FIEMAP_EXTENT_DATA_ENCRYPTED)
1923+
flags |= FIEMAP_EXTENT_ENCODED;
1924+
if (flags & (FIEMAP_EXTENT_DATA_TAIL | FIEMAP_EXTENT_DATA_INLINE))
1925+
flags |= FIEMAP_EXTENT_NOT_ALIGNED;
1926+
1927+
memset(&extent, 0, sizeof(extent));
1928+
extent.fe_logical = logical;
1929+
extent.fe_physical = phys;
1930+
extent.fe_length = len;
1931+
extent.fe_flags = flags;
1932+
1933+
dest += fieinfo->fi_extents_mapped;
1934+
memcpy(dest, &extent, sizeof(extent));
1935+
1936+
fieinfo->fi_extents_mapped++;
1937+
if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
1938+
return 1;
1939+
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
1940+
}
1941+
19011942
/*
19021943
* ni_fiemap - Helper for file_fiemap().
19031944
*
@@ -1908,6 +1949,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
19081949
__u64 vbo, __u64 len)
19091950
{
19101951
int err = 0;
1952+
struct fiemap_extent __user *fe_u = fieinfo->fi_extents_start;
1953+
struct fiemap_extent *fe_k = NULL;
19111954
struct ntfs_sb_info *sbi = ni->mi.sbi;
19121955
u8 cluster_bits = sbi->cluster_bits;
19131956
struct runs_tree *run;
@@ -1955,6 +1998,18 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
19551998
goto out;
19561999
}
19572000

2001+
/*
2002+
* To avoid lock problems replace pointer to user memory by pointer to kernel memory.
2003+
*/
2004+
fe_k = kmalloc_array(fieinfo->fi_extents_max,
2005+
sizeof(struct fiemap_extent),
2006+
GFP_NOFS | __GFP_ZERO);
2007+
if (!fe_k) {
2008+
err = -ENOMEM;
2009+
goto out;
2010+
}
2011+
fieinfo->fi_extents_start = fe_k;
2012+
19582013
end = vbo + len;
19592014
alloc_size = le64_to_cpu(attr->nres.alloc_size);
19602015
if (end > alloc_size)
@@ -2043,8 +2098,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
20432098
if (vbo + dlen >= end)
20442099
flags |= FIEMAP_EXTENT_LAST;
20452100

2046-
err = fiemap_fill_next_extent(fieinfo, vbo, lbo, dlen,
2047-
flags);
2101+
err = fiemap_fill_next_extent_k(fieinfo, vbo, lbo, dlen,
2102+
flags);
2103+
20482104
if (err < 0)
20492105
break;
20502106
if (err == 1) {
@@ -2064,7 +2120,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
20642120
if (vbo + bytes >= end)
20652121
flags |= FIEMAP_EXTENT_LAST;
20662122

2067-
err = fiemap_fill_next_extent(fieinfo, vbo, lbo, bytes, flags);
2123+
err = fiemap_fill_next_extent_k(fieinfo, vbo, lbo, bytes,
2124+
flags);
20682125
if (err < 0)
20692126
break;
20702127
if (err == 1) {
@@ -2077,7 +2134,19 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
20772134

20782135
up_read(run_lock);
20792136

2137+
/*
2138+
* Copy to user memory out of lock
2139+
*/
2140+
if (copy_to_user(fe_u, fe_k,
2141+
fieinfo->fi_extents_max *
2142+
sizeof(struct fiemap_extent))) {
2143+
err = -EFAULT;
2144+
}
2145+
20802146
out:
2147+
/* Restore original pointer. */
2148+
fieinfo->fi_extents_start = fe_u;
2149+
kfree(fe_k);
20812150
return err;
20822151
}
20832152

0 commit comments

Comments
 (0)