diff options
author | Florian Weimer <fweimer@redhat.com> | 2017-06-21 13:09:08 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2017-06-21 13:09:08 +0200 |
commit | 60149b28590be28051f99d0a343d7fbe002f2a8c (patch) | |
tree | 3eb9b2d7016cedd4178a193fe6c0146ec847f7ee | |
parent | 965d5c391c86eb3a812ce308411c32754f12a9d2 (diff) | |
download | glibc-60149b28590be28051f99d0a343d7fbe002f2a8c.tar.gz |
__inet_pton_length: Implement new internal helper function
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | resolv/Makefile | 3 | ||||
-rw-r--r-- | resolv/Versions | 1 | ||||
-rw-r--r-- | resolv/inet_pton.c | 159 | ||||
-rw-r--r-- | resolv/resolv-internal.h | 9 | ||||
-rw-r--r-- | resolv/tst-inet_pton.c | 549 | ||||
-rw-r--r-- | support/Makefile | 1 | ||||
-rw-r--r-- | support/xmprotect.c | 28 | ||||
-rw-r--r-- | support/xunistd.h | 2 |
9 files changed, 697 insertions, 73 deletions
@@ -1,5 +1,23 @@ 2017-06-21 Florian Weimer <fweimer@redhat.com> + Add the __inet_pton_length helper function. + * resolv/resolv-internal.h (__inet_pton_length): Declare. + * resolv/inet_pton (__inet_pton_length): Rename from __inet_pton. + Add length argument. + (__inet_pton): New function. + (inet_pton4): Add length argument. + (hex_digit_value): New function. + (inet_pton6): Add length argument. Call hex_digit_value. Use + memmove and memset to fill :: gap. + * resolv/Makefile (tests, tsts-static, tests-internal): Add + tst-inet_pton. + * resolv/tst-inet_pton.c: New file. + * support/Makefile (libsupport-routines): Add xmprotect. + * support/xunistd.h (xmprotect): Declare. + * support/xmprotect.c: New file. + +2017-06-21 Florian Weimer <fweimer@redhat.com> + Add IPv6 getaddrinfo coverage to tst-inet6_scopeid_pton.c. * inet/tst-inet6_scopeid_pton.c: Switch to <support/test-driver.c>. (call_gai, check_ai): New functions. diff --git a/resolv/Makefile b/resolv/Makefile index a9b355faed..8294d9481c 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -64,6 +64,9 @@ tests-internal += \ endif +# This test accesses __inet_ntop_range, an internal libc function. +tests-internal += tst-inet_pton + # This test sends millions of packets and is rather slow. xtests += tst-resolv-qtypes endif diff --git a/resolv/Versions b/resolv/Versions index e561bce1a4..f528ed51e8 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -27,6 +27,7 @@ libc { __h_errno; __resp; __res_maybe_init; __res_iclose; + __inet_pton_length; } } diff --git a/resolv/inet_pton.c b/resolv/inet_pton.c index 68f0fa5402..b95da47c17 100644 --- a/resolv/inet_pton.c +++ b/resolv/inet_pton.c @@ -1,3 +1,20 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + /* * Copyright (c) 1996,1999 by Internet Software Consortium. * @@ -15,58 +32,53 @@ * SOFTWARE. */ -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> #include <ctype.h> -#include <string.h> #include <errno.h> +#include <netinet/in.h> +#include <resolv/resolv-internal.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> -static int inet_pton4 (const char *src, unsigned char *dst); -static int inet_pton6 (const char *src, unsigned char *dst); +static int inet_pton4 (const char *src, const char *src_end, u_char *dst); +static int inet_pton6 (const char *src, const char *src_end, u_char *dst); -/* Convert from presentation format (which usually means ASCII printable) - * to network format (which is usually some kind of binary format). - * - * return: - * 1 if the address was valid for the specified address family - * 0 if the address wasn't valid (`dst' is untouched in this case) - * -1 if some other error occurred (`dst' is untouched in this case, too) - * author: - * Paul Vixie, 1996. - */ int -__inet_pton (int af, const char *src, void *dst) +__inet_pton_length (int af, const char *src, size_t srclen, void *dst) { switch (af) { case AF_INET: - return inet_pton4 (src, dst); + return inet_pton4 (src, src + srclen, dst); case AF_INET6: - return inet_pton6 (src, dst); + return inet_pton6 (src, src + srclen, dst); default: __set_errno (EAFNOSUPPORT); return -1; } } +libc_hidden_def (__inet_pton_length) + +/* Like __inet_pton_length, but use strlen (SRC) as the length of + SRC. */ +int +__inet_pton (int af, const char *src, void *dst) +{ + return __inet_pton_length (af, src, strlen (src), dst); +} libc_hidden_def (__inet_pton) weak_alias (__inet_pton, inet_pton) libc_hidden_weak (inet_pton) -/* Like inet_atonbut without all the hexadecimal, octal and shorthand. - * - * return: - * 1 if `src' is a valid dotted quad, else 0. - * notice: - * does not touch `dst' unless it's returning 1. - * author: - * Paul Vixie, 1996. - */ +/* Like inet_aton but without all the hexadecimal, octal and shorthand + (and trailing garbage is not ignored). Return 1 if SRC is a valid + dotted quad, else 0. This function does not touch DST unless it's + returning 1. + Author: Paul Vixie, 1996. */ static int -inet_pton4 (const char *src, unsigned char *dst) +inet_pton4 (const char *src, const char *end, unsigned char *dst) { int saw_digit, octets, ch; unsigned char tmp[NS_INADDRSZ], *tp; @@ -74,8 +86,9 @@ inet_pton4 (const char *src, unsigned char *dst) saw_digit = 0; octets = 0; *(tp = tmp) = 0; - while ((ch = *src++) != '\0') + while (src < end) { + ch = *src++; if (ch >= '0' && ch <= '9') { unsigned int new = *tp * 10 + (ch - '0'); @@ -108,22 +121,27 @@ inet_pton4 (const char *src, unsigned char *dst) return 1; } -/* Cconvert presentation level address to network order binary form. - * - * return: - * 1 if `src' is a valid [RFC1884 2.2] address, else 0. - * notice: - * (1) does not touch `dst' unless it's returning 1. - * (2) :: in a full address is silently ignored. - * credit: - * inspired by Mark Andrews. - * author: - * Paul Vixie, 1996. - */ +/* Return the value of CH as a hexademical digit, or -1 if it is a + different type of character. */ +static int +hex_digit_value (char ch) +{ + if ('0' <= ch && ch <= '9') + return ch - '0'; + if ('a' <= ch && ch <= 'f') + return ch - 'a' + 10; + if ('A' <= ch && ch <= 'F') + return ch - 'A' + 10; + return -1; +} + +/* Convert presentation-level IPv6 address to network order binary + form. Return 1 if SRC is a valid [RFC1884 2.2] address, else 0. + This function does not touch DST unless it's returning 1. + Author: Paul Vixie, 1996. Inspired by Mark Andrews. */ static int -inet_pton6 (const char *src, unsigned char *dst) +inet_pton6 (const char *src, const char *src_endp, unsigned char *dst) { - static const char xdigits[] = "0123456789abcdef"; unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *curtok; int ch, saw_xdigit; @@ -132,22 +150,28 @@ inet_pton6 (const char *src, unsigned char *dst) tp = memset (tmp, '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; + /* Leading :: requires some special handling. */ + if (src == src_endp) + return 0; if (*src == ':') - if (*++src != ':') - return 0; + { + ++src; + if (src == src_endp || *src != ':') + return 0; + } + curtok = src; saw_xdigit = 0; val = 0; - while ((ch = tolower (*src++)) != '\0') + while (src < src_endp) { - const char *pch; - - pch = strchr (xdigits, ch); - if (pch != NULL) + ch = *src++; + int digit = hex_digit_value (ch); + if (digit >= 0) { val <<= 4; - val |= (pch - xdigits); + val |= digit; if (val > 0xffff) return 0; saw_xdigit = 1; @@ -163,10 +187,8 @@ inet_pton6 (const char *src, unsigned char *dst) colonp = tp; continue; } - else if (*src == '\0') - { - return 0; - } + else if (src == src_endp) + return 0; if (tp + NS_INT16SZ > endp) return 0; *tp++ = (unsigned char) (val >> 8) & 0xff; @@ -175,8 +197,8 @@ inet_pton6 (const char *src, unsigned char *dst) val = 0; continue; } - if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && - inet_pton4 (curtok, tp) > 0) + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) + && inet_pton4 (curtok, src_endp, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; @@ -193,20 +215,13 @@ inet_pton6 (const char *src, unsigned char *dst) } if (colonp != NULL) { - /* - * Since some memmove's erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - const int n = tp - colonp; - int i; - + /* Replace :: with zeros. */ if (tp == endp) - return 0; - for (i = 1; i <= n; i++) - { - endp[- i] = colonp[n - i]; - colonp[n - i] = 0; - } + /* :: would expand to a zero-width field. */ + return 0; + size_t n = tp - colonp; + memmove (endp - n, colonp, n); + memset (colonp, 0, endp - n - colonp); tp = endp; } if (tp != endp) diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h index 0d69ce10d3..9afaa07d8b 100644 --- a/resolv/resolv-internal.h +++ b/resolv/resolv-internal.h @@ -56,4 +56,13 @@ enum int __res_nopt (res_state, int n0, unsigned char *buf, int buflen, int anslen) attribute_hidden; +/* Convert from presentation format (which usually means ASCII + printable) to network format (which is usually some kind of binary + format). The input is in the range [SRC, SRC + SRCLEN). The + output is written to DST (which has to be 4 or 16 bytes long, + depending on AF). Return 0 for invalid input, 1 for success, -1 + for an invalid address family. */ +int __inet_pton_length (int af, const char *src, size_t srclen, void *); +libc_hidden_proto (__inet_pton_length) + #endif /* _RESOLV_INTERNAL_H */ diff --git a/resolv/tst-inet_pton.c b/resolv/tst-inet_pton.c new file mode 100644 index 0000000000..7fffb24cdf --- /dev/null +++ b/resolv/tst-inet_pton.c @@ -0,0 +1,549 @@ +/* Test inet_pton functions. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <arpa/inet.h> +#include <resolv/resolv-internal.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <support/check.h> +#include <support/xunistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <unistd.h> + +/* Memory region created by next_to_fault_allocate. */ +struct next_to_fault +{ + /* The user data. */ + char *buffer; + size_t length; + + /* The entire allocated region. */ + void *region_start; + size_t region_size; +}; + +/* Allocate a buffer of SIZE bytes just before a page which is mapped + with PROT_NONE (so that overrunning the buffer will cause a + fault). */ +static struct next_to_fault +next_to_fault_allocate (size_t size) +{ + long page_size = sysconf (_SC_PAGE_SIZE); + TEST_VERIFY_EXIT (page_size > 0); + struct next_to_fault result; + result.region_size = roundup (size, page_size) + page_size; + TEST_VERIFY_EXIT (size + page_size > size); + TEST_VERIFY_EXIT (result.region_size > size); + result.region_start + = xmmap (NULL, result.region_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1); + /* Unmap the page after the allocation. */ + xmprotect (result.region_start + (result.region_size - page_size), + page_size, PROT_NONE); + /* Align the allocation within the region so that it ends just + before the PROT_NONE page. */ + result.buffer = result.region_start + result.region_size - page_size - size; + result.length = size; + return result; +} + +/* Deallocate the memory region allocated by + next_to_fault_allocate. */ +static void +next_to_fault_free (struct next_to_fault *ntf) +{ + xmunmap (ntf->region_start, ntf->region_size); + *ntf = (struct next_to_fault) { NULL, }; +} + +struct test_case +{ + /* The input data. */ + const char *input; + + /* True if AF_INET parses successfully. */ + bool ipv4_ok; + + /* True if AF_INET6 parses successfully. */ + bool ipv6_ok; + + /* Expected result for AF_INET. */ + unsigned char ipv4_expected[4]; + + /* Expected result for AF_INET6. */ + unsigned char ipv6_expected[16]; +}; + +static void +check_result (const char *what, const struct test_case *t, int family, + void *result_buffer, int inet_ret) +{ + TEST_VERIFY_EXIT (inet_ret >= -1); + TEST_VERIFY_EXIT (inet_ret <= 1); + + int ok; + const unsigned char *expected; + size_t result_size; + switch (family) + { + case AF_INET: + ok = t->ipv4_ok; + expected = t->ipv4_expected; + result_size = 4; + break; + case AF_INET6: + ok = t->ipv6_ok; + expected = t->ipv6_expected; + result_size = 16; + break; + default: + FAIL_EXIT1 ("invalid address family %d", family); + } + + if (inet_ret != ok) + { + support_record_failure (); + printf ("error: %s return value mismatch for [[%s]], family %d\n" + " expected: %d\n" + " actual: %d\n", + what, t->input, family, ok, inet_ret); + return; + } + if (memcmp (result_buffer, expected, result_size) != 0) + { + support_record_failure (); + printf ("error: %s result mismatch for [[%s]], family %d\n", + what, t->input, family); + } +} + +static void +run_one_test (const struct test_case *t) +{ + size_t test_len = strlen (t->input); + + struct next_to_fault ntf_out4 = next_to_fault_allocate (4); + struct next_to_fault ntf_out6 = next_to_fault_allocate (16); + + /* inet_pton requires NUL termination. */ + { + struct next_to_fault ntf_in = next_to_fault_allocate (test_len + 1); + memcpy (ntf_in.buffer, t->input, test_len + 1); + memset (ntf_out4.buffer, 0, 4); + check_result ("inet_pton", t, AF_INET, ntf_out4.buffer, + inet_pton (AF_INET, ntf_in.buffer, ntf_out4.buffer)); + memset (ntf_out6.buffer, 0, 16); + check_result ("inet_pton", t, AF_INET6, ntf_out6.buffer, + inet_pton (AF_INET6, ntf_in.buffer, ntf_out6.buffer)); + next_to_fault_free (&ntf_in); + } + + /* __inet_pton_length does not require NUL termination. */ + { + struct next_to_fault ntf_in = next_to_fault_allocate (test_len); + memcpy (ntf_in.buffer, t->input, test_len); + memset (ntf_out4.buffer, 0, 4); + check_result ("__inet_pton_length", t, AF_INET, ntf_out4.buffer, + __inet_pton_length (AF_INET, ntf_in.buffer, ntf_in.length, + ntf_out4.buffer)); + memset (ntf_out6.buffer, 0, 16); + check_result ("__inet_pton_length", t, AF_INET6, ntf_out6.buffer, + __inet_pton_length (AF_INET6, ntf_in.buffer, ntf_in.length, + ntf_out6.buffer)); + next_to_fault_free (&ntf_in); + } + + next_to_fault_free (&ntf_out4); + next_to_fault_free (&ntf_out6); +} + +/* The test cases were manually crafted and the set enhanced with + American Fuzzy Lop. */ +const struct test_case test_cases[] = + { + {.input = ".:", }, + {.input = "0.0.0.0", + .ipv4_ok = true, + .ipv4_expected = {0, 0, 0, 0}, + }, + {.input = "0.:", }, + {.input = "00", }, + {.input = "0000000", }, + {.input = "00000000000000000", }, + {.input = "092.", }, + {.input = "10.0.301.2", }, + {.input = "127.0.0.1", + .ipv4_ok = true, + .ipv4_expected = {127, 0, 0, 1}, + }, + {.input = "19..", }, + {.input = "192.0.2.-1", }, + {.input = "192.0.2.01", }, + {.input = "192.0.2.1.", }, + {.input = "192.0.2.1192.", }, + {.input = "192.0.2.192.\377..", }, + {.input = "192.0.2.256", }, + {.input = "192.0.2.27", + .ipv4_ok = true, + .ipv4_expected = {192, 0, 2, 27}, + }, + {.input = "192.0.201.", }, + {.input = "192.0.261.", }, + {.input = "192.0.2\256", }, + {.input = "192.0.\262.", }, + {.input = "192.062.", }, + {.input = "192.092.\256", }, + {.input = "192.0\2562.", }, + {.input = "192.192.0.2661\031", }, + {.input = "192.192.00n2.1.", }, + {.input = "192.192.2.190.", }, + {.input = "192.255.255.2555", }, + {.input = "192.92.219\023.", }, + {.input = "192.\260.2.", }, + {.input = "1:1::1:1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1 + }, + }, + {.input = "2", }, + {.input = "2.", }, + {.input = "2001:db8:00001::f", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf + }, + }, + {.input = "2001:db8:10000::f", }, + {.input = "2001:db8:1234:5678:abcd:ef01:2345:67", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x12, 0x34, 0x56, 0x78, + 0xab, 0xcd, 0xef, 0x1, 0x23, 0x45, 0x0, 0x67 + }, + }, + {.input = "2001:db8:1234:5678:abcd:ef01:2345:6789:1", }, + {.input = "2001:db8:1234:5678:abcd:ef01:2345::6789", }, + {.input = "2001:db8::0", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, + }, + {.input = "2001:db8::00", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, + }, + {.input = "2001:db8::1", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 + }, + }, + {.input = "2001:db8::10", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10 + }, + }, + {.input = "2001:db8::19", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19 + }, + }, + {.input = "2001:db8::1::\012", }, + {.input = "2001:db8::1::2\012", }, + {.input = "2001:db8::2", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 + }, + }, + {.input = "2001:db8::3", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3 + }, + }, + {.input = "2001:db8::4", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4 + }, + }, + {.input = "2001:db8::5", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5 + }, + }, + {.input = "2001:db8::6", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6 + }, + }, + {.input = "2001:db8::7", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7 + }, + }, + {.input = "2001:db8::8", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8 + }, + }, + {.input = "2001:db8::9", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9 + }, + }, + {.input = "2001:db8::A", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa + }, + }, + {.input = "2001:db8::B", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb + }, + }, + {.input = "2001:db8::C", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc + }, + }, + {.input = "2001:db8::D", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd + }, + }, + {.input = "2001:db8::E", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe + }, + }, + {.input = "2001:db8::F", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf + }, + }, + {.input = "2001:db8::a", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa + }, + }, + {.input = "2001:db8::b", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb + }, + }, + {.input = "2001:db8::c", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc + }, + }, + {.input = "2001:db8::d", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd + }, + }, + {.input = "2001:db8::e", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe + }, + }, + {.input = "2001:db8::f", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf + }, + }, + {.input = "2001:db8::ff", + .ipv6_ok = true, + .ipv6_expected = { + 0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff + }, + }, + {.input = "2001:db8::ffff:2\012", }, + {.input = "22", }, + {.input = "2222@", }, + {.input = "255.255.255.255", + .ipv4_ok = true, + .ipv4_expected = {255, 255, 255, 255}, + }, + {.input = "255.255.255.255\001", }, + {.input = "255.255.255.25555", }, + {.input = "2:", }, + {.input = "2:a:8:EEEE::EEEE:F:EEE8:EEEE\034*:", }, + {.input = "2:ff:1:1:7:ff:1:1:7.", }, + {.input = "2f:0000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000" + "0G01", + }, + {.input = "429495", }, + {.input = "5::5::", }, + {.input = "6.6.", }, + {.input = "992.", }, + {.input = "::", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, + }, + {.input = "::00001", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 + }, + }, + {.input = "::1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 + }, + }, + {.input = "::10000", }, + {.input = "::1:1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1 + }, + }, + {.input = "::ff:1:1:7.0.0.1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x0, 0x1, 0x0, 0x1, 0x7, 0x0, 0x0, 0x1 + }, + }, + {.input = "::ff:1:1:7:ff:1:1:7.", }, + {.input = "::ff:1:1:7ff:1:8:7.0.0.1", }, + {.input = "::ff:1:1:7ff:1:8f:1:1:71", }, + {.input = "::ffff:02fff:127.0.S1", }, + {.input = "::ffff:127.0.0.1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x1 + }, + }, + {.input = "::ffff:1:7.0.0.1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x0, 0x1, 0x7, 0x0, 0x0, 0x1 + }, + }, + {.input = ":\272", }, + {.input = "A:f:ff:1:1:D:ff:1:1::7.", }, + {.input = "AAAAA.", }, + {.input = "D:::", }, + {.input = "DF8F", }, + {.input = "F::", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, + }, + {.input = "F:A:8:EEEE:8:EEEE\034*:", }, + {.input = "F:a:8:EEEE:8:EEEE\034*:", }, + {.input = "F:ff:100:7ff:1:8:7.0.10.1", + .ipv6_ok = true, + .ipv6_expected = { + 0x0, 0xf, 0x0, 0xff, 0x1, 0x0, 0x7, 0xff, + 0x0, 0x1, 0x0, 0x8, 0x7, 0x0, 0xa, 0x1 + }, + }, + {.input = "d92.", }, + {.input = "ff:00000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000001", + }, + {.input = "fff2:2::ff2:2:f7", + .ipv6_ok = true, + .ipv6_expected = { + 0xff, 0xf2, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xf2, 0x0, 0x2, 0x0, 0xf7 + }, + }, + {.input = "ffff:ff:ff:fff:ff:ff:ff:", }, + {.input = "\272:", }, + {NULL} + }; + +static int +do_test (void) +{ + for (size_t i = 0; test_cases[i].input != NULL; ++i) + run_one_test (test_cases + i); + return 0; +} + +#include <support/test-driver.c> diff --git a/support/Makefile b/support/Makefile index a2480cdc70..423538d06a 100644 --- a/support/Makefile +++ b/support/Makefile @@ -74,6 +74,7 @@ libsupport-routines = \ xmemstream \ xmkdir \ xmmap \ + xmprotect \ xmunmap \ xopen \ xpipe \ diff --git a/support/xmprotect.c b/support/xmprotect.c new file mode 100644 index 0000000000..9410251c32 --- /dev/null +++ b/support/xmprotect.c @@ -0,0 +1,28 @@ +/* mprotect with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <support/check.h> +#include <support/xunistd.h> +#include <sys/mman.h> + +void +xmprotect (void *addr, size_t length, int prot) +{ + if (mprotect (addr, length, prot) != 0) + FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot); +} diff --git a/support/xunistd.h b/support/xunistd.h index 151d743e1f..c947bfd8fb 100644 --- a/support/xunistd.h +++ b/support/xunistd.h @@ -48,7 +48,7 @@ void xwrite (int, const void *, size_t); /* Invoke mmap with a zero file offset. */ void *xmmap (void *addr, size_t length, int prot, int flags, int fd); - +void xmprotect (void *addr, size_t length, int prot); void xmunmap (void *addr, size_t length); __END_DECLS |