1d23db91eSPedro F. Giffuni /*- 27abc09cdSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 37abc09cdSPedro F. Giffuni * 4d23db91eSPedro F. Giffuni * Copyright (c) 2017, Fedor Uporov 5d23db91eSPedro F. Giffuni * All rights reserved. 6d23db91eSPedro F. Giffuni * 7d23db91eSPedro F. Giffuni * Redistribution and use in source and binary forms, with or without 8d23db91eSPedro F. Giffuni * modification, are permitted provided that the following conditions 9d23db91eSPedro F. Giffuni * are met: 10d23db91eSPedro F. Giffuni * 1. Redistributions of source code must retain the above copyright 11d23db91eSPedro F. Giffuni * notice, this list of conditions and the following disclaimer. 12d23db91eSPedro F. Giffuni * 2. Redistributions in binary form must reproduce the above copyright 13d23db91eSPedro F. Giffuni * notice, this list of conditions and the following disclaimer in the 14d23db91eSPedro F. Giffuni * documentation and/or other materials provided with the distribution. 15d23db91eSPedro F. Giffuni * 16d23db91eSPedro F. Giffuni * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17d23db91eSPedro F. Giffuni * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18d23db91eSPedro F. Giffuni * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19d23db91eSPedro F. Giffuni * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20d23db91eSPedro F. Giffuni * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21d23db91eSPedro F. Giffuni * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22d23db91eSPedro F. Giffuni * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23d23db91eSPedro F. Giffuni * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24d23db91eSPedro F. Giffuni * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25d23db91eSPedro F. Giffuni * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26d23db91eSPedro F. Giffuni * SUCH DAMAGE. 27d23db91eSPedro F. Giffuni * 28d23db91eSPedro F. Giffuni * $FreeBSD$ 29d23db91eSPedro F. Giffuni */ 30d23db91eSPedro F. Giffuni 31d23db91eSPedro F. Giffuni #include <sys/param.h> 32d23db91eSPedro F. Giffuni #include <sys/systm.h> 33d23db91eSPedro F. Giffuni #include <sys/types.h> 34d23db91eSPedro F. Giffuni #include <sys/stat.h> 35d23db91eSPedro F. Giffuni #include <sys/kernel.h> 36d23db91eSPedro F. Giffuni #include <sys/malloc.h> 37d23db91eSPedro F. Giffuni #include <sys/vnode.h> 38d23db91eSPedro F. Giffuni #include <sys/bio.h> 39d23db91eSPedro F. Giffuni #include <sys/buf.h> 40d23db91eSPedro F. Giffuni #include <sys/endian.h> 41d23db91eSPedro F. Giffuni #include <sys/conf.h> 42d23db91eSPedro F. Giffuni #include <sys/mount.h> 43d23db91eSPedro F. Giffuni 44d23db91eSPedro F. Giffuni #include <fs/ext2fs/fs.h> 45d23db91eSPedro F. Giffuni #include <fs/ext2fs/ext2fs.h> 46512f29d1SFedor Uporov #include <fs/ext2fs/ext2_dinode.h> 47d23db91eSPedro F. Giffuni #include <fs/ext2fs/inode.h> 48512f29d1SFedor Uporov #include <fs/ext2fs/ext2_dir.h> 49512f29d1SFedor Uporov #include <fs/ext2fs/htree.h> 50512f29d1SFedor Uporov #include <fs/ext2fs/ext2_extattr.h> 51d23db91eSPedro F. Giffuni #include <fs/ext2fs/ext2_extern.h> 52d23db91eSPedro F. Giffuni 53512f29d1SFedor Uporov #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \ 54512f29d1SFedor Uporov (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \ 55512f29d1SFedor Uporov sizeof(uint16_t)) 56512f29d1SFedor Uporov 57512f29d1SFedor Uporov #define EXT2_INODE_CSUM_HI_EXTRA_END \ 58512f29d1SFedor Uporov (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \ 59512f29d1SFedor Uporov E2FS_REV0_INODE_SIZE) 60512f29d1SFedor Uporov 61512f29d1SFedor Uporov #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \ 62512f29d1SFedor Uporov (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \ 63512f29d1SFedor Uporov sizeof(uint16_t)) 64512f29d1SFedor Uporov 65512f29d1SFedor Uporov void 66512f29d1SFedor Uporov ext2_sb_csum_set_seed(struct m_ext2fs *fs) 67512f29d1SFedor Uporov { 68512f29d1SFedor Uporov 69512f29d1SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED)) 70512f29d1SFedor Uporov fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed; 71512f29d1SFedor Uporov else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 72512f29d1SFedor Uporov fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid, 73512f29d1SFedor Uporov sizeof(fs->e2fs->e2fs_uuid)); 74512f29d1SFedor Uporov } 75512f29d1SFedor Uporov else 76512f29d1SFedor Uporov fs->e2fs_csum_seed = 0; 77512f29d1SFedor Uporov } 78512f29d1SFedor Uporov 79512f29d1SFedor Uporov int 80512f29d1SFedor Uporov ext2_sb_csum_verify(struct m_ext2fs *fs) 81512f29d1SFedor Uporov { 82512f29d1SFedor Uporov 83512f29d1SFedor Uporov if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) { 84512f29d1SFedor Uporov printf( 85512f29d1SFedor Uporov "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt); 86512f29d1SFedor Uporov return (EINVAL); 87512f29d1SFedor Uporov } 88512f29d1SFedor Uporov if (fs->e2fs->e4fs_sbchksum != 89512f29d1SFedor Uporov calculate_crc32c(~0, (const char *)fs->e2fs, 90512f29d1SFedor Uporov offsetof(struct ext2fs, e4fs_sbchksum))) { 91512f29d1SFedor Uporov printf( 92512f29d1SFedor Uporov "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n", 93512f29d1SFedor Uporov fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0, 94512f29d1SFedor Uporov (const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum))); 95512f29d1SFedor Uporov return (EINVAL); 96512f29d1SFedor Uporov } 97512f29d1SFedor Uporov 98512f29d1SFedor Uporov return (0); 99512f29d1SFedor Uporov } 100512f29d1SFedor Uporov 101512f29d1SFedor Uporov void 102512f29d1SFedor Uporov ext2_sb_csum_set(struct m_ext2fs *fs) 103512f29d1SFedor Uporov { 104512f29d1SFedor Uporov 105512f29d1SFedor Uporov fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs, 106512f29d1SFedor Uporov offsetof(struct ext2fs, e4fs_sbchksum)); 107512f29d1SFedor Uporov } 108512f29d1SFedor Uporov 109512f29d1SFedor Uporov static uint32_t 110512f29d1SFedor Uporov ext2_extattr_blk_csum(struct inode *ip, uint64_t facl, 111512f29d1SFedor Uporov struct ext2fs_extattr_header *header) 112512f29d1SFedor Uporov { 113512f29d1SFedor Uporov struct m_ext2fs *fs; 114512f29d1SFedor Uporov uint32_t crc, old_crc; 115512f29d1SFedor Uporov 116512f29d1SFedor Uporov fs = ip->i_e2fs; 117512f29d1SFedor Uporov 118512f29d1SFedor Uporov old_crc = header->h_checksum; 119512f29d1SFedor Uporov 120512f29d1SFedor Uporov header->h_checksum = 0; 121512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl)); 122512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize); 123512f29d1SFedor Uporov header->h_checksum = old_crc; 124512f29d1SFedor Uporov 125512f29d1SFedor Uporov return (crc); 126512f29d1SFedor Uporov } 127512f29d1SFedor Uporov 128512f29d1SFedor Uporov int 129512f29d1SFedor Uporov ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp) 130512f29d1SFedor Uporov { 131512f29d1SFedor Uporov struct ext2fs_extattr_header *header; 132512f29d1SFedor Uporov 133512f29d1SFedor Uporov header = (struct ext2fs_extattr_header *)bp->b_data; 134512f29d1SFedor Uporov 135512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) && 136512f29d1SFedor Uporov (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) { 137512f29d1SFedor Uporov printf("WARNING: bad extattr csum detected, ip=%lu - run fsck\n", 138512f29d1SFedor Uporov (unsigned long)ip->i_number); 139512f29d1SFedor Uporov return (EIO); 140512f29d1SFedor Uporov } 141512f29d1SFedor Uporov 142512f29d1SFedor Uporov return (0); 143512f29d1SFedor Uporov } 144512f29d1SFedor Uporov 145512f29d1SFedor Uporov void 146512f29d1SFedor Uporov ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp) 147512f29d1SFedor Uporov { 148512f29d1SFedor Uporov struct ext2fs_extattr_header *header; 149512f29d1SFedor Uporov 150512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 151512f29d1SFedor Uporov return; 152512f29d1SFedor Uporov 153512f29d1SFedor Uporov header = (struct ext2fs_extattr_header *)bp->b_data; 154512f29d1SFedor Uporov header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header); 155512f29d1SFedor Uporov } 156512f29d1SFedor Uporov 1576d4a4ed7SFedor Uporov void 1586d4a4ed7SFedor Uporov ext2_init_dirent_tail(struct ext2fs_direct_tail *tp) 159512f29d1SFedor Uporov { 1606d4a4ed7SFedor Uporov memset(tp, 0, sizeof(struct ext2fs_direct_tail)); 1616d4a4ed7SFedor Uporov tp->e2dt_rec_len = sizeof(struct ext2fs_direct_tail); 1626d4a4ed7SFedor Uporov tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM; 1636d4a4ed7SFedor Uporov } 164512f29d1SFedor Uporov 165*e49d64a7SFedor Uporov int 166*e49d64a7SFedor Uporov ext2_is_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep) 167*e49d64a7SFedor Uporov { 168*e49d64a7SFedor Uporov struct m_ext2fs *fs; 169*e49d64a7SFedor Uporov struct ext2fs_direct_tail *tp; 170*e49d64a7SFedor Uporov 171*e49d64a7SFedor Uporov fs = ip->i_e2fs; 172*e49d64a7SFedor Uporov 173*e49d64a7SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 174*e49d64a7SFedor Uporov return (0); 175*e49d64a7SFedor Uporov 176*e49d64a7SFedor Uporov tp = (struct ext2fs_direct_tail *)ep; 177*e49d64a7SFedor Uporov if (tp->e2dt_reserved_zero1 == 0 && 178*e49d64a7SFedor Uporov tp->e2dt_rec_len == sizeof(struct ext2fs_direct_tail) && 179*e49d64a7SFedor Uporov tp->e2dt_reserved_zero2 == 0 && 180*e49d64a7SFedor Uporov tp->e2dt_reserved_ft == EXT2_FT_DIR_CSUM) 181*e49d64a7SFedor Uporov return (1); 182*e49d64a7SFedor Uporov 183*e49d64a7SFedor Uporov return (0); 184*e49d64a7SFedor Uporov } 185*e49d64a7SFedor Uporov 1866d4a4ed7SFedor Uporov struct ext2fs_direct_tail * 1876d4a4ed7SFedor Uporov ext2_dirent_get_tail(struct inode *ip, struct ext2fs_direct_2 *ep) 1886d4a4ed7SFedor Uporov { 1896d4a4ed7SFedor Uporov struct ext2fs_direct_2 *dep; 1906d4a4ed7SFedor Uporov void *top; 1916d4a4ed7SFedor Uporov unsigned int rec_len; 1926d4a4ed7SFedor Uporov 1936d4a4ed7SFedor Uporov dep = ep; 1946d4a4ed7SFedor Uporov top = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize); 1956d4a4ed7SFedor Uporov rec_len = dep->e2d_reclen; 1966d4a4ed7SFedor Uporov 1976d4a4ed7SFedor Uporov while (rec_len && !(rec_len & 0x3)) { 1986d4a4ed7SFedor Uporov dep = (struct ext2fs_direct_2 *)(((char *)dep) + rec_len); 1996d4a4ed7SFedor Uporov if ((void *)dep >= top) 2006d4a4ed7SFedor Uporov break; 2016d4a4ed7SFedor Uporov rec_len = dep->e2d_reclen; 2026d4a4ed7SFedor Uporov } 2036d4a4ed7SFedor Uporov 2046d4a4ed7SFedor Uporov if (dep != top) 2056d4a4ed7SFedor Uporov return (NULL); 2066d4a4ed7SFedor Uporov 207*e49d64a7SFedor Uporov if (ext2_is_dirent_tail(ip, dep)) 208*e49d64a7SFedor Uporov return ((struct ext2fs_direct_tail *)dep); 209512f29d1SFedor Uporov 210*e49d64a7SFedor Uporov return (NULL); 211512f29d1SFedor Uporov } 212512f29d1SFedor Uporov 213512f29d1SFedor Uporov static uint32_t 214512f29d1SFedor Uporov ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size) 215512f29d1SFedor Uporov { 216512f29d1SFedor Uporov struct m_ext2fs *fs; 217512f29d1SFedor Uporov char *buf; 218512f29d1SFedor Uporov uint32_t inum, gen, crc; 219512f29d1SFedor Uporov 220512f29d1SFedor Uporov fs = ip->i_e2fs; 221512f29d1SFedor Uporov 222512f29d1SFedor Uporov buf = (char *)ep; 223512f29d1SFedor Uporov 224512f29d1SFedor Uporov inum = ip->i_number; 225512f29d1SFedor Uporov gen = ip->i_gen; 226512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 227512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 228512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 229512f29d1SFedor Uporov 230512f29d1SFedor Uporov return (crc); 231512f29d1SFedor Uporov } 232512f29d1SFedor Uporov 2336d4a4ed7SFedor Uporov int 234512f29d1SFedor Uporov ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 235512f29d1SFedor Uporov { 236512f29d1SFedor Uporov uint32_t calculated; 237512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 238512f29d1SFedor Uporov 2396d4a4ed7SFedor Uporov tp = ext2_dirent_get_tail(ip, ep); 240512f29d1SFedor Uporov if (tp == NULL) 241512f29d1SFedor Uporov return (0); 242512f29d1SFedor Uporov 243512f29d1SFedor Uporov calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 244512f29d1SFedor Uporov if (calculated != tp->e2dt_checksum) 245512f29d1SFedor Uporov return (EIO); 246512f29d1SFedor Uporov 247512f29d1SFedor Uporov return (0); 248512f29d1SFedor Uporov } 249512f29d1SFedor Uporov 250512f29d1SFedor Uporov static struct ext2fs_htree_count * 251512f29d1SFedor Uporov ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset) 252512f29d1SFedor Uporov { 253512f29d1SFedor Uporov struct ext2fs_direct_2 *dp; 254512f29d1SFedor Uporov struct ext2fs_htree_root_info *root; 255512f29d1SFedor Uporov int count_offset; 256512f29d1SFedor Uporov 257512f29d1SFedor Uporov if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs)) 258512f29d1SFedor Uporov count_offset = 8; 259512f29d1SFedor Uporov else if (ep->e2d_reclen == 12) { 260512f29d1SFedor Uporov dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12); 261512f29d1SFedor Uporov if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12) 262512f29d1SFedor Uporov return (NULL); 263512f29d1SFedor Uporov 264512f29d1SFedor Uporov root = (struct ext2fs_htree_root_info *)(((char *)dp + 12)); 265512f29d1SFedor Uporov if (root->h_reserved1 || 266512f29d1SFedor Uporov root->h_info_len != sizeof(struct ext2fs_htree_root_info)) 267512f29d1SFedor Uporov return (NULL); 268512f29d1SFedor Uporov 269512f29d1SFedor Uporov count_offset = 32; 270512f29d1SFedor Uporov } else 271512f29d1SFedor Uporov return (NULL); 272512f29d1SFedor Uporov 273512f29d1SFedor Uporov if (offset) 274512f29d1SFedor Uporov *offset = count_offset; 275512f29d1SFedor Uporov 276512f29d1SFedor Uporov return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset)); 277512f29d1SFedor Uporov } 278512f29d1SFedor Uporov 279512f29d1SFedor Uporov static uint32_t 280512f29d1SFedor Uporov ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset, 281512f29d1SFedor Uporov int count, struct ext2fs_htree_tail *tp) 282512f29d1SFedor Uporov { 283512f29d1SFedor Uporov struct m_ext2fs *fs; 284512f29d1SFedor Uporov char *buf; 285512f29d1SFedor Uporov int size; 286512f29d1SFedor Uporov uint32_t inum, old_csum, gen, crc; 287512f29d1SFedor Uporov 288512f29d1SFedor Uporov fs = ip->i_e2fs; 289512f29d1SFedor Uporov 290512f29d1SFedor Uporov buf = (char *)ep; 291512f29d1SFedor Uporov 292512f29d1SFedor Uporov size = count_offset + (count * sizeof(struct ext2fs_htree_entry)); 293512f29d1SFedor Uporov old_csum = tp->ht_checksum; 294512f29d1SFedor Uporov tp->ht_checksum = 0; 295512f29d1SFedor Uporov 296512f29d1SFedor Uporov inum = ip->i_number; 297512f29d1SFedor Uporov gen = ip->i_gen; 298512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 299512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 300512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 301512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail)); 302512f29d1SFedor Uporov tp->ht_checksum = old_csum; 303512f29d1SFedor Uporov 304512f29d1SFedor Uporov return (crc); 305512f29d1SFedor Uporov } 306512f29d1SFedor Uporov 3076d4a4ed7SFedor Uporov int 308512f29d1SFedor Uporov ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 309512f29d1SFedor Uporov { 310512f29d1SFedor Uporov uint32_t calculated; 311512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 312512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 313512f29d1SFedor Uporov int count_offset, limit, count; 314512f29d1SFedor Uporov 315512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 316512f29d1SFedor Uporov if (cp == NULL) 317512f29d1SFedor Uporov return (0); 318512f29d1SFedor Uporov 319512f29d1SFedor Uporov limit = cp->h_entries_max; 320512f29d1SFedor Uporov count = cp->h_entries_num; 321512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 322512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 323512f29d1SFedor Uporov return (EIO); 324512f29d1SFedor Uporov 325512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 326512f29d1SFedor Uporov calculated = ext2_dx_csum(ip, ep, count_offset, count, tp); 327512f29d1SFedor Uporov 328512f29d1SFedor Uporov if (tp->ht_checksum != calculated) 329512f29d1SFedor Uporov return (EIO); 330512f29d1SFedor Uporov 331512f29d1SFedor Uporov return (0); 332512f29d1SFedor Uporov } 333512f29d1SFedor Uporov 334512f29d1SFedor Uporov int 335512f29d1SFedor Uporov ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp) 336512f29d1SFedor Uporov { 337512f29d1SFedor Uporov struct m_ext2fs *fs; 338512f29d1SFedor Uporov struct ext2fs_direct_2 *ep; 339512f29d1SFedor Uporov int error = 0; 340512f29d1SFedor Uporov 341512f29d1SFedor Uporov fs = ip->i_e2fs; 342512f29d1SFedor Uporov 343512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 344512f29d1SFedor Uporov return (error); 345512f29d1SFedor Uporov 346512f29d1SFedor Uporov ep = (struct ext2fs_direct_2 *)bp->b_data; 347512f29d1SFedor Uporov 3486d4a4ed7SFedor Uporov if (ext2_dirent_get_tail(ip, ep) != NULL) 349512f29d1SFedor Uporov error = ext2_dirent_csum_verify(ip, ep); 350512f29d1SFedor Uporov else if (ext2_get_dx_count(ip, ep, NULL) != NULL) 351512f29d1SFedor Uporov error = ext2_dx_csum_verify(ip, ep); 352512f29d1SFedor Uporov 353512f29d1SFedor Uporov if (error) 354512f29d1SFedor Uporov printf("WARNING: bad directory csum detected, ip=%lu" 355512f29d1SFedor Uporov " - run fsck\n", (unsigned long)ip->i_number); 356512f29d1SFedor Uporov 357512f29d1SFedor Uporov return (error); 358512f29d1SFedor Uporov } 359512f29d1SFedor Uporov 3606d4a4ed7SFedor Uporov void 361512f29d1SFedor Uporov ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 362512f29d1SFedor Uporov { 3636d4a4ed7SFedor Uporov struct m_ext2fs *fs; 364512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 365512f29d1SFedor Uporov 3666d4a4ed7SFedor Uporov fs = ip->i_e2fs; 3676d4a4ed7SFedor Uporov 3686d4a4ed7SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 3696d4a4ed7SFedor Uporov return; 3706d4a4ed7SFedor Uporov 3716d4a4ed7SFedor Uporov tp = ext2_dirent_get_tail(ip, ep); 372512f29d1SFedor Uporov if (tp == NULL) 373512f29d1SFedor Uporov return; 374512f29d1SFedor Uporov 375512f29d1SFedor Uporov tp->e2dt_checksum = 376512f29d1SFedor Uporov ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 377512f29d1SFedor Uporov } 378512f29d1SFedor Uporov 3796d4a4ed7SFedor Uporov void 380512f29d1SFedor Uporov ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 381512f29d1SFedor Uporov { 3826d4a4ed7SFedor Uporov struct m_ext2fs *fs; 383512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 384512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 385512f29d1SFedor Uporov int count_offset, limit, count; 386512f29d1SFedor Uporov 3876d4a4ed7SFedor Uporov fs = ip->i_e2fs; 3886d4a4ed7SFedor Uporov 3896d4a4ed7SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 3906d4a4ed7SFedor Uporov return; 3916d4a4ed7SFedor Uporov 392512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 393512f29d1SFedor Uporov if (cp == NULL) 394512f29d1SFedor Uporov return; 395512f29d1SFedor Uporov 396512f29d1SFedor Uporov limit = cp->h_entries_max; 397512f29d1SFedor Uporov count = cp->h_entries_num; 398512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 399512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 400512f29d1SFedor Uporov return; 401512f29d1SFedor Uporov 402512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 403512f29d1SFedor Uporov tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp); 404512f29d1SFedor Uporov } 405512f29d1SFedor Uporov 406512f29d1SFedor Uporov static uint32_t 407512f29d1SFedor Uporov ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp) 408512f29d1SFedor Uporov { 409512f29d1SFedor Uporov struct m_ext2fs *fs; 410512f29d1SFedor Uporov size_t size; 411512f29d1SFedor Uporov uint32_t inum, gen, crc; 412512f29d1SFedor Uporov 413512f29d1SFedor Uporov fs = ip->i_e2fs; 414512f29d1SFedor Uporov 415512f29d1SFedor Uporov size = EXT4_EXTENT_TAIL_OFFSET(ehp) + 416512f29d1SFedor Uporov offsetof(struct ext4_extent_tail, et_checksum); 417512f29d1SFedor Uporov 418512f29d1SFedor Uporov inum = ip->i_number; 419512f29d1SFedor Uporov gen = ip->i_gen; 420512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 421512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 422512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ehp, size); 423512f29d1SFedor Uporov 424512f29d1SFedor Uporov return (crc); 425512f29d1SFedor Uporov } 426512f29d1SFedor Uporov 427512f29d1SFedor Uporov int 428512f29d1SFedor Uporov ext2_extent_blk_csum_verify(struct inode *ip, void *data) 429512f29d1SFedor Uporov { 430512f29d1SFedor Uporov struct m_ext2fs *fs; 431512f29d1SFedor Uporov struct ext4_extent_header *ehp; 432512f29d1SFedor Uporov struct ext4_extent_tail *etp; 433512f29d1SFedor Uporov uint32_t provided, calculated; 434512f29d1SFedor Uporov 435512f29d1SFedor Uporov fs = ip->i_e2fs; 436512f29d1SFedor Uporov 437512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 438512f29d1SFedor Uporov return (0); 439512f29d1SFedor Uporov 440512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 441512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)ehp) + 442512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 443512f29d1SFedor Uporov 444512f29d1SFedor Uporov provided = etp->et_checksum; 445512f29d1SFedor Uporov calculated = ext2_extent_blk_csum(ip, ehp); 446512f29d1SFedor Uporov 447512f29d1SFedor Uporov if (provided != calculated) { 448512f29d1SFedor Uporov printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n", 449512f29d1SFedor Uporov (unsigned long)ip->i_number); 450512f29d1SFedor Uporov return (EIO); 451512f29d1SFedor Uporov } 452512f29d1SFedor Uporov 453512f29d1SFedor Uporov return (0); 454512f29d1SFedor Uporov } 455512f29d1SFedor Uporov 456512f29d1SFedor Uporov void 457512f29d1SFedor Uporov ext2_extent_blk_csum_set(struct inode *ip, void *data) 458512f29d1SFedor Uporov { 459512f29d1SFedor Uporov struct m_ext2fs *fs; 460512f29d1SFedor Uporov struct ext4_extent_header *ehp; 461512f29d1SFedor Uporov struct ext4_extent_tail *etp; 462512f29d1SFedor Uporov 463512f29d1SFedor Uporov fs = ip->i_e2fs; 464512f29d1SFedor Uporov 465512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 466512f29d1SFedor Uporov return; 467512f29d1SFedor Uporov 468512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 469512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)data) + 470512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 471512f29d1SFedor Uporov 472512f29d1SFedor Uporov etp->et_checksum = ext2_extent_blk_csum(ip, 473512f29d1SFedor Uporov (struct ext4_extent_header *)data); 474512f29d1SFedor Uporov } 475512f29d1SFedor Uporov 476512f29d1SFedor Uporov int 477512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 478512f29d1SFedor Uporov { 479512f29d1SFedor Uporov uint32_t hi, provided, calculated; 480512f29d1SFedor Uporov 481512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 482512f29d1SFedor Uporov return (0); 483512f29d1SFedor Uporov 484512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum; 485512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 486512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 487512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) { 488512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi; 489512f29d1SFedor Uporov provided |= (hi << 16); 490512f29d1SFedor Uporov } else 491512f29d1SFedor Uporov calculated &= 0xFFFF; 492512f29d1SFedor Uporov 493512f29d1SFedor Uporov if (provided != calculated) { 494512f29d1SFedor Uporov printf("WARNING: bad inode bitmap csum detected, " 495512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 496512f29d1SFedor Uporov return (EIO); 497512f29d1SFedor Uporov } 498512f29d1SFedor Uporov 499512f29d1SFedor Uporov return (0); 500512f29d1SFedor Uporov } 501512f29d1SFedor Uporov 502512f29d1SFedor Uporov void 503512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 504512f29d1SFedor Uporov { 505512f29d1SFedor Uporov uint32_t csum; 506512f29d1SFedor Uporov 507512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 508512f29d1SFedor Uporov return; 509512f29d1SFedor Uporov 510512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 511512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 512512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF; 513512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) 514512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16; 515512f29d1SFedor Uporov } 516512f29d1SFedor Uporov 517512f29d1SFedor Uporov int 518512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 519512f29d1SFedor Uporov { 520512f29d1SFedor Uporov uint32_t hi, provided, calculated, size; 521512f29d1SFedor Uporov 522512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 523512f29d1SFedor Uporov return (0); 524512f29d1SFedor Uporov 525512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 526512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum; 527512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 528512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) { 529512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi; 530512f29d1SFedor Uporov provided |= (hi << 16); 531512f29d1SFedor Uporov } else 532512f29d1SFedor Uporov calculated &= 0xFFFF; 533512f29d1SFedor Uporov 534512f29d1SFedor Uporov if (provided != calculated) { 535512f29d1SFedor Uporov printf("WARNING: bad block bitmap csum detected, " 536512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 537512f29d1SFedor Uporov return (EIO); 538512f29d1SFedor Uporov } 539512f29d1SFedor Uporov 540512f29d1SFedor Uporov return (0); 541512f29d1SFedor Uporov } 542512f29d1SFedor Uporov 543512f29d1SFedor Uporov void 544512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 545512f29d1SFedor Uporov { 546512f29d1SFedor Uporov uint32_t csum, size; 547512f29d1SFedor Uporov 548512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 549512f29d1SFedor Uporov return; 550512f29d1SFedor Uporov 551512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 552512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 553512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF; 554512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) 555512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16; 556512f29d1SFedor Uporov } 557512f29d1SFedor Uporov 558512f29d1SFedor Uporov static uint32_t 559512f29d1SFedor Uporov ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei) 560512f29d1SFedor Uporov { 561512f29d1SFedor Uporov struct m_ext2fs *fs; 562c4aa9a02SFedor Uporov uint32_t inode_csum_seed, inum, gen, crc; 563c4aa9a02SFedor Uporov uint16_t dummy_csum = 0; 564c4aa9a02SFedor Uporov unsigned int offset, csum_size; 565512f29d1SFedor Uporov 566512f29d1SFedor Uporov fs = ip->i_e2fs; 567c4aa9a02SFedor Uporov offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo); 568c4aa9a02SFedor Uporov csum_size = sizeof(dummy_csum); 569512f29d1SFedor Uporov inum = ip->i_number; 570c4aa9a02SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, 571c4aa9a02SFedor Uporov (uint8_t *)&inum, sizeof(inum)); 5726d4a4ed7SFedor Uporov gen = ip->i_gen; 573c4aa9a02SFedor Uporov inode_csum_seed = calculate_crc32c(crc, 574c4aa9a02SFedor Uporov (uint8_t *)&gen, sizeof(gen)); 575512f29d1SFedor Uporov 576c4aa9a02SFedor Uporov crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset); 577c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size); 578c4aa9a02SFedor Uporov offset += csum_size; 579c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + offset, 580c4aa9a02SFedor Uporov E2FS_REV0_INODE_SIZE - offset); 581512f29d1SFedor Uporov 582c4aa9a02SFedor Uporov if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) { 583c4aa9a02SFedor Uporov offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi); 584c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + 585c4aa9a02SFedor Uporov E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE); 586c4aa9a02SFedor Uporov 587c4aa9a02SFedor Uporov if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE && 588c4aa9a02SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 589c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, 590c4aa9a02SFedor Uporov csum_size); 591c4aa9a02SFedor Uporov offset += csum_size; 592c4aa9a02SFedor Uporov } 593c4aa9a02SFedor Uporov 594c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + offset, 595c4aa9a02SFedor Uporov EXT2_INODE_SIZE(fs) - offset); 596c4aa9a02SFedor Uporov } 597512f29d1SFedor Uporov 598512f29d1SFedor Uporov return (crc); 599512f29d1SFedor Uporov } 600512f29d1SFedor Uporov 601512f29d1SFedor Uporov int 602512f29d1SFedor Uporov ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei) 603512f29d1SFedor Uporov { 604512f29d1SFedor Uporov struct m_ext2fs *fs; 605512f29d1SFedor Uporov const static struct ext2fs_dinode ei_zero; 606512f29d1SFedor Uporov uint32_t hi, provided, calculated; 607512f29d1SFedor Uporov 608512f29d1SFedor Uporov fs = ip->i_e2fs; 609512f29d1SFedor Uporov 610512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 611512f29d1SFedor Uporov return (0); 612512f29d1SFedor Uporov 613512f29d1SFedor Uporov provided = ei->e2di_chksum_lo; 614512f29d1SFedor Uporov calculated = ext2_ei_csum(ip, ei); 615512f29d1SFedor Uporov 616512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 617512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 618512f29d1SFedor Uporov hi = ei->e2di_chksum_hi; 619512f29d1SFedor Uporov provided |= hi << 16; 620512f29d1SFedor Uporov } else 621512f29d1SFedor Uporov calculated &= 0xFFFF; 622512f29d1SFedor Uporov 623c4aa9a02SFedor Uporov if (provided != calculated) { 624c4aa9a02SFedor Uporov /* 625c4aa9a02SFedor Uporov * If it is first time used dinode, 626c4aa9a02SFedor Uporov * it is expected that it will be zeroed 627c4aa9a02SFedor Uporov * and we will not return checksum error in this case. 628c4aa9a02SFedor Uporov */ 629c4aa9a02SFedor Uporov if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode))) 630c4aa9a02SFedor Uporov return (0); 631c4aa9a02SFedor Uporov 632512f29d1SFedor Uporov return (EIO); 633c4aa9a02SFedor Uporov } 634512f29d1SFedor Uporov 635512f29d1SFedor Uporov return (0); 636512f29d1SFedor Uporov } 637512f29d1SFedor Uporov 638512f29d1SFedor Uporov void 639512f29d1SFedor Uporov ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei) 640512f29d1SFedor Uporov { 641512f29d1SFedor Uporov struct m_ext2fs *fs; 642512f29d1SFedor Uporov uint32_t crc; 643512f29d1SFedor Uporov 644512f29d1SFedor Uporov fs = ip->i_e2fs; 645512f29d1SFedor Uporov 646512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 647512f29d1SFedor Uporov return; 648512f29d1SFedor Uporov 649512f29d1SFedor Uporov crc = ext2_ei_csum(ip, ei); 650512f29d1SFedor Uporov 651512f29d1SFedor Uporov ei->e2di_chksum_lo = crc & 0xFFFF; 652512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 653512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) 654512f29d1SFedor Uporov ei->e2di_chksum_hi = crc >> 16; 655512f29d1SFedor Uporov } 656512f29d1SFedor Uporov 657d23db91eSPedro F. Giffuni static uint16_t 658d23db91eSPedro F. Giffuni ext2_crc16(uint16_t crc, const void *buffer, unsigned int len) 659d23db91eSPedro F. Giffuni { 660d23db91eSPedro F. Giffuni const unsigned char *cp = buffer; 661d23db91eSPedro F. Giffuni /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */ 662d23db91eSPedro F. Giffuni static uint16_t const crc16_table[256] = { 663d23db91eSPedro F. Giffuni 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 664d23db91eSPedro F. Giffuni 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 665d23db91eSPedro F. Giffuni 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 666d23db91eSPedro F. Giffuni 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 667d23db91eSPedro F. Giffuni 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 668d23db91eSPedro F. Giffuni 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 669d23db91eSPedro F. Giffuni 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 670d23db91eSPedro F. Giffuni 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 671d23db91eSPedro F. Giffuni 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 672d23db91eSPedro F. Giffuni 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 673d23db91eSPedro F. Giffuni 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 674d23db91eSPedro F. Giffuni 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 675d23db91eSPedro F. Giffuni 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 676d23db91eSPedro F. Giffuni 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 677d23db91eSPedro F. Giffuni 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 678d23db91eSPedro F. Giffuni 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 679d23db91eSPedro F. Giffuni 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 680d23db91eSPedro F. Giffuni 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 681d23db91eSPedro F. Giffuni 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 682d23db91eSPedro F. Giffuni 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 683d23db91eSPedro F. Giffuni 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 684d23db91eSPedro F. Giffuni 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 685d23db91eSPedro F. Giffuni 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 686d23db91eSPedro F. Giffuni 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 687d23db91eSPedro F. Giffuni 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 688d23db91eSPedro F. Giffuni 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 689d23db91eSPedro F. Giffuni 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 690d23db91eSPedro F. Giffuni 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 691d23db91eSPedro F. Giffuni 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 692d23db91eSPedro F. Giffuni 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 693d23db91eSPedro F. Giffuni 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 694d23db91eSPedro F. Giffuni 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 695d23db91eSPedro F. Giffuni }; 696d23db91eSPedro F. Giffuni 697d23db91eSPedro F. Giffuni while (len--) 698d23db91eSPedro F. Giffuni crc = (((crc >> 8) & 0xffU) ^ 699d23db91eSPedro F. Giffuni crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; 700d23db91eSPedro F. Giffuni return crc; 701d23db91eSPedro F. Giffuni } 702d23db91eSPedro F. Giffuni 703d23db91eSPedro F. Giffuni static uint16_t 704d23db91eSPedro F. Giffuni ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd) 705d23db91eSPedro F. Giffuni { 706d23db91eSPedro F. Giffuni size_t offset; 707512f29d1SFedor Uporov uint32_t csum32; 708512f29d1SFedor Uporov uint16_t crc, dummy_csum; 709d23db91eSPedro F. Giffuni 710d23db91eSPedro F. Giffuni offset = offsetof(struct ext2_gd, ext4bgd_csum); 711d23db91eSPedro F. Giffuni 712512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 713512f29d1SFedor Uporov csum32 = calculate_crc32c(fs->e2fs_csum_seed, 714512f29d1SFedor Uporov (uint8_t *)&block_group, sizeof(block_group)); 715512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset); 716512f29d1SFedor Uporov dummy_csum = 0; 717512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum, 718512f29d1SFedor Uporov sizeof(dummy_csum)); 719512f29d1SFedor Uporov offset += sizeof(dummy_csum); 720512f29d1SFedor Uporov if (offset < fs->e2fs->e3fs_desc_size) 721512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset, 722512f29d1SFedor Uporov fs->e2fs->e3fs_desc_size - offset); 723512f29d1SFedor Uporov 724512f29d1SFedor Uporov crc = csum32 & 0xFFFF; 725512f29d1SFedor Uporov return (crc); 726512f29d1SFedor Uporov } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) { 727d23db91eSPedro F. Giffuni crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid, 728d23db91eSPedro F. Giffuni sizeof(fs->e2fs->e2fs_uuid)); 729d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)&block_group, 730d23db91eSPedro F. Giffuni sizeof(block_group)); 731d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd, offset); 732d23db91eSPedro F. Giffuni offset += sizeof(gd->ext4bgd_csum); /* skip checksum */ 733d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && 734d23db91eSPedro F. Giffuni offset < fs->e2fs->e3fs_desc_size) 735d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd + offset, 736d23db91eSPedro F. Giffuni fs->e2fs->e3fs_desc_size - offset); 737d23db91eSPedro F. Giffuni return (crc); 738d23db91eSPedro F. Giffuni } 739d23db91eSPedro F. Giffuni 740d23db91eSPedro F. Giffuni return (0); 741d23db91eSPedro F. Giffuni } 742d23db91eSPedro F. Giffuni 743d23db91eSPedro F. Giffuni int 744d23db91eSPedro F. Giffuni ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev) 745d23db91eSPedro F. Giffuni { 746d23db91eSPedro F. Giffuni unsigned int i; 747d23db91eSPedro F. Giffuni int error = 0; 748d23db91eSPedro F. Giffuni 749d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) { 750d23db91eSPedro F. Giffuni if (fs->e2fs_gd[i].ext4bgd_csum != 751d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) { 752d23db91eSPedro F. Giffuni printf( 753d23db91eSPedro F. Giffuni "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n", 754d23db91eSPedro F. Giffuni devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum, 755d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])); 756512f29d1SFedor Uporov error = EIO; 757d23db91eSPedro F. Giffuni break; 758d23db91eSPedro F. Giffuni } 759d23db91eSPedro F. Giffuni } 760d23db91eSPedro F. Giffuni 761d23db91eSPedro F. Giffuni return (error); 762d23db91eSPedro F. Giffuni } 763d23db91eSPedro F. Giffuni 764d23db91eSPedro F. Giffuni void 765d23db91eSPedro F. Giffuni ext2_gd_csum_set(struct m_ext2fs *fs) 766d23db91eSPedro F. Giffuni { 767d23db91eSPedro F. Giffuni unsigned int i; 768d23db91eSPedro F. Giffuni 769d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) 770d23db91eSPedro F. Giffuni fs->e2fs_gd[i].ext4bgd_csum = 771d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i]); 772d23db91eSPedro F. Giffuni } 773