mirror of
git://sourceware.org/git/glibc.git
synced 2025-02-17 13:00:43 +08:00
[BZ #4181]
2007-03-15 Jakub Jelinek <jakub@redhat.com> [BZ #4181] * inet/inet6_opt.c (add_padding): Only insert padding if npad > 0. (inet6_opt_append): Don't check extlen is big enough if extbuf is NULL. (inet6_opt_finish): Likewise. * inet/Makefile (tests): Add test-inet6_opt. * inet/test-inet6_opt.c: New test. * sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Never reallocate the buffer, instead fail for MSG_TRUNC or for EBUSY NLMSG_ERR. Instead use a page sized buffer. * sysdeps/unix/sysv/linux/check_pf.c (make_request): Use page sized buffer.
This commit is contained in:
parent
02c906999c
commit
6cb988fa7b
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
||||
2007-03-15 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
[BZ #4181]
|
||||
* inet/inet6_opt.c (add_padding): Only insert padding if npad > 0.
|
||||
(inet6_opt_append): Don't check extlen is big enough if extbuf
|
||||
is NULL.
|
||||
(inet6_opt_finish): Likewise.
|
||||
* inet/Makefile (tests): Add test-inet6_opt.
|
||||
* inet/test-inet6_opt.c: New test.
|
||||
|
||||
* sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Never
|
||||
reallocate the buffer, instead fail for MSG_TRUNC or for EBUSY
|
||||
NLMSG_ERR. Instead use a page sized buffer.
|
||||
* sysdeps/unix/sysv/linux/check_pf.c (make_request): Use page sized
|
||||
buffer.
|
||||
|
||||
2007-03-14 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* sysdeps/alpha/fpu/s_llround.c: New file.
|
||||
|
@ -52,7 +52,7 @@ routines := htonl htons \
|
||||
aux := check_pf ifreq
|
||||
|
||||
tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
|
||||
tst-gethnm test-ifaddrs bug-if1
|
||||
tst-gethnm test-ifaddrs bug-if1 test-inet6_opt
|
||||
|
||||
include ../Rules
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 2006.
|
||||
|
||||
@ -51,7 +51,7 @@ add_padding (uint8_t *extbuf, int offset, int npad)
|
||||
{
|
||||
if (npad == 1)
|
||||
extbuf[offset] = IP6OPT_PAD1;
|
||||
else
|
||||
else if (npad > 0)
|
||||
{
|
||||
struct ip6_opt *pad_opt = (struct ip6_opt *) (extbuf + offset);
|
||||
|
||||
@ -102,21 +102,17 @@ inet6_opt_append (void *extbuf, socklen_t extlen, int offset, uint8_t type,
|
||||
int data_offset = offset + sizeof (struct ip6_opt);
|
||||
int npad = (align - data_offset % align) & (align - 1);
|
||||
|
||||
/* Now we can check whether the buffer is large enough. */
|
||||
if (data_offset + npad + len > extlen)
|
||||
return -1;
|
||||
|
||||
if (npad != 0)
|
||||
{
|
||||
if (extbuf != NULL)
|
||||
add_padding (extbuf, offset, npad);
|
||||
|
||||
offset += npad;
|
||||
}
|
||||
|
||||
/* Now prepare the option itself. */
|
||||
if (extbuf != NULL)
|
||||
{
|
||||
/* Now we can check whether the buffer is large enough. */
|
||||
if (data_offset + npad + len > extlen)
|
||||
return -1;
|
||||
|
||||
add_padding (extbuf, offset, npad);
|
||||
|
||||
offset += npad;
|
||||
|
||||
/* Now prepare the option itself. */
|
||||
struct ip6_opt *opt = (struct ip6_opt *) ((uint8_t *) extbuf + offset);
|
||||
|
||||
opt->ip6o_type = type;
|
||||
@ -124,6 +120,8 @@ inet6_opt_append (void *extbuf, socklen_t extlen, int offset, uint8_t type,
|
||||
|
||||
*databufp = opt + 1;
|
||||
}
|
||||
else
|
||||
offset += npad;
|
||||
|
||||
return offset + sizeof (struct ip6_opt) + len;
|
||||
}
|
||||
@ -145,12 +143,14 @@ inet6_opt_finish (void *extbuf, socklen_t extlen, int offset)
|
||||
/* Required padding at the end. */
|
||||
int npad = (8 - (offset & 7)) & 7;
|
||||
|
||||
/* Make sure the buffer is large enough. */
|
||||
if (offset + npad > extlen)
|
||||
return -1;
|
||||
|
||||
if (extbuf != NULL)
|
||||
add_padding (extbuf, offset, npad);
|
||||
{
|
||||
/* Make sure the buffer is large enough. */
|
||||
if (offset + npad > extlen)
|
||||
return -1;
|
||||
|
||||
add_padding (extbuf, offset, npad);
|
||||
}
|
||||
|
||||
return offset + npad;
|
||||
}
|
||||
|
207
inet/test-inet6_opt.c
Normal file
207
inet/test-inet6_opt.c
Normal file
@ -0,0 +1,207 @@
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OPT_X 42
|
||||
#define OPT_Y 43
|
||||
#define OPT_Z 44
|
||||
|
||||
static void *
|
||||
encode_inet6_opt (socklen_t *elp)
|
||||
{
|
||||
void *eb = NULL;
|
||||
socklen_t el;
|
||||
int cl;
|
||||
void *db;
|
||||
int offset;
|
||||
uint8_t val1;
|
||||
uint16_t val2;
|
||||
uint32_t val4;
|
||||
uint64_t val8;
|
||||
|
||||
*elp = 0;
|
||||
#define CHECK() \
|
||||
if (cl == -1) \
|
||||
{ \
|
||||
printf ("cl == -1 on line %d\n", __LINE__); \
|
||||
free (eb); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
/* Estimate the length */
|
||||
cl = inet6_opt_init (NULL, 0);
|
||||
CHECK ();
|
||||
cl = inet6_opt_append (NULL, 0, cl, OPT_X, 12, 8, NULL);
|
||||
CHECK ();
|
||||
cl = inet6_opt_append (NULL, 0, cl, OPT_Y, 7, 4, NULL);
|
||||
CHECK ();
|
||||
cl = inet6_opt_append (NULL, 0, cl, OPT_Z, 7, 1, NULL);
|
||||
CHECK ();
|
||||
cl = inet6_opt_finish (NULL, 0, cl);
|
||||
CHECK ();
|
||||
el = cl;
|
||||
|
||||
eb = malloc (el + 8);
|
||||
if (eb == NULL)
|
||||
{
|
||||
puts ("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
/* Canary. */
|
||||
memcpy (eb + el, "deadbeef", 8);
|
||||
|
||||
cl = inet6_opt_init (eb, el);
|
||||
CHECK ();
|
||||
|
||||
cl = inet6_opt_append (eb, el, cl, OPT_X, 12, 8, &db);
|
||||
CHECK ();
|
||||
val4 = 0x12345678;
|
||||
offset = inet6_opt_set_val (db, 0, &val4, sizeof (val4));
|
||||
val8 = 0x0102030405060708LL;
|
||||
inet6_opt_set_val (db, offset, &val8, sizeof (val8));
|
||||
|
||||
cl = inet6_opt_append (eb, el, cl, OPT_Y, 7, 4, &db);
|
||||
CHECK ();
|
||||
val1 = 0x01;
|
||||
offset = inet6_opt_set_val (db, 0, &val1, sizeof (val1));
|
||||
val2 = 0x1331;
|
||||
offset = inet6_opt_set_val (db, offset, &val2, sizeof (val2));
|
||||
val4 = 0x01020304;
|
||||
inet6_opt_set_val (db, offset, &val4, sizeof (val4));
|
||||
|
||||
cl = inet6_opt_append (eb, el, cl, OPT_Z, 7, 1, &db);
|
||||
CHECK ();
|
||||
inet6_opt_set_val (db, 0, (void *) "abcdefg", 7);
|
||||
|
||||
cl = inet6_opt_finish (eb, el, cl);
|
||||
CHECK ();
|
||||
|
||||
if (memcmp (eb + el, "deadbeef", 8) != 0)
|
||||
{
|
||||
puts ("Canary corrupted");
|
||||
free (eb);
|
||||
return NULL;
|
||||
}
|
||||
*elp = el;
|
||||
return eb;
|
||||
}
|
||||
|
||||
int
|
||||
decode_inet6_opt (void *eb, socklen_t el)
|
||||
{
|
||||
int ret = 0;
|
||||
int seq = 0;
|
||||
int cl = 0;
|
||||
int offset;
|
||||
uint8_t type;
|
||||
socklen_t len;
|
||||
uint8_t val1;
|
||||
uint16_t val2;
|
||||
uint32_t val4;
|
||||
uint64_t val8;
|
||||
void *db;
|
||||
char buf[8];
|
||||
|
||||
while ((cl = inet6_opt_next (eb, el, cl, &type, &len, &db)) != -1)
|
||||
switch (type)
|
||||
{
|
||||
case OPT_X:
|
||||
if (seq++ != 0)
|
||||
{
|
||||
puts ("OPT_X is not first");
|
||||
ret = 1;
|
||||
}
|
||||
if (len != 12)
|
||||
{
|
||||
printf ("OPT_X's length %d != 12\n", len);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, 0, &val4, sizeof (val4));
|
||||
if (val4 != 0x12345678)
|
||||
{
|
||||
printf ("OPT_X's val4 %x != 0x12345678\n", val4);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, offset, &val8, sizeof (val8));
|
||||
if (offset != len || val8 != 0x0102030405060708LL)
|
||||
{
|
||||
printf ("OPT_X's val8 %llx != 0x0102030405060708\n",
|
||||
(long long) val8);
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
case OPT_Y:
|
||||
if (seq++ != 1)
|
||||
{
|
||||
puts ("OPT_Y is not second");
|
||||
ret = 1;
|
||||
}
|
||||
if (len != 7)
|
||||
{
|
||||
printf ("OPT_Y's length %d != 7\n", len);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, 0, &val1, sizeof (val1));
|
||||
if (val1 != 0x01)
|
||||
{
|
||||
printf ("OPT_Y's val1 %x != 0x01\n", val1);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, offset, &val2, sizeof (val2));
|
||||
if (val2 != 0x1331)
|
||||
{
|
||||
printf ("OPT_Y's val2 %x != 0x1331\n", val2);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, offset, &val4, sizeof (val4));
|
||||
if (offset != len || val4 != 0x01020304)
|
||||
{
|
||||
printf ("OPT_Y's val4 %x != 0x01020304\n", val4);
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
case OPT_Z:
|
||||
if (seq++ != 2)
|
||||
{
|
||||
puts ("OPT_Z is not third");
|
||||
ret = 1;
|
||||
}
|
||||
if (len != 7)
|
||||
{
|
||||
printf ("OPT_Z's length %d != 7\n", len);
|
||||
ret = 1;
|
||||
}
|
||||
offset = inet6_opt_get_val (db, 0, buf, 7);
|
||||
if (offset != len || memcmp (buf, "abcdefg", 7) != 0)
|
||||
{
|
||||
buf[7] = '\0';
|
||||
printf ("OPT_Z's buf \"%s\" != \"abcdefg\"\n", buf);
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown option %d\n", type);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if (seq != 3)
|
||||
{
|
||||
puts ("Didn't see all of OPT_X, OPT_Y and OPT_Z");
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
void *eb;
|
||||
socklen_t el;
|
||||
eb = encode_inet6_opt (&el);
|
||||
if (eb == NULL)
|
||||
return 1;
|
||||
if (decode_inet6_opt (eb, el))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* Determine protocol families for which interfaces exist. Linux version.
|
||||
Copyright (C) 2003, 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2006, 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
|
||||
@ -71,17 +71,38 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
||||
memset (&nladdr, '\0', sizeof (nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
|
||||
#ifdef PAGE_SIZE
|
||||
/* Help the compiler optimize out the malloc call if PAGE_SIZE
|
||||
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
|
||||
const size_t buf_size = PAGE_SIZE;
|
||||
#else
|
||||
const size_t buf_size = __getpagesize ();
|
||||
#endif
|
||||
bool use_malloc = false;
|
||||
char *buf;
|
||||
|
||||
if (__libc_use_alloca (buf_size))
|
||||
buf = alloca (buf_size);
|
||||
else
|
||||
{
|
||||
buf = malloc (buf_size);
|
||||
if (buf != NULL)
|
||||
use_malloc = true;
|
||||
else
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
struct iovec iov = { buf, buf_size };
|
||||
|
||||
if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
|
||||
(struct sockaddr *) &nladdr,
|
||||
sizeof (nladdr))) < 0)
|
||||
return -1;
|
||||
goto out_fail;
|
||||
|
||||
*seen_ipv4 = false;
|
||||
*seen_ipv6 = false;
|
||||
|
||||
bool done = false;
|
||||
char buf[4096];
|
||||
struct iovec iov = { buf, sizeof (buf) };
|
||||
struct in6ailist
|
||||
{
|
||||
struct in6addrinfo info;
|
||||
@ -101,10 +122,10 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
||||
|
||||
ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
|
||||
if (read_len < 0)
|
||||
return -1;
|
||||
goto out_fail;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC)
|
||||
return -1;
|
||||
goto out_fail;
|
||||
|
||||
struct nlmsghdr *nlmh;
|
||||
for (nlmh = (struct nlmsghdr *) buf;
|
||||
@ -186,7 +207,7 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
||||
{
|
||||
*in6ai = malloc (in6ailistlen * sizeof (**in6ai));
|
||||
if (*in6ai == NULL)
|
||||
return -1;
|
||||
goto out_fail;
|
||||
|
||||
*in6ailen = in6ailistlen;
|
||||
|
||||
@ -198,6 +219,13 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
||||
while (in6ailist != NULL);
|
||||
}
|
||||
|
||||
if (use_malloc)
|
||||
free (buf);
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
if (use_malloc)
|
||||
free (buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -122,37 +122,36 @@ int
|
||||
__netlink_request (struct netlink_handle *h, int type)
|
||||
{
|
||||
struct netlink_res *nlm_next;
|
||||
struct netlink_res **new_nlm_list;
|
||||
static volatile size_t buf_size = 4096;
|
||||
char *buf;
|
||||
struct sockaddr_nl nladdr;
|
||||
struct nlmsghdr *nlmh;
|
||||
ssize_t read_len;
|
||||
bool done = false;
|
||||
|
||||
#ifdef PAGE_SIZE
|
||||
/* Help the compiler optimize out the malloc call if PAGE_SIZE
|
||||
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
|
||||
const size_t buf_size = PAGE_SIZE;
|
||||
#else
|
||||
const size_t buf_size = __getpagesize ();
|
||||
#endif
|
||||
bool use_malloc = false;
|
||||
char *buf;
|
||||
|
||||
if (__netlink_sendreq (h, type) < 0)
|
||||
return -1;
|
||||
|
||||
size_t this_buf_size = buf_size;
|
||||
size_t orig_this_buf_size = this_buf_size;
|
||||
if (__libc_use_alloca (this_buf_size))
|
||||
buf = alloca (this_buf_size);
|
||||
if (__libc_use_alloca (buf_size))
|
||||
buf = alloca (buf_size);
|
||||
else
|
||||
{
|
||||
buf = malloc (this_buf_size);
|
||||
buf = malloc (buf_size);
|
||||
if (buf != NULL)
|
||||
use_malloc = true;
|
||||
else
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
struct iovec iov = { buf, this_buf_size };
|
||||
struct iovec iov = { buf, buf_size };
|
||||
|
||||
if (h->nlm_list != NULL)
|
||||
new_nlm_list = &h->end_ptr->next;
|
||||
else
|
||||
new_nlm_list = &h->nlm_list;
|
||||
if (__netlink_sendreq (h, type) < 0)
|
||||
goto out_fail;
|
||||
|
||||
while (! done)
|
||||
{
|
||||
@ -172,48 +171,7 @@ __netlink_request (struct netlink_handle *h, int type)
|
||||
continue;
|
||||
|
||||
if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
|
||||
{
|
||||
if (this_buf_size >= SIZE_MAX / 2)
|
||||
goto out_fail;
|
||||
|
||||
nlm_next = *new_nlm_list;
|
||||
while (nlm_next != NULL)
|
||||
{
|
||||
struct netlink_res *tmpptr;
|
||||
|
||||
tmpptr = nlm_next->next;
|
||||
free (nlm_next);
|
||||
nlm_next = tmpptr;
|
||||
}
|
||||
*new_nlm_list = NULL;
|
||||
|
||||
if (__libc_use_alloca (2 * this_buf_size))
|
||||
buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
|
||||
else
|
||||
{
|
||||
this_buf_size *= 2;
|
||||
|
||||
char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
|
||||
if (new_buf == NULL)
|
||||
goto out_fail;
|
||||
buf = new_buf;
|
||||
|
||||
use_malloc = true;
|
||||
}
|
||||
buf_size = this_buf_size;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = this_buf_size;
|
||||
|
||||
/* Increase sequence number, so that we can distinguish
|
||||
between old and new request messages. */
|
||||
h->seq++;
|
||||
|
||||
if (__netlink_sendreq (h, type) < 0)
|
||||
goto out_fail;
|
||||
|
||||
continue;
|
||||
}
|
||||
goto out_fail;
|
||||
|
||||
size_t count = 0;
|
||||
size_t remaining_len = read_len;
|
||||
@ -237,36 +195,6 @@ __netlink_request (struct netlink_handle *h, int type)
|
||||
struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
|
||||
if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
|
||||
errno = EIO;
|
||||
else if (nlerr->error == -EBUSY
|
||||
&& orig_this_buf_size != this_buf_size)
|
||||
{
|
||||
/* If EBUSY and MSG_TRUNC was seen, try again with a new
|
||||
netlink socket. */
|
||||
struct netlink_handle hold = *h;
|
||||
if (__netlink_open (h) < 0)
|
||||
{
|
||||
*h = hold;
|
||||
goto out_fail;
|
||||
}
|
||||
__netlink_close (&hold);
|
||||
orig_this_buf_size = this_buf_size;
|
||||
nlm_next = *new_nlm_list;
|
||||
while (nlm_next != NULL)
|
||||
{
|
||||
struct netlink_res *tmpptr;
|
||||
|
||||
tmpptr = nlm_next->next;
|
||||
free (nlm_next);
|
||||
nlm_next = tmpptr;
|
||||
}
|
||||
*new_nlm_list = NULL;
|
||||
count = 0;
|
||||
h->seq++;
|
||||
|
||||
if (__netlink_sendreq (h, type) < 0)
|
||||
goto out_fail;
|
||||
break;
|
||||
}
|
||||
else
|
||||
errno = -nlerr->error;
|
||||
goto out_fail;
|
||||
|
Loading…
Reference in New Issue
Block a user