## Coverage Report

#### Created: 2023-09-23 17:42

    /libfido2/src/netlink.c

    Line
    Count
    Source (jump to first uncovered line)
    1
    /*
    2
     * Copyright (c) 2020 Yubico AB. All rights reserved.
    3
     * Use of this source code is governed by a BSD-style
    4
     * license that can be found in the LICENSE file.
    5
     * SPDX-License-Identifier: BSD-2-Clause
    6
     */
    7
    8
    #include <sys/socket.h>
    9
    10
    #include <linux/genetlink.h>
    11
    #include <linux/netlink.h>
    12
    #include <linux/nfc.h>
    13
    14
    #include <errno.h>
    15
    #include <limits.h>
    16
    17
    #include "fido.h"
    18
    #include "netlink.h"
    19
    20
    #ifdef FIDO_FUZZ
    21
    static ssize_t (*fuzz_read)(int, void *, size_t);
    22
    static ssize_t (*fuzz_write)(int, const void *, size_t);
    23
    539k
    # define READ   fuzz_read
    24
    540k
    # define WRITE  fuzz_write
    25
    #else
    26
    # define READ   read
    27
    # define WRITE  write
    28
    #endif
    29
    30
    #ifndef SOL_NETLINK
    31
    #define SOL_NETLINK     270
    32
    #endif
    33
    34
    531
    #define NETLINK_POLL_MS 100
    35
    36
    /* XXX avoid signed NLA_ALIGNTO */
    37
    #undef NLA_HDRLEN
    38
    #define NLA_HDRLEN      NLMSG_ALIGN(sizeof(struct nlattr))
    39
    40
    typedef struct nlmsgbuf {
    41
            size_t         siz; /* alloc size */
    42
            size_t         len; /* of payload */
    43
            unsigned char *ptr; /* in payload */
    44
            union {
    45
                    struct nlmsghdr   nlmsg;
    46
                    char              buf[NLMSG_HDRLEN]; /* align */
    47
            }              u;
    48
            unsigned char  payload[];
    49
    } nlmsgbuf_t;
    50
    51
    typedef struct genlmsgbuf {
    52
            union {
    53
                    struct genlmsghdr genl;
    54
                    char              buf[GENL_HDRLEN];  /* align */
    55
            }              u;
    56
    } genlmsgbuf_t;
    57
    58
    typedef struct nlamsgbuf {
    59
            size_t         siz; /* alloc size */
    60
            size_t         len; /* of payload */
    61
            unsigned char *ptr; /* in payload */
    62
            union {
    63
                    struct nlattr     nla;
    64
                    char              buf[NLA_HDRLEN];   /* align */
    65
            }              u;
    66
            unsigned char  payload[];
    67
    } nlamsgbuf_t;
    68
    69
    typedef struct nl_family {
    70
            uint16_t id;
    71
            uint32_t mcastgrp;
    72
    } nl_family_t;
    73
    74
    typedef struct nl_poll {
    75
            uint32_t     dev;
    76
            unsigned int eventcnt;
    77
    } nl_poll_t;
    78
    79
    typedef struct nl_target {
    80
            int       found;
    81
            uint32_t *value;
    82
    } nl_target_t;
    83
    84
    static const void *
    85
    nlmsg_ptr(const nlmsgbuf_t *m)
    86
    1.07M
    {
    87
    1.07M
            return (&m->u.nlmsg);
    88
    1.07M
    }
    89
    90
    static size_t
    91
    nlmsg_len(const nlmsgbuf_t *m)
    92
    1.61M
    {
    93
    1.61M
            return (m->u.nlmsg.nlmsg_len);
    94
    1.61M
    }
    95
    96
    static uint16_t
    97
    nlmsg_type(const nlmsgbuf_t *m)
    98
    8.46k
    {
    99
    8.46k
            return (m->u.nlmsg.nlmsg_type);
    100
    8.46k
    }
    101
    102
    static nlmsgbuf_t *
    103
    nlmsg_new(uint16_t type, uint16_t flags, size_t len)
    104
    549k
    {
    105
    549k
            nlmsgbuf_t *m;
    106
    549k
            size_t siz;
    107
    108
    549k
            if (len > SIZE_MAX - sizeof(*m) ||
    109
    549k
                (siz = sizeof(*m) + len) > UINT16_MAX ||
    110
    549k
                (m = calloc(1, siz)) == NULL)
    111
    1.46k
                    return (NULL);
    112
    113
    548k
            m->siz = siz;
    114
    548k
            m->len = len;
    115
    548k
            m->ptr = m->payload;
    116
    548k
            m->u.nlmsg.nlmsg_type = type;
    117
    548k
            m->u.nlmsg.nlmsg_flags = NLM_F_REQUEST | flags;
    118
    548k
            m->u.nlmsg.nlmsg_len = NLMSG_HDRLEN;
    119
    120
    548k
            return (m);
    121
    549k
    }
    122
    123
    static nlamsgbuf_t *
    124
    nla_from_buf(const unsigned char **ptr, size_t *len)
    125
    20.0k
    {
    126
    20.0k
            nlamsgbuf_t h, *a;
    127
    20.0k
            size_t nlalen, skip;
    128
    129
    20.0k
            if (*len < sizeof(h.u))
    130
    2.90k
                    return (NULL);
    131
    132
    17.1k
            memset(&h, 0, sizeof(h));
    133
    17.1k
            memcpy(&h.u, *ptr, sizeof(h.u));
    134
    135
    17.1k
            if ((nlalen = h.u.nla.nla_len) < sizeof(h.u) || nlalen > *len ||
    136
    17.1k
                nlalen - sizeof(h.u) > UINT16_MAX ||
    137
    17.1k
                nlalen > SIZE_MAX - sizeof(*a) ||
    138
    17.1k
                (skip = NLMSG_ALIGN(nlalen)) > *len ||
    139
    17.1k
                (a = calloc(1, sizeof(*a) + nlalen - sizeof(h.u))) == NULL)
    140
    2.36k
                    return (NULL);
    141
    142
    14.7k
            memcpy(&a->u, *ptr, nlalen);
    143
    14.7k
            a->siz = sizeof(*a) + nlalen - sizeof(h.u);
    144
    14.7k
            a->ptr = a->payload;
    145
    14.7k
            a->len = nlalen - sizeof(h.u);
    146
    14.7k
            *ptr += skip;
    147
    14.7k
            *len -= skip;
    148
    149
    14.7k
            return (a);
    150
    17.1k
    }
    151
    152
    static nlamsgbuf_t *
    153
    nla_getattr(nlamsgbuf_t *a)
    154
    7.87k
    {
    155
    7.87k
            return (nla_from_buf((void *)&a->ptr, &a->len));
    156
    7.87k
    }
    157
    158
    static uint16_t
    159
    nla_type(const nlamsgbuf_t *a)
    160
    20.6k
    {
    161
    20.6k
            return (a->u.nla.nla_type);
    162
    20.6k
    }
    163
    164
    static nlamsgbuf_t *
    165
    nlmsg_getattr(nlmsgbuf_t *m)
    166
    12.1k
    {
    167
    12.1k
            return (nla_from_buf((void *)&m->ptr, &m->len));
    168
    12.1k
    }
    169
    170
    static int
    171
    nla_read(nlamsgbuf_t *a, void *buf, size_t cnt)
    172
    2.67k
    {
    173
    2.67k
            if (cnt > a->u.nla.nla_len ||
    174
    2.67k
                fido_buf_read((void *)&a->ptr, &a->len, buf, cnt) < 0)
    175
    29
                    return (-1);
    176
    177
    2.65k
            a->u.nla.nla_len = (uint16_t)(a->u.nla.nla_len - cnt);
    178
    179
    2.65k
            return (0);
    180
    2.67k
    }
    181
    182
    static nlmsgbuf_t *
    183
    nlmsg_from_buf(const unsigned char **ptr, size_t *len)
    184
    5.56k
    {
    185
    5.56k
            nlmsgbuf_t h, *m;
    186
    5.56k
            size_t msglen, skip;
    187
    188
    5.56k
            if (*len < sizeof(h.u))
    189
    381
                    return (NULL);
    190
    191
    5.18k
            memset(&h, 0, sizeof(h));
    192
    5.18k
            memcpy(&h.u, *ptr, sizeof(h.u));
    193
    194
    5.18k
            if ((msglen = h.u.nlmsg.nlmsg_len) < sizeof(h.u) || msglen > *len ||
    195
    5.18k
                msglen - sizeof(h.u) > UINT16_MAX ||
    196
    5.18k
                (skip = NLMSG_ALIGN(msglen)) > *len ||
    197
    5.18k
                (m = nlmsg_new(0, 0, msglen - sizeof(h.u))) == NULL)
    198
    453
                    return (NULL);
    199
    200
    4.73k
            memcpy(&m->u, *ptr, msglen);
    201
    4.73k
            *ptr += skip;
    202
    4.73k
            *len -= skip;
    203
    204
    4.73k
            return (m);
    205
    5.18k
    }
    206
    207
    static int
    208
    nlmsg_read(nlmsgbuf_t *m, void *buf, size_t cnt)
    209
    3.39k
    {
    210
    3.39k
            if (cnt > m->u.nlmsg.nlmsg_len ||
    211
    3.39k
                fido_buf_read((void *)&m->ptr, &m->len, buf, cnt) < 0)
    212
    311
                    return (-1);
    213
    214
    3.08k
            m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len - cnt);
    215
    216
    3.08k
            return (0);
    217
    3.39k
    }
    218
    219
    static int
    220
    nlmsg_write(nlmsgbuf_t *m, const void *buf, size_t cnt)
    221
    3.78M
    {
    222
    3.78M
            if (cnt > UINT32_MAX - m->u.nlmsg.nlmsg_len ||
    223
    3.78M
                fido_buf_write(&m->ptr, &m->len, buf, cnt) < 0)
    224
    0
                    return (-1);
    225
    226
    3.78M
            m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len + cnt);
    227
    228
    3.78M
            return (0);
    229
    3.78M
    }
    230
    231
    static int
    232
    nlmsg_set_genl(nlmsgbuf_t *m, uint8_t cmd)
    233
    543k
    {
    234
    543k
            genlmsgbuf_t g;
    235
    236
    543k
            memset(&g, 0, sizeof(g));
    237
    543k
            g.u.genl.cmd = cmd;
    238
    543k
            g.u.genl.version = NFC_GENL_VERSION;
    239
    240
    543k
            return (nlmsg_write(m, &g, sizeof(g)));
    241
    543k
    }
    242
    243
    static int
    244
    nlmsg_get_genl(nlmsgbuf_t *m, uint8_t cmd)
    245
    2.39k
    {
    246
    2.39k
            genlmsgbuf_t g;
    247
    248
    2.39k
            memset(&g, 0, sizeof(g));
    249
    250
    2.39k
            if (nlmsg_read(m, &g, sizeof(g)) < 0 || g.u.genl.cmd != cmd)
    251
    584
                    return (-1);
    252
    253
    1.80k
            return (0);
    254
    2.39k
    }
    255
    256
    static int
    257
    nlmsg_get_status(nlmsgbuf_t *m)
    258
    1.00k
    {
    259
    1.00k
            int status;
    260
    261
    1.00k
            if (nlmsg_read(m, &status, sizeof(status)) < 0 || status == INT_MIN)
    262
    36
                    return (-1);
    263
    966
            if (status < 0)
    264
    153
                    status = -status;
    265
    266
    966
            return (status);
    267
    1.00k
    }
    268
    269
    static int
    270
    nlmsg_setattr(nlmsgbuf_t *m, uint16_t type, const void *ptr, size_t len)
    271
    1.08M
    {
    272
    1.08M
            int r;
    273
    1.08M
            char *padding;
    274
    1.08M
            size_t skip;
    275
    1.08M
            nlamsgbuf_t a;
    276
    277
    1.08M
            if ((skip = NLMSG_ALIGN(len)) > UINT16_MAX - sizeof(a.u) ||
    278
    1.08M
                skip < len || (padding = calloc(1, skip - len)) == NULL)
    279
    2.81k
                    return (-1);
    280
    281
    1.08M
            memset(&a, 0, sizeof(a));
    282
    1.08M
            a.u.nla.nla_type = type;
    283
    1.08M
            a.u.nla.nla_len = (uint16_t)(len + sizeof(a.u));
    284
    1.08M
            r = nlmsg_write(m, &a.u, sizeof(a.u)) < 0 ||
    285
    1.08M
                nlmsg_write(m, ptr, len) < 0 ||
    286
    1.08M
                nlmsg_write(m, padding, skip - len) < 0 ? -1 : 0;
    287
    288
    1.08M
            free(padding);
    289
    290
    1.08M
            return (r);
    291
    1.08M
    }
    292
    293
    static int
    294
    nlmsg_set_u16(nlmsgbuf_t *m, uint16_t type, uint16_t val)
    295
    541k
    {
    296
    541k
            return (nlmsg_setattr(m, type, &val, sizeof(val)));
    297
    541k
    }
    298
    299
    static int
    300
    nlmsg_set_u32(nlmsgbuf_t *m, uint16_t type, uint32_t val)
    301
    2.01k
    {
    302
    2.01k
            return (nlmsg_setattr(m, type, &val, sizeof(val)));
    303
    2.01k
    }
    304
    305
    static int
    306
    nlmsg_set_str(nlmsgbuf_t *m, uint16_t type, const char *val)
    307
    540k
    {
    308
    540k
            return (nlmsg_setattr(m, type, val, strlen(val) + 1));
    309
    540k
    }
    310
    311
    static int
    312
    nla_get_u16(nlamsgbuf_t *a, uint16_t *v)
    313
    1.03k
    {
    314
    1.03k
            return (nla_read(a, v, sizeof(*v)));
    315
    1.03k
    }
    316
    317
    static int
    318
    nla_get_u32(nlamsgbuf_t *a, uint32_t *v)
    319
    1.27k
    {
    320
    1.27k
            return (nla_read(a, v, sizeof(*v)));
    321
    1.27k
    }
    322
    323
    static char *
    324
    nla_get_str(nlamsgbuf_t *a)
    325
    409
    {
    326
    409
            size_t n;
    327
    409
            char *s = NULL;
    328
    329
    409
            if ((n = a->len) < 1 || a->ptr[n - 1] != '\0' ||
    330
    409
                (s = calloc(1, n)) == NULL || nla_read(a, s, n) < 0) {
    331
    43
                    free(s);
    332
    43
                    return (NULL);
    333
    43
            }
    334
    366
            s[n - 1] = '\0';
    335
    336
    366
            return (s);
    337
    409
    }
    338
    339
    static int
    340
    nlmsg_tx(int fd, const nlmsgbuf_t *m)
    341
    540k
    {
    342
    540k
            ssize_t r;
    343
    344
    540k
            if ((r = WRITE(fd, nlmsg_ptr(m), nlmsg_len(m))) == -1) {
    345
    1.37k
                    fido_log_error(errno, "%s: write", __func__);
    346
    1.37k
                    return (-1);
    347
    1.37k
            }
    348
    539k
            if (r < 0 || (size_t)r != nlmsg_len(m)) {
    349
    0
                    fido_log_debug("%s: %zd != %zu", __func__, r, nlmsg_len(m));
    350
    0
                    return (-1);
    351
    0
            }
    352
    539k
            fido_log_xxd(nlmsg_ptr(m), nlmsg_len(m), "%s", __func__);
    353
    354
    539k
            return (0);
    355
    539k
    }
    356
    357
    static ssize_t
    358
    nlmsg_rx(int fd, unsigned char *ptr, size_t len, int ms)
    359
    539k
    {
    360
    539k
            ssize_t r;
    361
    362
    539k
            if (len > SSIZE_MAX) {
    363
    0
                    fido_log_debug("%s: len", __func__);
    364
    0
                    return (-1);
    365
    0
            }
    366
    539k
            if (fido_hid_unix_wait(fd, ms, NULL) < 0) {
    367
    0
                    fido_log_debug("%s: fido_hid_unix_wait", __func__);
    368
    0
                    return (-1);
    369
    0
            }
    370
    539k
            if ((r = READ(fd, ptr, len)) == -1) {
    371
    1.41k
                    fido_log_error(errno, "%s: read %zd", __func__, r);
    372
    1.41k
                    return (-1);
    373
    1.41k
            }
    374
    538k
            fido_log_xxd(ptr, (size_t)r, "%s", __func__);
    375
    376
    538k
            return (r);
    377
    539k
    }
    378
    379
    static int
    380
    nlmsg_iter(nlmsgbuf_t *m, void *arg, int (*parser)(nlamsgbuf_t *, void *))
    381
    1.77k
    {
    382
    1.77k
            nlamsgbuf_t *a;
    383
    1.77k
            int r;
    384
    385
    12.1k
            while ((a = nlmsg_getattr(m)) != NULL) {
    386
    10.5k
                    r = parser(a, arg);
    387
    10.5k
                    free(a);
    388
    10.5k
                    if (r < 0) {
    389
    118
                            fido_log_debug("%s: parser", __func__);
    390
    118
                            return (-1);
    391
    118
                    }
    392
    10.5k
            }
    393
    394
    1.65k
            return (0);
    395
    1.77k
    }
    396
    397
    static int
    398
    nla_iter(nlamsgbuf_t *g, void *arg, int (*parser)(nlamsgbuf_t *, void *))
    399
    3.81k
    {
    400
    3.81k
            nlamsgbuf_t *a;
    401
    3.81k
            int r;
    402
    403
    7.87k
            while ((a = nla_getattr(g)) != NULL) {
    404
    4.26k
                    r = parser(a, arg);
    405
    4.26k
                    free(a);
    406
    4.26k
                    if (r < 0) {
    407
    194
                            fido_log_debug("%s: parser", __func__);
    408
    194
                            return (-1);
    409
    194
                    }
    410
    4.26k
            }
    411
    412
    3.61k
            return (0);
    413
    3.81k
    }
    414
    415
    static int
    416
    nl_parse_reply(const uint8_t *blob, size_t blob_len, uint16_t msg_type,
    417
        uint8_t genl_cmd, void *arg, int (*parser)(nlamsgbuf_t *, void *))
    418
    538k
    {
    419
    538k
            nlmsgbuf_t *m;
    420
    538k
            int r;
    421
    422
    541k
            while (blob_len) {
    423
    5.56k
                    if ((m = nlmsg_from_buf(&blob, &blob_len)) == NULL) {
    424
    834
                            fido_log_debug("%s: nlmsg", __func__);
    425
    834
                            return (-1);
    426
    834
                    }
    427
    4.73k
                    if (nlmsg_type(m) == NLMSG_ERROR) {
    428
    1.00k
                            r = nlmsg_get_status(m);
    429
    1.00k
                            free(m);
    430
    1.00k
                            return (r);
    431
    1.00k
                    }
    432
    3.73k
                    if (nlmsg_type(m) != msg_type ||
    433
    3.73k
                        nlmsg_get_genl(m, genl_cmd) < 0) {
    434
    1.92k
                            fido_log_debug("%s: skipping", __func__);
    435
    1.92k
                            free(m);
    436
    1.92k
                            continue;
    437
    1.92k
                    }
    438
    1.80k
                    if (parser != NULL && nlmsg_iter(m, arg, parser) < 0) {
    439
    118
                            fido_log_debug("%s: nlmsg_iter", __func__);
    440
    118
                            free(m);
    441
    118
                            return (-1);
    442
    118
                    }
    443
    1.69k
                    free(m);
    444
    1.69k
            }
    445
    446
    536k
            return (0);
    447
    538k
    }
    448
    449
    static int
    450
    parse_mcastgrp(nlamsgbuf_t *a, void *arg)
    451
    2.01k
    {
    452
    2.01k
            nl_family_t *family = arg;
    453
    2.01k
            char *name;
    454
    455
    2.01k
            switch (nla_type(a)) {
    456
    409
            case CTRL_ATTR_MCAST_GRP_NAME:
    457
    409
                    if ((name = nla_get_str(a)) == NULL ||
    458
    409
                        strcmp(name, NFC_GENL_MCAST_EVENT_NAME) != 0) {
    459
    89
                            free(name);
    460
    89
                            return (-1); /* XXX skip? */
    461
    89
                    }
    462
    320
                    free(name);
    463
    320
                    return (0);
    464
    1.32k
            case CTRL_ATTR_MCAST_GRP_ID:
    465
    1.32k
                    if (family->mcastgrp)
    466
    363
                            break;
    467
    961
                    if (nla_get_u32(a, &family->mcastgrp) < 0) {
    468
    8
                            fido_log_debug("%s: group", __func__);
    469
    8
                            return (-1);
    470
    8
                    }
    471
    953
                    return (0);
    472
    2.01k
            }
    473
    474
    640
            fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
    475
    476
    640
            return (0);
    477
    2.01k
    }
    478
    479
    static int
    480
    parse_mcastgrps(nlamsgbuf_t *a, void *arg)
    481
    2.25k
    {
    482
    2.25k
            return (nla_iter(a, arg, parse_mcastgrp));
    483
    2.25k
    }
    484
    485
    static int
    486
    parse_family(nlamsgbuf_t *a, void *arg)
    487
    9.72k
    {
    488
    9.72k
            nl_family_t *family = arg;
    489
    490
    9.72k
            switch (nla_type(a)) {
    491
    1.58k
            case CTRL_ATTR_FAMILY_ID:
    492
    1.58k
                    if (family->id)
    493
    550
                            break;
    494
    1.03k
                    if (nla_get_u16(a, &family->id) < 0) {
    495
    16
                            fido_log_debug("%s: id", __func__);
    496
    16
                            return (-1);
    497
    16
                    }
    498
    1.01k
                    return (0);
    499
    1.56k
            case CTRL_ATTR_MCAST_GROUPS:
    500
    1.56k
                    return (nla_iter(a, family, parse_mcastgrps));
    501
    9.72k
            }
    502
    503
    7.13k
            fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
    504
    505
    7.13k
            return (0);
    506
    9.72k
    }
    507
    508
    static int
    509
    nl_get_nfc_family(int fd, uint16_t *type, uint32_t *mcastgrp)
    510
    543k
    {
    511
    543k
            nlmsgbuf_t *m;
    512
    543k
            uint8_t reply[512];
    513
    543k
            nl_family_t family;
    514
    543k
            ssize_t r;
    515
    543k
            int ok;
    516
    517
    543k
            if ((m = nlmsg_new(GENL_ID_CTRL, 0, 64)) == NULL ||
    518
    543k
                nlmsg_set_genl(m, CTRL_CMD_GETFAMILY) < 0 ||
    519
    543k
                nlmsg_set_u16(m, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL) < 0 ||
    520
    543k
                nlmsg_set_str(m, CTRL_ATTR_FAMILY_NAME, NFC_GENL_NAME) < 0 ||
    521
    543k
                nlmsg_tx(fd, m) < 0) {
    522
    5.40k
                    free(m);
    523
    5.40k
                    return (-1);
    524
    5.40k
            }
    525
    537k
            free(m);
    526
    537k
            memset(&family, 0, sizeof(family));
    527
    537k
            if ((r = nlmsg_rx(fd, reply, sizeof(reply), -1)) < 0) {
    528
    1.36k
                    fido_log_debug("%s: nlmsg_rx", __func__);
    529
    1.36k
                    return (-1);
    530
    1.36k
            }
    531
    536k
            if ((ok = nl_parse_reply(reply, (size_t)r, GENL_ID_CTRL,
    532
    536k
                CTRL_CMD_NEWFAMILY, &family, parse_family)) != 0) {
    533
    964
                    fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
    534
    964
                    return (-1);
    535
    964
            }
    536
    535k
            if (family.id == 0 || family.mcastgrp == 0) {
    537
    534k
                    fido_log_debug("%s: missing attr", __func__);
    538
    534k
                    return (-1);
    539
    534k
            }
    540
    733
            *type = family.id;
    541
    733
            *mcastgrp = family.mcastgrp;
    542
    543
    733
            return (0);
    544
    535k
    }
    545
    546
    static int
    547
    parse_target(nlamsgbuf_t *a, void *arg)
    548
    234
    {
    549
    234
            nl_target_t *t = arg;
    550
    551
    234
            if (t->found || nla_type(a) != NFC_ATTR_TARGET_INDEX) {
    552
    219
                    fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
    553
    219
                    return (0);
    554
    219
            }
    555
    15
            if (nla_get_u32(a, t->value) < 0) {
    556
    3
                    fido_log_debug("%s: target", __func__);
    557
    3
                    return (-1);
    558
    3
            }
    559
    12
            t->found = 1;
    560
    561
    12
            return (0);
    562
    15
    }
    563
    564
    int
    565
    fido_nl_power_nfc(fido_nl_t *nl, uint32_t dev)
    566
    733
    {
    567
    733
            nlmsgbuf_t *m;
    568
    733
            uint8_t reply[512];
    569
    733
            ssize_t r;
    570
    733
            int ok;
    571
    572
    733
            if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL ||
    573
    733
                nlmsg_set_genl(m, NFC_CMD_DEV_UP) < 0 ||
    574
    733
                nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
    575
    733
                nlmsg_tx(nl->fd, m) < 0) {
    576
    211
                    free(m);
    577
    211
                    return (-1);
    578
    211
            }
    579
    522
            free(m);
    580
    522
            if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) {
    581
    36
                    fido_log_debug("%s: nlmsg_rx", __func__);
    582
    36
                    return (-1);
    583
    36
            }
    584
    486
            if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
    585
    486
                NFC_CMD_DEV_UP, NULL, NULL)) != 0 && ok != EALREADY) {
    586
    147
                    fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
    587
    147
                    return (-1);
    588
    147
            }
    589
    590
    339
            return (0);
    591
    486
    }
    592
    593
    static int
    594
    nl_nfc_poll(fido_nl_t *nl, uint32_t dev)
    595
    649
    {
    596
    649
            nlmsgbuf_t *m;
    597
    649
            uint8_t reply[512];
    598
    649
            ssize_t r;
    599
    649
            int ok;
    600
    601
    649
            if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL ||
    602
    649
                nlmsg_set_genl(m, NFC_CMD_START_POLL) < 0 ||
    603
    649
                nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
    604
    649
                nlmsg_set_u32(m, NFC_ATTR_PROTOCOLS, NFC_PROTO_ISO14443_MASK) < 0 ||
    605
    649
                nlmsg_tx(nl->fd, m) < 0) {
    606
    24
                    free(m);
    607
    24
                    return (-1);
    608
    24
            }
    609
    625
            free(m);
    610
    625
            if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) {
    611
    5
                    fido_log_debug("%s: nlmsg_rx", __func__);
    612
    5
                    return (-1);
    613
    5
            }
    614
    620
            if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
    615
    620
                NFC_CMD_START_POLL, NULL, NULL)) != 0) {
    616
    89
                    fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
    617
    89
                    return (-1);
    618
    89
            }
    619
    620
    531
            return (0);
    621
    620
    }
    622
    623
    static int
    624
    nl_dump_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target, int ms)
    625
    113
    {
    626
    113
            nlmsgbuf_t *m;
    627
    113
            nl_target_t t;
    628
    113
            uint8_t reply[512];
    629
    113
            ssize_t r;
    630
    113
            int ok;
    631
    632
    113
            if ((m = nlmsg_new(nl->nfc_type, NLM_F_DUMP, 64)) == NULL ||
    633
    113
                nlmsg_set_genl(m, NFC_CMD_GET_TARGET) < 0 ||
    634
    113
                nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
    635
    113
                nlmsg_tx(nl->fd, m) < 0) {
    636
    6
                    free(m);
    637
    6
                    return (-1);
    638
    6
            }
    639
    107
            free(m);
    640
    107
            if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), ms)) < 0) {
    641
    2
                    fido_log_debug("%s: nlmsg_rx", __func__);
    642
    2
                    return (-1);
    643
    2
            }
    644
    105
            memset(&t, 0, sizeof(t));
    645
    105
            t.value = target;
    646
    105
            if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
    647
    105
                NFC_CMD_GET_TARGET, &t, parse_target)) != 0) {
    648
    78
                    fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
    649
    78
                    return (-1);
    650
    78
            }
    651
    27
            if (!t.found) {
    652
    20
                    fido_log_debug("%s: target not found", __func__);
    653
    20
                    return (-1);
    654
    20
            }
    655
    656
    7
            return (0);
    657
    27
    }
    658
    659
    static int
    660
    parse_nfc_event(nlamsgbuf_t *a, void *arg)
    661
    545
    {
    662
    545
            nl_poll_t *ctx = arg;
    663
    545
            uint32_t dev;
    664
    665
    545
            if (nla_type(a) != NFC_ATTR_DEVICE_INDEX) {
    666
    242
                    fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
    667
    242
                    return (0);
    668
    242
            }
    669
    303
            if (nla_get_u32(a, &dev) < 0) {
    670
    2
                    fido_log_debug("%s: dev", __func__);
    671
    2
                    return (-1);
    672
    2
            }
    673
    301
            if (dev == ctx->dev)
    674
    138
                    ctx->eventcnt++;
    675
    163
            else
    676
    163
                    fido_log_debug("%s: ignoring dev 0x%x", __func__, dev);
    677
    678
    301
            return (0);
    679
    303
    }
    680
    681
    int
    682
    fido_nl_get_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target)
    683
    649
    {
    684
    649
            uint8_t reply[512];
    685
    649
            nl_poll_t ctx;
    686
    649
            ssize_t r;
    687
    649
            int ok;
    688
    689
    649
            if (nl_nfc_poll(nl, dev) < 0) {
    690
    118
                    fido_log_debug("%s: nl_nfc_poll", __func__);
    691
    118
                    return (-1);
    692
    118
            }
    693
    #ifndef FIDO_FUZZ
    694
            if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
    695
                &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) {
    696
                    fido_log_error(errno, "%s: setsockopt add", __func__);
    697
                    return (-1);
    698
            }
    699
    #endif
    700
    531
            r = nlmsg_rx(nl->fd, reply, sizeof(reply), NETLINK_POLL_MS);
    701
    #ifndef FIDO_FUZZ
    702
            if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
    703
                &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) {
    704
                    fido_log_error(errno, "%s: setsockopt drop", __func__);
    705
                    return (-1);
    706
            }
    707
    #endif
    708
    531
            if (r < 0) {
    709
    3
                    fido_log_debug("%s: nlmsg_rx", __func__);
    710
    3
                    return (-1);
    711
    3
            }
    712
    528
            memset(&ctx, 0, sizeof(ctx));
    713
    528
            ctx.dev = dev;
    714
    528
            if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
    715
    528
                NFC_EVENT_TARGETS_FOUND, &ctx, parse_nfc_event)) != 0) {
    716
    142
                    fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
    717
    142
                    return (-1);
    718
    142
            }
    719
    386
            if (ctx.eventcnt == 0) {
    720
    273
                    fido_log_debug("%s: dev 0x%x not observed", __func__, dev);
    721
    273
                    return (-1);
    722
    273
            }
    723
    113
            if (nl_dump_nfc_target(nl, dev, target, -1) < 0) {
    724
    106
                    fido_log_debug("%s: nl_dump_nfc_target", __func__);
    725
    106
                    return (-1);
    726
    106
            }
    727
    728
    7
            return (0);
    729
    113
    }
    730
    731
    void
    732
    fido_nl_free(fido_nl_t **nlp)
    733
    544k
    {
    734
    544k
            fido_nl_t *nl;
    735
    736
    544k
            if (nlp == NULL || (nl = *nlp) == NULL)
    737
    0
                    return;
    738
    544k
            if (nl->fd != -1 && close(nl->fd) == -1)
    739
    0
                    fido_log_error(errno, "%s: close", __func__);
    740
    741
    544k
            free(nl);
    742
    544k
            *nlp = NULL;
    743
    544k
    }
    744
    745
    fido_nl_t *
    746
    fido_nl_new(void)
    747
    545k
    {
    748
    545k
            fido_nl_t *nl;
    749
    545k
            int ok = -1;
    750
    751
    545k
            if ((nl = calloc(1, sizeof(*nl))) == NULL)
    752
    1.30k
                    return (NULL);
    753
    544k
            if ((nl->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
    754
    544k
                NETLINK_GENERIC)) == -1) {
    755
    0
                    fido_log_error(errno, "%s: socket", __func__);
    756
    0
                    goto fail;
    757
    0
            }
    758
    544k
            nl->saddr.nl_family = AF_NETLINK;
    759
    544k
            if (bind(nl->fd, (struct sockaddr *)&nl->saddr,
    760
    544k
                sizeof(nl->saddr)) == -1) {
    761
    1.34k
                    fido_log_error(errno, "%s: bind", __func__);
    762
    1.34k
                    goto fail;
    763
    1.34k
            }
    764
    543k
            if (nl_get_nfc_family(nl->fd, &nl->nfc_type, &nl->nfc_mcastgrp) < 0) {
    765
    542k
                    fido_log_debug("%s: nl_get_nfc_family", __func__);
    766
    542k
                    goto fail;
    767
    542k
            }
    768
    769
    733
            ok = 0;
    770
    544k
    fail:
    771
    544k
            if (ok < 0)
    772
    543k
                    fido_nl_free(&nl);
    773
    774
    544k
            return (nl);
    775
    733
    }
    776
    777
    #ifdef FIDO_FUZZ
    778
    void
    779
    set_netlink_io_functions(ssize_t (*read_f)(int, void *, size_t),
    780
        ssize_t (*write_f)(int, const void *, size_t))
    781
    2.14k
    {
    782
    2.14k
            fuzz_read = read_f;
    783
    2.14k
            fuzz_write = write_f;
    784
    2.14k
    }
    785
    #endif