Skip to content

Commit 0dcd3c9

Browse files
author
Gao Xiang
committed
erofs: fix extended inode could cross boundary
Each ondisk inode should be aligned with inode slot boundary (32-byte alignment) because of nid calculation formula, so all compact inodes (32 byte) cannot across page boundary. However, extended inode is now 64-byte form, which can across page boundary in principle if the location is specified on purpose, although it's hard to be generated by mkfs due to the allocation policy and rarely used by Android use case now mainly for > 4GiB files. For now, only two fields `i_ctime_nsec` and `i_nlink' couldn't be read from disk properly and cause out-of-bound memory read with random value. Let's fix now. Fixes: 431339b ("staging: erofs: add inode operations") Cc: <[email protected]> # 4.19+ Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Gao Xiang <[email protected]>
1 parent 592e7cd commit 0dcd3c9

File tree

1 file changed

+79
-42
lines changed

1 file changed

+79
-42
lines changed

fs/erofs/inode.c

Lines changed: 79 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,80 @@
88

99
#include <trace/events/erofs.h>
1010

11-
/* no locking */
12-
static int erofs_read_inode(struct inode *inode, void *data)
11+
/*
12+
* if inode is successfully read, return its inode page (or sometimes
13+
* the inode payload page if it's an extended inode) in order to fill
14+
* inline data if possible.
15+
*/
16+
static struct page *erofs_read_inode(struct inode *inode,
17+
unsigned int *ofs)
1318
{
19+
struct super_block *sb = inode->i_sb;
20+
struct erofs_sb_info *sbi = EROFS_SB(sb);
1421
struct erofs_inode *vi = EROFS_I(inode);
15-
struct erofs_inode_compact *dic = data;
16-
struct erofs_inode_extended *die;
22+
const erofs_off_t inode_loc = iloc(sbi, vi->nid);
23+
24+
erofs_blk_t blkaddr, nblks = 0;
25+
struct page *page;
26+
struct erofs_inode_compact *dic;
27+
struct erofs_inode_extended *die, *copied = NULL;
28+
unsigned int ifmt;
29+
int err;
1730

18-
const unsigned int ifmt = le16_to_cpu(dic->i_format);
19-
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
20-
erofs_blk_t nblks = 0;
31+
blkaddr = erofs_blknr(inode_loc);
32+
*ofs = erofs_blkoff(inode_loc);
2133

22-
vi->datalayout = erofs_inode_datalayout(ifmt);
34+
erofs_dbg("%s, reading inode nid %llu at %u of blkaddr %u",
35+
__func__, vi->nid, *ofs, blkaddr);
36+
37+
page = erofs_get_meta_page(sb, blkaddr);
38+
if (IS_ERR(page)) {
39+
erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld",
40+
vi->nid, PTR_ERR(page));
41+
return page;
42+
}
2343

44+
dic = page_address(page) + *ofs;
45+
ifmt = le16_to_cpu(dic->i_format);
46+
47+
vi->datalayout = erofs_inode_datalayout(ifmt);
2448
if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
2549
erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu",
2650
vi->datalayout, vi->nid);
27-
DBG_BUGON(1);
28-
return -EOPNOTSUPP;
51+
err = -EOPNOTSUPP;
52+
goto err_out;
2953
}
3054

3155
switch (erofs_inode_version(ifmt)) {
3256
case EROFS_INODE_LAYOUT_EXTENDED:
33-
die = data;
34-
3557
vi->inode_isize = sizeof(struct erofs_inode_extended);
58+
/* check if the inode acrosses page boundary */
59+
if (*ofs + vi->inode_isize <= PAGE_SIZE) {
60+
*ofs += vi->inode_isize;
61+
die = (struct erofs_inode_extended *)dic;
62+
} else {
63+
const unsigned int gotten = PAGE_SIZE - *ofs;
64+
65+
copied = kmalloc(vi->inode_isize, GFP_NOFS);
66+
if (!copied) {
67+
err = -ENOMEM;
68+
goto err_out;
69+
}
70+
memcpy(copied, dic, gotten);
71+
unlock_page(page);
72+
put_page(page);
73+
74+
page = erofs_get_meta_page(sb, blkaddr + 1);
75+
if (IS_ERR(page)) {
76+
erofs_err(sb, "failed to get inode payload page (nid: %llu), err %ld",
77+
vi->nid, PTR_ERR(page));
78+
kfree(copied);
79+
return page;
80+
}
81+
*ofs = vi->inode_isize - gotten;
82+
memcpy((u8 *)copied + gotten, page_address(page), *ofs);
83+
die = copied;
84+
}
3685
vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
3786

3887
inode->i_mode = le16_to_cpu(die->i_mode);
@@ -69,9 +118,12 @@ static int erofs_read_inode(struct inode *inode, void *data)
69118
/* total blocks for compressed files */
70119
if (erofs_inode_is_data_compressed(vi->datalayout))
71120
nblks = le32_to_cpu(die->i_u.compressed_blocks);
121+
122+
kfree(copied);
72123
break;
73124
case EROFS_INODE_LAYOUT_COMPACT:
74125
vi->inode_isize = sizeof(struct erofs_inode_compact);
126+
*ofs += vi->inode_isize;
75127
vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
76128

77129
inode->i_mode = le16_to_cpu(dic->i_mode);
@@ -111,22 +163,27 @@ static int erofs_read_inode(struct inode *inode, void *data)
111163
erofs_err(inode->i_sb,
112164
"unsupported on-disk inode version %u of nid %llu",
113165
erofs_inode_version(ifmt), vi->nid);
114-
DBG_BUGON(1);
115-
return -EOPNOTSUPP;
166+
err = -EOPNOTSUPP;
167+
goto err_out;
116168
}
117169

118170
if (!nblks)
119171
/* measure inode.i_blocks as generic filesystems */
120172
inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
121173
else
122174
inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
123-
return 0;
175+
return page;
124176

125177
bogusimode:
126178
erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu",
127179
inode->i_mode, vi->nid);
180+
err = -EFSCORRUPTED;
181+
err_out:
128182
DBG_BUGON(1);
129-
return -EFSCORRUPTED;
183+
kfree(copied);
184+
unlock_page(page);
185+
put_page(page);
186+
return ERR_PTR(err);
130187
}
131188

132189
static int erofs_fill_symlink(struct inode *inode, void *data,
@@ -146,7 +203,7 @@ static int erofs_fill_symlink(struct inode *inode, void *data,
146203
if (!lnk)
147204
return -ENOMEM;
148205

149-
m_pofs += vi->inode_isize + vi->xattr_isize;
206+
m_pofs += vi->xattr_isize;
150207
/* inline symlink data shouldn't cross page boundary as well */
151208
if (m_pofs + inode->i_size > PAGE_SIZE) {
152209
kfree(lnk);
@@ -167,37 +224,17 @@ static int erofs_fill_symlink(struct inode *inode, void *data,
167224

168225
static int erofs_fill_inode(struct inode *inode, int isdir)
169226
{
170-
struct super_block *sb = inode->i_sb;
171227
struct erofs_inode *vi = EROFS_I(inode);
172228
struct page *page;
173-
void *data;
174-
int err;
175-
erofs_blk_t blkaddr;
176229
unsigned int ofs;
177-
erofs_off_t inode_loc;
230+
int err = 0;
178231

179232
trace_erofs_fill_inode(inode, isdir);
180-
inode_loc = iloc(EROFS_SB(sb), vi->nid);
181-
blkaddr = erofs_blknr(inode_loc);
182-
ofs = erofs_blkoff(inode_loc);
183-
184-
erofs_dbg("%s, reading inode nid %llu at %u of blkaddr %u",
185-
__func__, vi->nid, ofs, blkaddr);
186233

187-
page = erofs_get_meta_page(sb, blkaddr);
188-
189-
if (IS_ERR(page)) {
190-
erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld",
191-
vi->nid, PTR_ERR(page));
234+
/* read inode base data from disk */
235+
page = erofs_read_inode(inode, &ofs);
236+
if (IS_ERR(page))
192237
return PTR_ERR(page);
193-
}
194-
195-
DBG_BUGON(!PageUptodate(page));
196-
data = page_address(page);
197-
198-
err = erofs_read_inode(inode, data + ofs);
199-
if (err)
200-
goto out_unlock;
201238

202239
/* setup the new inode */
203240
switch (inode->i_mode & S_IFMT) {
@@ -210,7 +247,7 @@ static int erofs_fill_inode(struct inode *inode, int isdir)
210247
inode->i_fop = &erofs_dir_fops;
211248
break;
212249
case S_IFLNK:
213-
err = erofs_fill_symlink(inode, data, ofs);
250+
err = erofs_fill_symlink(inode, page_address(page), ofs);
214251
if (err)
215252
goto out_unlock;
216253
inode_nohighmem(inode);

0 commit comments

Comments
 (0)