Public bug reported:
# libevent: backport evdns server NULL-deref crash fix to 2.1.12-stable
**Summary:** `libevent`'s DNS *server* code (`evdns.c`, `request_parse()`)
dereferences
an uninitialized `NULL` pointer when it receives a UDP datagram shorter than the
12-byte DNS header, crashing (SIGSEGV) any application that uses libevent's
evdns
server facility. This is upstream bug [libevent#1231][1], **already fixed on
`master`** by commit `d076d2df` but **never released in a stable tarball**, so
the
distro's `2.1.12-stable` package is still affected. Please backport the one-line
fix.
---
## Package
| | |
|---|---|
| Source package | `libevent` |
| Version affected | `2.1.12-stable-10ubuntu0.1` (Ubuntu 26.04.1 LTS
"resolute") |
| Binary packages | `libevent-2.1-7t64`, `libevent-core-2.1-7t64` (amd64) |
| Also affects | Debian's `libevent` `2.1.12-stable-*`, and every distro
shipping the 2.1.12 stable release (upstream 2020-07-05) |
| Fixed upstream in | commit `d076d2df843bc5fb` on `master` (2021-11-30); not
in any released tarball |
## Impact
Denial of service: a single malformed UDP datagram crashes the process. Any
program
that opens a libevent evdns **server** port is affected. The most widely
deployed
example is **Tor**, whose `DNSPort` uses this API — a crafted short packet to
the
DNSPort takes Tor down, and under systemd it repeatedly trips the service
restart
limiter.
Reachability depends on the application's binding:
- Normally the evdns server port is bound to loopback, so this is a **local
DoS**
(any local process can crash the service).
- In transparent-proxy / DNS-redirect setups (e.g. Tor as a system-wide
transparent
proxy, where firewall rules redirect *all* UDP port 53 into the DNSPort),
**any
local process — and any LAN host in gateway configurations — can crash the
daemon**
by sending fewer than 12 bytes to port 53.
No CVE is assigned to upstream issue #1231 as far as I can find; it is
nonetheless a
straightforward remotely/locally triggerable crash and I'd suggest treating it
as a
security-relevant DoS.
## Root cause
In `evdns.c`, the server-side `request_parse()`:
```c
static int
request_parse(u8 *packet, int length, struct evdns_server_port *port, ...)
{
...
struct server_request *server_req = NULL; /* starts NULL */
/* Read the 12-byte DNS header. Each GET16 does: if (j+2 > length) goto
err; */
GET16(trans_id);
GET16(flags);
GET16(questions);
GET16(answers);
GET16(authority);
GET16(additional);
...
/* server_req is allocated only AFTER the whole header has parsed: */
server_req = mm_malloc(sizeof(struct server_request));
...
err:
if (server_req->base.questions) { /* <-- NULL deref: server_req is still
NULL */
for (i = 0; i < server_req->base.nquestions; ++i)
mm_free(server_req->base.questions[i]);
mm_free(server_req->base.questions);
}
mm_free(server_req);
return -1;
}
```
If the datagram is shorter than 12 bytes, one of the header `GET16` macros
jumps to
`err:` **before** `server_req` has been allocated, so `server_req` is still
`NULL`.
The cleanup then reads `server_req->base.questions`. `base` is the last member
of
`struct server_request`, sitting after a 128-byte `sockaddr_storage`, so the
access
lands at offset ~`0xe0` — i.e. a read of address `0x00000000000000e0`, which
faults.
This missing `NULL` guard was introduced by commit `991f0ed3` ("evdns: do not
check
server_req twice", a bad assumption that `server_req` can't be `NULL` at
`err:`),
which shipped in `2.1.12-stable`. It was reverted upstream in `d076d2df`.
## The fix (already upstream — please cherry-pick)
Upstream commit `d076d2df843bc5fb` — *Revert "evdns: do not check server_req
twice"*
(reverts `991f0ed3`, "Fixes: #1231") — restores the `NULL` guard:
```diff
err:
- if (server_req->base.questions) {
- for (i = 0; i < server_req->base.nquestions; ++i)
- mm_free(server_req->base.questions[i]);
- mm_free(server_req->base.questions);
+ if (server_req) {
+ if (server_req->base.questions) {
+ for (i = 0; i < server_req->base.nquestions; ++i)
+ mm_free(server_req->base.questions[i]);
+ mm_free(server_req->base.questions);
+ }
+ mm_free(server_req);
}
- mm_free(server_req);
return -1;
```
Request: add this as a distro patch (a debian/patches quilt patch cherry-picking
`d076d2df`) to the `2.1.12-stable-10ubuntu*` / Debian `2.1.12-stable-*` package.
## Steps to reproduce
Tested on Ubuntu 26.04.1 LTS, `libevent 2.1.12-stable-10ubuntu0.1`, using Tor
(`0.4.9.11-0ubuntu0.26.04.1`) as a convenient evdns-server host.
1. Run a Tor instance with a DNSPort, e.g. a minimal `torrc`:
```
DataDirectory /tmp/torrepro
SocksPort 0
DNSPort 127.0.0.1:15353
Log notice stderr
```
`tor -f /tmp/torrepro/torrc` (wait until `127.0.0.1:15353` is listening).
2. Send a datagram shorter than the 12-byte DNS header:
```
bash -c 'printf "\x00\x00" > /dev/udp/127.0.0.1/15353'
```
3. Tor dies with `Caught signal 11` (SIGSEGV). Any length from 2 to 11 bytes
reproduces reliably; a well-formed >=12-byte header does not.
Under gdb the fault is `SIGSEGV` at `si_addr = 0xe0`, with the crashing frame
inside
`libevent-2.1.so.7` (offset `+0xcd7d`), called from `event_base_loop` — i.e. the
evdns server read path, not the host application.
### Minimal libevent-only reproducer (no Tor)
For a repro that exercises libevent directly (compile with
`cc repro.c -levent -o repro`, needs `libevent-dev`):
```c
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/util.h>
#include <netinet/in.h>
#include <string.h>
static void cb(struct evdns_server_request *req, void *d) {
(void)d; evdns_server_request_respond(req, 0);
}
int main(void) {
struct event_base *base = event_base_new();
evutil_socket_t s = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(15353);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
bind(s, (struct sockaddr *)&sin, sizeof sin);
evutil_make_socket_nonblocking(s);
evdns_add_server_port_with_base(base, s, 0, cb, NULL);
event_base_dispatch(base);
return 0;
}
```
Then `bash -c 'printf "\x00\x00" > /dev/udp/127.0.0.1/15353'` crashes it
identically.
## References
- Upstream issue: libevent#1231 — "evdns crashes in parse_request on malformed
DNS packets" (closed) — https://github.com/libevent/libevent/issues/1231
- Fixing commit: `d076d2df843bc5fb` — Revert "evdns: do not check server_req
twice" — https://github.com/libevent/libevent/commit/d076d2df843bc5fb
- Regression-introducing commit: `991f0ed3d86ffca0c017ab83cd239289912bdaad`
---
### How to file
**Ubuntu (Launchpad):** run `ubuntu-bug libevent-2.1-7t64` on the affected
machine
(attaches package/version automatically), or file at
https://bugs.launchpad.net/ubuntu/+source/libevent/+filebug — paste the sections
above. Tag `patch` and mention it's a straightforward cherry-pick of an
upstream fix.
**Debian:** `reportbug --severity=important libevent-2.1-7t64` (submits to
[email protected]), or email a report to that address. Consider tagging
`security` given it is a triggerable crash.
[1]: https://github.com/libevent/libevent/issues/1231
➜ alltor ubuntu-bug libevent-2.1-7t64
REDACTED config part /etc/cloud/cloud.cfg.d/99-installer.cfg, insufficient
permissions
REDACTED config part
/etc/cloud/cloud.cfg.d/00-subiquity-disable-cloudinit-networking.cfg,
insufficient permissions
[49191] Sandbox: CanCreateUserNamespace() unshare(CLONE_NEWPID): EPERM
➜ alltor ls
README.md USER_GUIDE.md alltor alltor-test alltor-test.bak alltor.bak
libevent-evdns-backport-bug.md tor
➜ alltor cat libevent-evdns-backport-bug.md
# libevent: backport evdns server NULL-deref crash fix to 2.1.12-stable
**Summary:** `libevent`'s DNS *server* code (`evdns.c`, `request_parse()`)
dereferences
an uninitialized `NULL` pointer when it receives a UDP datagram shorter than the
12-byte DNS header, crashing (SIGSEGV) any application that uses libevent's
evdns
server facility. This is upstream bug [libevent#1231][1], **already fixed on
`master`** by commit `d076d2df` but **never released in a stable tarball**, so
the
distro's `2.1.12-stable` package is still affected. Please backport the one-line
fix.
---
## Package
| | |
|---|---|
| Source package | `libevent` |
| Version affected | `2.1.12-stable-10ubuntu0.1` (Ubuntu 26.04.1 LTS
"resolute") |
| Binary packages | `libevent-2.1-7t64`, `libevent-core-2.1-7t64` (amd64) |
| Also affects | Debian's `libevent` `2.1.12-stable-*`, and every distro
shipping the 2.1.12 stable release (upstream 2020-07-05) |
| Fixed upstream in | commit `d076d2df843bc5fb` on `master` (2021-11-30); not
in any released tarball |
## Impact
Denial of service: a single malformed UDP datagram crashes the process. Any
program
that opens a libevent evdns **server** port is affected. The most widely
deployed
example is **Tor**, whose `DNSPort` uses this API — a crafted short packet to
the
DNSPort takes Tor down, and under systemd it repeatedly trips the service
restart
limiter.
Reachability depends on the application's binding:
- Normally the evdns server port is bound to loopback, so this is a **local
DoS**
(any local process can crash the service).
- In transparent-proxy / DNS-redirect setups (e.g. Tor as a system-wide
transparent
proxy, where firewall rules redirect *all* UDP port 53 into the DNSPort),
**any
local process — and any LAN host in gateway configurations — can crash the
daemon**
by sending fewer than 12 bytes to port 53.
No CVE is assigned to upstream issue #1231 as far as I can find; it is
nonetheless a
straightforward remotely/locally triggerable crash and I'd suggest treating it
as a
security-relevant DoS.
## Root cause
In `evdns.c`, the server-side `request_parse()`:
```c
static int
request_parse(u8 *packet, int length, struct evdns_server_port *port, ...)
{
...
struct server_request *server_req = NULL; /* starts NULL */
/* Read the 12-byte DNS header. Each GET16 does: if (j+2 > length) goto
err; */
GET16(trans_id);
GET16(flags);
GET16(questions);
GET16(answers);
GET16(authority);
GET16(additional);
...
/* server_req is allocated only AFTER the whole header has parsed: */
server_req = mm_malloc(sizeof(struct server_request));
...
err:
if (server_req->base.questions) { /* <-- NULL deref: server_req is still
NULL */
for (i = 0; i < server_req->base.nquestions; ++i)
mm_free(server_req->base.questions[i]);
mm_free(server_req->base.questions);
}
mm_free(server_req);
return -1;
}
```
If the datagram is shorter than 12 bytes, one of the header `GET16` macros
jumps to
`err:` **before** `server_req` has been allocated, so `server_req` is still
`NULL`.
The cleanup then reads `server_req->base.questions`. `base` is the last member
of
`struct server_request`, sitting after a 128-byte `sockaddr_storage`, so the
access
lands at offset ~`0xe0` — i.e. a read of address `0x00000000000000e0`, which
faults.
This missing `NULL` guard was introduced by commit `991f0ed3` ("evdns: do not
check
server_req twice", a bad assumption that `server_req` can't be `NULL` at
`err:`),
which shipped in `2.1.12-stable`. It was reverted upstream in `d076d2df`.
## The fix (already upstream — please cherry-pick)
Upstream commit `d076d2df843bc5fb` — *Revert "evdns: do not check server_req
twice"*
(reverts `991f0ed3`, "Fixes: #1231") — restores the `NULL` guard:
```diff
err:
- if (server_req->base.questions) {
- for (i = 0; i < server_req->base.nquestions; ++i)
- mm_free(server_req->base.questions[i]);
- mm_free(server_req->base.questions);
+ if (server_req) {
+ if (server_req->base.questions) {
+ for (i = 0; i < server_req->base.nquestions; ++i)
+ mm_free(server_req->base.questions[i]);
+ mm_free(server_req->base.questions);
+ }
+ mm_free(server_req);
}
- mm_free(server_req);
return -1;
```
Request: add this as a distro patch (a debian/patches quilt patch cherry-picking
`d076d2df`) to the `2.1.12-stable-10ubuntu*` / Debian `2.1.12-stable-*` package.
## Steps to reproduce
Tested on Ubuntu 26.04.1 LTS, `libevent 2.1.12-stable-10ubuntu0.1`, using Tor
(`0.4.9.11-0ubuntu0.26.04.1`) as a convenient evdns-server host.
1. Run a Tor instance with a DNSPort, e.g. a minimal `torrc`:
```
DataDirectory /tmp/torrepro
SocksPort 0
DNSPort 127.0.0.1:15353
Log notice stderr
```
`tor -f /tmp/torrepro/torrc` (wait until `127.0.0.1:15353` is listening).
2. Send a datagram shorter than the 12-byte DNS header:
```
bash -c 'printf "\x00\x00" > /dev/udp/127.0.0.1/15353'
```
3. Tor dies with `Caught signal 11` (SIGSEGV). Any length from 2 to 11 bytes
reproduces reliably; a well-formed >=12-byte header does not.
Under gdb the fault is `SIGSEGV` at `si_addr = 0xe0`, with the crashing frame
inside
`libevent-2.1.so.7` (offset `+0xcd7d`), called from `event_base_loop` — i.e. the
evdns server read path, not the host application.
### Minimal libevent-only reproducer (no Tor)
For a repro that exercises libevent directly (compile with
`cc repro.c -levent -o repro`, needs `libevent-dev`):
```c
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/util.h>
#include <netinet/in.h>
#include <string.h>
static void cb(struct evdns_server_request *req, void *d) {
(void)d; evdns_server_request_respond(req, 0);
}
int main(void) {
struct event_base *base = event_base_new();
evutil_socket_t s = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(15353);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
bind(s, (struct sockaddr *)&sin, sizeof sin);
evutil_make_socket_nonblocking(s);
evdns_add_server_port_with_base(base, s, 0, cb, NULL);
event_base_dispatch(base);
return 0;
}
```
Then `bash -c 'printf "\x00\x00" > /dev/udp/127.0.0.1/15353'` crashes it
identically.
## References
- Upstream issue: libevent#1231 — "evdns crashes in parse_request on malformed
DNS packets" (closed) — https://github.com/libevent/libevent/issues/1231
- Fixing commit: `d076d2df843bc5fb` — Revert "evdns: do not check server_req
twice" — https://github.com/libevent/libevent/commit/d076d2df843bc5fb
- Regression-introducing commit: `991f0ed3d86ffca0c017ab83cd239289912bdaad`
ProblemType: Bug
DistroRelease: Ubuntu 26.04
Package: libevent-2.1-7t64 2.1.12-stable-10ubuntu0.1
ProcVersionSignature: Ubuntu 7.0.0-31.31-generic 7.0.14
Uname: Linux 7.0.0-31-generic x86_64
ApportVersion: 2.34.1-0ubuntu0.1
Architecture: amd64
CasperMD5CheckResult: pass
CurrentDesktop: ubuntu:GNOME
Date: Thu Sep 10 10:31:20 2026
InstallationDate: Installed on 2026-08-03 (38 days ago)
InstallationMedia: Ubuntu 26.04 "Resolute Raccoon" - Release amd64 (20260423.1)
ProcEnviron:
LANG=en_US.UTF-8
PATH=(custom, no user)
SHELL=/usr/bin/zsh
TERM=xterm-256color
XDG_RUNTIME_DIR=<set>
SourcePackage: libevent
UpgradeStatus: No upgrade log present (probably fresh install)
** Affects: libevent (Ubuntu)
Importance: Undecided
Status: New
** Tags: amd64 apport-bug resolute wayland-session
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2166986
Title:
evdns server crash
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/libevent/+bug/2166986/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs