Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'erofs-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs

Pull erofs updates from Gao Xiang:

- Validate xattr h_shared_count to report -EFSCORRUPTED explicitly for
crafted images

- Verify metadata accesses for file-backed mounts via rw_verify_area()

- Fix FS_IOC_GETFSLABEL to include the trailing NUL byte, consistent
with ext4 and xfs

- Properly handle 48-bit on-disk blocks/uniaddr for extra devices

- Fix an index underflow in the LZ4 in-place decompression that can
cause out-of-bounds accesses with crafted images

- Minor fixes and cleanups

* tag 'erofs-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
erofs: error out obviously illegal extents in advance
erofs: clean up encoded map flags
erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap()
erofs: handle 48-bit blocks/uniaddr for extra devices
erofs: include the trailing NUL in FS_IOC_GETFSLABEL
erofs: ensure all folios are managed in erofs_try_to_free_all_cached_folios()
erofs: verify metadata accesses for file-backed mounts
erofs: harden h_shared_count in erofs_init_inode_xattrs()

+80 -51
+14
fs/erofs/data.c
··· 30 30 { 31 31 pgoff_t index = (buf->off + offset) >> PAGE_SHIFT; 32 32 struct folio *folio = NULL; 33 + loff_t fpos; 34 + int err; 35 + 36 + /* 37 + * Metadata access for file-backed mounts reuses page cache of backing 38 + * fs inodes (only folio data will be needed) to prevent double caching. 39 + * However, the data access range must be verified here in advance. 40 + */ 41 + if (buf->file) { 42 + fpos = index << PAGE_SHIFT; 43 + err = rw_verify_area(READ, buf->file, &fpos, PAGE_SIZE); 44 + if (err < 0) 45 + return ERR_PTR(err); 46 + } 33 47 34 48 if (buf->page) { 35 49 folio = page_folio(buf->page);
+2 -2
fs/erofs/erofs_fs.h
··· 44 44 u8 tag[64]; /* digest(sha256), etc. */ 45 45 __le32 blocks_lo; /* total blocks count of this device */ 46 46 __le32 uniaddr_lo; /* unified starting block of this device */ 47 - __le32 blocks_hi; /* total blocks count MSB */ 47 + __le16 blocks_hi; /* total blocks count MSB */ 48 48 __le16 uniaddr_hi; /* unified starting block MSB */ 49 - u8 reserved[50]; 49 + u8 reserved[52]; 50 50 }; 51 51 #define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot) 52 52
+1 -1
fs/erofs/inode.c
··· 351 351 ret = clear_user(arg, 1); 352 352 else 353 353 ret = copy_to_user(arg, sbi->volume_name, 354 - strlen(sbi->volume_name)); 354 + strlen(sbi->volume_name) + 1); 355 355 return ret ? -EFAULT : 0; 356 356 } 357 357
+11 -12
fs/erofs/internal.h
··· 360 360 readahead_gfp_mask(as) & ~__GFP_RECLAIM); 361 361 } 362 362 363 - /* Has a disk mapping */ 364 - #define EROFS_MAP_MAPPED 0x0001 363 + /* Allocated on disk at @m_pa (e.g. NOT a fragment extent) */ 364 + #define EROFS_MAP_MAPPED 0x0001 365 365 /* Located in metadata (could be copied from bd_inode) */ 366 - #define EROFS_MAP_META 0x0002 367 - /* The extent is encoded */ 368 - #define EROFS_MAP_ENCODED 0x0004 369 - /* The length of extent is full */ 370 - #define EROFS_MAP_FULL_MAPPED 0x0008 366 + #define EROFS_MAP_META 0x0002 367 + /* @m_llen may be truncated by the runtime compared to the on-disk record */ 368 + #define EROFS_MAP_PARTIAL_MAPPED 0x0004 369 + /* The on-disk @m_llen may cover only part of the encoded data */ 370 + #define EROFS_MAP_PARTIAL_REF 0x0008 371 371 /* Located in the special packed inode */ 372 - #define __EROFS_MAP_FRAGMENT 0x0010 373 - /* The extent refers to partial decompressed data */ 374 - #define EROFS_MAP_PARTIAL_REF 0x0020 375 - 376 - #define EROFS_MAP_FRAGMENT (EROFS_MAP_MAPPED | __EROFS_MAP_FRAGMENT) 372 + #define EROFS_MAP_FRAGMENT 0x0010 373 + /* The encoded on-disk data will be fully handled (decompressed) */ 374 + #define EROFS_MAP_FULL(f) (!((f) & (EROFS_MAP_PARTIAL_MAPPED | \ 375 + EROFS_MAP_PARTIAL_REF))) 377 376 378 377 struct erofs_map_blocks { 379 378 struct erofs_buf buf;
+6 -2
fs/erofs/super.c
··· 129 129 struct erofs_fscache *fscache; 130 130 struct erofs_deviceslot *dis; 131 131 struct file *file; 132 + bool _48bit; 132 133 133 134 dis = erofs_read_metabuf(buf, sb, *pos, false); 134 135 if (IS_ERR(dis)) ··· 176 175 dif->file = file; 177 176 } 178 177 179 - dif->blocks = le32_to_cpu(dis->blocks_lo); 180 - dif->uniaddr = le32_to_cpu(dis->uniaddr_lo); 178 + _48bit = erofs_sb_has_48bit(sbi); 179 + dif->blocks = le32_to_cpu(dis->blocks_lo) | 180 + (_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0); 181 + dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) | 182 + (_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0); 181 183 sbi->total_blocks += dif->blocks; 182 184 *pos += EROFS_DEVT_SLOT_SIZE; 183 185 return 0;
+8
fs/erofs/xattr.c
··· 85 85 } 86 86 vi->xattr_name_filter = le32_to_cpu(ih->h_name_filter); 87 87 vi->xattr_shared_count = ih->h_shared_count; 88 + if ((u32)vi->xattr_shared_count * sizeof(__le32) > 89 + vi->xattr_isize - sizeof(struct erofs_xattr_ibody_header)) { 90 + erofs_err(sb, "invalid h_shared_count %u @ nid %llu", 91 + vi->xattr_shared_count, vi->nid); 92 + erofs_put_metabuf(&buf); 93 + ret = -EFSCORRUPTED; 94 + goto out_unlock; 95 + } 88 96 vi->xattr_shared_xattrs = kmalloc_objs(uint, vi->xattr_shared_count); 89 97 if (!vi->xattr_shared_xattrs) { 90 98 erofs_put_metabuf(&buf);
+10 -12
fs/erofs/zdata.c
··· 520 520 if (cachestrategy <= EROFS_ZIP_CACHE_DISABLED) 521 521 return false; 522 522 523 - if (!(fe->map.m_flags & EROFS_MAP_FULL_MAPPED)) 523 + if (fe->map.m_flags & EROFS_MAP_PARTIAL_MAPPED) 524 524 return true; 525 525 526 526 if (cachestrategy >= EROFS_ZIP_CACHE_READAROUND && ··· 605 605 if (!folio_trylock(folio)) 606 606 return -EBUSY; 607 607 608 - if (!erofs_folio_is_managed(sbi, folio)) 609 - continue; 608 + DBG_BUGON(!erofs_folio_is_managed(sbi, folio)); 610 609 pcl->compressed_bvecs[i].page = NULL; 611 610 folio_detach_private(folio); 612 611 folio_unlock(folio); ··· 1033 1034 /* bump split parts first to avoid several separate cases */ 1034 1035 ++split; 1035 1036 1036 - if (!(map->m_flags & EROFS_MAP_MAPPED)) { 1037 - folio_zero_segment(folio, cur, end); 1038 - tight = false; 1039 - } else if (map->m_flags & __EROFS_MAP_FRAGMENT) { 1037 + if (map->m_flags & EROFS_MAP_FRAGMENT) { 1040 1038 erofs_off_t fpos = offset + cur - map->m_la; 1041 1039 1042 1040 err = z_erofs_read_fragment(inode->i_sb, folio, cur, ··· 1041 1045 EROFS_I(inode)->z_fragmentoff + fpos); 1042 1046 if (err) 1043 1047 break; 1048 + tight = false; 1049 + } else if (!(map->m_flags & EROFS_MAP_MAPPED)) { 1050 + folio_zero_segment(folio, cur, end); 1044 1051 tight = false; 1045 1052 } else { 1046 1053 if (!f->pcl) { ··· 1080 1081 f->pcl->length = offset + end - map->m_la; 1081 1082 f->pcl->pageofs_out = map->m_la & ~PAGE_MASK; 1082 1083 } 1083 - if ((map->m_flags & EROFS_MAP_FULL_MAPPED) && 1084 - !(map->m_flags & EROFS_MAP_PARTIAL_REF) && 1084 + if (EROFS_MAP_FULL(map->m_flags) && 1085 1085 f->pcl->length == map->m_llen) 1086 1086 f->pcl->partial = false; 1087 1087 } 1088 1088 /* shorten the remaining extent to update progress */ 1089 1089 map->m_llen = offset + cur - map->m_la; 1090 - map->m_flags &= ~EROFS_MAP_FULL_MAPPED; 1090 + map->m_flags |= EROFS_MAP_PARTIAL_MAPPED; 1091 1091 if (cur <= pgs) { 1092 1092 split = cur < pgs; 1093 1093 tight = (bs == PAGE_SIZE); ··· 1840 1842 map->m_la = end; 1841 1843 err = z_erofs_map_blocks_iter(inode, map, 1842 1844 EROFS_GET_BLOCKS_READMORE); 1843 - if (err || !(map->m_flags & EROFS_MAP_ENCODED)) 1845 + if (err || !(map->m_flags & EROFS_MAP_MAPPED)) 1844 1846 return; 1845 1847 1846 1848 /* expand ra for the trailing edge if readahead */ ··· 1852 1854 end = round_up(end, PAGE_SIZE); 1853 1855 } else { 1854 1856 end = round_up(map->m_la, PAGE_SIZE); 1855 - if (!(map->m_flags & EROFS_MAP_ENCODED) || !map->m_llen) 1857 + if (!(map->m_flags & EROFS_MAP_MAPPED) || !map->m_llen) 1856 1858 return; 1857 1859 } 1858 1860
+25 -18
fs/erofs/zmap.c
··· 419 419 420 420 if ((flags & EROFS_GET_BLOCKS_FINDTAIL) && ztailpacking) 421 421 vi->z_fragmentoff = m.nextpackoff; 422 - map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED; 422 + map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_PARTIAL_MAPPED; 423 423 end = (m.lcn + 1ULL) << lclusterbits; 424 424 425 425 if (m.type != Z_EROFS_LCLUSTER_TYPE_NONHEAD && endoff >= m.clusterofs) { ··· 435 435 } else { 436 436 if (m.type != Z_EROFS_LCLUSTER_TYPE_NONHEAD) { 437 437 end = (m.lcn << lclusterbits) | m.clusterofs; 438 - map->m_flags |= EROFS_MAP_FULL_MAPPED; 438 + map->m_flags &= ~EROFS_MAP_PARTIAL_MAPPED; 439 439 m.delta[0] = 1; 440 440 } 441 441 /* get the corresponding first chunk */ ··· 473 473 } 474 474 475 475 if (m.headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN) { 476 - if (map->m_llen > map->m_plen) { 477 - DBG_BUGON(1); 478 - err = -EFSCORRUPTED; 479 - goto unmap_out; 480 - } 481 476 if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) 482 477 map->m_algorithmformat = Z_EROFS_COMPRESSION_INTERLACED; 483 478 else ··· 491 496 map->m_llen >= i_blocksize(inode))) { 492 497 err = z_erofs_get_extent_decompressedlen(&m); 493 498 if (!err) 494 - map->m_flags |= EROFS_MAP_FULL_MAPPED; 499 + map->m_flags &= ~EROFS_MAP_PARTIAL_MAPPED; 495 500 } 496 501 497 502 unmap_out: ··· 589 594 if (recsz > offsetof(struct z_erofs_extent, pstart_lo)) 590 595 vi->z_fragmentoff |= map->m_pa << 32; 591 596 } else if (map->m_plen & Z_EROFS_EXTENT_PLEN_MASK) { 592 - map->m_flags |= EROFS_MAP_MAPPED | 593 - EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED; 597 + map->m_flags |= EROFS_MAP_MAPPED; 594 598 fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT; 595 599 if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL) 596 600 map->m_flags |= EROFS_MAP_PARTIAL_REF; ··· 708 714 struct erofs_sb_info *sbi = EROFS_I_SB(inode); 709 715 u64 pend; 710 716 711 - if (!(map->m_flags & EROFS_MAP_ENCODED)) 717 + if (!(map->m_flags & EROFS_MAP_MAPPED)) 712 718 return 0; 713 719 if (unlikely(map->m_algorithmformat >= Z_EROFS_COMPRESSION_RUNTIME_MAX)) { 714 720 erofs_err(inode->i_sb, "unknown algorithm %d @ pos %llu for nid %llu, please upgrade kernel", 715 721 map->m_algorithmformat, map->m_la, EROFS_I(inode)->nid); 716 722 return -EOPNOTSUPP; 717 723 } 718 - if (unlikely(map->m_algorithmformat < Z_EROFS_COMPRESSION_MAX && 719 - !(sbi->available_compr_algs & (1 << map->m_algorithmformat)))) { 720 - erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu", 721 - map->m_algorithmformat, EROFS_I(inode)->nid); 724 + 725 + if (map->m_algorithmformat < Z_EROFS_COMPRESSION_MAX) { 726 + if (sbi->available_compr_algs ^ BIT(map->m_algorithmformat)) { 727 + erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu", 728 + map->m_algorithmformat, EROFS_I(inode)->nid); 729 + return -EFSCORRUPTED; 730 + } 731 + if (EROFS_MAP_FULL(map->m_flags) && map->m_llen < map->m_plen) { 732 + erofs_err(inode->i_sb, "too much compressed data @ la %llu of nid %llu", 733 + map->m_la, EROFS_I(inode)->nid); 734 + return -EFSCORRUPTED; 735 + } 736 + } else if (map->m_llen > map->m_plen) { 737 + erofs_err(inode->i_sb, "not enough plain data on disk @ la %llu of nid %llu", 738 + map->m_la, EROFS_I(inode)->nid); 722 739 return -EFSCORRUPTED; 723 740 } 724 741 if (unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE || ··· 786 781 iomap->bdev = inode->i_sb->s_bdev; 787 782 iomap->offset = map.m_la; 788 783 iomap->length = map.m_llen; 789 - if (map.m_flags & EROFS_MAP_MAPPED) { 784 + if (map.m_flags & EROFS_MAP_FRAGMENT) { 790 785 iomap->type = IOMAP_MAPPED; 791 - iomap->addr = map.m_flags & __EROFS_MAP_FRAGMENT ? 792 - IOMAP_NULL_ADDR : map.m_pa; 786 + iomap->addr = IOMAP_NULL_ADDR; 787 + } else if (map.m_flags & EROFS_MAP_MAPPED) { 788 + iomap->type = IOMAP_MAPPED; 789 + iomap->addr = map.m_pa; 793 790 } else { 794 791 iomap->type = IOMAP_HOLE; 795 792 iomap->addr = IOMAP_NULL_ADDR;
+3 -4
include/trace/events/erofs.h
··· 26 26 #define show_mflags(flags) __print_flags(flags, "", \ 27 27 { EROFS_MAP_MAPPED, "M" }, \ 28 28 { EROFS_MAP_META, "I" }, \ 29 - { EROFS_MAP_ENCODED, "E" }, \ 30 - { EROFS_MAP_FULL_MAPPED, "F" }, \ 31 - { EROFS_MAP_FRAGMENT, "R" }, \ 32 - { EROFS_MAP_PARTIAL_REF, "P" }) 29 + { EROFS_MAP_PARTIAL_MAPPED, "T" }, \ 30 + { EROFS_MAP_PARTIAL_REF, "P" }, \ 31 + { EROFS_MAP_FRAGMENT, "R" }) 33 32 34 33 TRACE_EVENT(erofs_lookup, 35 34