Operation on Resource in Wrong Phase of Lifetime

Description

Operation on Resource in Wrong Phase of Lifetime occurs when code performs operations on a resource that is inappropriate for the resource's current state in its lifecycle. This includes using a resource before it's ready, after it's been closed, during initialization, or in an invalid state. Common examples include reading from unopened files, writing to closed connections, or calling methods on partially constructed objects.

Risk

Undefined behavior from using resources in invalid states. Data corruption from writing to improperly prepared resources. Security vulnerabilities from bypassing initialization routines. Crashes from operating on deallocated resources. Information disclosure from accessing resources before sanitization. Authentication bypass from using sessions before validation.

Solution

Implement explicit state tracking for resources. Use state machines for complex resource lifecycles. Validate resource state before operations. Use factory patterns to ensure proper initialization. Implement proper cleanup sequences. Use language constructs that enforce lifecycle (RAII, try-with-resources).

Common Consequences

ImpactDetails
IntegrityScope: Data Corruption

Operations on unprepared resources corrupt data.
AvailabilityScope: Crashes

Invalid state operations cause failures.
SecurityScope: Bypass

Using resources before security checks complete.

Example Code + Solution Code

Vulnerable Code

// VULNERABLE: Operating on resources in wrong lifecycle phase
#include <stdio.h>
#include <stdlib.h>

// VULNERABLE: Using before open
FILE* global_log = NULL;

void log_event_vulnerable(const char* message) {
    // VULNERABLE: global_log may not be opened yet
    fprintf(global_log, "%s\n", message);  // Crash if NULL
}

void init_logging() {
    global_log = fopen("app.log", "a");
}

// VULNERABLE: Using after close
void process_file_vulnerable(const char* filename) {
    FILE* file = fopen(filename, "r");
    char buffer[1024];

    fread(buffer, 1, sizeof(buffer), file);
    fclose(file);

    // VULNERABLE: Using file after close
    fseek(file, 0, SEEK_SET);  // Undefined behavior
    fread(buffer, 1, sizeof(buffer), file);
}

// VULNERABLE: Using partially initialized structure
typedef struct {
    int (*process)(void* data);
    void* data;
    int size;
} Handler;

void use_handler_vulnerable(Handler* h) {
    // VULNERABLE: process may not be set yet
    h->process(h->data);  // Crash if process is NULL
}

// VULNERABLE: Socket use before connect
int socket_vulnerable() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);

    // VULNERABLE: Sending before connect
    char msg[] = "Hello";
    send(sock, msg, sizeof(msg), 0);  // Fails - not connected

    // Later: connect(sock, ...);
    return sock;
}

// VULNERABLE: Memory use during free
void double_use_vulnerable() {
    char* buffer = malloc(100);
    strcpy(buffer, "data");

    free(buffer);

    // VULNERABLE: Memory is being freed, not safe
    // Even within same function after free
    memset(buffer, 0, 100);  // Use after free
}
# VULNERABLE: Python resource lifecycle issues
class VulnerableConnection:
    def __init__(self):
        self.socket = None
        self.connected = False

    def send(self, data):
        # VULNERABLE: May not be connected
        self.socket.send(data)  # AttributeError or socket error

    def connect(self, host, port):
        self.socket = socket.socket()
        self.socket.connect((host, port))
        self.connected = True

# VULNERABLE: Using database before connection
class VulnerableDatabase:
    def __init__(self):
        self.connection = None
        self.cursor = None

    def query(self, sql):
        # VULNERABLE: cursor may not exist
        self.cursor.execute(sql)  # AttributeError
        return self.cursor.fetchall()

    def connect(self, connstr):
        self.connection = psycopg2.connect(connstr)
        self.cursor = self.connection.cursor()

# VULNERABLE: Using closed resource
def process_file_vulnerable(filename):
    f = open(filename, 'r')
    content = f.read()
    f.close()

    # VULNERABLE: File is closed
    f.seek(0)  # ValueError: I/O operation on closed file
    more_content = f.read()

# VULNERABLE: Using session before authentication
class VulnerableSession:
    def __init__(self):
        self.user = None
        self.permissions = None

    def get_user_data(self):
        # VULNERABLE: May be called before authenticate()
        return {
            'username': self.user.username,  # AttributeError
            'permissions': self.permissions
        }

    def authenticate(self, username, password):
        if verify_credentials(username, password):
            self.user = load_user(username)
            self.permissions = load_permissions(username)
// VULNERABLE: Java resource lifecycle issues
public class VulnerableLifecycle {

    private Connection connection;
    private PreparedStatement statement;

    // VULNERABLE: Using before initialization
    public ResultSet query(String sql) throws SQLException {
        // VULNERABLE: connection may be null
        statement = connection.prepareStatement(sql);
        return statement.executeQuery();
    }

    public void connect(String url) throws SQLException {
        connection = DriverManager.getConnection(url);
    }

    // VULNERABLE: Using after close
    public void processAndClose() throws SQLException {
        ResultSet rs = statement.executeQuery();

        connection.close();

        // VULNERABLE: Using connection after close
        while (rs.next()) {  // May fail - connection closed
            process(rs);
        }
    }

    // VULNERABLE: Builder used before complete
    public static class VulnerableBuilder {
        private String host;
        private int port;
        private Config config;

        public void connect() {
            // VULNERABLE: config may not be set
            Socket socket = new Socket(host, port);
            socket.setSoTimeout(config.getTimeout());  // NPE
        }

        public VulnerableBuilder host(String h) {
            this.host = h;
            return this;
        }

        public VulnerableBuilder config(Config c) {
            this.config = c;
            return this;
        }
    }
}

// VULNERABLE: Using object during construction
public class VulnerableDuringConstruction {

    private final List<String> items = new ArrayList<>();
    private Thread workerThread;

    public VulnerableDuringConstruction() {
        // VULNERABLE: Starting thread that uses 'this' before construction complete
        workerThread = new Thread(() -> {
            // 'this' may not be fully constructed
            processItems();
        });
        workerThread.start();
    }

    public void processItems() {
        for (String item : items) {  // items may be null
            process(item);
        }
    }
}
// VULNERABLE: JavaScript resource lifecycle issues
class VulnerableService {
    constructor() {
        this.db = null;
        this.initialized = false;
    }

    // VULNERABLE: Using before initialization
    async query(sql) {
        // VULNERABLE: db may be null
        return await this.db.query(sql);
    }

    async initialize() {
        this.db = await connectDatabase();
        this.initialized = true;
    }

    // VULNERABLE: Using after disposal
    async dispose() {
        await this.db.close();
        this.db = null;
    }

    async fetchData() {
        // Called after dispose
        // VULNERABLE: db is null
        return await this.db.query('SELECT * FROM data');
    }
}

// VULNERABLE: WebSocket used in wrong state
class VulnerableWebSocket {
    constructor(url) {
        this.ws = new WebSocket(url);
    }

    // VULNERABLE: Sending before connection open
    send(message) {
        // VULNERABLE: WebSocket may not be OPEN yet
        this.ws.send(JSON.stringify(message));
        // Error: Still in CONNECTING state
    }
}

// VULNERABLE: Promise-based initialization not awaited
class VulnerableAsync {
    constructor() {
        this.data = null;
        this.init();  // VULNERABLE: Not awaited
    }

    async init() {
        this.data = await fetchData();  // Takes time
    }

    process() {
        // VULNERABLE: May be called before init completes
        return this.data.map(item => item.value);  // data is null
    }
}

Fixed Code

// SAFE: Proper lifecycle management in C
#include <stdio.h>
#include <stdlib.h>

// SAFE: State tracking for resources
typedef enum {
    LOG_UNINITIALIZED,
    LOG_OPEN,
    LOG_CLOSED
} LogState;

FILE* global_log = NULL;
LogState log_state = LOG_UNINITIALIZED;

void init_logging() {
    global_log = fopen("app.log", "a");
    if (global_log) {
        log_state = LOG_OPEN;
    }
}

void log_event_safe(const char* message) {
    // SAFE: Check state before use
    if (log_state != LOG_OPEN || global_log == NULL) {
        return;  // Or initialize, or error
    }
    fprintf(global_log, "%s\n", message);
}

// SAFE: Proper resource lifecycle
void process_file_safe(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) return;

    char buffer[1024];
    fread(buffer, 1, sizeof(buffer), file);

    // Process while file is open
    process_data(buffer);

    // SAFE: Close when done, don't use after
    fclose(file);
    file = NULL;
}

// SAFE: Validate handler state
typedef struct {
    int (*process)(void* data);
    void* data;
    int size;
    int initialized;
} SafeHandler;

int use_handler_safe(SafeHandler* h) {
    // SAFE: Validate before use
    if (!h || !h->initialized || !h->process) {
        return -1;
    }
    return h->process(h->data);
}

SafeHandler* create_handler(int (*proc)(void*), void* data, int size) {
    SafeHandler* h = calloc(1, sizeof(SafeHandler));
    if (!h) return NULL;

    h->process = proc;
    h->data = data;
    h->size = size;
    h->initialized = 1;  // Mark as ready

    return h;
}

// SAFE: Proper socket lifecycle
int socket_safe() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) return -1;

    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    // SAFE: Connect before send
    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        close(sock);
        return -1;
    }

    // SAFE: Socket is connected
    char msg[] = "Hello";
    send(sock, msg, sizeof(msg), 0);

    return sock;
}
# SAFE: Python with proper lifecycle management
from enum import Enum, auto
import contextlib

class ConnectionState(Enum):
    DISCONNECTED = auto()
    CONNECTING = auto()
    CONNECTED = auto()
    CLOSED = auto()

class SafeConnection:
    def __init__(self):
        self.socket = None
        self.state = ConnectionState.DISCONNECTED

    def send(self, data):
        # SAFE: Validate state
        if self.state != ConnectionState.CONNECTED:
            raise RuntimeError(f"Cannot send in state {self.state}")
        self.socket.send(data)

    def connect(self, host, port):
        if self.state != ConnectionState.DISCONNECTED:
            raise RuntimeError("Already connected or connecting")

        self.state = ConnectionState.CONNECTING
        try:
            self.socket = socket.socket()
            self.socket.connect((host, port))
            self.state = ConnectionState.CONNECTED
        except Exception:
            self.state = ConnectionState.DISCONNECTED
            raise

    def close(self):
        if self.socket:
            self.socket.close()
        self.state = ConnectionState.CLOSED

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

# SAFE: Context manager for proper lifecycle
class SafeDatabase:
    def __init__(self, connstr):
        self.connstr = connstr
        self.connection = None
        self.cursor = None

    def connect(self):
        self.connection = psycopg2.connect(self.connstr)
        self.cursor = self.connection.cursor()
        return self

    def query(self, sql, params=None):
        if not self.cursor:
            raise RuntimeError("Not connected - call connect() first")
        self.cursor.execute(sql, params)
        return self.cursor.fetchall()

    def close(self):
        if self.cursor:
            self.cursor.close()
        if self.connection:
            self.connection.close()

    def __enter__(self):
        return self.connect()

    def __exit__(self, *args):
        self.close()

# SAFE: Using context manager
def process_database():
    with SafeDatabase("host=localhost") as db:
        results = db.query("SELECT * FROM users")
        # db automatically closed after block

# SAFE: Session with state validation
class SafeSession:
    def __init__(self):
        self.user = None
        self.permissions = None
        self.authenticated = False

    def authenticate(self, username, password):
        if verify_credentials(username, password):
            self.user = load_user(username)
            self.permissions = load_permissions(username)
            self.authenticated = True
            return True
        return False

    def get_user_data(self):
        # SAFE: Validate state
        if not self.authenticated:
            raise RuntimeError("Session not authenticated")
        return {
            'username': self.user.username,
            'permissions': self.permissions
        }
// SAFE: Java with proper lifecycle management
public class SafeLifecycle implements AutoCloseable {

    private Connection connection;
    private PreparedStatement statement;
    private boolean connected = false;

    public void connect(String url) throws SQLException {
        connection = DriverManager.getConnection(url);
        connected = true;
    }

    public ResultSet query(String sql) throws SQLException {
        // SAFE: Validate state
        if (!connected || connection == null) {
            throw new IllegalStateException("Not connected");
        }
        statement = connection.prepareStatement(sql);
        return statement.executeQuery();
    }

    // SAFE: Process before close
    public void processAndClose() throws SQLException {
        try {
            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                process(rs);
            }
        } finally {
            close();
        }
    }

    @Override
    public void close() throws SQLException {
        connected = false;
        if (statement != null) {
            statement.close();
        }
        if (connection != null) {
            connection.close();
        }
    }
}

// SAFE: Builder with validation
public static class SafeBuilder {
    private String host;
    private int port;
    private Config config;
    private boolean hostSet = false;
    private boolean portSet = false;

    public SafeBuilder host(String h) {
        this.host = h;
        this.hostSet = true;
        return this;
    }

    public SafeBuilder port(int p) {
        this.port = p;
        this.portSet = true;
        return this;
    }

    public SafeBuilder config(Config c) {
        this.config = c;
        return this;
    }

    public Connection build() throws IllegalStateException {
        // SAFE: Validate all required fields set
        if (!hostSet || !portSet) {
            throw new IllegalStateException("Host and port required");
        }

        Config c = config != null ? config : Config.defaults();
        return new Connection(host, port, c);
    }
}

// SAFE: Avoid publishing 'this' during construction
public class SafeDuringConstruction {

    private final List<String> items = new ArrayList<>();

    public SafeDuringConstruction() {
        // Don't start threads in constructor
    }

    // Factory method for proper initialization
    public static SafeDuringConstruction create() {
        SafeDuringConstruction instance = new SafeDuringConstruction();
        instance.startWorker();  // After construction complete
        return instance;
    }

    private void startWorker() {
        Thread workerThread = new Thread(this::processItems);
        workerThread.start();
    }
}
// SAFE: JavaScript with proper lifecycle
class SafeService {
    constructor() {
        this.db = null;
        this.state = 'uninitialized';
    }

    async initialize() {
        this.state = 'initializing';
        this.db = await connectDatabase();
        this.state = 'ready';
    }

    async query(sql) {
        // SAFE: Validate state
        if (this.state !== 'ready') {
            throw new Error(`Service not ready: ${this.state}`);
        }
        return await this.db.query(sql);
    }

    async dispose() {
        if (this.db) {
            await this.db.close();
            this.db = null;
        }
        this.state = 'disposed';
    }

    // Factory method ensures initialization
    static async create() {
        const service = new SafeService();
        await service.initialize();
        return service;
    }
}

// SAFE: WebSocket with state handling
class SafeWebSocket {
    constructor(url) {
        this.ws = new WebSocket(url);
        this.ready = false;
        this.queue = [];

        this.ws.onopen = () => {
            this.ready = true;
            // Send queued messages
            this.queue.forEach(msg => this.ws.send(msg));
            this.queue = [];
        };
    }

    send(message) {
        const data = JSON.stringify(message);
        if (this.ready && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(data);
        } else {
            // Queue for when ready
            this.queue.push(data);
        }
    }
}

// SAFE: Async initialization with factory
class SafeAsync {
    constructor() {
        this.data = null;
    }

    async init() {
        this.data = await fetchData();
    }

    process() {
        if (!this.data) {
            throw new Error('Not initialized');
        }
        return this.data.map(item => item.value);
    }

    static async create() {
        const instance = new SafeAsync();
        await instance.init();
        return instance;
    }
}

Exploited in the Wild

Use-After-Close Exploits

Database connections used after close causing data corruption.

Pre-Initialization Bypass

Security checks bypassed by using resources before initialization.

Double-Free via Lifecycle

Memory corruption from incorrect lifecycle management.


Tools to test/exploit

  • State machine testing frameworks.

  • Static analysis for lifecycle violations.

  • Fuzzing with lifecycle-aware oracles.


CVE Examples

  • CVE-2019-11477: TCP resource lifecycle issues (SACK panic).

  • CVE-2020-12654: Use of uninitialized wireless driver structures.


References

  1. MITRE. "CWE-666: Operation on Resource in Wrong Phase of Lifetime." https://cwe.mitre.org/data/definitions/666.html

  2. State machine design patterns.