mirror of
https://github.com/yrutschle/sslh.git
synced 2026-10-22 18:12:10 +03:00
misc hardening: connection drop, NULL deref, OOB writes, dead option
- shovel(): fd2fd() returns FD_NODATA (-1) when a spurious wakeup meets an empty socket (EAGAIN), but the switch treated -1 like FD_CNXCLOSED and tore down a healthy connection. Only FD_CNXCLOSED closes now. - decrease_forked_connection(): hash_find() can return NULL (stale SIGCHLD after a fork-limit rejection); dereferencing it crashed. Guard and log instead. - hexdump(): sprintf() into a 76-byte stack buffer with a "%06x" offset that needs 12 chars once the dump passes 16 MB. Enlarge the buffer and bound all writes with snprintf(). - printsettings(): sprintf() of config-supplied host strings into a fixed buffer; use snprintf(). - echosrv: recvfrom() into data+prefix_len with size sizeof(data)-prefix_len lets the terminating NUL write land one byte past the stack buffer (verified with ASan at udp_echo, and a >64KB prefix overflows the memcpy). Bound the prefix, reserve one byte for the terminator, and skip the echo on recvfrom() error instead of writing data[prefix_len-1]. - msg_int_error used verbose_system_error, leaving the documented --verbose-int-error option dead. Point it at its own setting. - Remove "echoѕrv-conf.h" (with Cyrillic ѕ, U+0455): a stale 2020 sslh-conf.h copy committed under a filename that is visually identical to echosrv-conf.h but referenced by nothing.
This commit is contained in:
1 parent
b9d9f9112f
commit
bb89714216
7 files changed
+23
-120
No files matched your search
@@ -68,9 +68,13 @@ void start_echo(int fd)
|
||||
int first = 1;
|
||||
|
||||
prefix_len = strlen(cfg.prefix);
|
||||
if (prefix_len >= sizeof(buffer)) {
|
||||
fprintf(stderr, "prefix too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
strcpy(buffer, cfg.prefix);
|
||||
memcpy(buffer, cfg.prefix, prefix_len);
|
||||
|
||||
while (1) {
|
||||
ret = read(fd, buffer + prefix_len, sizeof(buffer) - prefix_len);
|
||||
@@ -147,19 +151,24 @@ void udp_echo(struct listen_endpoint* listen_socket)
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
size_t prefix_len = strlen(cfg.prefix);
|
||||
if (prefix_len >= sizeof(data) - 1) {
|
||||
fprintf(stderr, "prefix too long\n");
|
||||
return;
|
||||
}
|
||||
memcpy(data, cfg.prefix, prefix_len);
|
||||
|
||||
while (1) {
|
||||
addrlen = sizeof(src_addr);
|
||||
ssize_t len = recvfrom(listen_socket->socketfd,
|
||||
data + prefix_len,
|
||||
sizeof(data) - prefix_len,
|
||||
sizeof(data) - prefix_len - 1,
|
||||
0,
|
||||
&src_addr,
|
||||
&addrlen);
|
||||
|
||||
if (len < 0) {
|
||||
perror("recvfrom");
|
||||
continue;
|
||||
}
|
||||
*(data + prefix_len + len) = 0;
|
||||
fprintf(stderr, "%zd %s\n", len, data + prefix_len);
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sat Nov 7 09:19:26 2020.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2019 Yves Rutschle
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef C2S_SSLHCFG_H
|
||||
#define C2S_SSLHCFG_H
|
||||
#ifdef LIBCONFIG
|
||||
# include <libconfig.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "probe.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
struct sslhcfg_listen_item {
|
||||
char* host;
|
||||
char* port;
|
||||
int keepalive;
|
||||
};
|
||||
|
||||
struct sslhcfg_protocols_item {
|
||||
char* name;
|
||||
char* host;
|
||||
char* port;
|
||||
int service_is_present;
|
||||
char* service;
|
||||
int fork;
|
||||
int tfo_ok;
|
||||
int log_level;
|
||||
int keepalive;
|
||||
size_t sni_hostnames_len;
|
||||
char** sni_hostnames;
|
||||
size_t alpn_protocols_len;
|
||||
char** alpn_protocols;
|
||||
size_t regex_patterns_len;
|
||||
char** regex_patterns;
|
||||
int minlength_is_present;
|
||||
int minlength;
|
||||
T_PROBE* probe;
|
||||
struct addrinfo* saddr;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct sslhcfg_item {
|
||||
char* prefix;
|
||||
int verbose;
|
||||
int foreground;
|
||||
int inetd;
|
||||
int numeric;
|
||||
int transparent;
|
||||
int timeout;
|
||||
int user_is_present;
|
||||
char* user;
|
||||
int pidfile_is_present;
|
||||
char* pidfile;
|
||||
int chroot_is_present;
|
||||
char* chroot;
|
||||
char* syslog_facility;
|
||||
char* on_timeout;
|
||||
size_t listen_len;
|
||||
struct sslhcfg_listen_item* listen;
|
||||
size_t protocols_len;
|
||||
struct sslhcfg_protocols_item* protocols;
|
||||
};
|
||||
|
||||
int sslhcfg_parse_file(
|
||||
const char* filename,
|
||||
struct sslhcfg_item* sslhcfg,
|
||||
const char** errmsg);
|
||||
|
||||
void sslhcfg_fprint(
|
||||
FILE* out,
|
||||
struct sslhcfg_item *sslhcfg,
|
||||
int depth);
|
||||
|
||||
int sslhcfg_cl_parse(
|
||||
int argc,
|
||||
char* argv[],
|
||||
struct sslhcfg_item *sslhcfg);
|
||||
|
||||
#endif
|
||||
@@ -48,7 +48,7 @@ msg_info msg_fd = {
|
||||
/* Internal errors: inconsistent states, impossible values, things that should never happen, and are therefore the sign of memory corruption: hence the LOG_CRIT */
|
||||
msg_info msg_int_error = {
|
||||
LOG_CRIT,
|
||||
&cfg.verbose_system_error
|
||||
&cfg.verbose_int_error
|
||||
};
|
||||
|
||||
/* System errors: when the system around us fails us: memory allocation, fork, ... */
|
||||
|
||||
@@ -88,20 +88,20 @@ struct sslhcfg_protocols_item* timeout_protocol(void)
|
||||
void hexdump(msg_info msg_info, const char *mem, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
char str[10 + HEXDUMP_COLS * 4 + 2];
|
||||
char str[12 + HEXDUMP_COLS * 4 + 2]; /* offset <= 12, hex+ascii 64, '\n'+'\0' */
|
||||
int c = 0; /* index in str */
|
||||
|
||||
for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
|
||||
{
|
||||
/* print offset */
|
||||
if(i % HEXDUMP_COLS == 0)
|
||||
c += sprintf(&str[c], "0x%06x: ", i);
|
||||
c += snprintf(&str[c], sizeof(str) - c, "0x%06x: ", i);
|
||||
|
||||
/* print hex data */
|
||||
if(i < len)
|
||||
c += sprintf(&str[c], "%02x ", 0xFF & mem[i]);
|
||||
c += snprintf(&str[c], sizeof(str) - c, "%02x ", 0xFF & mem[i]);
|
||||
else /* end of block, just aligning for ASCII dump */
|
||||
c+= sprintf(&str[c], " ");
|
||||
c += snprintf(&str[c], sizeof(str) - c, " ");
|
||||
|
||||
/* print ASCII dump */
|
||||
if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) {
|
||||
|
||||
@@ -142,6 +142,10 @@ static int pid_cmp(hash_item item1, hash_item item2)
|
||||
void decrease_forked_connection(struct loop_info* loop, pid_t pid) {
|
||||
struct pid2proto p2p = { .pid = pid };
|
||||
struct pid2proto* found = hash_find(loop->pid2proto, &p2p);
|
||||
if (!found) {
|
||||
print_message(msg_int_error, "SIGCHLD for unknown pid %d\n", pid);
|
||||
return;
|
||||
}
|
||||
dec_proto_connections(found->proto);
|
||||
dec_listen_connections(found->endpoint);
|
||||
|
||||
|
||||
+3
-3
@@ -74,16 +74,16 @@ static void printsettings(void)
|
||||
for (i = 0; i < cfg.protocols_len; i++ ) {
|
||||
p = &cfg.protocols[i];
|
||||
if (p->is_unix) {
|
||||
sprintf(buf, "unix socket: %s", p->host);
|
||||
snprintf(buf, sizeof(buf), "unix socket: %s", p->host);
|
||||
} else {
|
||||
if (p->resolve_on_forward) {
|
||||
strcpy(buf, "resolve on forward: ");
|
||||
size_t len = strlen(buf);
|
||||
sprintf(buf+len, "%s:%s", p->host, p->port);
|
||||
snprintf(buf+len, sizeof(buf)-len, "%s:%s", p->host, p->port);
|
||||
} else {
|
||||
sprintaddr(buf, sizeof(buf), p->saddr);
|
||||
size_t len = strlen(buf);
|
||||
sprintf(buf+len, " family %d %d",
|
||||
snprintf(buf+len, sizeof(buf)-len, " family %d %d",
|
||||
p->saddr->ai_family,
|
||||
p->saddr->ai_addr->sa_family);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ static void shovel(struct connection *cnx, int active_fd, struct loop_info* fd_i
|
||||
print_message(msg_fd, "activity on fd%d\n", read_q->fd);
|
||||
|
||||
switch(fd2fd(write_q, read_q)) {
|
||||
case -1:
|
||||
case FD_CNXCLOSED:
|
||||
tidy_connection(cnx, fd_info);
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user