LCOV - code coverage report
Current view: top level - src - simpletlv.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 91.2 % 136 124
Test Date: 2025-12-04 16:15:14 Functions: 100.0 % 11 11
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 77.7 % 94 73

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * simpletlv.c: Simple TLV encoding and decoding functions
       3                 :             :  *
       4                 :             :  * Copyright (C) 2016 - 2018 Red Hat, Inc.
       5                 :             :  *
       6                 :             :  * Authors: Robert Relyea <rrelyea@redhat.com>
       7                 :             :  *          Jakub Jelen <jjelen@redhat.com>
       8                 :             :  *
       9                 :             :  * This library is free software; you can redistribute it and/or
      10                 :             :  * modify it under the terms of the GNU Lesser General Public
      11                 :             :  * License as published by the Free Software Foundation; either
      12                 :             :  * version 2.1 of the License, or (at your option) any later version.
      13                 :             :  *
      14                 :             :  * This library is distributed in the hope that it will be useful,
      15                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17                 :             :  * Lesser General Public License for more details.
      18                 :             :  *
      19                 :             :  * You should have received a copy of the GNU Lesser General Public
      20                 :             :  * License along with this library; if not, write to the Free Software
      21                 :             :  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      22                 :             :  */
      23                 :             : 
      24                 :             : #include "config.h"
      25                 :             : 
      26                 :             : #include <glib.h>
      27                 :             : #include <stdio.h>
      28                 :             : #include <string.h>
      29                 :             : #include <ctype.h>
      30                 :             : #include <stdlib.h>
      31                 :             : 
      32                 :             : #include "simpletlv.h"
      33                 :             : #include "common.h"
      34                 :             : 
      35                 :             : int
      36                 :         931 : simpletlv_get_length(struct simpletlv_member *tlv, size_t tlv_len,
      37                 :             :                      enum simpletlv_buffer_type buffer_type)
      38                 :             : {
      39                 :             :     size_t i, len = 0;
      40                 :             :     int child_length;
      41                 :             : 
      42         [ +  + ]:        5863 :     for (i = 0; i < tlv_len; i++) {
      43                 :             :         /* This TLV is skipped */
      44         [ +  + ]:        4936 :         if (tlv[i].type == SIMPLETLV_TYPE_NONE)
      45                 :         182 :             continue;
      46                 :             : 
      47                 :             :         /* We can not unambiguously split the buffers
      48                 :             :          * for recursive structures
      49                 :             :          */
      50         [ +  + ]:        4754 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND
      51         [ +  + ]:         152 :             && buffer_type != SIMPLETLV_BOTH)
      52                 :             :             return -1;
      53                 :             : 
      54                 :        4750 :         child_length = tlv[i].length;
      55         [ +  + ]:        4750 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) {
      56                 :         148 :             child_length = simpletlv_get_length(tlv[i].value.child,
      57                 :             :                 tlv[i].length, SIMPLETLV_BOTH);
      58                 :             :         }
      59         [ +  + ]:        4750 :         if (buffer_type & SIMPLETLV_TL) {
      60                 :             :             len += 1/*TAG*/;
      61         [ +  + ]:        4307 :             if (child_length < 255)
      62                 :        4271 :                 len += 1;
      63                 :             :             else
      64                 :          36 :                 len += 3;
      65                 :             :         }
      66         [ +  + ]:        4750 :         if (buffer_type & SIMPLETLV_VALUE) {
      67                 :        4308 :             len += child_length;
      68                 :             :         }
      69                 :             :     }
      70                 :         927 :     return len;
      71                 :             : }
      72                 :             : 
      73                 :             : static int
      74                 :         581 : simpletlv_encode_internal(struct simpletlv_member *tlv, size_t tlv_len,
      75                 :             :                           unsigned char **out, size_t outlen,
      76                 :             :                           unsigned char **newptr, int buffer_type)
      77                 :             : {
      78                 :         581 :     unsigned char *tmp = NULL, *a = NULL, *p = NULL, *newp = NULL;
      79                 :             :     size_t tmp_len = 0, p_len, i;
      80                 :             :     int expect_len = 0, rv;
      81                 :             : 
      82                 :         581 :     expect_len = simpletlv_get_length(tlv, tlv_len, buffer_type);
      83   [ +  +  +  - ]:         581 :     if (expect_len == 0 && newptr != NULL && out != NULL)
      84                 :           1 :         *newptr = *out; /* Corner case for zero-length values */
      85         [ +  + ]:         581 :     if (expect_len <= 0)
      86                 :             :         return expect_len;
      87                 :             : 
      88         [ +  + ]:         577 :     if (outlen == 0 && out != NULL) {
      89                 :             :         /* allocate a new buffer */
      90                 :         380 :         a = g_malloc(expect_len);
      91                 :             :         tmp = a;
      92                 :             :         tmp_len = expect_len;
      93   [ +  +  +  - ]:         197 :     } else if ((int)outlen >= expect_len && out != NULL) {
      94                 :         194 :         tmp = *out;
      95                 :         194 :         tmp_len = outlen;
      96                 :             :     } else {
      97                 :             :         /* we can not fit the data */
      98                 :             :         return -1;
      99                 :             :     }
     100                 :         574 :     p = tmp;
     101                 :             :     p_len = tmp_len;
     102         [ +  + ]:        3950 :     for (i = 0; i < tlv_len; i++) {
     103                 :        3376 :         size_t child_length = tlv[i].length;
     104                 :             : 
     105                 :             :         /* This TLV is skipped */
     106         [ +  + ]:        3376 :         if (tlv[i].type == SIMPLETLV_TYPE_NONE)
     107                 :          91 :             continue;
     108                 :             : 
     109         [ +  + ]:        3285 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) {
     110                 :         146 :             child_length = simpletlv_get_length(tlv[i].value.child,
     111                 :             :                 tlv[i].length, SIMPLETLV_BOTH);
     112                 :             :         }
     113         [ +  + ]:        3285 :         if (buffer_type & SIMPLETLV_TL) {
     114                 :        3065 :             rv = simpletlv_put_tag(tlv[i].tag, child_length,
     115                 :             :                 p, p_len, &newp);
     116         [ -  + ]:        3065 :             if (rv < 0)
     117                 :           0 :                 goto failure;
     118                 :        3065 :             p = newp;
     119                 :             :         }
     120         [ +  + ]:        3285 :         if (buffer_type & SIMPLETLV_VALUE) {
     121         [ +  + ]:        3064 :             if (tlv[i].type == SIMPLETLV_TYPE_LEAF) {
     122                 :        2918 :                 memcpy(p, tlv[i].value.value, tlv[i].length);
     123                 :        2918 :                 p += tlv[i].length;
     124                 :             :             } else {
     125                 :             :                 /* recurse */
     126                 :         146 :                 rv = simpletlv_encode_internal(tlv[i].value.child,
     127                 :         146 :                     tlv[i].length, &p, p_len, &newp, buffer_type);
     128         [ -  + ]:         146 :                 if (rv < 0)
     129                 :           0 :                     goto failure;
     130                 :         146 :                 p = newp;
     131                 :             :             }
     132                 :             :         }
     133                 :        3285 :         p_len = tmp_len - (p - tmp);
     134                 :             :     }
     135         [ +  + ]:         574 :     if (newptr)
     136                 :         146 :         *newptr = p;
     137                 :             :     if (out)
     138                 :         574 :         *out = tmp;
     139                 :         574 :     return tmp_len - p_len;
     140                 :             : 
     141                 :           0 : failure:
     142                 :           0 :     g_free(a);
     143                 :           0 :     return -1;
     144                 :             : }
     145                 :             : 
     146                 :             : int
     147                 :         382 : simpletlv_encode(struct simpletlv_member *tlv, size_t tlv_len,
     148                 :             :                  unsigned char **out, size_t outlen, unsigned char **newptr)
     149                 :             : {
     150                 :         382 :     return simpletlv_encode_internal(tlv, tlv_len, out, outlen, newptr,
     151                 :             :         SIMPLETLV_BOTH);
     152                 :             : }
     153                 :             : 
     154                 :             : int
     155                 :          26 : simpletlv_encode_tl(struct simpletlv_member *tlv, size_t tlv_len,
     156                 :             :                     unsigned char **out, size_t outlen, unsigned char **newptr)
     157                 :             : {
     158                 :          26 :     return simpletlv_encode_internal(tlv, tlv_len, out, outlen, newptr,
     159                 :             :         SIMPLETLV_TL);
     160                 :             : }
     161                 :             : 
     162                 :             : int
     163                 :          27 : simpletlv_encode_val(struct simpletlv_member *tlv, size_t tlv_len,
     164                 :             :                      unsigned char **out, size_t outlen, unsigned char **newptr)
     165                 :             : {
     166                 :          27 :     return simpletlv_encode_internal(tlv, tlv_len, out, outlen, newptr,
     167                 :             :         SIMPLETLV_VALUE);
     168                 :             : }
     169                 :             : 
     170                 :             : 
     171                 :             : /*
     172                 :             :  * Put a tag/length record to a file in Simple TLV based on the  datalen
     173                 :             :  * content length.
     174                 :             :  */
     175                 :             : int
     176                 :        3065 : simpletlv_put_tag(unsigned char tag, size_t datalen, unsigned char *out,
     177                 :             :                   size_t outlen, unsigned char **ptr)
     178                 :             : {
     179                 :             :     unsigned char *p = out;
     180                 :             : 
     181   [ +  -  -  + ]:        3065 :     if (outlen < 2 || (outlen < 4 && datalen >= 0xff))
     182                 :             :         return -1;
     183                 :             : 
     184                 :             :     /* tag is just number between 0x01 and 0xFE */
     185         [ -  + ]:        3065 :     if (tag == 0x00 || tag == 0xff)
     186                 :             :         return -1;
     187                 :             : 
     188                 :        3065 :     *p++ = tag; /* tag is single byte */
     189         [ +  + ]:        3065 :     if (datalen < 0xff) {
     190                 :             :         /* short value up to 255 */
     191                 :        3047 :         *p++ = (unsigned char)datalen; /* is in the second byte */
     192         [ -  + ]:          18 :     } else if (datalen < 0xffff) {
     193                 :             :         /* longer values up to 65535 */
     194                 :          18 :         *p++ = (unsigned char)0xff; /* first byte is 0xff */
     195                 :          18 :         *p++ = (unsigned char)datalen & 0xff;
     196                 :          18 :         *p++ = (unsigned char)(datalen >> 8) & 0xff; /* LE */
     197                 :             :     } else {
     198                 :             :         /* we can't store more than two bytes in Simple TLV */
     199                 :             :         return -1;
     200                 :             :     }
     201         [ +  - ]:        3065 :     if (ptr != NULL)
     202                 :        3065 :         *ptr = p;
     203                 :             :     return 0;
     204                 :             : }
     205                 :             : 
     206                 :             : /* Read the TL file and return appropriate tag and the length of associated
     207                 :             :  * content.
     208                 :             :  */
     209                 :             : int
     210                 :         847 : simpletlv_read_tag(unsigned char **buf, size_t buflen, unsigned char *tag_out,
     211                 :             :                    size_t *taglen)
     212                 :             : {
     213                 :             :     size_t len;
     214                 :         847 :     unsigned char *p = *buf;
     215                 :             : 
     216         [ +  + ]:         847 :     if (buflen < 2) {
     217                 :           1 :         *buf = p+buflen;
     218                 :           1 :         return -1;
     219                 :             :     }
     220                 :             : 
     221                 :         846 :     *tag_out = *p++;
     222                 :         846 :     len = *p++;
     223         [ +  + ]:         846 :     if (len == 0xff) {
     224                 :             :         /* don't crash on bad data */
     225         [ +  + ]:           3 :         if (buflen < 4) {
     226                 :           1 :             *taglen = 0;
     227                 :           1 :             return -1;
     228                 :             :         }
     229                 :             :         /* skip two bytes (the size) */
     230                 :           2 :         len = lebytes2ushort(p);
     231                 :           2 :         p+=2;
     232                 :             :     }
     233                 :         845 :     *taglen = len;
     234                 :         845 :     *buf = p;
     235                 :         845 :     return 0;
     236                 :             : }
     237                 :             : 
     238                 :             : /*
     239                 :             :  * Merges two structures into one, creating a new shallow copy of both
     240                 :             :  * of the structures.
     241                 :             :  * Resulting length is the sum of  a_len  and  b_len  arguments.
     242                 :             :  */
     243                 :             : struct simpletlv_member *
     244                 :          93 : simpletlv_merge(const struct simpletlv_member *a, size_t a_len,
     245                 :             :                 const struct simpletlv_member *b, size_t b_len)
     246                 :             : {
     247                 :             :     int offset;
     248                 :             :     struct simpletlv_member *r;
     249                 :          93 :     size_t r_len = a_len + b_len;
     250                 :             : 
     251   [ -  +  -  - ]:          93 :     r = g_new(struct simpletlv_member, r_len);
     252                 :             : 
     253                 :             :     /* the ugly way */
     254                 :          93 :     offset = a_len * sizeof(struct simpletlv_member);
     255                 :          93 :     memcpy(r, a, offset);
     256                 :          93 :     memcpy(&r[a_len], b, b_len * sizeof(struct simpletlv_member));
     257                 :          93 :     return r;
     258                 :             : }
     259                 :             : 
     260                 :             : void
     261                 :         287 : simpletlv_free(struct simpletlv_member *tlv, size_t tlvlen)
     262                 :             : {
     263                 :             :     size_t i;
     264         [ +  - ]:         287 :     if (tlv == NULL)
     265                 :             :         return;
     266                 :             : 
     267         [ +  + ]:        2829 :     for (i = 0; i < tlvlen; i++) {
     268         [ +  + ]:        2542 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) {
     269                 :          68 :             simpletlv_free(tlv[i].value.child, tlv[i].length);
     270                 :             :         } else {
     271                 :        2474 :             g_free(tlv[i].value.value);
     272                 :             :         }
     273                 :             :     }
     274                 :         287 :     g_free(tlv);
     275                 :             : }
     276                 :             : 
     277                 :             : struct simpletlv_member *
     278                 :         219 : simpletlv_clone(struct simpletlv_member *tlv, size_t tlvlen)
     279                 :             : {
     280                 :             :     size_t i = 0, j;
     281                 :             :     struct simpletlv_member *new = NULL;
     282                 :             : 
     283   [ -  +  -  - ]:         219 :     new = g_new(struct simpletlv_member, tlvlen);
     284                 :             : 
     285         [ +  + ]:         923 :     for (i = 0; i < tlvlen; i++) {
     286                 :         704 :         new[i].type = tlv[i].type;
     287                 :         704 :         new[i].tag = tlv[i].tag;
     288                 :         704 :         new[i].length = tlv[i].length;
     289         [ +  + ]:         704 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) {
     290                 :          82 :             new[i].value.child = simpletlv_clone(
     291                 :             :                 tlv[i].value.child, tlv[i].length);
     292         [ -  + ]:          82 :             if (new[i].value.child == NULL)
     293                 :           0 :                 goto failure;
     294                 :             :         } else {
     295                 :         622 :             new[i].value.value = g_memdup2(tlv[i].value.value, tlv[i].length);
     296                 :             :         }
     297                 :             :     }
     298                 :             :     return new;
     299                 :             : 
     300                 :             : failure:
     301         [ #  # ]:           0 :     for (j = 0; j < i; j++) {
     302         [ #  # ]:           0 :         if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) {
     303                 :           0 :             simpletlv_free(new[j].value.child, new[j].length);
     304                 :             :         } else {
     305                 :           0 :             g_free(new[j].value.value);
     306                 :             :         }
     307                 :             :     }
     308                 :           0 :     g_free(new);
     309                 :           0 :     return NULL;
     310                 :             : }
     311                 :             : 
     312                 :             : struct simpletlv_member *
     313                 :           5 : simpletlv_parse(unsigned char *data, size_t data_len, size_t *outtlv_len)
     314                 :             : {
     315                 :             :     unsigned char *p, *p_end;
     316                 :             :     unsigned char tag;
     317                 :             :     size_t vlen;
     318                 :           5 :     GArray *tlv = g_array_new(FALSE, FALSE, sizeof(struct simpletlv_member));
     319                 :             : 
     320                 :           5 :     p = data;
     321                 :           5 :     p_end = p + data_len;
     322         [ +  + ]:         521 :     while (p < p_end) {
     323                 :             :         struct simpletlv_member tlvp;
     324                 :             : 
     325                 :             :         /* we can return what was parsed successfully */
     326         [ +  + ]:         519 :         if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
     327                 :             :             break;
     328                 :             :         }
     329         [ +  + ]:         517 :         if (vlen > (size_t) (p_end - p)) {
     330                 :             :             break;
     331                 :             :         }
     332                 :             : 
     333                 :         516 :         tlvp.tag = tag;
     334                 :         516 :         tlvp.length = vlen;
     335                 :         516 :         tlvp.value.value = g_memdup2(p, vlen);
     336                 :         516 :         tlvp.type = SIMPLETLV_TYPE_LEAF;
     337                 :         516 :         g_array_append_val(tlv, tlvp);
     338                 :             : 
     339                 :         516 :         p += vlen;
     340                 :             :     }
     341                 :             : 
     342                 :           5 :     *outtlv_len = tlv->len;
     343                 :           5 :     return (struct simpletlv_member *)(void *)g_array_free(tlv, FALSE);
     344                 :             : }
     345                 :             : 
     346                 :             : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
        

Generated by: LCOV version 2.0-1