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