The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/ext2fs/ext2_csum.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: db47c746a00c05b4a83e5614603a21b4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.