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> 46*512f29d1SFedor Uporov #include <fs/ext2fs/ext2_dinode.h> 47d23db91eSPedro F. Giffuni #include <fs/ext2fs/inode.h> 48*512f29d1SFedor Uporov #include <fs/ext2fs/ext2_dir.h> 49*512f29d1SFedor Uporov #include <fs/ext2fs/htree.h> 50*512f29d1SFedor Uporov #include <fs/ext2fs/ext2_extattr.h> 51d23db91eSPedro F. Giffuni #include <fs/ext2fs/ext2_extern.h> 52d23db91eSPedro F. Giffuni 53*512f29d1SFedor Uporov #define EXT2_BG_INODE_BITMAP_CSUM_HI_END \ 54*512f29d1SFedor Uporov (offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \ 55*512f29d1SFedor Uporov sizeof(uint16_t)) 56*512f29d1SFedor Uporov 57*512f29d1SFedor Uporov #define EXT2_INODE_CSUM_HI_EXTRA_END \ 58*512f29d1SFedor Uporov (offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \ 59*512f29d1SFedor Uporov E2FS_REV0_INODE_SIZE) 60*512f29d1SFedor Uporov 61*512f29d1SFedor Uporov #define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \ 62*512f29d1SFedor Uporov (offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \ 63*512f29d1SFedor Uporov sizeof(uint16_t)) 64*512f29d1SFedor Uporov 65*512f29d1SFedor Uporov void 66*512f29d1SFedor Uporov ext2_sb_csum_set_seed(struct m_ext2fs *fs) 67*512f29d1SFedor Uporov { 68*512f29d1SFedor Uporov 69*512f29d1SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED)) 70*512f29d1SFedor Uporov fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed; 71*512f29d1SFedor Uporov else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 72*512f29d1SFedor Uporov fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid, 73*512f29d1SFedor Uporov sizeof(fs->e2fs->e2fs_uuid)); 74*512f29d1SFedor Uporov } 75*512f29d1SFedor Uporov else 76*512f29d1SFedor Uporov fs->e2fs_csum_seed = 0; 77*512f29d1SFedor Uporov } 78*512f29d1SFedor Uporov 79*512f29d1SFedor Uporov int 80*512f29d1SFedor Uporov ext2_sb_csum_verify(struct m_ext2fs *fs) 81*512f29d1SFedor Uporov { 82*512f29d1SFedor Uporov 83*512f29d1SFedor Uporov if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) { 84*512f29d1SFedor Uporov printf( 85*512f29d1SFedor Uporov "WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt); 86*512f29d1SFedor Uporov return (EINVAL); 87*512f29d1SFedor Uporov } 88*512f29d1SFedor Uporov if (fs->e2fs->e4fs_sbchksum != 89*512f29d1SFedor Uporov calculate_crc32c(~0, (const char *)fs->e2fs, 90*512f29d1SFedor Uporov offsetof(struct ext2fs, e4fs_sbchksum))) { 91*512f29d1SFedor Uporov printf( 92*512f29d1SFedor Uporov "WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n", 93*512f29d1SFedor Uporov fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0, 94*512f29d1SFedor Uporov (const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum))); 95*512f29d1SFedor Uporov return (EINVAL); 96*512f29d1SFedor Uporov } 97*512f29d1SFedor Uporov 98*512f29d1SFedor Uporov return (0); 99*512f29d1SFedor Uporov } 100*512f29d1SFedor Uporov 101*512f29d1SFedor Uporov void 102*512f29d1SFedor Uporov ext2_sb_csum_set(struct m_ext2fs *fs) 103*512f29d1SFedor Uporov { 104*512f29d1SFedor Uporov 105*512f29d1SFedor Uporov fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs, 106*512f29d1SFedor Uporov offsetof(struct ext2fs, e4fs_sbchksum)); 107*512f29d1SFedor Uporov } 108*512f29d1SFedor Uporov 109*512f29d1SFedor Uporov static uint32_t 110*512f29d1SFedor Uporov ext2_extattr_blk_csum(struct inode *ip, uint64_t facl, 111*512f29d1SFedor Uporov struct ext2fs_extattr_header *header) 112*512f29d1SFedor Uporov { 113*512f29d1SFedor Uporov struct m_ext2fs *fs; 114*512f29d1SFedor Uporov uint32_t crc, old_crc; 115*512f29d1SFedor Uporov 116*512f29d1SFedor Uporov fs = ip->i_e2fs; 117*512f29d1SFedor Uporov 118*512f29d1SFedor Uporov old_crc = header->h_checksum; 119*512f29d1SFedor Uporov 120*512f29d1SFedor Uporov header->h_checksum = 0; 121*512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl)); 122*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize); 123*512f29d1SFedor Uporov header->h_checksum = old_crc; 124*512f29d1SFedor Uporov 125*512f29d1SFedor Uporov return (crc); 126*512f29d1SFedor Uporov } 127*512f29d1SFedor Uporov 128*512f29d1SFedor Uporov int 129*512f29d1SFedor Uporov ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp) 130*512f29d1SFedor Uporov { 131*512f29d1SFedor Uporov struct ext2fs_extattr_header *header; 132*512f29d1SFedor Uporov 133*512f29d1SFedor Uporov header = (struct ext2fs_extattr_header *)bp->b_data; 134*512f29d1SFedor Uporov 135*512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) && 136*512f29d1SFedor Uporov (header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) { 137*512f29d1SFedor Uporov printf("WARNING: bad extattr csum detected, ip=%lu - run fsck\n", 138*512f29d1SFedor Uporov (unsigned long)ip->i_number); 139*512f29d1SFedor Uporov return (EIO); 140*512f29d1SFedor Uporov } 141*512f29d1SFedor Uporov 142*512f29d1SFedor Uporov return (0); 143*512f29d1SFedor Uporov } 144*512f29d1SFedor Uporov 145*512f29d1SFedor Uporov void 146*512f29d1SFedor Uporov ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp) 147*512f29d1SFedor Uporov { 148*512f29d1SFedor Uporov struct ext2fs_extattr_header *header; 149*512f29d1SFedor Uporov 150*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 151*512f29d1SFedor Uporov return; 152*512f29d1SFedor Uporov 153*512f29d1SFedor Uporov header = (struct ext2fs_extattr_header *)bp->b_data; 154*512f29d1SFedor Uporov header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header); 155*512f29d1SFedor Uporov } 156*512f29d1SFedor Uporov 157*512f29d1SFedor Uporov static struct ext2fs_direct_tail * 158*512f29d1SFedor Uporov ext2_get_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep) 159*512f29d1SFedor Uporov { 160*512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 161*512f29d1SFedor Uporov 162*512f29d1SFedor Uporov tp = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize); 163*512f29d1SFedor Uporov if (tp->e2dt_reserved_zero1 || 164*512f29d1SFedor Uporov tp->e2dt_rec_len != sizeof(struct ext2fs_direct_tail) || 165*512f29d1SFedor Uporov tp->e2dt_reserved_zero2 || 166*512f29d1SFedor Uporov tp->e2dt_reserved_ft != EXT2_FT_DIR_CSUM) 167*512f29d1SFedor Uporov return (NULL); 168*512f29d1SFedor Uporov 169*512f29d1SFedor Uporov return (tp); 170*512f29d1SFedor Uporov } 171*512f29d1SFedor Uporov 172*512f29d1SFedor Uporov static uint32_t 173*512f29d1SFedor Uporov ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size) 174*512f29d1SFedor Uporov { 175*512f29d1SFedor Uporov struct m_ext2fs *fs; 176*512f29d1SFedor Uporov char *buf; 177*512f29d1SFedor Uporov uint32_t inum, gen, crc; 178*512f29d1SFedor Uporov 179*512f29d1SFedor Uporov fs = ip->i_e2fs; 180*512f29d1SFedor Uporov 181*512f29d1SFedor Uporov buf = (char *)ep; 182*512f29d1SFedor Uporov 183*512f29d1SFedor Uporov inum = ip->i_number; 184*512f29d1SFedor Uporov gen = ip->i_gen; 185*512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 186*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 187*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 188*512f29d1SFedor Uporov 189*512f29d1SFedor Uporov return (crc); 190*512f29d1SFedor Uporov } 191*512f29d1SFedor Uporov 192*512f29d1SFedor Uporov static int 193*512f29d1SFedor Uporov ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 194*512f29d1SFedor Uporov { 195*512f29d1SFedor Uporov uint32_t calculated; 196*512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 197*512f29d1SFedor Uporov 198*512f29d1SFedor Uporov tp = ext2_get_dirent_tail(ip, ep); 199*512f29d1SFedor Uporov if (tp == NULL) 200*512f29d1SFedor Uporov return (0); 201*512f29d1SFedor Uporov 202*512f29d1SFedor Uporov calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 203*512f29d1SFedor Uporov if (calculated != tp->e2dt_checksum) 204*512f29d1SFedor Uporov return (EIO); 205*512f29d1SFedor Uporov 206*512f29d1SFedor Uporov return (0); 207*512f29d1SFedor Uporov } 208*512f29d1SFedor Uporov 209*512f29d1SFedor Uporov static struct ext2fs_htree_count * 210*512f29d1SFedor Uporov ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset) 211*512f29d1SFedor Uporov { 212*512f29d1SFedor Uporov struct ext2fs_direct_2 *dp; 213*512f29d1SFedor Uporov struct ext2fs_htree_root_info *root; 214*512f29d1SFedor Uporov int count_offset; 215*512f29d1SFedor Uporov 216*512f29d1SFedor Uporov if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs)) 217*512f29d1SFedor Uporov count_offset = 8; 218*512f29d1SFedor Uporov else if (ep->e2d_reclen == 12) { 219*512f29d1SFedor Uporov dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12); 220*512f29d1SFedor Uporov if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12) 221*512f29d1SFedor Uporov return (NULL); 222*512f29d1SFedor Uporov 223*512f29d1SFedor Uporov root = (struct ext2fs_htree_root_info *)(((char *)dp + 12)); 224*512f29d1SFedor Uporov if (root->h_reserved1 || 225*512f29d1SFedor Uporov root->h_info_len != sizeof(struct ext2fs_htree_root_info)) 226*512f29d1SFedor Uporov return (NULL); 227*512f29d1SFedor Uporov 228*512f29d1SFedor Uporov count_offset = 32; 229*512f29d1SFedor Uporov } else 230*512f29d1SFedor Uporov return (NULL); 231*512f29d1SFedor Uporov 232*512f29d1SFedor Uporov if (offset) 233*512f29d1SFedor Uporov *offset = count_offset; 234*512f29d1SFedor Uporov 235*512f29d1SFedor Uporov return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset)); 236*512f29d1SFedor Uporov } 237*512f29d1SFedor Uporov 238*512f29d1SFedor Uporov static uint32_t 239*512f29d1SFedor Uporov ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset, 240*512f29d1SFedor Uporov int count, struct ext2fs_htree_tail *tp) 241*512f29d1SFedor Uporov { 242*512f29d1SFedor Uporov struct m_ext2fs *fs; 243*512f29d1SFedor Uporov char *buf; 244*512f29d1SFedor Uporov int size; 245*512f29d1SFedor Uporov uint32_t inum, old_csum, gen, crc; 246*512f29d1SFedor Uporov 247*512f29d1SFedor Uporov fs = ip->i_e2fs; 248*512f29d1SFedor Uporov 249*512f29d1SFedor Uporov buf = (char *)ep; 250*512f29d1SFedor Uporov 251*512f29d1SFedor Uporov size = count_offset + (count * sizeof(struct ext2fs_htree_entry)); 252*512f29d1SFedor Uporov old_csum = tp->ht_checksum; 253*512f29d1SFedor Uporov tp->ht_checksum = 0; 254*512f29d1SFedor Uporov 255*512f29d1SFedor Uporov inum = ip->i_number; 256*512f29d1SFedor Uporov gen = ip->i_gen; 257*512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 258*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 259*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 260*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail)); 261*512f29d1SFedor Uporov tp->ht_checksum = old_csum; 262*512f29d1SFedor Uporov 263*512f29d1SFedor Uporov return (crc); 264*512f29d1SFedor Uporov } 265*512f29d1SFedor Uporov 266*512f29d1SFedor Uporov static int 267*512f29d1SFedor Uporov ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 268*512f29d1SFedor Uporov { 269*512f29d1SFedor Uporov uint32_t calculated; 270*512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 271*512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 272*512f29d1SFedor Uporov int count_offset, limit, count; 273*512f29d1SFedor Uporov 274*512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 275*512f29d1SFedor Uporov if (cp == NULL) 276*512f29d1SFedor Uporov return (0); 277*512f29d1SFedor Uporov 278*512f29d1SFedor Uporov limit = cp->h_entries_max; 279*512f29d1SFedor Uporov count = cp->h_entries_num; 280*512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 281*512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 282*512f29d1SFedor Uporov return (EIO); 283*512f29d1SFedor Uporov 284*512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 285*512f29d1SFedor Uporov calculated = ext2_dx_csum(ip, ep, count_offset, count, tp); 286*512f29d1SFedor Uporov 287*512f29d1SFedor Uporov if (tp->ht_checksum != calculated) 288*512f29d1SFedor Uporov return (EIO); 289*512f29d1SFedor Uporov 290*512f29d1SFedor Uporov return (0); 291*512f29d1SFedor Uporov } 292*512f29d1SFedor Uporov 293*512f29d1SFedor Uporov int 294*512f29d1SFedor Uporov ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp) 295*512f29d1SFedor Uporov { 296*512f29d1SFedor Uporov struct m_ext2fs *fs; 297*512f29d1SFedor Uporov struct ext2fs_direct_2 *ep; 298*512f29d1SFedor Uporov int error = 0; 299*512f29d1SFedor Uporov 300*512f29d1SFedor Uporov fs = ip->i_e2fs; 301*512f29d1SFedor Uporov 302*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 303*512f29d1SFedor Uporov return (error); 304*512f29d1SFedor Uporov 305*512f29d1SFedor Uporov ep = (struct ext2fs_direct_2 *)bp->b_data; 306*512f29d1SFedor Uporov 307*512f29d1SFedor Uporov if (ext2_get_dirent_tail(ip, ep) != NULL) 308*512f29d1SFedor Uporov error = ext2_dirent_csum_verify(ip, ep); 309*512f29d1SFedor Uporov else if (ext2_get_dx_count(ip, ep, NULL) != NULL) 310*512f29d1SFedor Uporov error = ext2_dx_csum_verify(ip, ep); 311*512f29d1SFedor Uporov 312*512f29d1SFedor Uporov if (error) 313*512f29d1SFedor Uporov printf("WARNING: bad directory csum detected, ip=%lu" 314*512f29d1SFedor Uporov " - run fsck\n", (unsigned long)ip->i_number); 315*512f29d1SFedor Uporov 316*512f29d1SFedor Uporov return (error); 317*512f29d1SFedor Uporov } 318*512f29d1SFedor Uporov 319*512f29d1SFedor Uporov static void 320*512f29d1SFedor Uporov ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 321*512f29d1SFedor Uporov { 322*512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 323*512f29d1SFedor Uporov 324*512f29d1SFedor Uporov tp = ext2_get_dirent_tail(ip, ep); 325*512f29d1SFedor Uporov if (tp == NULL) 326*512f29d1SFedor Uporov return; 327*512f29d1SFedor Uporov 328*512f29d1SFedor Uporov tp->e2dt_checksum = 329*512f29d1SFedor Uporov ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 330*512f29d1SFedor Uporov } 331*512f29d1SFedor Uporov 332*512f29d1SFedor Uporov static void 333*512f29d1SFedor Uporov ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 334*512f29d1SFedor Uporov { 335*512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 336*512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 337*512f29d1SFedor Uporov int count_offset, limit, count; 338*512f29d1SFedor Uporov 339*512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 340*512f29d1SFedor Uporov if (cp == NULL) 341*512f29d1SFedor Uporov return; 342*512f29d1SFedor Uporov 343*512f29d1SFedor Uporov limit = cp->h_entries_max; 344*512f29d1SFedor Uporov count = cp->h_entries_num; 345*512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 346*512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 347*512f29d1SFedor Uporov return; 348*512f29d1SFedor Uporov 349*512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 350*512f29d1SFedor Uporov tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp); 351*512f29d1SFedor Uporov } 352*512f29d1SFedor Uporov 353*512f29d1SFedor Uporov void 354*512f29d1SFedor Uporov ext2_dir_blk_csum_set_mem(struct inode *ip, char *buf, int size) 355*512f29d1SFedor Uporov { 356*512f29d1SFedor Uporov struct m_ext2fs *fs; 357*512f29d1SFedor Uporov struct ext2fs_direct_2 *ep; 358*512f29d1SFedor Uporov 359*512f29d1SFedor Uporov fs = ip->i_e2fs; 360*512f29d1SFedor Uporov 361*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 362*512f29d1SFedor Uporov return; 363*512f29d1SFedor Uporov 364*512f29d1SFedor Uporov ep = (struct ext2fs_direct_2 *)buf; 365*512f29d1SFedor Uporov 366*512f29d1SFedor Uporov if (ext2_htree_has_idx(ip)) { 367*512f29d1SFedor Uporov if (ext2_get_dx_count(ip, ep, NULL) != NULL) 368*512f29d1SFedor Uporov ext2_dx_csum_set(ip, ep); 369*512f29d1SFedor Uporov } else { 370*512f29d1SFedor Uporov if (ext2_get_dirent_tail(ip, ep) != NULL) 371*512f29d1SFedor Uporov ext2_dirent_csum_set(ip, ep); 372*512f29d1SFedor Uporov } 373*512f29d1SFedor Uporov } 374*512f29d1SFedor Uporov 375*512f29d1SFedor Uporov void 376*512f29d1SFedor Uporov ext2_dir_blk_csum_set(struct inode *ip, struct buf *bp) 377*512f29d1SFedor Uporov { 378*512f29d1SFedor Uporov 379*512f29d1SFedor Uporov ext2_dir_blk_csum_set_mem(ip, bp->b_data, bp->b_bufsize); 380*512f29d1SFedor Uporov } 381*512f29d1SFedor Uporov 382*512f29d1SFedor Uporov static uint32_t 383*512f29d1SFedor Uporov ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp) 384*512f29d1SFedor Uporov { 385*512f29d1SFedor Uporov struct m_ext2fs *fs; 386*512f29d1SFedor Uporov size_t size; 387*512f29d1SFedor Uporov uint32_t inum, gen, crc; 388*512f29d1SFedor Uporov 389*512f29d1SFedor Uporov fs = ip->i_e2fs; 390*512f29d1SFedor Uporov 391*512f29d1SFedor Uporov size = EXT4_EXTENT_TAIL_OFFSET(ehp) + 392*512f29d1SFedor Uporov offsetof(struct ext4_extent_tail, et_checksum); 393*512f29d1SFedor Uporov 394*512f29d1SFedor Uporov inum = ip->i_number; 395*512f29d1SFedor Uporov gen = ip->i_gen; 396*512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 397*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 398*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ehp, size); 399*512f29d1SFedor Uporov 400*512f29d1SFedor Uporov return (crc); 401*512f29d1SFedor Uporov } 402*512f29d1SFedor Uporov 403*512f29d1SFedor Uporov int 404*512f29d1SFedor Uporov ext2_extent_blk_csum_verify(struct inode *ip, void *data) 405*512f29d1SFedor Uporov { 406*512f29d1SFedor Uporov struct m_ext2fs *fs; 407*512f29d1SFedor Uporov struct ext4_extent_header *ehp; 408*512f29d1SFedor Uporov struct ext4_extent_tail *etp; 409*512f29d1SFedor Uporov uint32_t provided, calculated; 410*512f29d1SFedor Uporov 411*512f29d1SFedor Uporov fs = ip->i_e2fs; 412*512f29d1SFedor Uporov 413*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 414*512f29d1SFedor Uporov return (0); 415*512f29d1SFedor Uporov 416*512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 417*512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)ehp) + 418*512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 419*512f29d1SFedor Uporov 420*512f29d1SFedor Uporov provided = etp->et_checksum; 421*512f29d1SFedor Uporov calculated = ext2_extent_blk_csum(ip, ehp); 422*512f29d1SFedor Uporov 423*512f29d1SFedor Uporov if (provided != calculated) { 424*512f29d1SFedor Uporov printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n", 425*512f29d1SFedor Uporov (unsigned long)ip->i_number); 426*512f29d1SFedor Uporov return (EIO); 427*512f29d1SFedor Uporov } 428*512f29d1SFedor Uporov 429*512f29d1SFedor Uporov return (0); 430*512f29d1SFedor Uporov } 431*512f29d1SFedor Uporov 432*512f29d1SFedor Uporov void 433*512f29d1SFedor Uporov ext2_extent_blk_csum_set(struct inode *ip, void *data) 434*512f29d1SFedor Uporov { 435*512f29d1SFedor Uporov struct m_ext2fs *fs; 436*512f29d1SFedor Uporov struct ext4_extent_header *ehp; 437*512f29d1SFedor Uporov struct ext4_extent_tail *etp; 438*512f29d1SFedor Uporov 439*512f29d1SFedor Uporov fs = ip->i_e2fs; 440*512f29d1SFedor Uporov 441*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 442*512f29d1SFedor Uporov return; 443*512f29d1SFedor Uporov 444*512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 445*512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)data) + 446*512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 447*512f29d1SFedor Uporov 448*512f29d1SFedor Uporov etp->et_checksum = ext2_extent_blk_csum(ip, 449*512f29d1SFedor Uporov (struct ext4_extent_header *)data); 450*512f29d1SFedor Uporov } 451*512f29d1SFedor Uporov 452*512f29d1SFedor Uporov int 453*512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 454*512f29d1SFedor Uporov { 455*512f29d1SFedor Uporov uint32_t hi, provided, calculated; 456*512f29d1SFedor Uporov 457*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 458*512f29d1SFedor Uporov return (0); 459*512f29d1SFedor Uporov 460*512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum; 461*512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 462*512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 463*512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) { 464*512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi; 465*512f29d1SFedor Uporov provided |= (hi << 16); 466*512f29d1SFedor Uporov } else 467*512f29d1SFedor Uporov calculated &= 0xFFFF; 468*512f29d1SFedor Uporov 469*512f29d1SFedor Uporov if (provided != calculated) { 470*512f29d1SFedor Uporov printf("WARNING: bad inode bitmap csum detected, " 471*512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 472*512f29d1SFedor Uporov return (EIO); 473*512f29d1SFedor Uporov } 474*512f29d1SFedor Uporov 475*512f29d1SFedor Uporov return (0); 476*512f29d1SFedor Uporov } 477*512f29d1SFedor Uporov 478*512f29d1SFedor Uporov void 479*512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 480*512f29d1SFedor Uporov { 481*512f29d1SFedor Uporov uint32_t csum; 482*512f29d1SFedor Uporov 483*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 484*512f29d1SFedor Uporov return; 485*512f29d1SFedor Uporov 486*512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 487*512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 488*512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF; 489*512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) 490*512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16; 491*512f29d1SFedor Uporov } 492*512f29d1SFedor Uporov 493*512f29d1SFedor Uporov int 494*512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 495*512f29d1SFedor Uporov { 496*512f29d1SFedor Uporov uint32_t hi, provided, calculated, size; 497*512f29d1SFedor Uporov 498*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 499*512f29d1SFedor Uporov return (0); 500*512f29d1SFedor Uporov 501*512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 502*512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum; 503*512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 504*512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) { 505*512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi; 506*512f29d1SFedor Uporov provided |= (hi << 16); 507*512f29d1SFedor Uporov } else 508*512f29d1SFedor Uporov calculated &= 0xFFFF; 509*512f29d1SFedor Uporov 510*512f29d1SFedor Uporov if (provided != calculated) { 511*512f29d1SFedor Uporov printf("WARNING: bad block bitmap csum detected, " 512*512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 513*512f29d1SFedor Uporov return (EIO); 514*512f29d1SFedor Uporov } 515*512f29d1SFedor Uporov 516*512f29d1SFedor Uporov return (0); 517*512f29d1SFedor Uporov } 518*512f29d1SFedor Uporov 519*512f29d1SFedor Uporov void 520*512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 521*512f29d1SFedor Uporov { 522*512f29d1SFedor Uporov uint32_t csum, size; 523*512f29d1SFedor Uporov 524*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 525*512f29d1SFedor Uporov return; 526*512f29d1SFedor Uporov 527*512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 528*512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 529*512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF; 530*512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) 531*512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16; 532*512f29d1SFedor Uporov } 533*512f29d1SFedor Uporov 534*512f29d1SFedor Uporov static uint32_t 535*512f29d1SFedor Uporov ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei) 536*512f29d1SFedor Uporov { 537*512f29d1SFedor Uporov struct m_ext2fs *fs; 538*512f29d1SFedor Uporov uint16_t old_lo, old_hi; 539*512f29d1SFedor Uporov uint32_t inum, gen, crc; 540*512f29d1SFedor Uporov 541*512f29d1SFedor Uporov fs = ip->i_e2fs; 542*512f29d1SFedor Uporov 543*512f29d1SFedor Uporov old_lo = ei->e2di_chksum_lo; 544*512f29d1SFedor Uporov ei->e2di_chksum_lo = 0; 545*512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE && 546*512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 547*512f29d1SFedor Uporov old_hi = ei->e2di_chksum_hi; 548*512f29d1SFedor Uporov ei->e2di_chksum_hi = 0; 549*512f29d1SFedor Uporov } 550*512f29d1SFedor Uporov 551*512f29d1SFedor Uporov inum = ip->i_number; 552*512f29d1SFedor Uporov gen = ip->i_gen; 553*512f29d1SFedor Uporov 554*512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 555*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 556*512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei, fs->e2fs->e2fs_inode_size); 557*512f29d1SFedor Uporov 558*512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 559*512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) 560*512f29d1SFedor Uporov ei->e2di_chksum_hi = old_hi; 561*512f29d1SFedor Uporov 562*512f29d1SFedor Uporov return (crc); 563*512f29d1SFedor Uporov } 564*512f29d1SFedor Uporov 565*512f29d1SFedor Uporov int 566*512f29d1SFedor Uporov ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei) 567*512f29d1SFedor Uporov { 568*512f29d1SFedor Uporov struct m_ext2fs *fs; 569*512f29d1SFedor Uporov const static struct ext2fs_dinode ei_zero; 570*512f29d1SFedor Uporov uint32_t hi, provided, calculated; 571*512f29d1SFedor Uporov 572*512f29d1SFedor Uporov fs = ip->i_e2fs; 573*512f29d1SFedor Uporov 574*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 575*512f29d1SFedor Uporov return (0); 576*512f29d1SFedor Uporov 577*512f29d1SFedor Uporov /* Check case, when dinode was not initialized */ 578*512f29d1SFedor Uporov if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode))) 579*512f29d1SFedor Uporov return (0); 580*512f29d1SFedor Uporov 581*512f29d1SFedor Uporov provided = ei->e2di_chksum_lo; 582*512f29d1SFedor Uporov calculated = ext2_ei_csum(ip, ei); 583*512f29d1SFedor Uporov 584*512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 585*512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 586*512f29d1SFedor Uporov hi = ei->e2di_chksum_hi; 587*512f29d1SFedor Uporov provided |= hi << 16; 588*512f29d1SFedor Uporov } else 589*512f29d1SFedor Uporov calculated &= 0xFFFF; 590*512f29d1SFedor Uporov 591*512f29d1SFedor Uporov if (provided != calculated) 592*512f29d1SFedor Uporov return (EIO); 593*512f29d1SFedor Uporov 594*512f29d1SFedor Uporov return (0); 595*512f29d1SFedor Uporov } 596*512f29d1SFedor Uporov 597*512f29d1SFedor Uporov void 598*512f29d1SFedor Uporov ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei) 599*512f29d1SFedor Uporov { 600*512f29d1SFedor Uporov struct m_ext2fs *fs; 601*512f29d1SFedor Uporov uint32_t crc; 602*512f29d1SFedor Uporov 603*512f29d1SFedor Uporov fs = ip->i_e2fs; 604*512f29d1SFedor Uporov 605*512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 606*512f29d1SFedor Uporov return; 607*512f29d1SFedor Uporov 608*512f29d1SFedor Uporov crc = ext2_ei_csum(ip, ei); 609*512f29d1SFedor Uporov 610*512f29d1SFedor Uporov ei->e2di_chksum_lo = crc & 0xFFFF; 611*512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 612*512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) 613*512f29d1SFedor Uporov ei->e2di_chksum_hi = crc >> 16; 614*512f29d1SFedor Uporov } 615*512f29d1SFedor Uporov 616d23db91eSPedro F. Giffuni static uint16_t 617d23db91eSPedro F. Giffuni ext2_crc16(uint16_t crc, const void *buffer, unsigned int len) 618d23db91eSPedro F. Giffuni { 619d23db91eSPedro F. Giffuni const unsigned char *cp = buffer; 620d23db91eSPedro F. Giffuni /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */ 621d23db91eSPedro F. Giffuni static uint16_t const crc16_table[256] = { 622d23db91eSPedro F. Giffuni 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 623d23db91eSPedro F. Giffuni 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 624d23db91eSPedro F. Giffuni 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 625d23db91eSPedro F. Giffuni 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 626d23db91eSPedro F. Giffuni 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 627d23db91eSPedro F. Giffuni 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 628d23db91eSPedro F. Giffuni 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 629d23db91eSPedro F. Giffuni 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 630d23db91eSPedro F. Giffuni 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 631d23db91eSPedro F. Giffuni 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 632d23db91eSPedro F. Giffuni 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 633d23db91eSPedro F. Giffuni 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 634d23db91eSPedro F. Giffuni 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 635d23db91eSPedro F. Giffuni 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 636d23db91eSPedro F. Giffuni 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 637d23db91eSPedro F. Giffuni 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 638d23db91eSPedro F. Giffuni 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 639d23db91eSPedro F. Giffuni 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 640d23db91eSPedro F. Giffuni 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 641d23db91eSPedro F. Giffuni 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 642d23db91eSPedro F. Giffuni 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 643d23db91eSPedro F. Giffuni 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 644d23db91eSPedro F. Giffuni 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 645d23db91eSPedro F. Giffuni 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 646d23db91eSPedro F. Giffuni 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 647d23db91eSPedro F. Giffuni 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 648d23db91eSPedro F. Giffuni 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 649d23db91eSPedro F. Giffuni 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 650d23db91eSPedro F. Giffuni 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 651d23db91eSPedro F. Giffuni 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 652d23db91eSPedro F. Giffuni 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 653d23db91eSPedro F. Giffuni 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 654d23db91eSPedro F. Giffuni }; 655d23db91eSPedro F. Giffuni 656d23db91eSPedro F. Giffuni while (len--) 657d23db91eSPedro F. Giffuni crc = (((crc >> 8) & 0xffU) ^ 658d23db91eSPedro F. Giffuni crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; 659d23db91eSPedro F. Giffuni return crc; 660d23db91eSPedro F. Giffuni } 661d23db91eSPedro F. Giffuni 662d23db91eSPedro F. Giffuni static uint16_t 663d23db91eSPedro F. Giffuni ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd) 664d23db91eSPedro F. Giffuni { 665d23db91eSPedro F. Giffuni size_t offset; 666*512f29d1SFedor Uporov uint32_t csum32; 667*512f29d1SFedor Uporov uint16_t crc, dummy_csum; 668d23db91eSPedro F. Giffuni 669d23db91eSPedro F. Giffuni offset = offsetof(struct ext2_gd, ext4bgd_csum); 670d23db91eSPedro F. Giffuni 671*512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 672*512f29d1SFedor Uporov csum32 = calculate_crc32c(fs->e2fs_csum_seed, 673*512f29d1SFedor Uporov (uint8_t *)&block_group, sizeof(block_group)); 674*512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset); 675*512f29d1SFedor Uporov dummy_csum = 0; 676*512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum, 677*512f29d1SFedor Uporov sizeof(dummy_csum)); 678*512f29d1SFedor Uporov offset += sizeof(dummy_csum); 679*512f29d1SFedor Uporov if (offset < fs->e2fs->e3fs_desc_size) 680*512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset, 681*512f29d1SFedor Uporov fs->e2fs->e3fs_desc_size - offset); 682*512f29d1SFedor Uporov 683*512f29d1SFedor Uporov crc = csum32 & 0xFFFF; 684*512f29d1SFedor Uporov return (crc); 685*512f29d1SFedor Uporov } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) { 686d23db91eSPedro F. Giffuni crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid, 687d23db91eSPedro F. Giffuni sizeof(fs->e2fs->e2fs_uuid)); 688d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)&block_group, 689d23db91eSPedro F. Giffuni sizeof(block_group)); 690d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd, offset); 691d23db91eSPedro F. Giffuni offset += sizeof(gd->ext4bgd_csum); /* skip checksum */ 692d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && 693d23db91eSPedro F. Giffuni offset < fs->e2fs->e3fs_desc_size) 694d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd + offset, 695d23db91eSPedro F. Giffuni fs->e2fs->e3fs_desc_size - offset); 696d23db91eSPedro F. Giffuni return (crc); 697d23db91eSPedro F. Giffuni } 698d23db91eSPedro F. Giffuni 699d23db91eSPedro F. Giffuni return (0); 700d23db91eSPedro F. Giffuni } 701d23db91eSPedro F. Giffuni 702d23db91eSPedro F. Giffuni int 703d23db91eSPedro F. Giffuni ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev) 704d23db91eSPedro F. Giffuni { 705d23db91eSPedro F. Giffuni unsigned int i; 706d23db91eSPedro F. Giffuni int error = 0; 707d23db91eSPedro F. Giffuni 708d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) { 709d23db91eSPedro F. Giffuni if (fs->e2fs_gd[i].ext4bgd_csum != 710d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) { 711d23db91eSPedro F. Giffuni printf( 712d23db91eSPedro F. Giffuni "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n", 713d23db91eSPedro F. Giffuni devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum, 714d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])); 715*512f29d1SFedor Uporov error = EIO; 716d23db91eSPedro F. Giffuni break; 717d23db91eSPedro F. Giffuni } 718d23db91eSPedro F. Giffuni } 719d23db91eSPedro F. Giffuni 720d23db91eSPedro F. Giffuni return (error); 721d23db91eSPedro F. Giffuni } 722d23db91eSPedro F. Giffuni 723d23db91eSPedro F. Giffuni void 724d23db91eSPedro F. Giffuni ext2_gd_csum_set(struct m_ext2fs *fs) 725d23db91eSPedro F. Giffuni { 726d23db91eSPedro F. Giffuni unsigned int i; 727d23db91eSPedro F. Giffuni 728d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) 729d23db91eSPedro F. Giffuni fs->e2fs_gd[i].ext4bgd_csum = 730d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i]); 731d23db91eSPedro F. Giffuni } 732