Merge "logd: add a SerializedLogBuffer suitable for compression"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index b6b6984..c33d5af 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1533,8 +1533,7 @@
         keys_.pop_front();
     }
 
-    std::shared_ptr<RSA> result = keys_[0];
-    return result;
+    return Key();
 }
 
 void atransport::ResetKeys() {
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index bd76ff4..9b5e5f7 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -45,6 +45,7 @@
 #include <vector>
 
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <gtest/gtest.h>
 
 #include "fastboot_driver.h"
@@ -76,8 +77,7 @@
 }
 
 bool FastBootTest::IsFastbootOverTcp() {
-    // serial contains ":" is treated as host ip and port number
-    return (device_serial.find(":") != std::string::npos);
+    return android::base::StartsWith(device_serial, "tcp:");
 }
 
 bool FastBootTest::UsbStillAvailible() {
@@ -182,19 +182,14 @@
 }
 
 void FastBootTest::ConnectTcpFastbootDevice() {
-    std::size_t found = device_serial.find(":");
-    if (found != std::string::npos) {
-        for (int i = 0; i < MAX_TCP_TRIES && !transport; i++) {
-            std::string error;
-            std::unique_ptr<Transport> tcp(
-                    tcp::Connect(device_serial.substr(0, found), tcp::kDefaultPort, &error)
-                            .release());
-            if (tcp)
-                transport =
-                        std::unique_ptr<TransportSniffer>(new TransportSniffer(std::move(tcp), 0));
-            if (transport != nullptr) break;
-            std::this_thread::sleep_for(std::chrono::milliseconds(10));
-        }
+    for (int i = 0; i < MAX_TCP_TRIES && !transport; i++) {
+        std::string error;
+        std::unique_ptr<Transport> tcp(
+                tcp::Connect(device_serial.substr(4), tcp::kDefaultPort, &error).release());
+        if (tcp)
+            transport = std::unique_ptr<TransportSniffer>(new TransportSniffer(std::move(tcp), 0));
+        if (transport != nullptr) break;
+        std::this_thread::sleep_for(std::chrono::milliseconds(10));
     }
 }
 
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index b2c7a27..0c184af 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -301,10 +301,13 @@
     return true;
 }
 
+static bool needs_block_encryption(const FstabEntry& entry);
+static bool should_use_metadata_encryption(const FstabEntry& entry);
+
 // Read the primary superblock from an ext4 filesystem.  On failure return
 // false.  If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
-static bool read_ext4_superblock(const std::string& blk_device, struct ext4_super_block* sb,
-                                 int* fs_stat) {
+static bool read_ext4_superblock(const std::string& blk_device, const FstabEntry& entry,
+                                 struct ext4_super_block* sb, int* fs_stat) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
 
     if (fd < 0) {
@@ -321,7 +324,29 @@
         LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
         // not a valid fs, tune2fs, fsck, and mount  will all fail.
         *fs_stat |= FS_STAT_INVALID_MAGIC;
-        return false;
+
+        bool encrypted = should_use_metadata_encryption(entry) || needs_block_encryption(entry);
+        if (entry.mount_point == "/data" &&
+            (!encrypted || android::base::StartsWith(blk_device, "/dev/block/dm-"))) {
+            // try backup superblock, if main superblock is corrupted
+            for (unsigned int blocksize = EXT4_MIN_BLOCK_SIZE; blocksize <= EXT4_MAX_BLOCK_SIZE;
+                 blocksize *= 2) {
+                uint64_t superblock = blocksize * 8;
+                if (blocksize == EXT4_MIN_BLOCK_SIZE) superblock++;
+
+                if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), superblock * blocksize)) !=
+                    sizeof(*sb)) {
+                    PERROR << "Can't read '" << blk_device << "' superblock";
+                    return false;
+                }
+                if (is_ext4_superblock_valid(sb) &&
+                    (1 << (10 + sb->s_log_block_size) == blocksize)) {
+                    *fs_stat &= ~FS_STAT_INVALID_MAGIC;
+                    break;
+                }
+            }
+        }
+        if (*fs_stat & FS_STAT_INVALID_MAGIC) return false;
     }
     *fs_stat |= FS_STAT_IS_EXT4;
     LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
@@ -662,7 +687,7 @@
     if (is_extfs(entry.fs_type)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
             if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
                 (sb.s_state & EXT4_VALID_FS) == 0) {
                 LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
@@ -692,7 +717,7 @@
          entry.fs_mgr_flags.fs_verity || entry.fs_mgr_flags.ext_meta_csum)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
             tune_reserved_size(blk_device, entry, &sb, &fs_stat);
             tune_encrypt(blk_device, entry, &sb, &fs_stat);
             tune_verity(blk_device, entry, &sb, &fs_stat);
diff --git a/fs_mgr/libsnapshot/fuzz.sh b/fs_mgr/libsnapshot/fuzz.sh
index 0e57674..5995cef 100755
--- a/fs_mgr/libsnapshot/fuzz.sh
+++ b/fs_mgr/libsnapshot/fuzz.sh
@@ -11,7 +11,7 @@
 
 build_normal() (
     pushd $(gettop)
-    NATIVE_COVERAGE="" NATIVE_LINE_COVERAGE="" COVERAGE_PATHS="" m ${FUZZ_TARGET}
+    NATIVE_COVERAGE="" NATIVE_LINE_COVERAGE="" NATIVE_COVERAGE_PATHS="" m ${FUZZ_TARGET}
     ret=$?
     popd
     return ${ret}
@@ -19,7 +19,7 @@
 
 build_cov() {
     pushd $(gettop)
-    NATIVE_COVERAGE="true" NATIVE_LINE_COVERAGE="true" COVERAGE_PATHS="${PROJECT_PATH}" m ${FUZZ_TARGET}
+    NATIVE_COVERAGE="true" NATIVE_LINE_COVERAGE="true" NATIVE_COVERAGE_PATHS="${PROJECT_PATH}" m ${FUZZ_TARGET}
     ret=$?
     popd
     return ${ret}
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 5909cff..55214f5 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2277,6 +2277,10 @@
         auto operations_it = install_operation_map.find(target_partition->name());
         if (operations_it != install_operation_map.end()) {
             cow_creator->operations = operations_it->second;
+        } else {
+            LOG(INFO) << target_partition->name()
+                      << " isn't included in the payload, skipping the cow creation.";
+            continue;
         }
 
         cow_creator->extra_extents.clear();
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
index 60bf796..051584c 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
@@ -62,6 +62,8 @@
                                                std::string(it->second) + target_suffix_, &p});
         }
     }
+
+    partial_update_ = manifest.partial_update();
 }
 
 bool SnapshotMetadataUpdater::ShrinkPartitions() const {
@@ -82,6 +84,18 @@
 }
 
 bool SnapshotMetadataUpdater::DeletePartitions() const {
+    // For partial update, not all dynamic partitions are included in the payload.
+    // TODO(xunchang) delete the untouched partitions whose group is in the payload.
+    // e.g. Delete vendor in the following scenario
+    // On device:
+    //   Group A: system, vendor
+    // In payload:
+    //   Group A: system
+    if (partial_update_) {
+        LOG(INFO) << "Skip deleting partitions for partial update";
+        return true;
+    }
+
     std::vector<std::string> partitions_to_delete;
     // Don't delete partitions in groups where the group name doesn't have target_suffix,
     // e.g. default.
@@ -139,6 +153,11 @@
 }
 
 bool SnapshotMetadataUpdater::DeleteGroups() const {
+    if (partial_update_) {
+        LOG(INFO) << "Skip deleting groups for partial update";
+        return true;
+    }
+
     std::vector<std::string> existing_groups = builder_->ListGroups();
     for (const auto& existing_group_name : existing_groups) {
         // Don't delete groups without target suffix, e.g. default.
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater.h b/fs_mgr/libsnapshot/snapshot_metadata_updater.h
index 83c9460..5b1cbf9 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater.h
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater.h
@@ -79,6 +79,7 @@
     const std::string target_suffix_;
     std::vector<Group> groups_;
     std::vector<Partition> partitions_;
+    bool partial_update_{false};
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index f82a602..de3d912 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -52,10 +52,19 @@
 
 bool TestPartitionOpener::GetInfo(const std::string& partition_name,
                                   android::fs_mgr::BlockDeviceInfo* info) const {
-    if (partition_name == "super") {
-        return PartitionOpener::GetInfo(fake_super_path_, info);
+    if (partition_name != "super") {
+        return PartitionOpener::GetInfo(partition_name, info);
     }
-    return PartitionOpener::GetInfo(partition_name, info);
+
+    if (PartitionOpener::GetInfo(fake_super_path_, info)) {
+        // SnapshotUpdateTest uses a relatively small super partition, which requires a small
+        // alignment and 0 offset to work. For the purpose of this test, hardcode the alignment
+        // and offset. This test isn't about testing liblp or libdm.
+        info->alignment_offset = 0;
+        info->alignment = std::min<uint32_t>(info->alignment, static_cast<uint32_t>(128_KiB));
+        return true;
+    }
+    return false;
 }
 
 std::string TestPartitionOpener::GetDeviceString(const std::string& partition_name) const {
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
index 8a11eaa..202e39b 100644
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -77,4 +77,5 @@
 message DeltaArchiveManifest {
     repeated PartitionUpdate partitions = 13;
     optional DynamicPartitionMetadata dynamic_partition_metadata = 15;
+    optional bool partial_update = 16;
 }
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 0ac66f2..0b456e7 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1221,6 +1221,20 @@
     return {};
 }
 
+static Result<void> MountLinkerConfigForDefaultNamespace() {
+    // No need to mount linkerconfig for default mount namespace if the path does not exist (which
+    // would mean it is already mounted)
+    if (access("/linkerconfig/default", 0) != 0) {
+        return {};
+    }
+
+    if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) {
+        return ErrnoError() << "Failed to mount linker configuration for default mount namespace.";
+    }
+
+    return {};
+}
+
 static bool IsApexUpdatable() {
     static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false);
     return updatable;
@@ -1319,11 +1333,14 @@
 }
 
 static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) {
-    if (SwitchToDefaultMountNamespace()) {
-        return {};
-    } else {
-        return Error() << "Failed to enter into default mount namespace";
+    if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) {
+        return result.error();
     }
+    if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) {
+        return result.error();
+    }
+    LOG(INFO) << "Switched to default mount namespace";
+    return {};
 }
 
 // Builtin-function-map start
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index f3b584c..b9d5d67 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -176,20 +176,6 @@
     return true;
 }
 
-static Result<void> MountLinkerConfigForDefaultNamespace() {
-    // No need to mount linkerconfig for default mount namespace if the path does not exist (which
-    // would mean it is already mounted)
-    if (access("/linkerconfig/default", 0) != 0) {
-        return {};
-    }
-
-    if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) {
-        return ErrnoError() << "Failed to mount linker configuration for default mount namespace.";
-    }
-
-    return {};
-}
-
 static android::base::unique_fd bootstrap_ns_fd;
 static android::base::unique_fd default_ns_fd;
 
@@ -290,40 +276,20 @@
     return success;
 }
 
-bool SwitchToDefaultMountNamespace() {
-    if (IsRecoveryMode()) {
-        // we don't have multiple namespaces in recovery mode
-        return true;
+Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace) {
+    if (IsRecoveryMode() || !IsApexUpdatable()) {
+        // we don't have multiple namespaces in recovery mode or if apex is not updatable
+        return {};
     }
-    if (default_ns_id != GetMountNamespaceId()) {
-        if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
-            PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
-            return false;
-        }
-
-        if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) {
-            LOG(ERROR) << result.error();
-            return false;
+    const auto& ns_id = target_mount_namespace == NS_BOOTSTRAP ? bootstrap_ns_id : default_ns_id;
+    const auto& ns_fd = target_mount_namespace == NS_BOOTSTRAP ? bootstrap_ns_fd : default_ns_fd;
+    const auto& ns_name = target_mount_namespace == NS_BOOTSTRAP ? "bootstrap" : "default";
+    if (ns_id != GetMountNamespaceId() && ns_fd.get() != -1) {
+        if (setns(ns_fd.get(), CLONE_NEWNS) == -1) {
+            return ErrnoError() << "Failed to switch to " << ns_name << " mount namespace.";
         }
     }
-
-    LOG(INFO) << "Switched to default mount namespace";
-    return true;
-}
-
-bool SwitchToBootstrapMountNamespaceIfNeeded() {
-    if (IsRecoveryMode()) {
-        // we don't have multiple namespaces in recovery mode
-        return true;
-    }
-    if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
-        IsApexUpdatable()) {
-        if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
-            PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
-            return false;
-        }
-    }
-    return true;
+    return {};
 }
 
 }  // namespace init
diff --git a/init/mount_namespace.h b/init/mount_namespace.h
index c41a449..d4d6f82 100644
--- a/init/mount_namespace.h
+++ b/init/mount_namespace.h
@@ -16,12 +16,15 @@
 
 #pragma once
 
+#include <android-base/result.h>
+
 namespace android {
 namespace init {
 
+enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT };
+
 bool SetupMountNamespaces();
-bool SwitchToDefaultMountNamespace();
-bool SwitchToBootstrapMountNamespaceIfNeeded();
+base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index ffd58a3..19e83cc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -544,6 +544,18 @@
     return still_running;
 }
 
+static Result<void> UnmountAllApexes() {
+    const char* args[] = {"/system/bin/apexd", "--unmount-all"};
+    int status;
+    if (logwrap_fork_execvp(arraysize(args), args, &status, false, LOG_KLOG, true, nullptr) != 0) {
+        return ErrnoError() << "Failed to call '/system/bin/apexd --unmount-all'";
+    }
+    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+        return {};
+    }
+    return Error() << "'/system/bin/apexd --unmount-all' failed : " << status;
+}
+
 //* Reboot / shutdown the system.
 // cmd ANDROID_RB_* as defined in android_reboot.h
 // reason Reason string like "reboot", "shutdown,userrequested"
@@ -698,6 +710,11 @@
     // 5. drop caches and disable zram backing device, if exist
     KillZramBackingDevice();
 
+    LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t;
+    // 6. unmount active apexes, otherwise they might prevent clean unmount of /data.
+    if (auto ret = UnmountAllApexes(); !ret.ok()) {
+        LOG(ERROR) << ret.error();
+    }
     UmountStat stat =
             TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore);
     // Follow what linux shutdown is doing: one more sync with little bit delay
@@ -736,18 +753,6 @@
     StartSendingMessages();
 }
 
-static Result<void> UnmountAllApexes() {
-    const char* args[] = {"/system/bin/apexd", "--unmount-all"};
-    int status;
-    if (logwrap_fork_execvp(arraysize(args), args, &status, false, LOG_KLOG, true, nullptr) != 0) {
-        return ErrnoError() << "Failed to call '/system/bin/apexd --unmount-all'";
-    }
-    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-        return {};
-    }
-    return Error() << "'/system/bin/apexd --unmount-all' failed : " << status;
-}
-
 static std::chrono::milliseconds GetMillisProperty(const std::string& name,
                                                    std::chrono::milliseconds default_value) {
     auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
@@ -831,7 +836,7 @@
         sub_reason = "apex";
         return result;
     }
-    if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
+    if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP)) {
         sub_reason = "ns_switch";
         return Error() << "Failed to switch to bootstrap namespace";
     }
diff --git a/init/service.cpp b/init/service.cpp
index 165b848..68365b3 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -465,6 +465,16 @@
         pre_apexd_ = true;
     }
 
+    // For pre-apexd services, override mount namespace as "bootstrap" one before starting.
+    // Note: "ueventd" is supposed to be run in "default" mount namespace even if it's pre-apexd
+    // to support loading firmwares from APEXes.
+    std::optional<MountNamespace> override_mount_namespace;
+    if (name_ == "ueventd") {
+        override_mount_namespace = NS_DEFAULT;
+    } else if (pre_apexd_) {
+        override_mount_namespace = NS_BOOTSTRAP;
+    }
+
     post_data_ = ServiceList::GetInstance().IsPostData();
 
     LOG(INFO) << "starting service '" << name_ << "'...";
@@ -496,7 +506,8 @@
     if (pid == 0) {
         umask(077);
 
-        if (auto result = EnterNamespaces(namespaces_, name_, pre_apexd_); !result.ok()) {
+        if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace);
+            !result.ok()) {
             LOG(FATAL) << "Service '" << name_
                        << "' failed to set up namespaces: " << result.error();
         }
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 484c2c8..05e632b 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -194,7 +194,8 @@
     return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd));
 }
 
-Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
+Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name,
+                             std::optional<MountNamespace> override_mount_namespace) {
     for (const auto& [nstype, path] : info.namespaces_to_enter) {
         if (auto result = EnterNamespace(nstype, path.c_str()); !result.ok()) {
             return result;
@@ -202,9 +203,10 @@
     }
 
 #if defined(__ANDROID__)
-    if (pre_apexd) {
-        if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
-            return Error() << "could not enter into the bootstrap mount namespace";
+    if (override_mount_namespace.has_value()) {
+        if (auto result = SwitchToMountNamespaceIfNeeded(override_mount_namespace.value());
+            !result.ok()) {
+            return result;
         }
     }
 #endif
diff --git a/init/service_utils.h b/init/service_utils.h
index 3f1071e..e74f8c1 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -19,12 +19,14 @@
 #include <sys/resource.h>
 #include <sys/types.h>
 
+#include <optional>
 #include <string>
 #include <vector>
 
 #include <android-base/unique_fd.h>
 #include <cutils/iosched_policy.h>
 
+#include "mount_namespace.h"
 #include "result.h"
 
 namespace android {
@@ -66,7 +68,8 @@
     // Pair of namespace type, path to name.
     std::vector<std::pair<int, std::string>> namespaces_to_enter;
 };
-Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd);
+Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name,
+                             std::optional<MountNamespace> override_mount_namespace);
 
 struct ProcessAttributes {
     std::string console;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 427ac4b..01551e2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -490,6 +490,9 @@
     chown root log /proc/slabinfo
     chmod 0440 /proc/slabinfo
 
+    chown root log /proc/pagetypeinfo
+    chmod 0440 /proc/pagetypeinfo
+
     #change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
     chown root system /proc/kmsg
     chmod 0440 /proc/kmsg
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 7dfd0d0..d1ed649 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -231,7 +231,7 @@
 
     if (req->read_size) {
         /* Prepare SECURITY PROTOCOL IN command. */
-        out_cdb.length = __builtin_bswap32(req->read_size);
+        in_cdb.length = __builtin_bswap32(req->read_size);
         sg_io_hdr_t io_hdr;
         set_sg_io_hdr(&io_hdr, SG_DXFER_FROM_DEV, sizeof(in_cdb), sizeof(sense_buffer),
                       req->read_size, read_buf, (unsigned char*)&in_cdb, sense_buffer);