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/dev/sfxge/common/ef10_image.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-2018 Solarflare Communications Inc.
    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 are met:
    9  *
   10  * 1. Redistributions of source code must retain the above copyright notice,
   11  *    this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright notice,
   13  *    this list of conditions and the following disclaimer in the documentation
   14  *    and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * The views and conclusions contained in the software and documentation are
   29  * those of the authors and should not be interpreted as representing official
   30  * policies, either expressed or implied, of the FreeBSD Project.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "efx.h"
   37 #include "efx_impl.h"
   38 
   39 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
   40 
   41 #if EFSYS_OPT_IMAGE_LAYOUT
   42 
   43 /*
   44  * Utility routines to support limited parsing of ASN.1 tags. This is not a
   45  * general purpose ASN.1 parser, but is sufficient to locate the required
   46  * objects in a signed image with CMS headers.
   47  */
   48 
   49 /* DER encodings for ASN.1 tags (see ITU-T X.690) */
   50 #define ASN1_TAG_INTEGER            (0x02)
   51 #define ASN1_TAG_OCTET_STRING       (0x04)
   52 #define ASN1_TAG_OBJ_ID             (0x06)
   53 #define ASN1_TAG_SEQUENCE           (0x30)
   54 #define ASN1_TAG_SET                (0x31)
   55 
   56 #define ASN1_TAG_IS_PRIM(tag)       ((tag & 0x20) == 0)
   57 
   58 #define ASN1_TAG_PRIM_CONTEXT(n)    (0x80 + (n))
   59 #define ASN1_TAG_CONS_CONTEXT(n)    (0xA0 + (n))
   60 
   61 typedef struct efx_asn1_cursor_s {
   62         uint8_t         *buffer;
   63         uint32_t        length;
   64 
   65         uint8_t         tag;
   66         uint32_t        hdr_size;
   67         uint32_t        val_size;
   68 } efx_asn1_cursor_t;
   69 
   70 /* Parse header of DER encoded ASN.1 TLV and match tag */
   71 static  __checkReturn   efx_rc_t
   72 efx_asn1_parse_header_match_tag(
   73         __inout         efx_asn1_cursor_t       *cursor,
   74         __in            uint8_t                 tag)
   75 {
   76         efx_rc_t rc;
   77 
   78         if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) {
   79                 rc = EINVAL;
   80                 goto fail1;
   81         }
   82 
   83         cursor->tag = cursor->buffer[0];
   84         if (cursor->tag != tag) {
   85                 /* Tag not matched */
   86                 rc = ENOENT;
   87                 goto fail2;
   88         }
   89 
   90         if ((cursor->tag & 0x1F) == 0x1F) {
   91                 /* Long tag format not used in CMS syntax */
   92                 rc = EINVAL;
   93                 goto fail3;
   94         }
   95 
   96         if ((cursor->buffer[1] & 0x80) == 0) {
   97                 /* Short form: length is 0..127 */
   98                 cursor->hdr_size = 2;
   99                 cursor->val_size = cursor->buffer[1];
  100         } else {
  101                 /* Long form: length encoded as [0x80+nbytes][length bytes] */
  102                 uint32_t nbytes = cursor->buffer[1] & 0x7F;
  103                 uint32_t offset;
  104 
  105                 if (nbytes == 0) {
  106                         /* Indefinite length not allowed in DER encoding */
  107                         rc = EINVAL;
  108                         goto fail4;
  109                 }
  110                 if (2 + nbytes > cursor->length) {
  111                         /* Header length overflows image buffer */
  112                         rc = EINVAL;
  113                         goto fail6;
  114                 }
  115                 if (nbytes > sizeof (uint32_t)) {
  116                         /* Length encoding too big */
  117                         rc = E2BIG;
  118                         goto fail5;
  119                 }
  120                 cursor->hdr_size = 2 + nbytes;
  121                 cursor->val_size = 0;
  122                 for (offset = 2; offset < cursor->hdr_size; offset++) {
  123                         cursor->val_size =
  124                             (cursor->val_size << 8) | cursor->buffer[offset];
  125                 }
  126         }
  127 
  128         if ((cursor->hdr_size + cursor->val_size) > cursor->length) {
  129                 /* Length overflows image buffer */
  130                 rc = E2BIG;
  131                 goto fail7;
  132         }
  133 
  134         return (0);
  135 
  136 fail7:
  137         EFSYS_PROBE(fail7);
  138 fail6:
  139         EFSYS_PROBE(fail6);
  140 fail5:
  141         EFSYS_PROBE(fail5);
  142 fail4:
  143         EFSYS_PROBE(fail4);
  144 fail3:
  145         EFSYS_PROBE(fail3);
  146 fail2:
  147         EFSYS_PROBE(fail2);
  148 fail1:
  149         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  150 
  151         return (rc);
  152 }
  153 
  154 /* Enter nested ASN.1 TLV (contained in value of current TLV) */
  155 static  __checkReturn   efx_rc_t
  156 efx_asn1_enter_tag(
  157         __inout         efx_asn1_cursor_t       *cursor,
  158         __in            uint8_t                 tag)
  159 {
  160         efx_rc_t rc;
  161 
  162         if (cursor == NULL) {
  163                 rc = EINVAL;
  164                 goto fail1;
  165         }
  166 
  167         if (ASN1_TAG_IS_PRIM(tag)) {
  168                 /* Cannot enter a primitive tag */
  169                 rc = ENOTSUP;
  170                 goto fail2;
  171         }
  172         rc = efx_asn1_parse_header_match_tag(cursor, tag);
  173         if (rc != 0) {
  174                 /* Invalid TLV or wrong tag */
  175                 goto fail3;
  176         }
  177 
  178         /* Limit cursor range to nested TLV */
  179         cursor->buffer += cursor->hdr_size;
  180         cursor->length = cursor->val_size;
  181 
  182         return (0);
  183 
  184 fail3:
  185         EFSYS_PROBE(fail3);
  186 fail2:
  187         EFSYS_PROBE(fail2);
  188 fail1:
  189         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  190 
  191         return (rc);
  192 }
  193 
  194 /*
  195  * Check that the current ASN.1 TLV matches the given tag and value.
  196  * Advance cursor to next TLV on a successful match.
  197  */
  198 static  __checkReturn   efx_rc_t
  199 efx_asn1_match_tag_value(
  200         __inout         efx_asn1_cursor_t       *cursor,
  201         __in            uint8_t                 tag,
  202         __in            const void              *valp,
  203         __in            uint32_t                val_size)
  204 {
  205         efx_rc_t rc;
  206 
  207         if (cursor == NULL) {
  208                 rc = EINVAL;
  209                 goto fail1;
  210         }
  211         rc = efx_asn1_parse_header_match_tag(cursor, tag);
  212         if (rc != 0) {
  213                 /* Invalid TLV or wrong tag */
  214                 goto fail2;
  215         }
  216         if (cursor->val_size != val_size) {
  217                 /* Value size is different */
  218                 rc = EINVAL;
  219                 goto fail3;
  220         }
  221         if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) {
  222                 /* Value content is different */
  223                 rc = EINVAL;
  224                 goto fail4;
  225         }
  226         cursor->buffer += cursor->hdr_size + cursor->val_size;
  227         cursor->length -= cursor->hdr_size + cursor->val_size;
  228 
  229         return (0);
  230 
  231 fail4:
  232         EFSYS_PROBE(fail4);
  233 fail3:
  234         EFSYS_PROBE(fail3);
  235 fail2:
  236         EFSYS_PROBE(fail2);
  237 fail1:
  238         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  239 
  240         return (rc);
  241 }
  242 
  243 /* Advance cursor to next TLV */
  244 static  __checkReturn   efx_rc_t
  245 efx_asn1_skip_tag(
  246         __inout         efx_asn1_cursor_t       *cursor,
  247         __in            uint8_t                 tag)
  248 {
  249         efx_rc_t rc;
  250 
  251         if (cursor == NULL) {
  252                 rc = EINVAL;
  253                 goto fail1;
  254         }
  255 
  256         rc = efx_asn1_parse_header_match_tag(cursor, tag);
  257         if (rc != 0) {
  258                 /* Invalid TLV or wrong tag */
  259                 goto fail2;
  260         }
  261         cursor->buffer += cursor->hdr_size + cursor->val_size;
  262         cursor->length -= cursor->hdr_size + cursor->val_size;
  263 
  264         return (0);
  265 
  266 fail2:
  267         EFSYS_PROBE(fail2);
  268 fail1:
  269         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  270 
  271         return (rc);
  272 }
  273 
  274 /* Return pointer to value octets and value size from current TLV */
  275 static  __checkReturn   efx_rc_t
  276 efx_asn1_get_tag_value(
  277         __inout         efx_asn1_cursor_t       *cursor,
  278         __in            uint8_t                 tag,
  279         __out           uint8_t                 **valp,
  280         __out           uint32_t                *val_sizep)
  281 {
  282         efx_rc_t rc;
  283 
  284         if (cursor == NULL || valp == NULL || val_sizep == NULL) {
  285                 rc = EINVAL;
  286                 goto fail1;
  287         }
  288 
  289         rc = efx_asn1_parse_header_match_tag(cursor, tag);
  290         if (rc != 0) {
  291                 /* Invalid TLV or wrong tag */
  292                 goto fail2;
  293         }
  294         *valp = cursor->buffer + cursor->hdr_size;
  295         *val_sizep = cursor->val_size;
  296 
  297         return (0);
  298 
  299 fail2:
  300         EFSYS_PROBE(fail2);
  301 fail1:
  302         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  303 
  304         return (rc);
  305 }
  306 
  307 /*
  308  * Utility routines for parsing CMS headers (see RFC2315, PKCS#7)
  309  */
  310 
  311 /* OID 1.2.840.113549.1.7.2 */
  312 static const uint8_t PKCS7_SignedData[] =
  313 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
  314 
  315 /* OID 1.2.840.113549.1.7.1 */
  316 static const uint8_t PKCS7_Data[] =
  317 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
  318 
  319 /* SignedData structure version */
  320 static const uint8_t SignedData_Version[] =
  321 { 0x03 };
  322 
  323 /*
  324  * Check for a valid image in signed image format. This uses CMS syntax
  325  * (see RFC2315, PKCS#7) to provide signatures, and certificates required
  326  * to validate the signatures. The encapsulated content is in unsigned image
  327  * format (reflash header, image code, trailer checksum).
  328  */
  329 static  __checkReturn   efx_rc_t
  330 efx_check_signed_image_header(
  331         __in            void            *bufferp,
  332         __in            uint32_t        buffer_size,
  333         __out           uint32_t        *content_offsetp,
  334         __out           uint32_t        *content_lengthp)
  335 {
  336         efx_asn1_cursor_t cursor;
  337         uint8_t *valp;
  338         uint32_t val_size;
  339         efx_rc_t rc;
  340 
  341         if (content_offsetp == NULL || content_lengthp == NULL) {
  342                 rc = EINVAL;
  343                 goto fail1;
  344         }
  345         cursor.buffer = (uint8_t *)bufferp;
  346         cursor.length = buffer_size;
  347 
  348         /* ContextInfo */
  349         rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
  350         if (rc != 0)
  351                 goto fail2;
  352 
  353         /* ContextInfo.contentType */
  354         rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
  355             PKCS7_SignedData, sizeof (PKCS7_SignedData));
  356         if (rc != 0)
  357                 goto fail3;
  358 
  359         /* ContextInfo.content */
  360         rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
  361         if (rc != 0)
  362                 goto fail4;
  363 
  364         /* SignedData */
  365         rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
  366         if (rc != 0)
  367                 goto fail5;
  368 
  369         /* SignedData.version */
  370         rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER,
  371             SignedData_Version, sizeof (SignedData_Version));
  372         if (rc != 0)
  373                 goto fail6;
  374 
  375         /* SignedData.digestAlgorithms */
  376         rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET);
  377         if (rc != 0)
  378                 goto fail7;
  379 
  380         /* SignedData.encapContentInfo */
  381         rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
  382         if (rc != 0)
  383                 goto fail8;
  384 
  385         /* SignedData.encapContentInfo.econtentType */
  386         rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
  387             PKCS7_Data, sizeof (PKCS7_Data));
  388         if (rc != 0)
  389                 goto fail9;
  390 
  391         /* SignedData.encapContentInfo.econtent */
  392         rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
  393         if (rc != 0)
  394                 goto fail10;
  395 
  396         /*
  397          * The octet string contains the image header, image code bytes and
  398          * image trailer CRC (same as unsigned image layout).
  399          */
  400         valp = NULL;
  401         val_size = 0;
  402         rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING,
  403             &valp, &val_size);
  404         if (rc != 0)
  405                 goto fail11;
  406 
  407         if ((valp == NULL) || (val_size == 0)) {
  408                 rc = EINVAL;
  409                 goto fail12;
  410         }
  411         if (valp < (uint8_t *)bufferp) {
  412                 rc = EINVAL;
  413                 goto fail13;
  414         }
  415         if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) {
  416                 rc = EINVAL;
  417                 goto fail14;
  418         }
  419 
  420         *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp);
  421         *content_lengthp = val_size;
  422 
  423         return (0);
  424 
  425 fail14:
  426         EFSYS_PROBE(fail14);
  427 fail13:
  428         EFSYS_PROBE(fail13);
  429 fail12:
  430         EFSYS_PROBE(fail12);
  431 fail11:
  432         EFSYS_PROBE(fail11);
  433 fail10:
  434         EFSYS_PROBE(fail10);
  435 fail9:
  436         EFSYS_PROBE(fail9);
  437 fail8:
  438         EFSYS_PROBE(fail8);
  439 fail7:
  440         EFSYS_PROBE(fail7);
  441 fail6:
  442         EFSYS_PROBE(fail6);
  443 fail5:
  444         EFSYS_PROBE(fail5);
  445 fail4:
  446         EFSYS_PROBE(fail4);
  447 fail3:
  448         EFSYS_PROBE(fail3);
  449 fail2:
  450         EFSYS_PROBE(fail2);
  451 fail1:
  452         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  453 
  454         return (rc);
  455 }
  456 
  457 static  __checkReturn   efx_rc_t
  458 efx_check_unsigned_image(
  459         __in            void            *bufferp,
  460         __in            uint32_t        buffer_size)
  461 {
  462         efx_image_header_t *header;
  463         efx_image_trailer_t *trailer;
  464         uint32_t crc;
  465         efx_rc_t rc;
  466 
  467         EFX_STATIC_ASSERT(sizeof (*header) == EFX_IMAGE_HEADER_SIZE);
  468         EFX_STATIC_ASSERT(sizeof (*trailer) == EFX_IMAGE_TRAILER_SIZE);
  469 
  470         /* Must have at least enough space for required image header fields */
  471         if (buffer_size < (EFX_FIELD_OFFSET(efx_image_header_t, eih_size) +
  472                 sizeof (header->eih_size))) {
  473                 rc = ENOSPC;
  474                 goto fail1;
  475         }
  476         header = (efx_image_header_t *)bufferp;
  477 
  478         if (header->eih_magic != EFX_IMAGE_HEADER_MAGIC) {
  479                 rc = EINVAL;
  480                 goto fail2;
  481         }
  482 
  483         /*
  484          * Check image header version is same or higher than lowest required
  485          * version.
  486          */
  487         if (header->eih_version < EFX_IMAGE_HEADER_VERSION) {
  488                 rc = EINVAL;
  489                 goto fail3;
  490         }
  491 
  492         /* Buffer must have space for image header, code and image trailer. */
  493         if (buffer_size < (header->eih_size + header->eih_code_size +
  494                 EFX_IMAGE_TRAILER_SIZE)) {
  495                 rc = ENOSPC;
  496                 goto fail4;
  497         }
  498 
  499         /* Check CRC from image buffer matches computed CRC. */
  500         trailer = (efx_image_trailer_t *)((uint8_t *)header +
  501             header->eih_size + header->eih_code_size);
  502 
  503         crc = efx_crc32_calculate(0, (uint8_t *)header,
  504             (header->eih_size + header->eih_code_size));
  505 
  506         if (trailer->eit_crc != crc) {
  507                 rc = EINVAL;
  508                 goto fail5;
  509         }
  510 
  511         return (0);
  512 
  513 fail5:
  514         EFSYS_PROBE(fail5);
  515 fail4:
  516         EFSYS_PROBE(fail4);
  517 fail3:
  518         EFSYS_PROBE(fail3);
  519 fail2:
  520         EFSYS_PROBE(fail2);
  521 fail1:
  522         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  523 
  524         return (rc);
  525 }
  526 
  527         __checkReturn   efx_rc_t
  528 efx_check_reflash_image(
  529         __in            void                    *bufferp,
  530         __in            uint32_t                buffer_size,
  531         __out           efx_image_info_t        *infop)
  532 {
  533         efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE;
  534         uint32_t image_offset;
  535         uint32_t image_size;
  536         void *imagep;
  537         efx_rc_t rc;
  538 
  539         EFSYS_ASSERT(infop != NULL);
  540         if (infop == NULL) {
  541                 rc = EINVAL;
  542                 goto fail1;
  543         }
  544         memset(infop, 0, sizeof (*infop));
  545 
  546         if (bufferp == NULL || buffer_size == 0) {
  547                 rc = EINVAL;
  548                 goto fail2;
  549         }
  550 
  551         /*
  552          * Check if the buffer contains an image in signed format, and if so,
  553          * locate the image header.
  554          */
  555         rc = efx_check_signed_image_header(bufferp, buffer_size,
  556             &image_offset, &image_size);
  557         if (rc == 0) {
  558                 /*
  559                  * Buffer holds signed image format. Check that the encapsulated
  560                  * content is in unsigned image format.
  561                  */
  562                 format = EFX_IMAGE_FORMAT_SIGNED;
  563         } else {
  564                 /* Check if the buffer holds image in unsigned image format */
  565                 format = EFX_IMAGE_FORMAT_UNSIGNED;
  566                 image_offset = 0;
  567                 image_size = buffer_size;
  568         }
  569         if (image_offset + image_size > buffer_size) {
  570                 rc = E2BIG;
  571                 goto fail3;
  572         }
  573         imagep = (uint8_t *)bufferp + image_offset;
  574 
  575         /* Check unsigned image layout (image header, code, image trailer) */
  576         rc = efx_check_unsigned_image(imagep, image_size);
  577         if (rc != 0)
  578                 goto fail4;
  579 
  580         /* Return image details */
  581         infop->eii_format = format;
  582         infop->eii_imagep = bufferp;
  583         infop->eii_image_size = buffer_size;
  584         infop->eii_headerp = (efx_image_header_t *)imagep;
  585 
  586         return (0);
  587 
  588 fail4:
  589         EFSYS_PROBE(fail4);
  590 fail3:
  591         EFSYS_PROBE(fail3);
  592 fail2:
  593         EFSYS_PROBE(fail2);
  594         infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
  595         infop->eii_imagep = NULL;
  596         infop->eii_image_size = 0;
  597 
  598 fail1:
  599         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  600 
  601         return (rc);
  602 }
  603 
  604         __checkReturn   efx_rc_t
  605 efx_build_signed_image_write_buffer(
  606         __out_bcount(buffer_size)
  607                         uint8_t                 *bufferp,
  608         __in            uint32_t                buffer_size,
  609         __in            efx_image_info_t        *infop,
  610         __out           efx_image_header_t      **headerpp)
  611 {
  612         signed_image_chunk_hdr_t chunk_hdr;
  613         uint32_t hdr_offset;
  614         struct {
  615                 uint32_t offset;
  616                 uint32_t size;
  617         } cms_header, image_header, code, image_trailer, signature;
  618         efx_rc_t rc;
  619 
  620         EFSYS_ASSERT((infop != NULL) && (headerpp != NULL));
  621 
  622         if ((bufferp == NULL) || (buffer_size == 0) ||
  623             (infop == NULL) || (headerpp == NULL)) {
  624                 /* Invalid arguments */
  625                 rc = EINVAL;
  626                 goto fail1;
  627         }
  628         if ((infop->eii_format != EFX_IMAGE_FORMAT_SIGNED) ||
  629             (infop->eii_imagep == NULL) ||
  630             (infop->eii_headerp == NULL) ||
  631             ((uint8_t *)infop->eii_headerp < (uint8_t *)infop->eii_imagep) ||
  632             (infop->eii_image_size < EFX_IMAGE_HEADER_SIZE) ||
  633             ((size_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep) >
  634             (infop->eii_image_size - EFX_IMAGE_HEADER_SIZE))) {
  635                 /* Invalid image info */
  636                 rc = EINVAL;
  637                 goto fail2;
  638         }
  639 
  640         /* Locate image chunks in original signed image */
  641         cms_header.offset = 0;
  642         cms_header.size =
  643             (uint32_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep);
  644         if ((cms_header.size > buffer_size) ||
  645             (cms_header.offset > (buffer_size - cms_header.size))) {
  646                 rc = EINVAL;
  647                 goto fail3;
  648         }
  649 
  650         image_header.offset = cms_header.offset + cms_header.size;
  651         image_header.size = infop->eii_headerp->eih_size;
  652         if ((image_header.size > buffer_size) ||
  653             (image_header.offset > (buffer_size - image_header.size))) {
  654                 rc = EINVAL;
  655                 goto fail4;
  656         }
  657 
  658         code.offset = image_header.offset + image_header.size;
  659         code.size = infop->eii_headerp->eih_code_size;
  660         if ((code.size > buffer_size) ||
  661             (code.offset > (buffer_size - code.size))) {
  662                 rc = EINVAL;
  663                 goto fail5;
  664         }
  665 
  666         image_trailer.offset = code.offset + code.size;
  667         image_trailer.size = EFX_IMAGE_TRAILER_SIZE;
  668         if ((image_trailer.size > buffer_size) ||
  669             (image_trailer.offset > (buffer_size - image_trailer.size))) {
  670                 rc = EINVAL;
  671                 goto fail6;
  672         }
  673 
  674         signature.offset = image_trailer.offset + image_trailer.size;
  675         signature.size = (uint32_t)(infop->eii_image_size - signature.offset);
  676         if ((signature.size > buffer_size) ||
  677             (signature.offset > (buffer_size - signature.size))) {
  678                 rc = EINVAL;
  679                 goto fail7;
  680         }
  681 
  682         EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size +
  683             image_header.size + code.size + image_trailer.size +
  684             signature.size);
  685 
  686         /* BEGIN CSTYLED */
  687         /*
  688          * Build signed image partition, inserting chunk headers.
  689          *
  690          *  Signed Image:                  Image in NVRAM partition:
  691          *
  692          *  +-----------------+            +-----------------+
  693          *  | CMS header      |            |  mcfw.update    |<----+
  694          *  +-----------------+            |                 |     |
  695          *  | reflash header  |            +-----------------+     |
  696          *  +-----------------+            | chunk header:   |-->--|-+
  697          *  | mcfw.update     |            | REFLASH_TRAILER |     | |
  698          *  |                 |            +-----------------+     | |
  699          *  +-----------------+        +-->| CMS header      |     | |
  700          *  | reflash trailer |        |   +-----------------+     | |
  701          *  +-----------------+        |   | chunk header:   |->-+ | |
  702          *  | signature       |        |   | REFLASH_HEADER  |   | | |
  703          *  +-----------------+        |   +-----------------+   | | |
  704          *                             |   | reflash header  |<--+ | |
  705          *                             |   +-----------------+     | |
  706          *                             |   | chunk header:   |-->--+ |
  707          *                             |   | IMAGE           |       |
  708          *                             |   +-----------------+       |
  709          *                             |   | reflash trailer |<------+
  710          *                             |   +-----------------+
  711          *                             |   | chunk header:   |
  712          *                             |   | SIGNATURE       |->-+
  713          *                             |   +-----------------+   |
  714          *                             |   | signature       |<--+
  715          *                             |   +-----------------+
  716          *                             |   | ...unused...    |
  717          *                             |   +-----------------+
  718          *                             +-<-| chunk header:   |
  719          *                             >-->| CMS_HEADER      |
  720          *                                 +-----------------+
  721          *
  722          * Each chunk header gives the partition offset and length of the image
  723          * chunk's data. The image chunk data is immediately followed by the
  724          * chunk header for the next chunk.
  725          *
  726          * The data chunk for the firmware code must be at the start of the
  727          * partition (needed for the bootloader). The first chunk header in the
  728          * chain (for the CMS header) is stored at the end of the partition. The
  729          * chain of chunk headers maintains the same logical order of image
  730          * chunks as the original signed image file. This set of constraints
  731          * results in the layout used for the data chunks and chunk headers.
  732          */
  733         /* END CSTYLED */
  734         memset(bufferp, 0xFF, buffer_size);
  735 
  736         EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN);
  737         memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN);
  738 
  739         /*
  740          * CMS header
  741          */
  742         if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) {
  743                 rc = ENOSPC;
  744                 goto fail8;
  745         }
  746         hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN;
  747 
  748         chunk_hdr.magic         = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
  749         chunk_hdr.version       = SIGNED_IMAGE_CHUNK_HDR_VERSION;
  750         chunk_hdr.id            = SIGNED_IMAGE_CHUNK_CMS_HEADER;
  751         chunk_hdr.offset        = code.size + SIGNED_IMAGE_CHUNK_HDR_LEN;
  752         chunk_hdr.len           = cms_header.size;
  753 
  754         memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr));
  755 
  756         if ((chunk_hdr.len > buffer_size) ||
  757             (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
  758                 rc = ENOSPC;
  759                 goto fail9;
  760         }
  761         memcpy(bufferp + chunk_hdr.offset,
  762             infop->eii_imagep + cms_header.offset,
  763             cms_header.size);
  764 
  765         /*
  766          * Image header
  767          */
  768         hdr_offset = chunk_hdr.offset + chunk_hdr.len;
  769         if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
  770                 rc = ENOSPC;
  771                 goto fail10;
  772         }
  773         chunk_hdr.magic         = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
  774         chunk_hdr.version       = SIGNED_IMAGE_CHUNK_HDR_VERSION;
  775         chunk_hdr.id            = SIGNED_IMAGE_CHUNK_REFLASH_HEADER;
  776         chunk_hdr.offset        = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
  777         chunk_hdr.len           = image_header.size;
  778 
  779         memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
  780 
  781         if ((chunk_hdr.len > buffer_size) ||
  782             (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
  783                 rc = ENOSPC;
  784                 goto fail11;
  785         }
  786         memcpy(bufferp + chunk_hdr.offset,
  787             infop->eii_imagep + image_header.offset,
  788             image_header.size);
  789 
  790         *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset);
  791 
  792         /*
  793          * Firmware code
  794          */
  795         hdr_offset = chunk_hdr.offset + chunk_hdr.len;
  796         if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
  797                 rc = ENOSPC;
  798                 goto fail12;
  799         }
  800         chunk_hdr.magic         = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
  801         chunk_hdr.version       = SIGNED_IMAGE_CHUNK_HDR_VERSION;
  802         chunk_hdr.id            = SIGNED_IMAGE_CHUNK_IMAGE;
  803         chunk_hdr.offset        = 0;
  804         chunk_hdr.len           = code.size;
  805 
  806         memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
  807 
  808         if ((chunk_hdr.len > buffer_size) ||
  809             (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
  810                 rc = ENOSPC;
  811                 goto fail13;
  812         }
  813         memcpy(bufferp + chunk_hdr.offset,
  814             infop->eii_imagep + code.offset,
  815             code.size);
  816 
  817         /*
  818          * Image trailer (CRC)
  819          */
  820         chunk_hdr.magic         = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
  821         chunk_hdr.version       = SIGNED_IMAGE_CHUNK_HDR_VERSION;
  822         chunk_hdr.id            = SIGNED_IMAGE_CHUNK_REFLASH_TRAILER;
  823         chunk_hdr.offset        = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
  824         chunk_hdr.len           = image_trailer.size;
  825 
  826         hdr_offset = code.size;
  827         if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
  828                 rc = ENOSPC;
  829                 goto fail14;
  830         }
  831 
  832         memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
  833 
  834         if ((chunk_hdr.len > buffer_size) ||
  835             (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
  836                 rc = ENOSPC;
  837                 goto fail15;
  838         }
  839         memcpy((uint8_t *)bufferp + chunk_hdr.offset,
  840             infop->eii_imagep + image_trailer.offset,
  841             image_trailer.size);
  842 
  843         /*
  844          * Signature
  845          */
  846         hdr_offset = chunk_hdr.offset + chunk_hdr.len;
  847         if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
  848                 rc = ENOSPC;
  849                 goto fail16;
  850         }
  851         chunk_hdr.magic         = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
  852         chunk_hdr.version       = SIGNED_IMAGE_CHUNK_HDR_VERSION;
  853         chunk_hdr.id            = SIGNED_IMAGE_CHUNK_SIGNATURE;
  854         chunk_hdr.offset        = chunk_hdr.offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
  855         chunk_hdr.len           = signature.size;
  856 
  857         memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
  858 
  859         if ((chunk_hdr.len > buffer_size) ||
  860             (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
  861                 rc = ENOSPC;
  862                 goto fail17;
  863         }
  864         memcpy(bufferp + chunk_hdr.offset,
  865             infop->eii_imagep + signature.offset,
  866             signature.size);
  867 
  868         return (0);
  869 
  870 fail17:
  871         EFSYS_PROBE(fail17);
  872 fail16:
  873         EFSYS_PROBE(fail16);
  874 fail15:
  875         EFSYS_PROBE(fail15);
  876 fail14:
  877         EFSYS_PROBE(fail14);
  878 fail13:
  879         EFSYS_PROBE(fail13);
  880 fail12:
  881         EFSYS_PROBE(fail12);
  882 fail11:
  883         EFSYS_PROBE(fail11);
  884 fail10:
  885         EFSYS_PROBE(fail10);
  886 fail9:
  887         EFSYS_PROBE(fail9);
  888 fail8:
  889         EFSYS_PROBE(fail8);
  890 fail7:
  891         EFSYS_PROBE(fail7);
  892 fail6:
  893         EFSYS_PROBE(fail6);
  894 fail5:
  895         EFSYS_PROBE(fail5);
  896 fail4:
  897         EFSYS_PROBE(fail4);
  898 fail3:
  899         EFSYS_PROBE(fail3);
  900 fail2:
  901         EFSYS_PROBE(fail2);
  902 fail1:
  903         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  904 
  905         return (rc);
  906 }
  907 
  908 #endif  /* EFSYS_OPT_IMAGE_LAYOUT */
  909 
  910 #endif  /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */

Cache object: 9d47d710f127d8207ba3cab8a002255d


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