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 157512f29d1SFedor Uporov static struct ext2fs_direct_tail * 158512f29d1SFedor Uporov ext2_get_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep) 159512f29d1SFedor Uporov { 160512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 161512f29d1SFedor Uporov 162512f29d1SFedor Uporov tp = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize); 163512f29d1SFedor Uporov if (tp->e2dt_reserved_zero1 || 164512f29d1SFedor Uporov tp->e2dt_rec_len != sizeof(struct ext2fs_direct_tail) || 165512f29d1SFedor Uporov tp->e2dt_reserved_zero2 || 166512f29d1SFedor Uporov tp->e2dt_reserved_ft != EXT2_FT_DIR_CSUM) 167512f29d1SFedor Uporov return (NULL); 168512f29d1SFedor Uporov 169512f29d1SFedor Uporov return (tp); 170512f29d1SFedor Uporov } 171512f29d1SFedor Uporov 172512f29d1SFedor Uporov static uint32_t 173512f29d1SFedor Uporov ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size) 174512f29d1SFedor Uporov { 175512f29d1SFedor Uporov struct m_ext2fs *fs; 176512f29d1SFedor Uporov char *buf; 177512f29d1SFedor Uporov uint32_t inum, gen, crc; 178512f29d1SFedor Uporov 179512f29d1SFedor Uporov fs = ip->i_e2fs; 180512f29d1SFedor Uporov 181512f29d1SFedor Uporov buf = (char *)ep; 182512f29d1SFedor Uporov 183512f29d1SFedor Uporov inum = ip->i_number; 184512f29d1SFedor Uporov gen = ip->i_gen; 185512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 186512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 187512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 188512f29d1SFedor Uporov 189512f29d1SFedor Uporov return (crc); 190512f29d1SFedor Uporov } 191512f29d1SFedor Uporov 192512f29d1SFedor Uporov static int 193512f29d1SFedor Uporov ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 194512f29d1SFedor Uporov { 195512f29d1SFedor Uporov uint32_t calculated; 196512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 197512f29d1SFedor Uporov 198512f29d1SFedor Uporov tp = ext2_get_dirent_tail(ip, ep); 199512f29d1SFedor Uporov if (tp == NULL) 200512f29d1SFedor Uporov return (0); 201512f29d1SFedor Uporov 202512f29d1SFedor Uporov calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 203512f29d1SFedor Uporov if (calculated != tp->e2dt_checksum) 204512f29d1SFedor Uporov return (EIO); 205512f29d1SFedor Uporov 206512f29d1SFedor Uporov return (0); 207512f29d1SFedor Uporov } 208512f29d1SFedor Uporov 209512f29d1SFedor Uporov static struct ext2fs_htree_count * 210512f29d1SFedor Uporov ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset) 211512f29d1SFedor Uporov { 212512f29d1SFedor Uporov struct ext2fs_direct_2 *dp; 213512f29d1SFedor Uporov struct ext2fs_htree_root_info *root; 214512f29d1SFedor Uporov int count_offset; 215512f29d1SFedor Uporov 216512f29d1SFedor Uporov if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs)) 217512f29d1SFedor Uporov count_offset = 8; 218512f29d1SFedor Uporov else if (ep->e2d_reclen == 12) { 219512f29d1SFedor Uporov dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12); 220512f29d1SFedor Uporov if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12) 221512f29d1SFedor Uporov return (NULL); 222512f29d1SFedor Uporov 223512f29d1SFedor Uporov root = (struct ext2fs_htree_root_info *)(((char *)dp + 12)); 224512f29d1SFedor Uporov if (root->h_reserved1 || 225512f29d1SFedor Uporov root->h_info_len != sizeof(struct ext2fs_htree_root_info)) 226512f29d1SFedor Uporov return (NULL); 227512f29d1SFedor Uporov 228512f29d1SFedor Uporov count_offset = 32; 229512f29d1SFedor Uporov } else 230512f29d1SFedor Uporov return (NULL); 231512f29d1SFedor Uporov 232512f29d1SFedor Uporov if (offset) 233512f29d1SFedor Uporov *offset = count_offset; 234512f29d1SFedor Uporov 235512f29d1SFedor Uporov return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset)); 236512f29d1SFedor Uporov } 237512f29d1SFedor Uporov 238512f29d1SFedor Uporov static uint32_t 239512f29d1SFedor Uporov ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset, 240512f29d1SFedor Uporov int count, struct ext2fs_htree_tail *tp) 241512f29d1SFedor Uporov { 242512f29d1SFedor Uporov struct m_ext2fs *fs; 243512f29d1SFedor Uporov char *buf; 244512f29d1SFedor Uporov int size; 245512f29d1SFedor Uporov uint32_t inum, old_csum, gen, crc; 246512f29d1SFedor Uporov 247512f29d1SFedor Uporov fs = ip->i_e2fs; 248512f29d1SFedor Uporov 249512f29d1SFedor Uporov buf = (char *)ep; 250512f29d1SFedor Uporov 251512f29d1SFedor Uporov size = count_offset + (count * sizeof(struct ext2fs_htree_entry)); 252512f29d1SFedor Uporov old_csum = tp->ht_checksum; 253512f29d1SFedor Uporov tp->ht_checksum = 0; 254512f29d1SFedor Uporov 255512f29d1SFedor Uporov inum = ip->i_number; 256512f29d1SFedor Uporov gen = ip->i_gen; 257512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 258512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 259512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)buf, size); 260512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail)); 261512f29d1SFedor Uporov tp->ht_checksum = old_csum; 262512f29d1SFedor Uporov 263512f29d1SFedor Uporov return (crc); 264512f29d1SFedor Uporov } 265512f29d1SFedor Uporov 266512f29d1SFedor Uporov static int 267512f29d1SFedor Uporov ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep) 268512f29d1SFedor Uporov { 269512f29d1SFedor Uporov uint32_t calculated; 270512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 271512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 272512f29d1SFedor Uporov int count_offset, limit, count; 273512f29d1SFedor Uporov 274512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 275512f29d1SFedor Uporov if (cp == NULL) 276512f29d1SFedor Uporov return (0); 277512f29d1SFedor Uporov 278512f29d1SFedor Uporov limit = cp->h_entries_max; 279512f29d1SFedor Uporov count = cp->h_entries_num; 280512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 281512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 282512f29d1SFedor Uporov return (EIO); 283512f29d1SFedor Uporov 284512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 285512f29d1SFedor Uporov calculated = ext2_dx_csum(ip, ep, count_offset, count, tp); 286512f29d1SFedor Uporov 287512f29d1SFedor Uporov if (tp->ht_checksum != calculated) 288512f29d1SFedor Uporov return (EIO); 289512f29d1SFedor Uporov 290512f29d1SFedor Uporov return (0); 291512f29d1SFedor Uporov } 292512f29d1SFedor Uporov 293512f29d1SFedor Uporov int 294512f29d1SFedor Uporov ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp) 295512f29d1SFedor Uporov { 296512f29d1SFedor Uporov struct m_ext2fs *fs; 297512f29d1SFedor Uporov struct ext2fs_direct_2 *ep; 298512f29d1SFedor Uporov int error = 0; 299512f29d1SFedor Uporov 300512f29d1SFedor Uporov fs = ip->i_e2fs; 301512f29d1SFedor Uporov 302512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 303512f29d1SFedor Uporov return (error); 304512f29d1SFedor Uporov 305512f29d1SFedor Uporov ep = (struct ext2fs_direct_2 *)bp->b_data; 306512f29d1SFedor Uporov 307512f29d1SFedor Uporov if (ext2_get_dirent_tail(ip, ep) != NULL) 308512f29d1SFedor Uporov error = ext2_dirent_csum_verify(ip, ep); 309512f29d1SFedor Uporov else if (ext2_get_dx_count(ip, ep, NULL) != NULL) 310512f29d1SFedor Uporov error = ext2_dx_csum_verify(ip, ep); 311512f29d1SFedor Uporov 312512f29d1SFedor Uporov if (error) 313512f29d1SFedor Uporov printf("WARNING: bad directory csum detected, ip=%lu" 314512f29d1SFedor Uporov " - run fsck\n", (unsigned long)ip->i_number); 315512f29d1SFedor Uporov 316512f29d1SFedor Uporov return (error); 317512f29d1SFedor Uporov } 318512f29d1SFedor Uporov 319512f29d1SFedor Uporov static void 320512f29d1SFedor Uporov ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 321512f29d1SFedor Uporov { 322512f29d1SFedor Uporov struct ext2fs_direct_tail *tp; 323512f29d1SFedor Uporov 324512f29d1SFedor Uporov tp = ext2_get_dirent_tail(ip, ep); 325512f29d1SFedor Uporov if (tp == NULL) 326512f29d1SFedor Uporov return; 327512f29d1SFedor Uporov 328512f29d1SFedor Uporov tp->e2dt_checksum = 329512f29d1SFedor Uporov ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep); 330512f29d1SFedor Uporov } 331512f29d1SFedor Uporov 332512f29d1SFedor Uporov static void 333512f29d1SFedor Uporov ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep) 334512f29d1SFedor Uporov { 335512f29d1SFedor Uporov struct ext2fs_htree_count *cp; 336512f29d1SFedor Uporov struct ext2fs_htree_tail *tp; 337512f29d1SFedor Uporov int count_offset, limit, count; 338512f29d1SFedor Uporov 339512f29d1SFedor Uporov cp = ext2_get_dx_count(ip, ep, &count_offset); 340512f29d1SFedor Uporov if (cp == NULL) 341512f29d1SFedor Uporov return; 342512f29d1SFedor Uporov 343512f29d1SFedor Uporov limit = cp->h_entries_max; 344512f29d1SFedor Uporov count = cp->h_entries_num; 345512f29d1SFedor Uporov if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) > 346512f29d1SFedor Uporov ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail)) 347512f29d1SFedor Uporov return; 348512f29d1SFedor Uporov 349512f29d1SFedor Uporov tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit); 350512f29d1SFedor Uporov tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp); 351512f29d1SFedor Uporov } 352512f29d1SFedor Uporov 353512f29d1SFedor Uporov void 354512f29d1SFedor Uporov ext2_dir_blk_csum_set_mem(struct inode *ip, char *buf, int size) 355512f29d1SFedor Uporov { 356512f29d1SFedor Uporov struct m_ext2fs *fs; 357512f29d1SFedor Uporov struct ext2fs_direct_2 *ep; 358512f29d1SFedor Uporov 359512f29d1SFedor Uporov fs = ip->i_e2fs; 360512f29d1SFedor Uporov 361512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 362512f29d1SFedor Uporov return; 363512f29d1SFedor Uporov 364512f29d1SFedor Uporov ep = (struct ext2fs_direct_2 *)buf; 365512f29d1SFedor Uporov 366512f29d1SFedor Uporov if (ext2_htree_has_idx(ip)) { 367512f29d1SFedor Uporov if (ext2_get_dx_count(ip, ep, NULL) != NULL) 368512f29d1SFedor Uporov ext2_dx_csum_set(ip, ep); 369512f29d1SFedor Uporov } else { 370512f29d1SFedor Uporov if (ext2_get_dirent_tail(ip, ep) != NULL) 371512f29d1SFedor Uporov ext2_dirent_csum_set(ip, ep); 372512f29d1SFedor Uporov } 373512f29d1SFedor Uporov } 374512f29d1SFedor Uporov 375512f29d1SFedor Uporov void 376512f29d1SFedor Uporov ext2_dir_blk_csum_set(struct inode *ip, struct buf *bp) 377512f29d1SFedor Uporov { 378512f29d1SFedor Uporov 379512f29d1SFedor Uporov ext2_dir_blk_csum_set_mem(ip, bp->b_data, bp->b_bufsize); 380512f29d1SFedor Uporov } 381512f29d1SFedor Uporov 382512f29d1SFedor Uporov static uint32_t 383512f29d1SFedor Uporov ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp) 384512f29d1SFedor Uporov { 385512f29d1SFedor Uporov struct m_ext2fs *fs; 386512f29d1SFedor Uporov size_t size; 387512f29d1SFedor Uporov uint32_t inum, gen, crc; 388512f29d1SFedor Uporov 389512f29d1SFedor Uporov fs = ip->i_e2fs; 390512f29d1SFedor Uporov 391512f29d1SFedor Uporov size = EXT4_EXTENT_TAIL_OFFSET(ehp) + 392512f29d1SFedor Uporov offsetof(struct ext4_extent_tail, et_checksum); 393512f29d1SFedor Uporov 394512f29d1SFedor Uporov inum = ip->i_number; 395512f29d1SFedor Uporov gen = ip->i_gen; 396512f29d1SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); 397512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); 398512f29d1SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ehp, size); 399512f29d1SFedor Uporov 400512f29d1SFedor Uporov return (crc); 401512f29d1SFedor Uporov } 402512f29d1SFedor Uporov 403512f29d1SFedor Uporov int 404512f29d1SFedor Uporov ext2_extent_blk_csum_verify(struct inode *ip, void *data) 405512f29d1SFedor Uporov { 406512f29d1SFedor Uporov struct m_ext2fs *fs; 407512f29d1SFedor Uporov struct ext4_extent_header *ehp; 408512f29d1SFedor Uporov struct ext4_extent_tail *etp; 409512f29d1SFedor Uporov uint32_t provided, calculated; 410512f29d1SFedor Uporov 411512f29d1SFedor Uporov fs = ip->i_e2fs; 412512f29d1SFedor Uporov 413512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 414512f29d1SFedor Uporov return (0); 415512f29d1SFedor Uporov 416512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 417512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)ehp) + 418512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 419512f29d1SFedor Uporov 420512f29d1SFedor Uporov provided = etp->et_checksum; 421512f29d1SFedor Uporov calculated = ext2_extent_blk_csum(ip, ehp); 422512f29d1SFedor Uporov 423512f29d1SFedor Uporov if (provided != calculated) { 424512f29d1SFedor Uporov printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n", 425512f29d1SFedor Uporov (unsigned long)ip->i_number); 426512f29d1SFedor Uporov return (EIO); 427512f29d1SFedor Uporov } 428512f29d1SFedor Uporov 429512f29d1SFedor Uporov return (0); 430512f29d1SFedor Uporov } 431512f29d1SFedor Uporov 432512f29d1SFedor Uporov void 433512f29d1SFedor Uporov ext2_extent_blk_csum_set(struct inode *ip, void *data) 434512f29d1SFedor Uporov { 435512f29d1SFedor Uporov struct m_ext2fs *fs; 436512f29d1SFedor Uporov struct ext4_extent_header *ehp; 437512f29d1SFedor Uporov struct ext4_extent_tail *etp; 438512f29d1SFedor Uporov 439512f29d1SFedor Uporov fs = ip->i_e2fs; 440512f29d1SFedor Uporov 441512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 442512f29d1SFedor Uporov return; 443512f29d1SFedor Uporov 444512f29d1SFedor Uporov ehp = (struct ext4_extent_header *)data; 445512f29d1SFedor Uporov etp = (struct ext4_extent_tail *)(((char *)data) + 446512f29d1SFedor Uporov EXT4_EXTENT_TAIL_OFFSET(ehp)); 447512f29d1SFedor Uporov 448512f29d1SFedor Uporov etp->et_checksum = ext2_extent_blk_csum(ip, 449512f29d1SFedor Uporov (struct ext4_extent_header *)data); 450512f29d1SFedor Uporov } 451512f29d1SFedor Uporov 452512f29d1SFedor Uporov int 453512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 454512f29d1SFedor Uporov { 455512f29d1SFedor Uporov uint32_t hi, provided, calculated; 456512f29d1SFedor Uporov 457512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 458512f29d1SFedor Uporov return (0); 459512f29d1SFedor Uporov 460512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum; 461512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 462512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 463512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) { 464512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi; 465512f29d1SFedor Uporov provided |= (hi << 16); 466512f29d1SFedor Uporov } else 467512f29d1SFedor Uporov calculated &= 0xFFFF; 468512f29d1SFedor Uporov 469512f29d1SFedor Uporov if (provided != calculated) { 470512f29d1SFedor Uporov printf("WARNING: bad inode bitmap csum detected, " 471512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 472512f29d1SFedor Uporov return (EIO); 473512f29d1SFedor Uporov } 474512f29d1SFedor Uporov 475512f29d1SFedor Uporov return (0); 476512f29d1SFedor Uporov } 477512f29d1SFedor Uporov 478512f29d1SFedor Uporov void 479512f29d1SFedor Uporov ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 480512f29d1SFedor Uporov { 481512f29d1SFedor Uporov uint32_t csum; 482512f29d1SFedor Uporov 483512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 484512f29d1SFedor Uporov return; 485512f29d1SFedor Uporov 486512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, 487512f29d1SFedor Uporov fs->e2fs->e2fs_ipg / 8); 488512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF; 489512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) 490512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16; 491512f29d1SFedor Uporov } 492512f29d1SFedor Uporov 493512f29d1SFedor Uporov int 494512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp) 495512f29d1SFedor Uporov { 496512f29d1SFedor Uporov uint32_t hi, provided, calculated, size; 497512f29d1SFedor Uporov 498512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 499512f29d1SFedor Uporov return (0); 500512f29d1SFedor Uporov 501512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 502512f29d1SFedor Uporov provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum; 503512f29d1SFedor Uporov calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 504512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) { 505512f29d1SFedor Uporov hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi; 506512f29d1SFedor Uporov provided |= (hi << 16); 507512f29d1SFedor Uporov } else 508512f29d1SFedor Uporov calculated &= 0xFFFF; 509512f29d1SFedor Uporov 510512f29d1SFedor Uporov if (provided != calculated) { 511512f29d1SFedor Uporov printf("WARNING: bad block bitmap csum detected, " 512512f29d1SFedor Uporov "cg=%d - run fsck\n", cg); 513512f29d1SFedor Uporov return (EIO); 514512f29d1SFedor Uporov } 515512f29d1SFedor Uporov 516512f29d1SFedor Uporov return (0); 517512f29d1SFedor Uporov } 518512f29d1SFedor Uporov 519512f29d1SFedor Uporov void 520512f29d1SFedor Uporov ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp) 521512f29d1SFedor Uporov { 522512f29d1SFedor Uporov uint32_t csum, size; 523512f29d1SFedor Uporov 524512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 525512f29d1SFedor Uporov return; 526512f29d1SFedor Uporov 527512f29d1SFedor Uporov size = fs->e2fs_fpg / 8; 528512f29d1SFedor Uporov csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size); 529512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF; 530512f29d1SFedor Uporov if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) 531512f29d1SFedor Uporov fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16; 532512f29d1SFedor Uporov } 533512f29d1SFedor Uporov 534512f29d1SFedor Uporov static uint32_t 535512f29d1SFedor Uporov ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei) 536512f29d1SFedor Uporov { 537512f29d1SFedor Uporov struct m_ext2fs *fs; 538*c4aa9a02SFedor Uporov uint32_t inode_csum_seed, inum, gen, crc; 539*c4aa9a02SFedor Uporov uint16_t dummy_csum = 0; 540*c4aa9a02SFedor Uporov unsigned int offset, csum_size; 541512f29d1SFedor Uporov 542512f29d1SFedor Uporov fs = ip->i_e2fs; 543*c4aa9a02SFedor Uporov offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo); 544*c4aa9a02SFedor Uporov csum_size = sizeof(dummy_csum); 545512f29d1SFedor Uporov inum = ip->i_number; 546512f29d1SFedor Uporov gen = ip->i_gen; 547*c4aa9a02SFedor Uporov crc = calculate_crc32c(fs->e2fs_csum_seed, 548*c4aa9a02SFedor Uporov (uint8_t *)&inum, sizeof(inum)); 549*c4aa9a02SFedor Uporov inode_csum_seed = calculate_crc32c(crc, 550*c4aa9a02SFedor Uporov (uint8_t *)&gen, sizeof(gen)); 551512f29d1SFedor Uporov 552*c4aa9a02SFedor Uporov crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset); 553*c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size); 554*c4aa9a02SFedor Uporov offset += csum_size; 555*c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + offset, 556*c4aa9a02SFedor Uporov E2FS_REV0_INODE_SIZE - offset); 557512f29d1SFedor Uporov 558*c4aa9a02SFedor Uporov if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) { 559*c4aa9a02SFedor Uporov offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi); 560*c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + 561*c4aa9a02SFedor Uporov E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE); 562*c4aa9a02SFedor Uporov 563*c4aa9a02SFedor Uporov if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE && 564*c4aa9a02SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 565*c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, 566*c4aa9a02SFedor Uporov csum_size); 567*c4aa9a02SFedor Uporov offset += csum_size; 568*c4aa9a02SFedor Uporov } 569*c4aa9a02SFedor Uporov 570*c4aa9a02SFedor Uporov crc = calculate_crc32c(crc, (uint8_t *)ei + offset, 571*c4aa9a02SFedor Uporov EXT2_INODE_SIZE(fs) - offset); 572*c4aa9a02SFedor Uporov } 573512f29d1SFedor Uporov 574512f29d1SFedor Uporov return (crc); 575512f29d1SFedor Uporov } 576512f29d1SFedor Uporov 577512f29d1SFedor Uporov int 578512f29d1SFedor Uporov ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei) 579512f29d1SFedor Uporov { 580512f29d1SFedor Uporov struct m_ext2fs *fs; 581512f29d1SFedor Uporov const static struct ext2fs_dinode ei_zero; 582512f29d1SFedor Uporov uint32_t hi, provided, calculated; 583512f29d1SFedor Uporov 584512f29d1SFedor Uporov fs = ip->i_e2fs; 585512f29d1SFedor Uporov 586512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 587512f29d1SFedor Uporov return (0); 588512f29d1SFedor Uporov 589512f29d1SFedor Uporov provided = ei->e2di_chksum_lo; 590512f29d1SFedor Uporov calculated = ext2_ei_csum(ip, ei); 591512f29d1SFedor Uporov 592512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 593512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { 594512f29d1SFedor Uporov hi = ei->e2di_chksum_hi; 595512f29d1SFedor Uporov provided |= hi << 16; 596512f29d1SFedor Uporov } else 597512f29d1SFedor Uporov calculated &= 0xFFFF; 598512f29d1SFedor Uporov 599*c4aa9a02SFedor Uporov if (provided != calculated) { 600*c4aa9a02SFedor Uporov /* 601*c4aa9a02SFedor Uporov * If it is first time used dinode, 602*c4aa9a02SFedor Uporov * it is expected that it will be zeroed 603*c4aa9a02SFedor Uporov * and we will not return checksum error in this case. 604*c4aa9a02SFedor Uporov */ 605*c4aa9a02SFedor Uporov if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode))) 606*c4aa9a02SFedor Uporov return (0); 607*c4aa9a02SFedor Uporov 608512f29d1SFedor Uporov return (EIO); 609*c4aa9a02SFedor Uporov } 610512f29d1SFedor Uporov 611512f29d1SFedor Uporov return (0); 612512f29d1SFedor Uporov } 613512f29d1SFedor Uporov 614512f29d1SFedor Uporov void 615512f29d1SFedor Uporov ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei) 616512f29d1SFedor Uporov { 617512f29d1SFedor Uporov struct m_ext2fs *fs; 618512f29d1SFedor Uporov uint32_t crc; 619512f29d1SFedor Uporov 620512f29d1SFedor Uporov fs = ip->i_e2fs; 621512f29d1SFedor Uporov 622512f29d1SFedor Uporov if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 623512f29d1SFedor Uporov return; 624512f29d1SFedor Uporov 625512f29d1SFedor Uporov crc = ext2_ei_csum(ip, ei); 626512f29d1SFedor Uporov 627512f29d1SFedor Uporov ei->e2di_chksum_lo = crc & 0xFFFF; 628512f29d1SFedor Uporov if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && 629512f29d1SFedor Uporov ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) 630512f29d1SFedor Uporov ei->e2di_chksum_hi = crc >> 16; 631512f29d1SFedor Uporov } 632512f29d1SFedor Uporov 633d23db91eSPedro F. Giffuni static uint16_t 634d23db91eSPedro F. Giffuni ext2_crc16(uint16_t crc, const void *buffer, unsigned int len) 635d23db91eSPedro F. Giffuni { 636d23db91eSPedro F. Giffuni const unsigned char *cp = buffer; 637d23db91eSPedro F. Giffuni /* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */ 638d23db91eSPedro F. Giffuni static uint16_t const crc16_table[256] = { 639d23db91eSPedro F. Giffuni 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 640d23db91eSPedro F. Giffuni 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 641d23db91eSPedro F. Giffuni 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 642d23db91eSPedro F. Giffuni 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 643d23db91eSPedro F. Giffuni 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 644d23db91eSPedro F. Giffuni 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 645d23db91eSPedro F. Giffuni 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 646d23db91eSPedro F. Giffuni 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 647d23db91eSPedro F. Giffuni 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 648d23db91eSPedro F. Giffuni 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 649d23db91eSPedro F. Giffuni 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 650d23db91eSPedro F. Giffuni 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 651d23db91eSPedro F. Giffuni 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 652d23db91eSPedro F. Giffuni 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 653d23db91eSPedro F. Giffuni 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 654d23db91eSPedro F. Giffuni 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 655d23db91eSPedro F. Giffuni 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 656d23db91eSPedro F. Giffuni 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 657d23db91eSPedro F. Giffuni 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 658d23db91eSPedro F. Giffuni 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 659d23db91eSPedro F. Giffuni 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 660d23db91eSPedro F. Giffuni 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 661d23db91eSPedro F. Giffuni 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 662d23db91eSPedro F. Giffuni 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 663d23db91eSPedro F. Giffuni 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 664d23db91eSPedro F. Giffuni 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 665d23db91eSPedro F. Giffuni 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 666d23db91eSPedro F. Giffuni 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 667d23db91eSPedro F. Giffuni 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 668d23db91eSPedro F. Giffuni 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 669d23db91eSPedro F. Giffuni 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 670d23db91eSPedro F. Giffuni 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 671d23db91eSPedro F. Giffuni }; 672d23db91eSPedro F. Giffuni 673d23db91eSPedro F. Giffuni while (len--) 674d23db91eSPedro F. Giffuni crc = (((crc >> 8) & 0xffU) ^ 675d23db91eSPedro F. Giffuni crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; 676d23db91eSPedro F. Giffuni return crc; 677d23db91eSPedro F. Giffuni } 678d23db91eSPedro F. Giffuni 679d23db91eSPedro F. Giffuni static uint16_t 680d23db91eSPedro F. Giffuni ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd) 681d23db91eSPedro F. Giffuni { 682d23db91eSPedro F. Giffuni size_t offset; 683512f29d1SFedor Uporov uint32_t csum32; 684512f29d1SFedor Uporov uint16_t crc, dummy_csum; 685d23db91eSPedro F. Giffuni 686d23db91eSPedro F. Giffuni offset = offsetof(struct ext2_gd, ext4bgd_csum); 687d23db91eSPedro F. Giffuni 688512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 689512f29d1SFedor Uporov csum32 = calculate_crc32c(fs->e2fs_csum_seed, 690512f29d1SFedor Uporov (uint8_t *)&block_group, sizeof(block_group)); 691512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset); 692512f29d1SFedor Uporov dummy_csum = 0; 693512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum, 694512f29d1SFedor Uporov sizeof(dummy_csum)); 695512f29d1SFedor Uporov offset += sizeof(dummy_csum); 696512f29d1SFedor Uporov if (offset < fs->e2fs->e3fs_desc_size) 697512f29d1SFedor Uporov csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset, 698512f29d1SFedor Uporov fs->e2fs->e3fs_desc_size - offset); 699512f29d1SFedor Uporov 700512f29d1SFedor Uporov crc = csum32 & 0xFFFF; 701512f29d1SFedor Uporov return (crc); 702512f29d1SFedor Uporov } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) { 703d23db91eSPedro F. Giffuni crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid, 704d23db91eSPedro F. Giffuni sizeof(fs->e2fs->e2fs_uuid)); 705d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)&block_group, 706d23db91eSPedro F. Giffuni sizeof(block_group)); 707d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd, offset); 708d23db91eSPedro F. Giffuni offset += sizeof(gd->ext4bgd_csum); /* skip checksum */ 709d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && 710d23db91eSPedro F. Giffuni offset < fs->e2fs->e3fs_desc_size) 711d23db91eSPedro F. Giffuni crc = ext2_crc16(crc, (uint8_t *)gd + offset, 712d23db91eSPedro F. Giffuni fs->e2fs->e3fs_desc_size - offset); 713d23db91eSPedro F. Giffuni return (crc); 714d23db91eSPedro F. Giffuni } 715d23db91eSPedro F. Giffuni 716d23db91eSPedro F. Giffuni return (0); 717d23db91eSPedro F. Giffuni } 718d23db91eSPedro F. Giffuni 719d23db91eSPedro F. Giffuni int 720d23db91eSPedro F. Giffuni ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev) 721d23db91eSPedro F. Giffuni { 722d23db91eSPedro F. Giffuni unsigned int i; 723d23db91eSPedro F. Giffuni int error = 0; 724d23db91eSPedro F. Giffuni 725d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) { 726d23db91eSPedro F. Giffuni if (fs->e2fs_gd[i].ext4bgd_csum != 727d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) { 728d23db91eSPedro F. Giffuni printf( 729d23db91eSPedro F. Giffuni "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n", 730d23db91eSPedro F. Giffuni devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum, 731d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i])); 732512f29d1SFedor Uporov error = EIO; 733d23db91eSPedro F. Giffuni break; 734d23db91eSPedro F. Giffuni } 735d23db91eSPedro F. Giffuni } 736d23db91eSPedro F. Giffuni 737d23db91eSPedro F. Giffuni return (error); 738d23db91eSPedro F. Giffuni } 739d23db91eSPedro F. Giffuni 740d23db91eSPedro F. Giffuni void 741d23db91eSPedro F. Giffuni ext2_gd_csum_set(struct m_ext2fs *fs) 742d23db91eSPedro F. Giffuni { 743d23db91eSPedro F. Giffuni unsigned int i; 744d23db91eSPedro F. Giffuni 745d23db91eSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++) 746d23db91eSPedro F. Giffuni fs->e2fs_gd[i].ext4bgd_csum = 747d23db91eSPedro F. Giffuni ext2_gd_csum(fs, i, &fs->e2fs_gd[i]); 748d23db91eSPedro F. Giffuni } 749