aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2018-06-16 23:41:59 -0400
committerTheodore Ts'o <tytso@mit.edu>2018-06-16 23:41:59 -0400
commit8bc1379b82b8e809eef77a9fedbb75c6c297be19 (patch)
tree621b4e6f36dae1bf770c8bb9309028e80ece02c2
parente09463f220ca9a1a1ecfda84fcda658f99a1f12a (diff)
ext4: avoid running out of journal credits when appending to an inline file
Use a separate journal transaction if it turns out that we need to convert an inline file to use an data block. Otherwise we could end up failing due to not having journal credits. This addresses CVE-2018-10883. https://bugzilla.kernel.org/show_bug.cgi?id=200071 Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/inline.c38
-rw-r--r--fs/ext4/xattr.c19
3 files changed, 3 insertions, 57 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 856b6a54d82b..859d6433dcc1 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3013,9 +3013,6 @@ extern int ext4_inline_data_fiemap(struct inode *inode,
3013struct iomap; 3013struct iomap;
3014extern int ext4_inline_data_iomap(struct inode *inode, struct iomap *iomap); 3014extern int ext4_inline_data_iomap(struct inode *inode, struct iomap *iomap);
3015 3015
3016extern int ext4_try_to_evict_inline_data(handle_t *handle,
3017 struct inode *inode,
3018 int needed);
3019extern int ext4_inline_data_truncate(struct inode *inode, int *has_inline); 3016extern int ext4_inline_data_truncate(struct inode *inode, int *has_inline);
3020 3017
3021extern int ext4_convert_inline_data(struct inode *inode); 3018extern int ext4_convert_inline_data(struct inode *inode);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index d79115d8d716..851bc552d849 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -887,11 +887,11 @@ retry_journal:
887 flags |= AOP_FLAG_NOFS; 887 flags |= AOP_FLAG_NOFS;
888 888
889 if (ret == -ENOSPC) { 889 if (ret == -ENOSPC) {
890 ext4_journal_stop(handle);
890 ret = ext4_da_convert_inline_data_to_extent(mapping, 891 ret = ext4_da_convert_inline_data_to_extent(mapping,
891 inode, 892 inode,
892 flags, 893 flags,
893 fsdata); 894 fsdata);
894 ext4_journal_stop(handle);
895 if (ret == -ENOSPC && 895 if (ret == -ENOSPC &&
896 ext4_should_retry_alloc(inode->i_sb, &retries)) 896 ext4_should_retry_alloc(inode->i_sb, &retries))
897 goto retry_journal; 897 goto retry_journal;
@@ -1891,42 +1891,6 @@ out:
1891 return (error < 0 ? error : 0); 1891 return (error < 0 ? error : 0);
1892} 1892}
1893 1893
1894/*
1895 * Called during xattr set, and if we can sparse space 'needed',
1896 * just create the extent tree evict the data to the outer block.
1897 *
1898 * We use jbd2 instead of page cache to move data to the 1st block
1899 * so that the whole transaction can be committed as a whole and
1900 * the data isn't lost because of the delayed page cache write.
1901 */
1902int ext4_try_to_evict_inline_data(handle_t *handle,
1903 struct inode *inode,
1904 int needed)
1905{
1906 int error;
1907 struct ext4_xattr_entry *entry;
1908 struct ext4_inode *raw_inode;
1909 struct ext4_iloc iloc;
1910
1911 error = ext4_get_inode_loc(inode, &iloc);
1912 if (error)
1913 return error;
1914
1915 raw_inode = ext4_raw_inode(&iloc);
1916 entry = (struct ext4_xattr_entry *)((void *)raw_inode +
1917 EXT4_I(inode)->i_inline_off);
1918 if (EXT4_XATTR_LEN(entry->e_name_len) +
1919 EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) < needed) {
1920 error = -ENOSPC;
1921 goto out;
1922 }
1923
1924 error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
1925out:
1926 brelse(iloc.bh);
1927 return error;
1928}
1929
1930int ext4_inline_data_truncate(struct inode *inode, int *has_inline) 1894int ext4_inline_data_truncate(struct inode *inode, int *has_inline)
1931{ 1895{
1932 handle_t *handle; 1896 handle_t *handle;
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 72377b77fbd7..723df14f4084 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -2212,23 +2212,8 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
2212 if (EXT4_I(inode)->i_extra_isize == 0) 2212 if (EXT4_I(inode)->i_extra_isize == 0)
2213 return -ENOSPC; 2213 return -ENOSPC;
2214 error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); 2214 error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */);
2215 if (error) { 2215 if (error)
2216 if (error == -ENOSPC && 2216 return error;
2217 ext4_has_inline_data(inode)) {
2218 error = ext4_try_to_evict_inline_data(handle, inode,
2219 EXT4_XATTR_LEN(strlen(i->name) +
2220 EXT4_XATTR_SIZE(i->value_len)));
2221 if (error)
2222 return error;
2223 error = ext4_xattr_ibody_find(inode, i, is);
2224 if (error)
2225 return error;
2226 error = ext4_xattr_set_entry(i, s, handle, inode,
2227 false /* is_block */);
2228 }
2229 if (error)
2230 return error;
2231 }
2232 header = IHDR(inode, ext4_raw_inode(&is->iloc)); 2217 header = IHDR(inode, ext4_raw_inode(&is->iloc));
2233 if (!IS_LAST_ENTRY(s->first)) { 2218 if (!IS_LAST_ENTRY(s->first)) {
2234 header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); 2219 header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);