Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80ebe8c3 authored by David Anderson's avatar David Anderson
Browse files

snapuserd: Restrict where reads/writes to dm_user_header happen.

Only write to dm_user_header in the functions which explicitly need to
marshal it. This avoids leakage of dm-user specifics into core logic.

This also simplifies the existing control flow by allowing us to set an
error anywhere, or nowhere, as any "return false" from ProcessIORequest
will automatically set an error header.

Bug: 288273605
Test: snapuserd_test
Change-Id: I85f67208197d7ecc49e348ab3013827a38e84761
parent b6df0138
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -119,7 +119,6 @@ class Worker {
    }

    // Functions interacting with dm-user
    bool ReadDmUserHeader();
    bool WriteDmUserPayload(size_t size);
    bool DmuserReadRequest();

+34 −50
Original line number Diff line number Diff line
@@ -290,21 +290,6 @@ bool Worker::RunThread() {
    return true;
}

// Read Header from dm-user misc device. This gives
// us the sector number for which IO is issued by dm-snapshot device
bool Worker::ReadDmUserHeader() {
    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
        if (errno != ENOTBLK) {
            SNAP_PLOG(ERROR) << "Control-read failed";
        }

        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
        return false;
    }

    return true;
}

// Send the payload/data back to dm-user misc device.
bool Worker::WriteDmUserPayload(size_t size) {
    size_t payload_size = size;
@@ -345,19 +330,15 @@ bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) {
}

bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
    struct dm_user_header* header = bufsink_.GetHeaderPtr();
    size_t remaining_size = sz;
    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
    bool io_error = false;
    int ret = 0;

    do {
        // Process 1MB payload at a time
        size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size);

        header->type = DM_USER_RESP_SUCCESS;
        size_t total_bytes_read = 0;
        io_error = false;
        bufsink_.ResetBufferOffset();

        while (read_size) {
@@ -375,7 +356,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
                // device.
                if (!ReadDataFromBaseDevice(sector, size)) {
                    SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed";
                    header->type = DM_USER_RESP_ERROR;
                    return false;
                }

                ret = size;
@@ -384,26 +365,18 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
                // process it.
                if (!ProcessCowOp(it->second)) {
                    SNAP_LOG(ERROR) << "ProcessCowOp failed";
                    header->type = DM_USER_RESP_ERROR;
                    return false;
                }

                ret = BLOCK_SZ;
            }

            // Just return the header if it is an error
            if (header->type == DM_USER_RESP_ERROR) {
                RespondIOError();
                io_error = true;
                break;
            }

            read_size -= ret;
            total_bytes_read += ret;
            sector += (ret >> SECTOR_SHIFT);
            bufsink_.UpdateBufferOffset(ret);
        }

        if (!io_error) {
        if (!WriteDmUserPayload(total_bytes_read)) {
            return false;
        }
@@ -411,8 +384,7 @@ bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
        SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read
                        << " remaining_size: " << remaining_size;
        remaining_size -= total_bytes_read;
        }
    } while (remaining_size > 0 && !io_error);
    } while (remaining_size > 0);

    return true;
}
@@ -453,8 +425,6 @@ int Worker::ReadUnalignedSector(
}

bool Worker::ReadUnalignedSector(sector_t sector, size_t size) {
    struct dm_user_header* header = bufsink_.GetHeaderPtr();
    header->type = DM_USER_RESP_SUCCESS;
    bufsink_.ResetBufferOffset();
    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();

@@ -622,9 +592,15 @@ bool Worker::DmuserReadRequest() {
}

bool Worker::ProcessIORequest() {
    // Read Header from dm-user misc device. This gives
    // us the sector number for which IO is issued by dm-snapshot device
    struct dm_user_header* header = bufsink_.GetHeaderPtr();
    if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
        if (errno != ENOTBLK) {
            SNAP_PLOG(ERROR) << "Control-read failed";
        }

    if (!ReadDmUserHeader()) {
        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
        return false;
    }

@@ -634,26 +610,34 @@ bool Worker::ProcessIORequest() {
    SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
    SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;

    // Use the same header buffer as the response header.
    int request_type = header->type;
    header->type = DM_USER_RESP_SUCCESS;
    header_response_ = true;

    switch (header->type) {
        case DM_USER_REQ_MAP_READ: {
            if (!DmuserReadRequest()) {
                return false;
            }
    bool ok;
    switch (request_type) {
        case DM_USER_REQ_MAP_READ:
            ok = DmuserReadRequest();
            break;
        }

        case DM_USER_REQ_MAP_WRITE: {
        case DM_USER_REQ_MAP_WRITE:
            // TODO: We should not get any write request
            // to dm-user as we mount all partitions
            // as read-only. Need to verify how are TRIM commands
            // handled during mount.
            return false;
        }
            ok = false;
            break;

        default:
            ok = false;
            break;
    }

    return true;
    if (!ok && header->type != DM_USER_RESP_ERROR) {
        RespondIOError();
    }
    return ok;
}

}  // namespace snapshot