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

Commit 1abb40cf authored by Michael Ryleev's avatar Michael Ryleev Committed by android-build-merger
Browse files

Merge changes I40c9ea47,I593aeed5 am: c7878469

am: 5cf2f594

* commit '5cf2f594':
  trusty: storage: add tests
  trusty: storage: add client lib for testing

Change-Id: I39d2c1b49e92b15190fb92b66aa20e8586716957
parents fcd4ee48 5cf2f594
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
#
# Copyright (C) 2015 The Android Open-Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := libtrustystorage

LOCAL_SRC_FILES := \
	storage.c \

LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror

LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include

LOCAL_STATIC_LIBRARIES := \
	liblog \
	libtrusty \
	libtrustystorageinterface

include $(BUILD_STATIC_LIBRARY)
+154 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <stdint.h>
#include <trusty/interface/storage.h>

#define STORAGE_MAX_NAME_LENGTH_BYTES 159

__BEGIN_DECLS

typedef uint32_t storage_session_t;
typedef uint64_t file_handle_t;
typedef uint64_t storage_off_t;

#define STORAGE_INVALID_SESSION ((storage_session_t)-1)

/**
 * storage_ops_flags - storage related operation flags
 * @STORAGE_OP_COMPLETE: forces to commit current transaction
 */
enum storage_ops_flags {
    STORAGE_OP_COMPLETE = 0x1,
};

/**
 * storage_open_session() - Opens a storage session.
 * @device:    device node for talking with Trusty
 * @session_p: pointer to location in which to store session handle
 *             in case of success.
 *
 * Return: 0 on success, or an error code < 0 on failure.
 */
int storage_open_session(const char *device, storage_session_t *session_p, const char *port);

/**
 * storage_close_session() - Closes the session.
 * @session: the session to close
 */
void storage_close_session(storage_session_t session);

/**
 * storage_open_file() - Opens a file
 * @session:  the storage_session_t returned from a call to storage_open_session
 * @handle_p: pointer to location in which to store file handle in case of success
 * @name:     a null-terminated string identifier of the file to open.
 *            Cannot be more than STORAGE_MAX_NAME_LENGTH_BYTES in length.
 * @flags:    A bitmask consisting any storage_file_flag value or'ed together:
 * - STORAGE_FILE_OPEN_CREATE:           if this file does not exist, create it.
 * - STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: when specified, opening file with
 *                                       STORAGE_OPEN_FILE_CREATE flag will
 *                                       fail if the file already exists.
 *                                       Only meaningful if used in combination
 *                                       with STORAGE_FILE_OPEN_CREATE flag.
 * - STORAGE_FILE_OPEN_TRUNCATE: if this file already exists, discard existing
 *                               content and open it as a new file. No change
 *                               in semantics if the  file does not exist.
 * @opflags: a combination of @storage_op_flags
 *
 * Return: 0 on success, or an error code < 0 on failure.
 */
int storage_open_file(storage_session_t session, file_handle_t *handle_p,
                      const char *name, uint32_t flags, uint32_t opflags);

/**
 * storage_close_file() - Closes a file.
 * @handle: the file_handle_t retrieved from storage_open_file
 */
void storage_close_file(file_handle_t handle);

/**
 * storage_delete_file - Deletes a file.
 * @session: the storage_session_t returned from a call to storage_open_session
 * @name: the name of the file to delete
 * @opflags: a combination of @storage_op_flags
 *
 * Return: 0 on success, or an error code < 0 on failure.
 */
int storage_delete_file(storage_session_t session, const char *name,
                        uint32_t opflags);

/**
 * storage_read() - Reads a file at a given offset.
 * @handle: the file_handle_t retrieved from storage_open_file
 * @off: the start offset from whence to read in the file
 * @buf: the buffer in which to write the data read
 * @size: the size of buf and number of bytes to read
 *
 * Return: the number of bytes read on success, negative error code on failure
 */
ssize_t storage_read(file_handle_t handle,
                     storage_off_t off, void *buf, size_t size);

/**
 * storage_write() - Writes to a file at a given offset. Grows the file if necessary.
 * @handle: the file_handle_t retrieved from storage_open_file
 * @off: the start offset from whence to write in the file
 * @buf: the buffer containing the data to write
 * @size: the size of buf and number of bytes to write
 * @opflags: a combination of @storage_op_flags
 *
 * Return: the number of bytes written on success, negative error code on failure
 */
ssize_t storage_write(file_handle_t handle,
                      storage_off_t off, const void *buf, size_t size,
                      uint32_t opflags);

/**
 * storage_set_file_size() - Sets the size of the file.
 * @handle: the file_handle_t retrieved from storage_open_file
 * @off: the number of bytes to set as the new size of the file
 * @opflags: a combination of @storage_op_flags
 *
 * Return: 0 on success, negative error code on failure.
 */
int storage_set_file_size(file_handle_t handle, storage_off_t file_size,
                          uint32_t opflags);

/**
 * storage_get_file_size() - Gets the size of the file.
 * @session: the storage_session_t returned from a call to storage_open_session
 * @handle: the file_handle_t retrieved from storage_open_file
 * @size: pointer to storage_off_t in which to store the file size
 *
 * Return: 0 on success, negative error code on failure.
 */
int storage_get_file_size(file_handle_t handle, storage_off_t *size);


/**
 * storage_end_transaction: End current transaction
 * @session: the storage_session_t returned from a call to storage_open_session
 * @complete: if true, commit current transaction, discard it otherwise
 *
 * Return: 0 on success, negative error code on failure.
 */
int storage_end_transaction(storage_session_t session, bool complete);


__END_DECLS
+311 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/uio.h>

#include <trusty/tipc.h>
#include <trusty/lib/storage.h>

#define LOG_TAG "trusty_storage_client"
#include <cutils/log.h>

#define MAX_CHUNK_SIZE 4040

static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid)
{
    return ((uint64_t)s << 32) | fid;
}

static inline storage_session_t _to_session(file_handle_t fh)
{
    return (storage_session_t)(fh >> 32);
}

static inline uint32_t _to_handle(file_handle_t fh)
{
    return (uint32_t) fh;
}

static inline uint32_t _to_msg_flags(uint32_t opflags)
{
    uint32_t msg_flags = 0;

    if (opflags & STORAGE_OP_COMPLETE)
        msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE;

    return msg_flags;
}

static ssize_t check_response(struct storage_msg *msg, ssize_t res)
{
    if (res < 0)
        return res;

    if ((size_t)res < sizeof(*msg)) {
        ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg));
        return -EIO;
    }

    ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result);

    switch(msg->result) {
        case STORAGE_NO_ERROR:
            return res - sizeof(*msg);

        case STORAGE_ERR_NOT_FOUND:
            return -ENOENT;

        case STORAGE_ERR_EXIST:
            return -EEXIST;

        case STORAGE_ERR_NOT_VALID:
            return -EINVAL;

        case STORAGE_ERR_UNIMPLEMENTED:
            ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd);
            return -EINVAL;

        case STORAGE_ERR_ACCESS:
             return -EACCES;

        case STORAGE_ERR_TRANSACT:
             return -EBUSY;

        case STORAGE_ERR_GENERIC:
            ALOGE("cmd 0x%x: internal server error\n", msg->cmd);
            return -EIO;

        default:
            ALOGE("cmd 0x%x: unhandled server response %u\n",
                   msg->cmd, msg->result);
    }

    return -EIO;
}

static ssize_t send_reqv(storage_session_t session,
                         const struct iovec *tx_iovs, uint tx_iovcnt,
                         const struct iovec *rx_iovs, uint rx_iovcnt)
{
    ssize_t rc;

    rc = writev(session, tx_iovs, tx_iovcnt);
    if (rc < 0) {
        rc = -errno;
        ALOGE("failed to send request: %s\n", strerror(errno));
        return rc;
    }

    rc = readv(session, rx_iovs, rx_iovcnt);
    if (rc < 0) {
        rc = -errno;
        ALOGE("failed to recv response: %s\n", strerror(errno));
        return rc;
    }

    return rc;
}

int storage_open_session(const char *device, storage_session_t *session_p,
                         const char *port)
{
    int rc = tipc_connect(device, port);
    if (rc < 0)
        return rc;
    *session_p = (storage_session_t) rc;
    return 0;
}

void storage_close_session(storage_session_t session)
{
    tipc_close(session);
}


int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name,
                      uint32_t flags, uint32_t opflags)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)};
    struct storage_file_open_req req = { .flags = flags };
    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
    struct storage_file_open_resp rsp = { 0 };
    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};

    ssize_t rc = send_reqv(session, tx, 3, rx, 2);
    rc = check_response(&msg, rc);
    if (rc < 0)
        return rc;

    if ((size_t)rc != sizeof(rsp)) {
        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
        return -EIO;
    }

    *handle_p = make_file_handle(session, rsp.handle);
    return 0;
}

void storage_close_file(file_handle_t fh)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE };
    struct storage_file_close_req req = { .handle = _to_handle(fh)};
    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
    struct iovec rx[1] = {{&msg, sizeof(msg)}};

    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
    rc = check_response(&msg, rc);
    if (rc < 0) {
        ALOGE("close file failed (%d)\n", (int)rc);
    }
}

int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)};
    struct storage_file_delete_req req = { .flags = 0, };
    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
    struct iovec rx[1] = {{&msg, sizeof(msg)}};

    ssize_t rc = send_reqv(session, tx, 3, rx, 1);
    return check_response(&msg, rc);
}

static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_READ };
    struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off };
    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
    struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}};

    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
    return check_response(&msg, rc);
}

ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size)
{
    int rc;
    size_t bytes_read = 0;
    size_t chunk = MAX_CHUNK_SIZE;
    uint8_t *ptr = buf;

    while (size) {
        if (chunk > size)
            chunk = size;
        rc = _read_chunk(fh, off, ptr, chunk);
        if (rc < 0)
            return rc;
        if (rc == 0)
            break;
        off += rc;
        ptr += rc;
        bytes_read += rc;
        size -= rc;
    }
    return bytes_read;
}

static int _write_req(file_handle_t fh, storage_off_t off,
                      const void *buf, size_t size, uint32_t msg_flags)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, };
    struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, };
    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}};
    struct iovec rx[1] = {{&msg, sizeof(msg)}};

    ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1);
    rc = check_response(&msg, rc);
    return rc < 0 ? rc : size;
}

ssize_t storage_write(file_handle_t fh, storage_off_t off,
                      const void *buf, size_t size, uint32_t opflags)
{
    int rc;
    size_t bytes_written = 0;
    size_t chunk = MAX_CHUNK_SIZE;
    const uint8_t *ptr = buf;
    uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE);

    while (size) {
        if (chunk >= size) {
            /* last chunk in sequence */
            chunk = size;
            msg_flags = _to_msg_flags(opflags);
        }
        rc = _write_req(fh, off, ptr, chunk, msg_flags);
        if (rc < 0)
            return rc;
        if ((size_t)rc != chunk) {
            ALOGE("got partial write (%d)\n", (int)rc);
            return -EIO;
        }
        off += chunk;
        ptr += chunk;
        bytes_written += chunk;
        size -= chunk;
    }
    return bytes_written;
}

int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)};
    struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, };
    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
    struct iovec rx[1] = {{&msg, sizeof(msg)}};

    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
    return check_response(&msg, rc);
}

int storage_get_file_size(file_handle_t fh, storage_off_t *size_p)
{
    struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE };
    struct storage_file_get_size_req  req = { .handle = _to_handle(fh), };
    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
    struct storage_file_get_size_resp rsp;
    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};

    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
    rc = check_response(&msg, rc);
    if (rc < 0)
        return rc;

    if ((size_t)rc != sizeof(rsp)) {
        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
        return -EIO;
    }

    *size_p = rsp.size;
    return 0;
}

int storage_end_transaction(storage_session_t session, bool complete)
{
    struct storage_msg msg = {
        .cmd = STORAGE_END_TRANSACTION,
        .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0,
    };
    struct iovec iov = {&msg, sizeof(msg)};

    ssize_t rc = send_reqv(session, &iov, 1, &iov, 1);
    return check_response(&msg, rc);
}
+29 −0
Original line number Diff line number Diff line
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := secure-storage-unit-test
LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
LOCAL_STATIC_LIBRARIES := \
	libtrustystorageinterface \
	libtrustystorage \
	libtrusty \
	liblog
LOCAL_SRC_FILES := main.cpp
include $(BUILD_NATIVE_TEST)
+3040 −0

File added.

Preview size limit exceeded, changes collapsed.