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

Cache object: 2e20633c7dbe564dad66ebe5c70beb4f


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