MEDIUM: stick-table: allocate the table key of size buffer size

Keys are copied from samples to stick_table_key. If a key is larger
than the stick_table_key, we have an overflow. In pratice it does not
happen because it requires :
   1) a configuration with tune.bufsize larger than BUFSIZE (common)
   2) a stick-table configured with keys strictly larger than buffers
   3) extraction of data larger than BUFSIZE (eg: using payload())

Points 2 and 3 don't make any sense for a real world configuration. That
said the issue needs be fixed. The solution consists in allocating it the
same size as the global buffer size, just like the samples. This fixes the
issue.
This commit is contained in:
Willy Tarreau 2012-10-29 21:56:59 +01:00
parent 7e2c647ee7
commit 07115412d3
6 changed files with 31 additions and 31 deletions

View File

@ -48,15 +48,15 @@ static inline struct stktable_key *addr_to_stktable_key(struct sockaddr_storage
{
switch (addr->ss_family) {
case AF_INET:
static_table_key.key = (void *)&((struct sockaddr_in *)addr)->sin_addr;
static_table_key->key = (void *)&((struct sockaddr_in *)addr)->sin_addr;
break;
case AF_INET6:
static_table_key.key = (void *)&((struct sockaddr_in6 *)addr)->sin6_addr;
static_table_key->key = (void *)&((struct sockaddr_in6 *)addr)->sin6_addr;
break;
default:
return NULL;
}
return &static_table_key;
return static_table_key;
}

View File

@ -31,7 +31,7 @@
#define stktable_data_size(type) (sizeof(((union stktable_data*)0)->type))
#define stktable_data_cast(ptr, type) ((union stktable_data*)(ptr))->type
extern struct stktable_key static_table_key;
extern struct stktable_key *static_table_key;
struct stksess *stksess_new(struct stktable *t, struct stktable_key *key);
void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key);

View File

@ -176,15 +176,14 @@ union stktable_key_data {
struct in_addr ip; /* used to store an ipv4 key */
struct in6_addr ipv6; /* used to store an ipv6 key */
uint32_t integer; /* used to store an integer key */
char buf[BUFSIZE]; /* used to store a null terminated string key or a buffer of data */
char buf[0]; /* dynamically allocated, used to store a null terminated string key or a buffer of data */
};
/* stick table key */
struct stktable_key {
void *key; /* pointer on key buffer */
size_t key_len; /* data len to read in buff in case of null terminated string */
union stktable_key_data data; /* data */
union stktable_key_data data; /* data, must always be last */
};
#endif /* _TYPES_STICK_TABLE_H */

View File

@ -541,11 +541,11 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
switch (px->table.type) {
case STKTABLE_TYPE_IP:
uint32_key = htonl(inetaddr_host(args[4]));
static_table_key.key = &uint32_key;
static_table_key->key = &uint32_key;
break;
case STKTABLE_TYPE_IPV6:
inet_pton(AF_INET6, args[4], ip6_key);
static_table_key.key = &ip6_key;
static_table_key->key = &ip6_key;
break;
case STKTABLE_TYPE_INTEGER:
{
@ -561,13 +561,13 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
return;
}
uint32_key = (uint32_t) val;
static_table_key.key = &uint32_key;
static_table_key->key = &uint32_key;
break;
}
break;
case STKTABLE_TYPE_STRING:
static_table_key.key = args[4];
static_table_key.key_len = strlen(args[4]);
static_table_key->key = args[4];
static_table_key->key_len = strlen(args[4]);
break;
default:
switch (action) {
@ -592,7 +592,7 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
return;
}
ts = stktable_lookup_key(&px->table, &static_table_key);
ts = stktable_lookup_key(&px->table, static_table_key);
switch (action) {
case STAT_CLI_O_TAB:
@ -645,7 +645,7 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
if (ts)
stktable_touch(&px->table, ts, 1);
else {
ts = stksess_new(&px->table, &static_table_key);
ts = stksess_new(&px->table, static_table_key);
if (!ts) {
/* don't delete an entry which is currently referenced */
si->applet.ctx.cli.msg = "Unable to allocate a new entry\n";

View File

@ -745,6 +745,7 @@ void init(int argc, char **argv)
sample_trash_buf1 = (char *)calloc(1, global.tune.bufsize);
sample_trash_buf2 = (char *)calloc(1, global.tune.bufsize);
get_http_auth_buff = (char *)calloc(1, global.tune.bufsize);
static_table_key = calloc(1, sizeof(*static_table_key) + global.tune.bufsize);
fdinfo = (struct fdinfo *)calloc(1,

View File

@ -31,7 +31,7 @@
#include <types/global.h>
/* structure used to return a table key built from a sample */
struct stktable_key static_table_key;
struct stktable_key *static_table_key;
/*
* Free an allocated sticky session <ts>, and decrease sticky sessions counter
@ -618,42 +618,42 @@ struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, st
if (!sample_to_key[smp->type][t->type])
return NULL;
static_table_key.key_len = t->key_size;
static_table_key.key = sample_to_key[smp->type][t->type](smp, &static_table_key.data, &static_table_key.key_len);
static_table_key->key_len = t->key_size;
static_table_key->key = sample_to_key[smp->type][t->type](smp, &static_table_key->data, &static_table_key->key_len);
if (!static_table_key.key)
if (!static_table_key->key)
return NULL;
if (static_table_key.key_len == 0)
if (static_table_key->key_len == 0)
return NULL;
if ((static_table_key.key_len < t->key_size) && (t->type != STKTABLE_TYPE_STRING)) {
if ((static_table_key->key_len < t->key_size) && (t->type != STKTABLE_TYPE_STRING)) {
/* need padding with null */
/* assume static_table_key.key_len is less than sizeof(static_table_key.data.buf)
cause t->key_size is necessary less than sizeof(static_table_key.data) */
if ((char *)static_table_key.key > (char *)&static_table_key.data &&
(char *)static_table_key.key < (char *)&static_table_key.data + sizeof(static_table_key.data)) {
if ((char *)static_table_key->key > (char *)&static_table_key->data &&
(char *)static_table_key->key < (char *)&static_table_key->data + global.tune.bufsize) {
/* key buffer is part of the static_table_key private data buffer, but is not aligned */
if (sizeof(static_table_key.data) - ((char *)static_table_key.key - (char *)&static_table_key.data) < t->key_size) {
/* if not remain enougth place for padding , process a realign */
memmove(static_table_key.data.buf, static_table_key.key, static_table_key.key_len);
static_table_key.key = static_table_key.data.buf;
if (global.tune.bufsize - ((char *)static_table_key->key - (char *)&static_table_key->data) < t->key_size) {
/* if not remain enough place for padding , process a realign */
memmove(static_table_key->data.buf, static_table_key->key, static_table_key->key_len);
static_table_key->key = static_table_key->data.buf;
}
}
else if (static_table_key.key != static_table_key.data.buf) {
else if (static_table_key->key != static_table_key->data.buf) {
/* key definitly not part of the static_table_key private data buffer */
memcpy(static_table_key.data.buf, static_table_key.key, static_table_key.key_len);
static_table_key.key = static_table_key.data.buf;
memcpy(static_table_key->data.buf, static_table_key->key, static_table_key->key_len);
static_table_key->key = static_table_key->data.buf;
}
memset(static_table_key.key + static_table_key.key_len, 0, t->key_size - static_table_key.key_len);
memset(static_table_key->key + static_table_key->key_len, 0, t->key_size - static_table_key->key_len);
}
return &static_table_key;
return static_table_key;
}
/*