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

Cache object: 2481b76bf0c584f8b5315fc6aa217f83


[ 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.