Skip to content

Commit 713346c

Browse files
ZhaoLong Wangrichardweinberger
authored andcommitted
ubifs: Fix UBIFS ro fail due to truncate in the encrypted directory
The ubifs_compress() function does not compress the data When the data length is short than 128 bytes or the compressed data length is not ideal.It cause that the compressed length of the truncated data in the truncate_data_node() function may be greater than the length of the raw data read from the flash. The above two lengths are transferred to the ubifs_encrypt() function as parameters. This may lead to assertion fails and then the file system becomes read-only. This patch use the actual length of the data in the memory as the input parameter for assert comparison, which avoids the problem. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216213 Signed-off-by: ZhaoLong Wang <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 019ac05 commit 713346c

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

fs/ubifs/crypto.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ static bool ubifs_crypt_empty_dir(struct inode *inode)
2424
return ubifs_check_dir_empty(inode) == 0;
2525
}
2626

27+
/**
28+
* ubifs_encrypt - Encrypt data.
29+
* @inode: inode which refers to the data node
30+
* @dn: data node to encrypt
31+
* @in_len: length of data to be compressed
32+
* @out_len: allocated memory size for the data area of @dn
33+
* @block: logical block number of the block
34+
*
35+
* This function encrypt a possibly-compressed data in the data node.
36+
* The encrypted data length will store in @out_len.
37+
*/
2738
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
2839
unsigned int in_len, unsigned int *out_len, int block)
2940
{

fs/ubifs/journal.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,23 +1472,25 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
14721472
* @block: data block number
14731473
* @dn: data node to re-compress
14741474
* @new_len: new length
1475+
* @dn_size: size of the data node @dn in memory
14751476
*
14761477
* This function is used when an inode is truncated and the last data node of
14771478
* the inode has to be re-compressed/encrypted and re-written.
14781479
*/
14791480
static int truncate_data_node(const struct ubifs_info *c, const struct inode *inode,
14801481
unsigned int block, struct ubifs_data_node *dn,
1481-
int *new_len)
1482+
int *new_len, int dn_size)
14821483
{
14831484
void *buf;
1484-
int err, dlen, compr_type, out_len, old_dlen;
1485+
int err, dlen, compr_type, out_len, data_size;
14851486

14861487
out_len = le32_to_cpu(dn->size);
14871488
buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS);
14881489
if (!buf)
14891490
return -ENOMEM;
14901491

1491-
dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
1492+
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
1493+
data_size = dn_size - UBIFS_DATA_NODE_SZ;
14921494
compr_type = le16_to_cpu(dn->compr_type);
14931495

14941496
if (IS_ENCRYPTED(inode)) {
@@ -1508,11 +1510,11 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
15081510
}
15091511

15101512
if (IS_ENCRYPTED(inode)) {
1511-
err = ubifs_encrypt(inode, dn, out_len, &old_dlen, block);
1513+
err = ubifs_encrypt(inode, dn, out_len, &data_size, block);
15121514
if (err)
15131515
goto out;
15141516

1515-
out_len = old_dlen;
1517+
out_len = data_size;
15161518
} else {
15171519
dn->compr_size = 0;
15181520
}
@@ -1550,6 +1552,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
15501552
struct ubifs_trun_node *trun;
15511553
struct ubifs_data_node *dn;
15521554
int err, dlen, len, lnum, offs, bit, sz, sync = IS_SYNC(inode);
1555+
int dn_size;
15531556
struct ubifs_inode *ui = ubifs_inode(inode);
15541557
ino_t inum = inode->i_ino;
15551558
unsigned int blk;
@@ -1562,10 +1565,13 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
15621565
ubifs_assert(c, S_ISREG(inode->i_mode));
15631566
ubifs_assert(c, mutex_is_locked(&ui->ui_mutex));
15641567

1565-
sz = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ +
1566-
UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR;
1568+
dn_size = COMPRESSED_DATA_NODE_BUF_SZ;
15671569

1568-
sz += ubifs_auth_node_sz(c);
1570+
if (IS_ENCRYPTED(inode))
1571+
dn_size += UBIFS_CIPHER_BLOCK_SIZE;
1572+
1573+
sz = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ +
1574+
dn_size + ubifs_auth_node_sz(c);
15691575

15701576
ino = kmalloc(sz, GFP_NOFS);
15711577
if (!ino)
@@ -1596,15 +1602,15 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
15961602
if (dn_len <= 0 || dn_len > UBIFS_BLOCK_SIZE) {
15971603
ubifs_err(c, "bad data node (block %u, inode %lu)",
15981604
blk, inode->i_ino);
1599-
ubifs_dump_node(c, dn, sz - UBIFS_INO_NODE_SZ -
1600-
UBIFS_TRUN_NODE_SZ);
1605+
ubifs_dump_node(c, dn, dn_size);
16011606
goto out_free;
16021607
}
16031608

16041609
if (dn_len <= dlen)
16051610
dlen = 0; /* Nothing to do */
16061611
else {
1607-
err = truncate_data_node(c, inode, blk, dn, &dlen);
1612+
err = truncate_data_node(c, inode, blk, dn,
1613+
&dlen, dn_size);
16081614
if (err)
16091615
goto out_free;
16101616
}

0 commit comments

Comments
 (0)