sync with OpenBSD -current

This commit is contained in:
purplerain 2024-03-14 20:22:48 +00:00
parent 14b4e966dd
commit 8e82432ef8
Signed by: purplerain
GPG Key ID: F42C07F07E2E35B7
6 changed files with 184 additions and 144 deletions

View File

@ -2,6 +2,12 @@ NOTE: We are looking for help with a few things:
https://github.com/libexpat/libexpat/labels/help%20wanted
If you can help, please get in touch. Thanks!
Security fixes:
#839 #842 CVE-2024-28757 -- Prevent billion laughs attacks with
isolated use of external parsers. Please see the commit
message of commit 1d50b80cf31de87750103656f6eb693746854aa8
for details.
Release 2.6.0 Tue February 6 2024
Security fixes:
#789 #814 CVE-2023-52425 -- Fix quadratic runtime issues with big tokens

View File

@ -7779,6 +7779,8 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
static float
accountingGetCurrentAmplification(XML_Parser rootParser) {
// 1.........1.........12 => 22
const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
const XmlBigCount countBytesOutput
= rootParser->m_accounting.countBytesDirect
+ rootParser->m_accounting.countBytesIndirect;
@ -7786,7 +7788,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) {
= rootParser->m_accounting.countBytesDirect
? (countBytesOutput
/ (float)(rootParser->m_accounting.countBytesDirect))
: 1.0f;
: ((lenOfShortestInclude
+ rootParser->m_accounting.countBytesIndirect)
/ (float)lenOfShortestInclude);
assert(! rootParser->m_parentParser);
return amplificationFactor;
}

View File

@ -378,6 +378,63 @@ START_TEST(test_helper_unsigned_char_to_printable) {
fail("unsignedCharToPrintable result mistaken");
}
END_TEST
START_TEST(test_amplification_isolated_external_parser) {
// NOTE: Length 44 is precisely twice the length of "<!ENTITY a SYSTEM 'b'>"
// (22) that is used in function accountingGetCurrentAmplification in
// xmlparse.c.
// 1.........1.........1.........1.........1..4 => 44
const char doc[] = "<!ENTITY % p1 '123456789_123456789_1234567'>";
const int docLen = (int)sizeof(doc) - 1;
const float maximumToleratedAmplification = 2.0f;
struct TestCase {
int offsetOfThreshold;
enum XML_Status expectedStatus;
};
struct TestCase cases[] = {
{-2, XML_STATUS_ERROR}, {-1, XML_STATUS_ERROR}, {0, XML_STATUS_ERROR},
{+1, XML_STATUS_OK}, {+2, XML_STATUS_OK},
};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
const int offsetOfThreshold = cases[i].offsetOfThreshold;
const enum XML_Status expectedStatus = cases[i].expectedStatus;
const unsigned long long activationThresholdBytes
= docLen + offsetOfThreshold;
set_subtest("offsetOfThreshold=%d, expectedStatus=%d", offsetOfThreshold,
expectedStatus);
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
assert_true(XML_SetBillionLaughsAttackProtectionMaximumAmplification(
parser, maximumToleratedAmplification)
== XML_TRUE);
assert_true(XML_SetBillionLaughsAttackProtectionActivationThreshold(
parser, activationThresholdBytes)
== XML_TRUE);
XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
assert_true(ext_parser != NULL);
const enum XML_Status actualStatus
= _XML_Parse_SINGLE_BYTES(ext_parser, doc, docLen, XML_TRUE);
assert_true(actualStatus == expectedStatus);
if (actualStatus != XML_STATUS_OK) {
assert_true(XML_GetErrorCode(ext_parser)
== XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
}
XML_ParserFree(ext_parser);
XML_ParserFree(parser);
}
}
END_TEST
#endif // XML_GE == 1
void
@ -390,6 +447,8 @@ make_accounting_test_case(Suite *s) {
tcase_add_test(tc_accounting, test_accounting_precision);
tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
tcase_add_test__ifdef_xml_dtd(tc_accounting,
test_amplification_isolated_external_parser);
#else
UNUSED_P(s);
#endif /* XML_GE == 1 */

View File

@ -1,7 +1,7 @@
# $OpenBSD: Makefile,v 1.27 2022/10/22 17:50:28 gkoehler Exp $
# $OpenBSD: Makefile,v 1.28 2024/03/14 14:29:03 kettenis Exp $
# $NetBSD: Makefile,v 1.4 1995/04/20 22:41:08 cgd Exp $
SUBDIR= altivec_ast copy crypto dev ddb ffs \
SUBDIR= altivec_ast btcfi copy crypto dev ddb ffs \
fifofs fileops kern mfs_noperm \
net netinet netinet6 nfs ptrace sys uvm
.if exists(arch/${MACHINE}/Makefile)

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.438 2023/10/11 23:14:33 djm Exp $
.Dd $Mdocdate: October 11 2023 $
.\" $OpenBSD: ssh.1,v 1.439 2024/03/14 06:23:14 job Exp $
.Dd $Mdocdate: March 14 2024 $
.Dt SSH 1
.Os
.Sh NAME
@ -331,6 +331,7 @@ connection to the jump host described by
and then establishing a TCP forwarding to the ultimate destination from
there.
Multiple jump hops may be specified separated by comma characters.
IPv6 addresses can be specified by enclosing the address in square brackets.
This is a shortcut to specify a
.Cm ProxyJump
configuration directive.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ksyms.c,v 1.7 2024/03/12 17:22:24 cheloha Exp $ */
/* $OpenBSD: ksyms.c,v 1.8 2024/03/14 00:54:54 cheloha Exp $ */
/*
* Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
@ -23,7 +23,6 @@
#include <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -31,149 +30,60 @@
#include "btrace.h"
struct sym {
char *sym_name;
unsigned long sym_value; /* from st_value */
unsigned long sym_size; /* from st_size */
};
struct syms {
struct sym *table;
size_t nsymb;
int fd;
Elf *elf;
Elf_Scn *symtab;
size_t strtabndx, nsymb;
};
int sym_compare_search(const void *, const void *);
int sym_compare_sort(const void *, const void *);
int kelf_parse(struct syms *);
struct syms *
kelf_open(const char *path)
{
char *name;
Elf *elf;
Elf_Data *data = NULL;
Elf_Scn *scn = NULL, *symtab;
GElf_Sym sym;
GElf_Shdr shdr;
size_t i, shstrndx, strtabndx = SIZE_MAX, symtab_size;
unsigned long diff;
struct sym *tmp;
struct syms *syms = NULL;
int fd;
struct syms *syms;
int error;
if (elf_version(EV_CURRENT) == EV_NONE)
errx(1, "elf_version: %s", elf_errmsg(-1));
fd = open(path, O_RDONLY);
if (fd == -1) {
if ((syms = calloc(1, sizeof(*syms))) == NULL)
err(1, NULL);
syms->fd = open(path, O_RDONLY);
if (syms->fd == -1) {
warn("open: %s", path);
free(syms);
return NULL;
}
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
if ((syms->elf = elf_begin(syms->fd, ELF_C_READ, NULL)) == NULL) {
warnx("elf_begin: %s", elf_errmsg(-1));
goto bad;
}
if (elf_kind(elf) != ELF_K_ELF)
if (elf_kind(syms->elf) != ELF_K_ELF)
goto bad;
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
goto bad;
}
while ((scn = elf_nextscn(elf, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr) {
warnx("elf_getshdr: %s", elf_errmsg(-1));
goto bad;
}
if ((name = elf_strptr(elf, shstrndx, shdr.sh_name)) == NULL) {
warnx("elf_strptr: %s", elf_errmsg(-1));
goto bad;
}
if (strcmp(name, ELF_SYMTAB) == 0 &&
shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
symtab = scn;
symtab_size = shdr.sh_size / shdr.sh_entsize;
}
if (strcmp(name, ELF_STRTAB) == 0 &&
shdr.sh_type == SHT_STRTAB) {
strtabndx = elf_ndxscn(scn);
}
}
if (symtab == NULL) {
warnx("%s: %s: section not found", path, ELF_SYMTAB);
goto bad;
}
if (strtabndx == SIZE_MAX) {
warnx("%s: %s: section not found", path, ELF_STRTAB);
goto bad;
}
data = elf_rawdata(symtab, data);
if (data == NULL)
error = kelf_parse(syms);
if (error)
goto bad;
if ((syms = calloc(1, sizeof(*syms))) == NULL)
err(1, NULL);
syms->table = calloc(symtab_size, sizeof *syms->table);
if (syms->table == NULL)
err(1, NULL);
for (i = 0; i < symtab_size; i++) {
if (gelf_getsym(data, i, &sym) == NULL)
continue;
if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
continue;
name = elf_strptr(elf, strtabndx, sym.st_name);
if (name == NULL)
continue;
syms->table[syms->nsymb].sym_name = strdup(name);
if (syms->table[syms->nsymb].sym_name == NULL)
err(1, NULL);
syms->table[syms->nsymb].sym_value = sym.st_value;
syms->table[syms->nsymb].sym_size = sym.st_size;
syms->nsymb++;
}
tmp = reallocarray(syms->table, syms->nsymb, sizeof *syms->table);
if (tmp == NULL)
err(1, NULL);
syms->table = tmp;
/* Sort symbols in ascending order by address. */
qsort(syms->table, syms->nsymb, sizeof *syms->table, sym_compare_sort);
/*
* Some functions, particularly those written in assembly, have an
* st_size of zero. We can approximate a size for these by assuming
* that they extend from their st_value to that of the next function.
*/
for (i = 0; i < syms->nsymb; i++) {
if (syms->table[i].sym_size != 0)
continue;
/* Can't do anything for the last symbol. */
if (i + 1 == syms->nsymb)
continue;
diff = syms->table[i + 1].sym_value - syms->table[i].sym_value;
syms->table[i].sym_size = diff;
}
return syms;
bad:
elf_end(elf);
close(fd);
return syms;
kelf_close(syms);
return NULL;
}
void
kelf_close(struct syms *syms)
{
size_t i;
if (syms == NULL)
return;
for (i = 0; i < syms->nsymb; i++)
free(syms->table[i].sym_name);
free(syms->table);
elf_end(syms->elf);
close(syms->fd);
free(syms);
}
@ -181,46 +91,106 @@ int
kelf_snprintsym(struct syms *syms, char *str, size_t size, unsigned long pc,
unsigned long off)
{
struct sym key = { .sym_value = pc + off };
struct sym *entry;
Elf_Addr offset;
GElf_Sym sym;
Elf_Data *data = NULL;
Elf_Addr offset, bestoff = 0;
size_t i, bestidx = 0;
char *name;
int cnt;
if (syms == NULL)
goto fallback;
entry = bsearch(&key, syms->table, syms->nsymb, sizeof *syms->table,
sym_compare_search);
if (entry == NULL)
data = elf_rawdata(syms->symtab, data);
if (data == NULL)
goto fallback;
offset = pc - (entry->sym_value + off);
if (offset != 0) {
return snprintf(str, size, "\n%s+0x%llx",
entry->sym_name, (unsigned long long)offset);
for (i = 0; i < syms->nsymb; i++) {
if (gelf_getsym(data, i, &sym) == NULL)
continue;
if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
continue;
if (pc >= sym.st_value + off) {
if (pc < (sym.st_value + off + sym.st_size))
break;
/* Workaround for symbols w/o size, usually asm ones. */
if (sym.st_size == 0 && sym.st_value + off > bestoff) {
bestidx = i;
bestoff = sym.st_value + off;
}
}
}
return snprintf(str, size, "\n%s", entry->sym_name);
if (i == syms->nsymb) {
if (bestidx == 0 || gelf_getsym(data, bestidx, &sym) == NULL)
goto fallback;
}
name = elf_strptr(syms->elf, syms->strtabndx, sym.st_name);
if (name != NULL)
cnt = snprintf(str, size, "\n%s", name);
else
cnt = snprintf(str, size, "\n0x%llx", sym.st_value);
if (cnt < 0)
return cnt;
offset = pc - (sym.st_value + off);
if (offset != 0) {
int l;
l = snprintf(str + cnt, size > (size_t)cnt ? size - cnt : 0,
"+0x%llx", (unsigned long long)offset);
if (l < 0)
return l;
cnt += l;
}
return cnt;
fallback:
return snprintf(str, size, "\n0x%lx", pc);
}
int
sym_compare_sort(const void *ap, const void *bp)
kelf_parse(struct syms *syms)
{
const struct sym *a = ap, *b = bp;
GElf_Shdr shdr;
Elf_Scn *scn, *scnctf;
char *name;
size_t shstrndx;
if (a->sym_value < b->sym_value)
return -1;
return a->sym_value > b->sym_value;
}
int
sym_compare_search(const void *keyp, const void *entryp)
{
const struct sym *entry = entryp, *key = keyp;
if (key->sym_value < entry->sym_value)
return -1;
return key->sym_value >= entry->sym_value + entry->sym_size;
if (elf_getshdrstrndx(syms->elf, &shstrndx) != 0) {
warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
return 1;
}
scn = scnctf = NULL;
while ((scn = elf_nextscn(syms->elf, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr) {
warnx("elf_getshdr: %s", elf_errmsg(-1));
return 1;
}
if ((name = elf_strptr(syms->elf, shstrndx,
shdr.sh_name)) == NULL) {
warnx("elf_strptr: %s", elf_errmsg(-1));
return 1;
}
if (strcmp(name, ELF_SYMTAB) == 0 &&
shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
syms->symtab = scn;
syms->nsymb = shdr.sh_size / shdr.sh_entsize;
}
if (strcmp(name, ELF_STRTAB) == 0 &&
shdr.sh_type == SHT_STRTAB) {
syms->strtabndx = elf_ndxscn(scn);
}
}
if (syms->symtab == NULL)
warnx("symbol table not found");
return 0;
}