diff --git a/inet/inet_net.c b/inet/inet_net.c index 50b526705d..13a818176d 100644 --- a/inet/inet_net.c +++ b/inet/inet_net.c @@ -69,6 +69,8 @@ again: if (*cp == 'x' || *cp == 'X') digit = 0, base = 16, cp++; while ((c = *cp) != 0) { + if (val > 0xff) + return (INADDR_NONE); if (isdigit(c)) { if (base == 8 && (c == '8' || c == '9')) return (INADDR_NONE); diff --git a/nss/Makefile b/nss/Makefile index 3ee51f309e..09ce94aae7 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -367,6 +367,7 @@ tests += tst-nss-files-hosts-multi tests += tst-nss-files-hosts-getent tests += tst-nss-files-alias-leak tests += tst-nss-files-alias-truncated +tests += tst-nss-files-network # tst_fgetgrent currently only works with shared libraries test-srcs := tst_fgetgrent ifeq ($(run-built-tests),yes) diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c index ca94372024..f08daaf55f 100644 --- a/nss/nss_files/files-network.c +++ b/nss/nss_files/files-network.c @@ -42,7 +42,8 @@ LINE_PARSER STRING_FIELD (addr, isspace, 1); /* 'inet_network' does not add zeroes at the end if the network number - does not four byte values. We add them ourselves if necessary. */ + does not contain four byte values. We shift result ourselves if + necessary. */ cp = strchr (addr, '.'); if (cp != NULL) { @@ -56,20 +57,11 @@ LINE_PARSER ++n; } } - if (n < 4) - { - char *newp = (char *) alloca (strlen (addr) + (4 - n) * 2 + 1); - cp = stpcpy (newp, addr); - do - { - *cp++ = '.'; - *cp++ = '0'; - } - while (++n < 4); - *cp = '\0'; - addr = newp; - } result->n_net = __inet_network (addr); + if (result->n_net == INADDR_NONE) + return 0; + if (n < 4) + result->n_net <<= 8 * (4 - n); result->n_addrtype = AF_INET; }) diff --git a/nss/tst-nss-files-network.c b/nss/tst-nss-files-network.c new file mode 100644 index 0000000000..5aa0cd1db2 --- /dev/null +++ b/nss/tst-nss-files-network.c @@ -0,0 +1,96 @@ +/* Test long entries and truncated numbers in /etc/networks (bug 32573/32575). + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STACK_LIM 1048576 +#define STRING_SIZE (2 * STACK_LIM) + +struct support_chroot *chroot_env; + +static void +prepare (int argc, char **argv) +{ + int ret; + char *content; + char *entry = malloc (STRING_SIZE); + struct rlimit lim; + getrlimit (RLIMIT_STACK, &lim); + lim.rlim_cur = STACK_LIM; + setrlimit (RLIMIT_STACK, &lim); + if (entry == NULL) + { + puts ("malloc failed, cannot test"); + exit (1); + } + memset (entry, 'A', STRING_SIZE); + entry[STRING_SIZE - 1] = 0; + ret = asprintf (&content, "%s\n%s\nnet3 %s\n", + "net1 x0000000000Ff.077", /* legal 255.63.0.0 */ + "net2 xFF00000000.0.0.0", /* illegal */ + entry /* illegal */); + if (ret == -1) + { + puts ("asprintf failed, cannot test"); + exit (1); + } + free (entry); + chroot_env = support_chroot_create + ((struct support_chroot_configuration) + { + .networks = content + }); + +} + +static int +do_test (void) +{ + support_become_root (); + if (!support_can_chroot ()) + return EXIT_UNSUPPORTED; + + __nss_configure_lookup ("networks", "files"); + xdlopen (LIBNSS_FILES_SO, RTLD_NOW); + + xchroot (chroot_env->path_chroot); + + check_netent ("net1", getnetbyname ("net1"), + "name: net1\n" + "net: 0xff3f0000\n"); + check_netent ("net2", getnetbyname ("net2"), "error: HOST_NOT_FOUND\n"); + + support_chroot_free (chroot_env); + return 0; +} + +#define PREPARE prepare +#include diff --git a/support/namespace.h b/support/namespace.h index 456157a4e0..6b9b226f95 100644 --- a/support/namespace.h +++ b/support/namespace.h @@ -75,6 +75,7 @@ struct support_chroot_configuration const char *hosts; /* /etc/hosts. */ const char *host_conf; /* /etc/host.conf. */ const char *aliases; /* /etc/aliases. */ + const char *networks; /* /etc/networks. */ }; /* The result of the creation of a chroot. */ @@ -92,6 +93,7 @@ struct support_chroot char *path_hosts; /* /etc/hosts. */ char *path_host_conf; /* /etc/host.conf. */ char *path_aliases; /* /etc/aliases. */ + char *path_networks; /* /etc/networks. */ }; /* Create a chroot environment. The returned data should be freed diff --git a/support/support_chroot.c b/support/support_chroot.c index 2637dd1522..92c2a453aa 100644 --- a/support/support_chroot.c +++ b/support/support_chroot.c @@ -57,6 +57,7 @@ support_chroot_create (struct support_chroot_configuration conf) write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts); write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf); write_file (path_etc, "aliases", conf.aliases, &chroot->path_aliases); + write_file (path_etc, "networks", conf.networks, &chroot->path_networks); free (path_etc); @@ -79,5 +80,6 @@ support_chroot_free (struct support_chroot *chroot) free (chroot->path_hosts); free (chroot->path_host_conf); free (chroot->path_aliases); + free (chroot->path_networks); free (chroot); }