Fixes #4503.

### Problem

Transactions leak when `drop;` executes in a `branch_route` and modules
like `pua_dialoginfo` are loaded.  The leaked transactions persist
indefinitely in shared memory — no final reply is sent, no timer fires,
and `wait_handler()` never frees the cell.

### Cause

`set_kr()` accumulates flags with `|=`, but the first cleanup check in
`t_unref()` uses exact equality:

```c
if(unlikely(kr == REQ_ERR_DELAYED)) {    // fails when other flags are set
```

When `pua_dialoginfo` processes an INVITE, it calls `dialog_publish_multi()`
inline during `DLGCB_CREATED`, which goes through `pua_send_publish()` →
`tmb.t_request()` → `t_uac_prepare()` → `set_kr(REQ_FWDED)`.  If the
INVITE's `branch_route` then calls `drop;`, `t_relay_to()` ORs in
`REQ_ERR_DELAYED`, making `_tm_kr = REQ_FWDED | REQ_ERR_DELAYED` (17).

In `t_unref()`:
- Check 1: `17 == 16` → false
- Check 2: `17 == 0` → false
- Check 3: `(17 & 16)` true, but `(17 & ~(4|2|16|1))` = 0 → false

All three checks fail.  The transaction is orphaned.

This affects any module that calls `t_request()` or `t_uac_prepare()` inline
during INVITE processing — `pua_dialoginfo` is one common example.

### Fix

Change the check from exact equality to a bitwise test:

```c
-       if(unlikely(kr == REQ_ERR_DELAYED)) {
+       if(unlikely(kr & REQ_ERR_DELAYED)) {
```

The delayed-reply handler now fires whenever `REQ_ERR_DELAYED` is present,
regardless of other flags accumulated by `set_kr()`.

This is safe because:
- `REQ_ERR_DELAYED` is only set in `t_relay_to()` when `t_forward_nonack()`
  fails and the delayed-reply path is chosen — it is never set spuriously.
- `kill_transaction()` already handles the case where a final reply was
  previously sent (`FL_FINAL_REPLY` check → `t_release_transaction()`).

The existing check-3 fallback (lines 2077-2084) becomes unreachable after
this change but is harmless to leave in place.

### Workaround

On 6.1+ where `delayed_reply` is a runtime modparam, setting
`modparam("tm", "delayed_reply", 0)` avoids the vulnerable 
code path.
On ≤ 6.0.x, `TM_DELAYED_REPLY` is a compile-time `#define` (always on)
and there is no workaround — only this patch fixes the leak.

### Test results

Ten-scenario matrix across 6.0.3, 6.1.0, and 6.2.0-dev0 master.  1000
INVITEs per run, `fr_timer=5000`, `branch_route` with unconditional
`drop;`.  Contamination triggered naturally by loading `dialog` + `pua` +
`pua_dialoginfo` — no source modification beyond this patch.

| # | Version | Patch | `delayed_reply` | current | 5xx | SHM delta | Verdict |
|---|---------|-------|:---------------:|--------:|----:|----------:|---------|
| 1 | 6.0.3 | no | x | 431 | 0 | +7,150,272 | **LEAK** |
| 2 | 6.0.3 | yes | x | 0 | 353 | 0 | OK |
| 3 | 6.1.0 | no | 1 | 431 | 0 | +7,287,200 | **LEAK** |
| 4 | 6.1.0 | no | 0 | 0 | 375 | 0 | OK |
| 5 | 6.1.0 | yes | 1 | 0 | 407 | 0 | OK |
| 6 | 6.1.0 | yes | 0 | 0 | 336 | 0 | OK |
| 7 | 6.2.0-dev0 | no | 1 | 446 | 0 | +7,770,288 | **LEAK** |
| 8 | 6.2.0-dev0 | no | 0 | 0 | 461 | 0 | OK |
| 9 | 6.2.0-dev0 | yes | 1 | 0 | 448 | 0 | OK |
| 10 | 6.2.0-dev0 | yes | 0 | 0 | 448 | 0 | OK |

`delayed_reply` = x: not available as a modparam (compile-time, always on).
`current`: transactions remaining in hash table after test.
`5xx`: 500 replies sent by the delayed-reply handler (nonzero = cleanup ran).

---

*Note: AI tooling was used to assist with the code analysis, reproduction,
and test automation for this issue.  All diagnosis, testing, and review was
supervised by @NormB — the AI did not operate autonomously.  The root cause
identification, fix selection, and validation were guided and verified at
each step.*
You can view, comment on, or merge this pull request online at:

  https://github.com/kamailio/kamailio/pull/4644

-- Commit Summary --

  * tm: use bitwise check for REQ_ERR_DELAYED in t_unref()

-- File Changes --

    M src/modules/tm/t_lookup.c (2)

-- Patch Links --

https://github.com/kamailio/kamailio/pull/4644.patch
https://github.com/kamailio/kamailio/pull/4644.diff

-- 
Reply to this email directly or view it on GitHub:
https://github.com/kamailio/kamailio/pull/4644
You are receiving this because you are subscribed to this thread.

Message ID: <kamailio/kamailio/pull/[email protected]>
_______________________________________________
Kamailio - Development Mailing List -- [email protected]
To unsubscribe send an email to [email protected]
Important: keep the mailing list in the recipients, do not reply only to the 
sender!

Reply via email to