Safeguard
Application Security•

CWE-1341 Multiple Releases of the Same Resource or Handle

Closing a file descriptor or freeing memory twice can corrupt data or close the wrong resource. How double release bugs arise and how to design them out.

Safeguard Security Team
4 min read

CWE-1341 is the bug of closing or releasing a resource or handle more than once without a successful open in between. Double free and double close are the familiar forms. It appears in C and C++, and also in Java and Rust code that manages native handles.

How it happens

Code opens handles to memory, files, devices, sockets and services, and closes them when finished. The release call, such as free or delete in C and C++, or close on a file handle, often assumes the caller releases only once. A second call breaks that assumption and the behavior is undefined or insecure. MITRE lists memory corruption, data corruption and execution path corruption as possible results.

There is a subtler form. Handle identifiers are often reused. If the same identifier has been given to something new, a second close can close the wrong resource, and a check on the identifier may wrongly say the resource is still open. MITRE therefore discourages reuse of identifiers.

Error paths are the common source: a cleanup in a branch, then another cleanup at the end of the function.

/* Vulnerable: fd is closed in the error branch and again at the end */
int process(const char *path) {
    int fd = open(path, O_RDONLY);
    if (fd < 0) return -1;

    if (read_header(fd) != 0) {
        close(fd);          /* first close */
        status = -1;
    }
    /* ... */
    close(fd);              /* second close, possibly a different file now */
    return status;
}
/* Safer: one exit path, handle invalidated after close */
int process(const char *path) {
    int status = -1;
    int fd = open(path, O_RDONLY);
    if (fd < 0) return -1;

    if (read_header(fd) == 0) {
        status = 0;
    }

    close(fd);
    fd = -1;
    return status;
}

The record lists three CVEs:

  • CVE-2019-13351: a file descriptor double close can cause the wrong file to be associated with a file descriptor.
  • CVE-2006-5051: a chain where a signal handler contains too much functionality, introducing a race condition that leads to a double free.
  • CVE-2004-0772: a double free resulting from certain error conditions.

The file descriptor case shows why a double close is more than a crash: in a multithreaded program another thread may have been handed the same number, and the second close cuts it off or redirects it.

What an attacker gains

MITRE lists availability and integrity: crash, exit or restart, and corruption of data or memory. How far an attacker can push a double free into code execution depends on the allocator and the program, so treat memory corruption as serious.

How to find it

MITRE lists two methods:

  • Static analysis. For common APIs and resource types, tools often have signatures that spot double release.
  • Dynamic analysis. Compiler instrumentation such as AddressSanitizer (ASan) can indirectly detect some instances.

Add ASan to your test and fuzzing builds, and run tests that exercise the error paths, since that is where the second release usually lives. A dependency scan helps too if the bug is in a library you use. The free scanner at gold.safeguard.sh/scan runs in your browser with no login and covers up to 100 dependencies.

How to fix it

From the record:

  1. Change the logic so the resource is closed only once. This may need refactoring, and it is easy in small blocks but harder when several closes are buried in complex conditionals.
  2. Use a flag that is set when the resource opens, cleared when it closes, and checked before closing. It helps when closes are spread across cases, but adds complexity and needs discipline.
  3. After closing, set the variable to NULL or the language equivalent. Some APIs ignore null. Others crash or raise an exception, which MITRE says may still be preferable to corrupting an unrelated resource. Rated defense in depth.

Where the language allows it, use ownership based cleanup, such as RAII in C++ or Rust's ownership model, so release happens once by construction.

Quick check

Why can a second close of a file descriptor hit the wrong file? Descriptor numbers are reused. After the first close, the number may belong to a new file, and the second close releases that one.

Which tool class can catch some double frees at test time? Compiler instrumentation such as AddressSanitizer.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.