diff options
Diffstat (limited to 'fs/ubifs')
-rw-r--r-- | fs/ubifs/debug.c | 1 | ||||
-rw-r--r-- | fs/ubifs/dir.c | 13 | ||||
-rw-r--r-- | fs/ubifs/io.c | 29 |
3 files changed, 36 insertions, 7 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 7cd8a7b95299..80cdd64aa7c3 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -1129,6 +1129,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) err = PTR_ERR(dent); if (err == -ENOENT) break; + kfree(pdent); return err; } diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 358abc26dbc0..de0d63a347ac 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -747,7 +747,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, if (ubifs_crypt_is_encrypted(dir) && !fscrypt_has_permitted_context(dir, inode)) - return -EPERM; + return -EXDEV; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) @@ -1357,7 +1357,7 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, if (old_dir != new_dir) { if (ubifs_crypt_is_encrypted(new_dir) && !fscrypt_has_permitted_context(new_dir, old_inode)) - return -EPERM; + return -EXDEV; } if (unlink && is_dir) { @@ -1408,7 +1408,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_release; } + spin_lock(&whiteout->i_lock); whiteout->i_state |= I_LINKABLE; + spin_unlock(&whiteout->i_lock); + whiteout_ui = ubifs_inode(whiteout); whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); @@ -1501,7 +1504,11 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, inc_nlink(whiteout); mark_inode_dirty(whiteout); + + spin_lock(&whiteout->i_lock); whiteout->i_state &= ~I_LINKABLE; + spin_unlock(&whiteout->i_lock); + iput(whiteout); } @@ -1579,7 +1586,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, (old_dir != new_dir) && (!fscrypt_has_permitted_context(new_dir, fst_inode) || !fscrypt_has_permitted_context(old_dir, snd_inode))) - return -EPERM; + return -EXDEV; err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); if (err) diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 3be28900bf37..5b4d4b1087c4 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -237,7 +237,7 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum) int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, int offs, int quiet, int must_chk_crc) { - int err = -EINVAL, type, node_len; + int err = -EINVAL, type, node_len, dump_node = 1; uint32_t crc, node_crc, magic; const struct ubifs_ch *ch = buf; @@ -290,10 +290,22 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, out_len: if (!quiet) ubifs_err(c, "bad node length %d", node_len); + if (type == UBIFS_DATA_NODE && node_len > UBIFS_DATA_NODE_SZ) + dump_node = 0; out: if (!quiet) { ubifs_err(c, "bad node at LEB %d:%d", lnum, offs); - ubifs_dump_node(c, buf); + if (dump_node) { + ubifs_dump_node(c, buf); + } else { + int safe_len = min3(node_len, c->leb_size - offs, + (int)UBIFS_MAX_DATA_NODE_SZ); + pr_err("\tprevent out-of-bounds memory access\n"); + pr_err("\ttruncated data node length %d\n", safe_len); + pr_err("\tcorrupted data node:\n"); + print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, + buf, safe_len, 0); + } dump_stack(); } return err; @@ -319,7 +331,7 @@ void ubifs_pad(const struct ubifs_info *c, void *buf, int pad) { uint32_t crc; - ubifs_assert(pad >= 0 && !(pad & 7)); + ubifs_assert(pad >= 0); if (pad >= UBIFS_PAD_NODE_SZ) { struct ubifs_ch *ch = buf; @@ -715,6 +727,10 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) * write-buffer. */ memcpy(wbuf->buf + wbuf->used, buf, len); + if (aligned_len > len) { + ubifs_assert(aligned_len - len < 8); + ubifs_pad(c, wbuf->buf + wbuf->used + len, aligned_len - len); + } if (aligned_len == wbuf->avail) { dbg_io("flush jhead %s wbuf to LEB %d:%d", @@ -807,13 +823,18 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) } spin_lock(&wbuf->lock); - if (aligned_len) + if (aligned_len) { /* * And now we have what's left and what does not take whole * max. write unit, so write it to the write-buffer and we are * done. */ memcpy(wbuf->buf, buf + written, len); + if (aligned_len > len) { + ubifs_assert(aligned_len - len < 8); + ubifs_pad(c, wbuf->buf + len, aligned_len - len); + } + } if (c->leb_size - wbuf->offs >= c->max_write_size) wbuf->size = c->max_write_size; |