summaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/posix/getaddrinfo.c258
-rw-r--r--sysdeps/unix/sysv/linux/Makefile2
-rw-r--r--sysdeps/unix/sysv/linux/Versions2
-rw-r--r--sysdeps/unix/sysv/linux/bits/sched.h3
-rw-r--r--sysdeps/unix/sysv/linux/check_pf.c2
-rw-r--r--sysdeps/unix/sysv/linux/sched_getcpu.c36
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S50
7 files changed, 169 insertions, 184 deletions
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index da48d46afe..adb3c4f96a 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -61,6 +61,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <nscd/nscd-client.h>
#include <nscd/nscd_proto.h>
+#ifdef HAVE_NETLINK_ROUTE
+# include <kernel-features.h>
+#endif
+
#ifdef HAVE_LIBIDN
extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
extern int __idna_to_unicode_lzlz (const char *input, char **output,
@@ -142,118 +146,6 @@ static const struct addrinfo default_hints =
};
-#if 0
-/* Using Unix sockets this way is a security risk. */
-static int
-gaih_local (const char *name, const struct gaih_service *service,
- const struct addrinfo *req, struct addrinfo **pai)
-{
- struct utsname utsname;
-
- if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
- return GAIH_OKIFUNSPEC | -EAI_NONAME;
-
- if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
- if (uname (&utsname) < 0)
- return -EAI_SYSTEM;
-
- if (name != NULL)
- {
- if (strcmp(name, "localhost") &&
- strcmp(name, "local") &&
- strcmp(name, "unix") &&
- strcmp(name, utsname.nodename))
- return GAIH_OKIFUNSPEC | -EAI_NONAME;
- }
-
- if (req->ai_protocol || req->ai_socktype)
- {
- const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
-
- while (tp->name[0]
- && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
- || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
- || (req->ai_protocol != 0
- && !(tp->protoflag & GAI_PROTO_PROTOANY)
- && req->ai_protocol != tp->protocol)))
- ++tp;
-
- if (! tp->name[0])
- {
- if (req->ai_socktype)
- return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
- else
- return GAIH_OKIFUNSPEC | -EAI_SERVICE;
- }
- }
-
- *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
- + ((req->ai_flags & AI_CANONNAME)
- ? (strlen(utsname.nodename) + 1): 0));
- if (*pai == NULL)
- return -EAI_MEMORY;
-
- (*pai)->ai_next = NULL;
- (*pai)->ai_flags = req->ai_flags;
- (*pai)->ai_family = AF_LOCAL;
- (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
- (*pai)->ai_protocol = req->ai_protocol;
- (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
- (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
-
-#ifdef _HAVE_SA_LEN
- ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
- sizeof (struct sockaddr_un);
-#endif /* _HAVE_SA_LEN */
-
- ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
- memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
-
- if (service)
- {
- struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
-
- if (strchr (service->name, '/') != NULL)
- {
- if (strlen (service->name) >= sizeof (sunp->sun_path))
- return GAIH_OKIFUNSPEC | -EAI_SERVICE;
-
- strcpy (sunp->sun_path, service->name);
- }
- else
- {
- if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
- sizeof (sunp->sun_path))
- return GAIH_OKIFUNSPEC | -EAI_SERVICE;
-
- __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
- }
- }
- else
- {
- /* This is a dangerous use of the interface since there is a time
- window between the test for the file and the actual creation
- (done by the caller) in which a file with the same name could
- be created. */
- char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
-
- if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
- 0) != 0
- || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
- return -EAI_SYSTEM;
- }
-
- if (req->ai_flags & AI_CANONNAME)
- (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
- + sizeof (struct sockaddr_un),
- utsname.nodename);
- else
- (*pai)->ai_canonname = NULL;
- return 0;
-}
-#endif /* 0 */
-
-
static int
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
const struct addrinfo *req, struct gaih_servtuple *st)
@@ -1105,17 +997,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
return 0;
}
-#if 0
-static const struct gaih gaih[] =
- {
- { PF_INET6, gaih_inet },
- { PF_INET, gaih_inet },
-#if 0
- { PF_LOCAL, gaih_local },
-#endif
- { PF_UNSPEC, NULL }
- };
-#endif
struct sort_result
{
@@ -1218,6 +1099,10 @@ static const struct prefixentry default_labels[] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
7, 6 },
{ { .in6_u
+ = { .u6_addr8 = { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 32, 7 },
+ { { .in6_u
= { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
0, 1 }
@@ -1851,6 +1736,16 @@ gaiconf_reload (void)
}
+#if HAVE_NETLINK_ROUTE
+# if __ASSUME_NETLINK_SUPPORT == 0
+/* Defined in ifaddrs.c. */
+extern int __no_netlink_support attribute_hidden;
+# else
+# define __no_netlink_support 0
+# endif
+#endif
+
+
int
getaddrinfo (const char *name, const char *service,
const struct addrinfo *hints, struct addrinfo **pai)
@@ -1886,20 +1781,74 @@ getaddrinfo (const char *name, const char *service,
return EAI_BADFLAGS;
struct in6addrinfo *in6ai = NULL;
- size_t in6ailen;
+ size_t in6ailen = 0;
bool seen_ipv4 = false;
bool seen_ipv6 = false;
+#ifdef HAVE_NETLINK_ROUTE
+ int sockfd = -1;
+ pid_t nl_pid;
+#endif
/* We might need information about what kind of interfaces are available.
But even if AI_ADDRCONFIG is not used, if the user requested IPv6
addresses we have to know whether an address is deprecated or
temporary. */
if ((hints->ai_flags & AI_ADDRCONFIG) || hints->ai_family == PF_UNSPEC
|| hints->ai_family == PF_INET6)
- /* Determine whether we have IPv4 or IPv6 interfaces or both. We
- cannot cache the results since new interfaces could be added at
- any time. */
- __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
+ {
+ /* Determine whether we have IPv4 or IPv6 interfaces or both. We
+ cannot cache the results since new interfaces could be added at
+ any time. */
+ __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
+#ifdef HAVE_NETLINK_ROUTE
+ if (! __no_netlink_support)
+ {
+ sockfd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+ struct sockaddr_nl nladdr;
+ memset (&nladdr, '\0', sizeof (nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ socklen_t addr_len = sizeof (nladdr);
+
+ if (sockfd >= 0
+ && __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
+ && __getsockname (sockfd, (struct sockaddr *) &nladdr,
+ &addr_len) == 0
+ && make_request (sockfd, nladdr.nl_pid, &seen_ipv4, &seen_ipv6,
+ in6ai, in6ailen) == 0)
+ {
+ /* It worked. */
+ nl_pid = nladdr.nl_pid;
+ goto got_netlink_socket;
+ }
+
+ if (sockfd >= 0)
+ close_not_cancel_no_status (sockfd);
+#if __ASSUME_NETLINK_SUPPORT == 0
+ /* Remember that there is no netlink support. */
+ if (errno != EMFILE && errno != ENFILE)
+ __no_netlink_support = 1;
+#else
+ else
+ {
+ if (errno != EMFILE && errno != ENFILE)
+ sockfd = -2;
+
+ /* We cannot determine what interfaces are available. Be
+ pessimistic. */
+ seen_ipv4 = true;
+ seen_ipv6 = true;
+ return;
+ }
+#endif
+ }
+#endif
+ }
+
+#ifdef HAVE_NETLINK_ROUTE
+ got_netlink_socket:
+#endif
if (hints->ai_flags & AI_ADDRCONFIG)
{
/* Now make a decision on what we return, if anything. */
@@ -1951,58 +1900,6 @@ getaddrinfo (const char *name, const char *service,
end = NULL;
unsigned int naddrs = 0;
-#if 0
- /* If we would support more protocols than just IPv4 and IPv6 we
- would iterate over a table with appropriate callback functions.
- Since we currently only handle IPv4 and IPv6 this is not
- necessary. */
- const struct gaih *g = gaih;
- const struct gaih *pg = NULL;
- int j = 0;
- while (g->gaih)
- {
- if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
- {
- j++;
- if (pg == NULL || pg->gaih != g->gaih)
- {
- pg = g;
- i = g->gaih (name, pservice, hints, end, &naddrs);
- if (i != 0)
- {
- /* EAI_NODATA is a more specific result as it says that
- we found a result but it is not usable. */
- if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
- last_i = i;
-
- if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
- {
- ++g;
- continue;
- }
-
- freeaddrinfo (p);
- free (in6ai);
-
- return -(i & GAIH_EAI);
- }
- if (end)
- while (*end)
- {
- end = &((*end)->ai_next);
- ++nresults;
- }
- }
- }
- ++g;
- }
-
- if (j == 0)
- {
- free (in6ai);
- return EAI_FAMILY;
- }
-#else
if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET
|| hints->ai_family == AF_INET6)
{
@@ -2026,7 +1923,6 @@ getaddrinfo (const char *name, const char *service,
free (in6ai);
return EAI_FAMILY;
}
-#endif
if (naddrs > 1)
{
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 1d9443a5fe..78553b9795 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -112,7 +112,7 @@ endif
ifeq ($(subdir),posix)
sysdep_headers += bits/initspin.h
-sysdep_routines += exit-thread
+sysdep_routines += exit-thread sched_getcpu
endif
ifeq ($(subdir),inet)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index bb5b862689..5413ced74c 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -127,7 +127,7 @@ libc {
splice; tee; vmsplice;
}
GLIBC_2.6 {
- epoll_pwait; sync_file_range;
+ epoll_pwait; sync_file_range; sched_getcpu;
}
GLIBC_PRIVATE {
# functions used in other libraries
diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h
index 1d9c7b9f35..31db66f8ac 100644
--- a/sysdeps/unix/sysv/linux/bits/sched.h
+++ b/sysdeps/unix/sysv/linux/bits/sched.h
@@ -77,6 +77,9 @@ extern int clone (int (*__fn) (void *__arg), void *__child_stack,
/* Unshare the specified resources. */
extern int unshare (int __flags) __THROW;
+
+/* Get index of currently used CPU. */
+extern int sched_getcpu (void) __THROW;
#endif
__END_DECLS
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index 2b6c158226..3312da3af8 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -223,7 +223,7 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
out_fail:
if (use_malloc)
free (buf);
- return 0;
+ return -1;
}
diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c
new file mode 100644
index 0000000000..e41eee6431
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sched_getcpu.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2007 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sched.h>
+#include <sysdep.h>
+
+
+int
+sched_getcpu (void)
+{
+#ifdef __NR_getcpu
+ unsigned int cpu;
+ int r = INLINE_SYSCALL (getcpu, 3, &cpu, NULL, NULL);
+
+ return r == -1 ? r : cpu;
+#else
+ __set_errno (ENOSYS);
+ return -1;
+#endif
+}
diff --git a/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S b/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S
new file mode 100644
index 0000000000..8d74d53a76
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S
@@ -0,0 +1,50 @@
+/* Copyright (C) 2007 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <tls.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+/* For the calculation see asm/vsyscall.h. */
+#define VSYSCALL_ADDR_vgetcpu 0xffffffffff600800
+
+
+ENTRY (sched_getcpu)
+ /* Align stack and create local variable for result. */
+ sub $0x8, %rsp
+ cfi_adjust_cfa_offset(8)
+
+ movq %rsp, %rdi
+ xorl %esi, %esi
+ movl $VGETCPU_CACHE_OFFSET, %edx
+ addq %fs:0, %rdx
+
+ movq $VSYSCALL_ADDR_vgetcpu, %rax
+ callq *%rax
+
+ cmpq $-4095, %rdi
+ jae SYSCALL_ERROR_LABEL
+
+ movl (%rsp), %eax
+
+L(pseudo_end):
+ add $0x8, %rsp
+ cfi_adjust_cfa_offset(-8)
+ ret
+PSEUDO_END(sched_getcpu)