Coverage Report

Created: 2024-10-03 06:24

/src/SockFuzzer/third_party/xnu/bsd/netinet6/scope6.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2009-2013 Apple Inc. All rights reserved.
3
 *
4
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5
 *
6
 * This file contains Original Code and/or Modifications of Original Code
7
 * as defined in and that are subject to the Apple Public Source License
8
 * Version 2.0 (the 'License'). You may not use this file except in
9
 * compliance with the License. The rights granted to you under the License
10
 * may not be used to create, or enable the creation or redistribution of,
11
 * unlawful or unlicensed copies of an Apple operating system, or to
12
 * circumvent, violate, or enable the circumvention or violation of, any
13
 * terms of an Apple operating system software license agreement.
14
 *
15
 * Please obtain a copy of the License at
16
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17
 *
18
 * The Original Code and all software distributed under the License are
19
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23
 * Please see the License for the specific language governing rights and
24
 * limitations under the License.
25
 *
26
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27
 */
28
29
/*
30
 * Copyright (C) 2000 WIDE Project.
31
 * All rights reserved.
32
 *
33
 * Redistribution and use in source and binary forms, with or without
34
 * modification, are permitted provided that the following conditions
35
 * are met:
36
 * 1. Redistributions of source code must retain the above copyright
37
 *    notice, this list of conditions and the following disclaimer.
38
 * 2. Redistributions in binary form must reproduce the above copyright
39
 *    notice, this list of conditions and the following disclaimer in the
40
 *    documentation and/or other materials provided with the distribution.
41
 * 3. Neither the name of the project nor the names of its contributors
42
 *    may be used to endorse or promote products derived from this software
43
 *    without specific prior written permission.
44
 *
45
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55
 * SUCH DAMAGE.
56
 */
57
58
#include <sys/param.h>
59
#include <sys/malloc.h>
60
#include <sys/mbuf.h>
61
#include <sys/socket.h>
62
#include <sys/systm.h>
63
#include <sys/queue.h>
64
#include <sys/syslog.h>
65
#include <sys/mcache.h>
66
67
#include <net/route.h>
68
#include <net/if.h>
69
70
#include <netinet/in.h>
71
72
#include <netinet6/in6_var.h>
73
#include <netinet6/scope6_var.h>
74
75
#ifdef ENABLE_DEFAULT_SCOPE
76
int ip6_use_defzone = 1;
77
#else
78
int ip6_use_defzone = 0;
79
#endif
80
81
decl_lck_mtx_data(static, scope6_lock);
82
static struct scope6_id sid_default;
83
84
163k
#define SID(ifp) &IN6_IFEXTRA(ifp)->scope6_id
85
86
void
87
scope6_init(lck_grp_t *grp, lck_attr_t *attr)
88
1
{
89
1
  bzero(&sid_default, sizeof(sid_default));
90
1
  lck_mtx_init(&scope6_lock, grp, attr);
91
1
}
92
93
void
94
scope6_ifattach(struct ifnet *ifp)
95
1
{
96
1
  struct scope6_id *sid;
97
98
1
  VERIFY(IN6_IFEXTRA(ifp) != NULL);
99
0
  if_inet6data_lock_exclusive(ifp);
100
1
  sid = SID(ifp);
101
  /* N.B.: the structure is already zero'ed */
102
  /*
103
   * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
104
   * Should we rather hardcode here?
105
   */
106
1
  sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
107
1
  sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
108
#if MULTI_SCOPE
109
  /* by default, we don't care about scope boundary for these scopes. */
110
  sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
111
  sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
112
#endif
113
1
  if_inet6data_lock_done(ifp);
114
1
}
115
116
/*
117
 * Get a scope of the address. Node-local, link-local, site-local or global.
118
 */
119
int
120
in6_addrscope(struct in6_addr *addr)
121
259k
{
122
259k
  int scope;
123
124
259k
  if (addr->s6_addr8[0] == 0xfe) {
125
84.1k
    scope = addr->s6_addr8[1] & 0xc0;
126
127
84.1k
    switch (scope) {
128
81.7k
    case 0x80:
129
81.7k
      return IPV6_ADDR_SCOPE_LINKLOCAL;
130
1.96k
    case 0xc0:
131
1.96k
      return IPV6_ADDR_SCOPE_SITELOCAL;
132
493
    default:
133
493
      return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
134
84.1k
    }
135
84.1k
  }
136
137
174k
  if (addr->s6_addr8[0] == 0xff) {
138
47.3k
    scope = addr->s6_addr8[1] & 0x0f;
139
140
    /*
141
     * due to other scope such as reserved,
142
     * return scope doesn't work.
143
     */
144
47.3k
    switch (scope) {
145
33.0k
    case IPV6_ADDR_SCOPE_INTFACELOCAL:
146
33.0k
      return IPV6_ADDR_SCOPE_INTFACELOCAL;
147
13.1k
    case IPV6_ADDR_SCOPE_LINKLOCAL:
148
13.1k
      return IPV6_ADDR_SCOPE_LINKLOCAL;
149
0
    case IPV6_ADDR_SCOPE_SITELOCAL:
150
0
      return IPV6_ADDR_SCOPE_SITELOCAL;
151
1.08k
    default:
152
1.08k
      return IPV6_ADDR_SCOPE_GLOBAL;
153
47.3k
    }
154
47.3k
  }
155
156
  /*
157
   * Regard loopback and unspecified addresses as global, since
158
   * they have no ambiguity.
159
   */
160
127k
  if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
161
82.6k
    if (addr->s6_addr8[15] == 1) { /* loopback */
162
60.4k
      return IPV6_ADDR_SCOPE_LINKLOCAL;
163
60.4k
    }
164
22.1k
    if (addr->s6_addr8[15] == 0) { /* unspecified */
165
13.3k
      return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
166
13.3k
    }
167
22.1k
  }
168
169
53.6k
  return IPV6_ADDR_SCOPE_GLOBAL;
170
127k
}
171
172
int
173
in6_addr2scopeid(struct ifnet *ifp, struct in6_addr *addr)
174
81.4k
{
175
81.4k
  int scope = in6_addrscope(addr);
176
81.4k
  int retid = 0;
177
81.4k
  struct scope6_id *sid;
178
179
81.4k
  if_inet6data_lock_shared(ifp);
180
81.4k
  if (IN6_IFEXTRA(ifp) == NULL) {
181
0
    goto err;
182
0
  }
183
81.4k
  sid = SID(ifp);
184
81.4k
  switch (scope) {
185
0
  case IPV6_ADDR_SCOPE_NODELOCAL:
186
0
    retid = -1;     /* XXX: is this an appropriate value? */
187
0
    break;
188
48.2k
  case IPV6_ADDR_SCOPE_LINKLOCAL:
189
48.2k
    retid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
190
48.2k
    break;
191
1.90k
  case IPV6_ADDR_SCOPE_SITELOCAL:
192
1.90k
    retid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
193
1.90k
    break;
194
0
  case IPV6_ADDR_SCOPE_ORGLOCAL:
195
0
    retid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
196
0
    break;
197
31.3k
  default:
198
31.3k
    break;  /* XXX: value 0, treat as global. */
199
81.4k
  }
200
81.4k
err:
201
81.4k
  if_inet6data_lock_done(ifp);
202
203
81.4k
  return retid;
204
81.4k
}
205
206
/*
207
 * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
208
 * is unspecified (=0), needs to be specified, and the default zone ID can be
209
 * used, the default value will be used.
210
 * This routine then generates the kernel-internal form: if the address scope
211
 * of is interface-local or link-local, embed the interface index in the
212
 * address.
213
 */
214
int
215
sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
216
0
{
217
0
  struct ifnet *ifp;
218
0
  u_int32_t zoneid;
219
220
0
  if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) {
221
0
    zoneid = scope6_addr2default(&sin6->sin6_addr);
222
0
  }
223
224
0
  if (zoneid != 0 &&
225
0
      (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
226
0
      IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
227
    /*
228
     * At this moment, we only check interface-local and
229
     * link-local scope IDs, and use interface indices as the
230
     * zone IDs assuming a one-to-one mapping between interfaces
231
     * and links.
232
     */
233
0
    if (if_index < zoneid) {
234
0
      return ENXIO;
235
0
    }
236
0
    ifnet_head_lock_shared();
237
0
    ifp = ifindex2ifnet[zoneid];
238
0
    if (ifp == NULL) {      /* XXX: this can happen for some OS */
239
0
      ifnet_head_done();
240
0
      return ENXIO;
241
0
    }
242
0
    ifnet_head_done();
243
    /* XXX assignment to 16bit from 32bit variable */
244
0
    sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);
245
246
0
    sin6->sin6_scope_id = 0;
247
0
  }
248
249
0
  return 0;
250
0
}
251
252
void
253
rtkey_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
254
0
{
255
0
  VERIFY(rt_key(rt)->sa_family == AF_INET6);
256
257
0
  *sin6 = *((struct sockaddr_in6 *)(void *)rt_key(rt));
258
0
  sin6->sin6_scope_id = 0;
259
0
}
260
261
void
262
rtgw_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
263
0
{
264
0
  VERIFY(rt->rt_flags & RTF_GATEWAY);
265
266
0
  *sin6 = *((struct sockaddr_in6 *)(void *)rt->rt_gateway);
267
0
  sin6->sin6_scope_id = 0;
268
0
}
269
270
/*
271
 * generate standard sockaddr_in6 from embedded form.
272
 */
273
int
274
sa6_recoverscope(struct sockaddr_in6 *sin6, boolean_t attachcheck)
275
96.5k
{
276
96.5k
  u_int32_t zoneid;
277
278
96.5k
  if (sin6->sin6_scope_id != 0) {
279
0
    log(LOG_NOTICE,
280
0
        "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
281
0
        ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
282
    /* XXX: proceed anyway... */
283
0
  }
284
96.5k
  if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
285
96.5k
      IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
286
    /*
287
     * KAME assumption: link id == interface id
288
     */
289
50.8k
    zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
290
50.8k
    if (zoneid) {
291
      /* sanity check */
292
50.8k
      if (if_index < zoneid) {
293
0
        return ENXIO;
294
0
      }
295
      /*
296
       * We use the attachcheck parameter to skip the
297
       * interface attachment check.
298
       * Some callers might hold the ifnet_head lock in
299
       * exclusive mode. This means that:
300
       * 1) the interface can't go away -- hence we don't
301
       *    need to perform this check
302
       * 2) we can't perform this check because the lock is
303
       *    in exclusive mode and trying to lock it in shared
304
       *    mode would cause a deadlock.
305
       */
306
50.8k
      if (attachcheck) {
307
34.6k
        ifnet_head_lock_shared();
308
34.6k
        if (ifindex2ifnet[zoneid] == NULL) {
309
0
          ifnet_head_done();
310
0
          return ENXIO;
311
0
        }
312
34.6k
        ifnet_head_done();
313
34.6k
      }
314
50.8k
      sin6->sin6_addr.s6_addr16[1] = 0;
315
50.8k
      sin6->sin6_scope_id = zoneid;
316
50.8k
    }
317
50.8k
  }
318
319
96.5k
  return 0;
320
96.5k
}
321
322
void
323
scope6_setdefault(struct ifnet *ifp)
324
0
{
325
  /*
326
   * Currently, this function just set the default "link" according to
327
   * the given interface.
328
   * We might eventually have to separate the notion of "link" from
329
   * "interface" and provide a user interface to set the default.
330
   */
331
0
  lck_mtx_lock(&scope6_lock);
332
0
  if (ifp != NULL) {
333
0
    sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] =
334
0
        ifp->if_index;
335
0
    sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
336
0
        ifp->if_index;
337
0
  } else {
338
0
    sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0;
339
0
    sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
340
0
  }
341
0
  lck_mtx_unlock(&scope6_lock);
342
0
}
343
344
345
u_int32_t
346
scope6_addr2default(struct in6_addr *addr)
347
0
{
348
0
  u_int32_t id = 0;
349
0
  int index = in6_addrscope(addr);
350
351
  /*
352
   * special case: The loopback address should be considered as
353
   * link-local, but there's no ambiguity in the syntax.
354
   */
355
0
  if (IN6_IS_ADDR_LOOPBACK(addr)) {
356
0
    return 0;
357
0
  }
358
359
0
  lck_mtx_lock(&scope6_lock);
360
0
  id = sid_default.s6id_list[index];
361
0
  lck_mtx_unlock(&scope6_lock);
362
363
0
  return id;
364
0
}
365
366
/*
367
 * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
368
 * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
369
 * in the in6_addr structure, in6 will be modified.
370
 *
371
 * ret_id - unnecessary?
372
 */
373
int
374
in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
375
130k
{
376
130k
  int scope;
377
130k
  u_int32_t zoneid = 0;
378
130k
  struct scope6_id *sid;
379
380
  /*
381
   * special case: the loopback address can only belong to a loopback
382
   * interface.
383
   */
384
130k
  if (IN6_IS_ADDR_LOOPBACK(in6)) {
385
48.8k
    if (!(ifp->if_flags & IFF_LOOPBACK)) {
386
34.8k
      return EINVAL;
387
34.8k
    } else {
388
14.0k
      if (ret_id != NULL) {
389
8.87k
        *ret_id = 0; /* there's no ambiguity */
390
8.87k
      }
391
14.0k
      return 0;
392
14.0k
    }
393
48.8k
  }
394
395
81.6k
  scope = in6_addrscope(in6);
396
397
81.6k
  if_inet6data_lock_shared(ifp);
398
81.6k
  if (IN6_IFEXTRA(ifp) == NULL) {
399
0
    if_inet6data_lock_done(ifp);
400
0
    if (ret_id) {
401
0
      *ret_id = 0;
402
0
    }
403
0
    return EINVAL;
404
0
  }
405
81.6k
  sid = SID(ifp);
406
81.6k
  switch (scope) {
407
111
  case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
408
111
    zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
409
111
    break;
410
411
44.2k
  case IPV6_ADDR_SCOPE_LINKLOCAL:
412
44.2k
    zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
413
44.2k
    break;
414
415
59
  case IPV6_ADDR_SCOPE_SITELOCAL:
416
59
    zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
417
59
    break;
418
419
0
  case IPV6_ADDR_SCOPE_ORGLOCAL:
420
0
    zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
421
0
    break;
422
37.2k
  default:
423
37.2k
    zoneid = 0;     /* XXX: treat as global. */
424
37.2k
    break;
425
81.6k
  }
426
81.6k
  if_inet6data_lock_done(ifp);
427
428
81.6k
  if (ret_id != NULL) {
429
25.5k
    *ret_id = zoneid;
430
25.5k
  }
431
432
81.6k
  if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
433
44.3k
    in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
434
44.3k
  }
435
81.6k
  return 0;
436
81.6k
}
437
438
/*
439
 * Just clear the embedded scope identifier.  Return 0 if the original address
440
 * is intact; return non 0 if the address is modified.
441
 */
442
int
443
in6_clearscope(struct in6_addr *in6)
444
87.7k
{
445
87.7k
  int modified = 0;
446
447
87.7k
  if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
448
5.45k
    if (in6->s6_addr16[1] != 0) {
449
5.45k
      modified = 1;
450
5.45k
    }
451
5.45k
    in6->s6_addr16[1] = 0;
452
5.45k
  }
453
454
87.7k
  return modified;
455
87.7k
}