Merge "Use generated linker config only"
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index eb737bb..34c64d2 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -26,14 +26,14 @@
     ],
 }
 
-cc_library {
-    // Do not ever allow this library to be vendor_available as a shared library.
-    // It does not have a stable interface.
-    name: "libfs_mgr",
+cc_defaults {
+    name: "libfs_mgr_defaults",
     defaults: ["fs_mgr_defaults"],
-    recovery_available: true,
     export_include_dirs: ["include"],
     include_dirs: ["system/vold"],
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+    ],
     srcs: [
         "file_wait.cpp",
         "fs_mgr.cpp",
@@ -43,6 +43,7 @@
         "fs_mgr_overlayfs.cpp",
         "fs_mgr_roots.cpp",
         "fs_mgr_vendor_overlay.cpp",
+        ":libfiemap_srcs",
     ],
     shared_libs: [
         "libbase",
@@ -88,6 +89,42 @@
             ],
         },
     },
+    header_libs: [
+        "libfiemap_headers",
+    ],
+    export_header_lib_headers: [
+        "libfiemap_headers",
+    ],
+}
+
+// Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
+// Use libfs_mgr in recovery, first-stage-init, or when libfiemap or overlayfs
+// is not used.
+//
+// Use libfs_mgr_binder when not in recovery/first-stage init, or when overlayfs
+// or libfiemap is needed. In this case, libfiemap will proxy over binder to
+// gsid.
+cc_library {
+    // Do not ever allow this library to be vendor_available as a shared library.
+    // It does not have a stable interface.
+    name: "libfs_mgr",
+    recovery_available: true,
+    defaults: [
+        "libfs_mgr_defaults",
+    ],
+    srcs: [
+        ":libfiemap_passthrough_srcs",
+    ],
+}
+
+cc_library {
+    // Do not ever allow this library to be vendor_available as a shared library.
+    // It does not have a stable interface.
+    name: "libfs_mgr_binder",
+    defaults: [
+        "libfs_mgr_defaults",
+        "libfiemap_binder_defaults",
+    ],
 }
 
 cc_library_static {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 48ce4cd..15c9dfb 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1370,7 +1370,7 @@
         Fstab proc_mounts;
         if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
             LERROR << "Can't read /proc/mounts";
-            return -1;
+            return false;
         }
         // Now proceed with other bind mounts on top of /data.
         for (const auto& entry : proc_mounts) {
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 8dbbf4c..fdc1583 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -20,15 +20,8 @@
     export_include_dirs: ["include"],
 }
 
-cc_defaults {
-    name: "libfiemap_defaults",
-    defaults: ["fs_mgr_defaults"],
-    cflags: [
-        "-D_FILE_OFFSET_BITS=64",
-        "-Wall",
-        "-Werror",
-    ],
-
+filegroup {
+    name: "libfiemap_srcs",
     srcs: [
         "fiemap_writer.cpp",
         "image_manager.cpp",
@@ -36,55 +29,32 @@
         "split_fiemap_writer.cpp",
         "utility.cpp",
     ],
-
-    static_libs: [
-        "libdm",
-        "libext2_uuid",
-        "libext4_utils",
-        "liblp",
-        "libfs_mgr",
-    ],
-
-    shared_libs: [
-        "libbase",
-    ],
-
-    header_libs: [
-        "libfiemap_headers",
-        "liblog_headers",
-    ],
-
-    export_shared_lib_headers: [
-        "libbase",
-    ],
-
-    export_header_lib_headers: [
-        "libfiemap_headers",
-    ],
 }
 
-// Open up a binder IImageManager interface.
-cc_library_static {
-    name: "libfiemap_binder",
-    defaults: ["libfiemap_defaults"],
+filegroup {
+    name: "libfiemap_binder_srcs",
     srcs: [
         "binder.cpp",
     ],
+}
+
+cc_defaults {
+    name: "libfiemap_binder_defaults",
+    srcs: [":libfiemap_binder_srcs"],
     whole_static_libs: [
         "gsi_aidl_interface-cpp",
         "libgsi",
     ],
     shared_libs: [
         "libbinder",
+        "libutils",
     ],
 }
 
 // Open up a passthrough IImageManager interface. Use libfiemap_binder whenever
 // possible. This should only be used when binder is not available.
-cc_library_static {
-    name: "libfiemap_passthrough",
-    defaults: ["libfiemap_defaults"],
-    recovery_available: true,
+filegroup {
+    name: "libfiemap_passthrough_srcs",
     srcs: [
         "passthrough.cpp",
     ],
@@ -92,10 +62,10 @@
 
 cc_test {
     name: "fiemap_writer_test",
-    defaults: ["libfiemap_defaults"],
     static_libs: [
         "libbase",
         "libdm",
+        "libfs_mgr",
         "liblog",
     ],
 
@@ -112,7 +82,6 @@
 
 cc_test {
     name: "fiemap_image_test",
-    defaults: ["libfiemap_defaults"],
     static_libs: [
         "libdm",
         "libext4_utils",
@@ -120,6 +89,7 @@
         "liblp",
     ],
     shared_libs: [
+        "libbase",
         "libcrypto",
         "libcrypto_utils",
         "libcutils",
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 30d01a6..eadcecc 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -30,7 +30,6 @@
     static_libs: [
         "libcutils",
         "libdm",
-        "libfs_mgr",
         "libfstab",
         "liblp",
         "update_metadata-protos",
@@ -93,8 +92,8 @@
         "libsnapshot_hal_deps",
     ],
     srcs: [":libsnapshot_sources"],
-    whole_static_libs: [
-        "libfiemap_binder",
+    static_libs: [
+        "libfs_mgr_binder"
     ],
 }
 
@@ -103,8 +102,8 @@
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
-    whole_static_libs: [
-        "libfiemap_passthrough",
+    static_libs: [
+        "libfs_mgr",
     ],
 }
 
@@ -116,8 +115,8 @@
     ],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
-    whole_static_libs: [
-        "libfiemap_passthrough",
+    static_libs: [
+        "libfs_mgr",
     ],
 }
 
@@ -144,6 +143,7 @@
         "libstorage_literals_headers",
     ],
     static_libs: [
+        "libfs_mgr",
         "libgtest",
         "libgmock",
     ],
@@ -170,6 +170,7 @@
         "android.hardware.boot@1.1",
         "libfs_mgr",
         "libgmock",
+        "libgsi",
         "liblp",
         "libsnapshot",
         "libsnapshot_test_helpers",
@@ -189,7 +190,6 @@
     static_libs: [
         "libdm",
         "libext2_uuid",
-        "libfiemap_binder",
         "libfstab",
         "libsnapshot",
     ],
@@ -200,7 +200,7 @@
         "libbinder",
         "libbinderthreadstate",
         "libext4_utils",
-        "libfs_mgr",
+        "libfs_mgr_binder",
         "libhidlbase",
         "liblog",
         "liblp",
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 0f5af14..2da0103 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -606,17 +606,17 @@
 std::ostream& operator<<(std::ostream& os, Request request) {
     switch (request) {
         case Request::LOCK_SHARED:
-            return os << "LOCK_SHARED";
+            return os << "Shared";
         case Request::LOCK_EXCLUSIVE:
-            return os << "LOCK_EXCLUSIVE";
+            return os << "Exclusive";
         case Request::UNLOCK:
-            return os << "UNLOCK";
+            return os << "Unlock";
         case Request::EXIT:
-            return os << "EXIT";
+            return os << "Exit";
         case Request::UNKNOWN:
             [[fallthrough]];
         default:
-            return os << "UNKNOWN";
+            return os << "Unknown";
     }
 }
 
@@ -746,7 +746,7 @@
                         LockTestParam{Request::LOCK_SHARED, Request::LOCK_EXCLUSIVE}),
         [](const testing::TestParamInfo<LockTestP::ParamType>& info) {
             std::stringstream ss;
-            ss << info.param.first << "_" << info.param.second;
+            ss << info.param.first << info.param.second;
             return ss.str();
         });
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 5ca1fee..225bc9c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -834,7 +834,7 @@
 }
 
 static void HandleUserspaceReboot() {
-    if (!android::sysprop::InitProperties::userspace_reboot_in_progress().value_or(false)) {
+    if (!android::sysprop::InitProperties::is_userspace_reboot_supported().value_or(false)) {
         LOG(ERROR) << "Attempted a userspace reboot on a device that doesn't support it";
         return;
     }
diff --git a/init/service.cpp b/init/service.cpp
index a97935e..0e27ff1 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -325,8 +325,8 @@
                     LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
                                << (boot_completed ? "in 4 minutes" : "before boot completed");
                     // Notifies update_verifier and apexd
-                    SetProperty("sys.init.updatable_crashing", "1");
                     SetProperty("sys.init.updatable_crashing_process_name", name_);
+                    SetProperty("sys.init.updatable_crashing", "1");
                 }
             }
         } else {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 7676289..341275d 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -78,10 +78,31 @@
   CrcGenerateTable();
   Crc64GenerateTable();
 
-  std::vector<uint8_t> src(gnu_debugdata_size_);
-  if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
-    gnu_debugdata_offset_ = 0;
-    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+  // Verify the request is not larger than the max size_t value.
+  if (gnu_debugdata_size_ > SIZE_MAX) {
+    return nullptr;
+  }
+  size_t initial_buffer_size;
+  if (__builtin_mul_overflow(5, gnu_debugdata_size_, &initial_buffer_size)) {
+    return nullptr;
+  }
+
+  size_t buffer_increment;
+  if (__builtin_mul_overflow(2, gnu_debugdata_size_, &buffer_increment)) {
+    return nullptr;
+  }
+
+  std::unique_ptr<uint8_t[]> src(new (std::nothrow) uint8_t[gnu_debugdata_size_]);
+  if (src.get() == nullptr) {
+    return nullptr;
+  }
+
+  std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
+  if (!dst->Resize(initial_buffer_size)) {
+    return nullptr;
+  }
+
+  if (!memory_->ReadFully(gnu_debugdata_offset_, src.get(), gnu_debugdata_size_)) {
     return nullptr;
   }
 
@@ -89,21 +110,23 @@
   CXzUnpacker state;
   alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
   alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
-
   XzUnpacker_Construct(&state, &alloc);
 
-  std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
   int return_val;
   size_t src_offset = 0;
   size_t dst_offset = 0;
   ECoderStatus status;
-  dst->Resize(5 * gnu_debugdata_size_);
   do {
-    size_t src_remaining = src.size() - src_offset;
+    size_t src_remaining = gnu_debugdata_size_ - src_offset;
     size_t dst_remaining = dst->Size() - dst_offset;
-    if (dst_remaining < 2 * gnu_debugdata_size_) {
-      dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
-      dst_remaining += 2 * gnu_debugdata_size_;
+    if (dst_remaining < buffer_increment) {
+      size_t new_size;
+      if (__builtin_add_overflow(dst->Size(), buffer_increment, &new_size) ||
+          !dst->Resize(new_size)) {
+        XzUnpacker_Free(&state);
+        return nullptr;
+      }
+      dst_remaining += buffer_increment;
     }
     return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
                                  &src_remaining, true, CODER_FINISH_ANY, &status);
@@ -112,13 +135,13 @@
   } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
   XzUnpacker_Free(&state);
   if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
-    gnu_debugdata_offset_ = 0;
-    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
     return nullptr;
   }
 
   // Shrink back down to the exact size.
-  dst->Resize(dst_offset);
+  if (!dst->Resize(dst_offset)) {
+    return nullptr;
+  }
 
   return dst.release();
 }
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index a66cd5b..8de3d98 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -206,12 +206,12 @@
 }
 
 size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
-  if (addr >= raw_.size()) {
+  if (addr >= size_) {
     return 0;
   }
 
-  size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
-  const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
+  size_t bytes_left = size_ - static_cast<size_t>(addr);
+  const unsigned char* actual_base = static_cast<const unsigned char*>(raw_) + addr;
   size_t actual_len = std::min(bytes_left, size);
 
   memcpy(dst, actual_base, actual_len);
@@ -219,7 +219,7 @@
 }
 
 uint8_t* MemoryBuffer::GetPtr(size_t offset) {
-  if (offset < raw_.size()) {
+  if (offset < size_) {
     return &raw_[offset];
   }
   return nullptr;
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
index 3fe4bbb..a91e59f 100644
--- a/libunwindstack/MemoryBuffer.h
+++ b/libunwindstack/MemoryBuffer.h
@@ -29,18 +29,27 @@
 class MemoryBuffer : public Memory {
  public:
   MemoryBuffer() = default;
-  virtual ~MemoryBuffer() = default;
+  virtual ~MemoryBuffer() { free(raw_); }
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
 
   uint8_t* GetPtr(size_t offset);
 
-  void Resize(size_t size) { raw_.resize(size); }
+  bool Resize(size_t size) {
+    raw_ = reinterpret_cast<uint8_t*>(realloc(raw_, size));
+    if (raw_ == nullptr) {
+      size_ = 0;
+      return false;
+    }
+    size_ = size;
+    return true;
+  }
 
-  uint64_t Size() { return raw_.size(); }
+  uint64_t Size() { return size_; }
 
  private:
-  std::vector<uint8_t> raw_;
+  uint8_t* raw_ = nullptr;
+  size_t size_ = 0;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index c33908d..fc90dab 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -105,6 +105,9 @@
   void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; }
   void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; }
 
+  void FakeSetGnuDebugdataOffset(uint64_t offset) { gnu_debugdata_offset_ = offset; }
+  void FakeSetGnuDebugdataSize(uint64_t size) { gnu_debugdata_size_ = size; }
+
  private:
   std::unordered_map<std::string, uint64_t> globals_;
   std::string fake_build_id_;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index ea27e3e..3cf90fe 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -1944,4 +1944,23 @@
   CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000);
 }
 
+TEST_F(ElfInterfaceTest, huge_gnu_debugdata_size) {
+  ElfInterfaceFake interface(nullptr);
+
+  interface.FakeSetGnuDebugdataOffset(0x1000);
+  interface.FakeSetGnuDebugdataSize(0xffffffffffffffffUL);
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+
+  interface.FakeSetGnuDebugdataSize(0x4000000000000UL);
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+
+  // This should exceed the size_t value of the first allocation.
+#if defined(__LP64__)
+  interface.FakeSetGnuDebugdataSize(0x3333333333333334ULL);
+#else
+  interface.FakeSetGnuDebugdataSize(0x33333334);
+#endif
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+}
+
 }  // namespace unwindstack
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 42c6efb..89f048d 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -455,6 +455,7 @@
 };
 
 #undef COMPARE_WEAK
+#undef COMPARE_WEAK_FUNCTIONAL
 
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 07dd3f1..100e507 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -134,7 +134,8 @@
 void sp_report_race();
 void sp_report_stack_pointer();
 
-#undef COMPARE
+#undef COMPARE_STRONG
+#undef COMPARE_STRONG_FUNCTIONAL
 
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9cf11a4..fdfcde8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -978,9 +978,11 @@
 
 on userspace-reboot-requested
   # TODO(b/135984674): reset all necessary properties here.
-  setprop sys.boot_completed 0
-  setprop sys.init.updatable_crashing 0
+  setprop sys.boot_completed ""
+  setprop sys.init.updatable_crashing ""
+  setprop sys.init.updatable_crashing_process_name ""
   setprop apexd.status ""
+  setprop sys.user.0.ce_available ""
 
 on userspace-reboot-fs-remount
   # Make sure that vold is running.
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 0bd9e68..03b1099 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -16,6 +16,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <scsi/sg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -51,6 +52,50 @@
 
 #define MMC_BLOCK_SIZE 512
 
+/*
+ * There should be no timeout for security protocol ioctl call, so we choose a
+ * large number for timeout.
+ * 20000 millisecs == 20 seconds
+ */
+#define TIMEOUT 20000
+
+/*
+ * The sg device driver that supports new interface has a major version number of "3".
+ * SG_GET_VERSION_NUM ioctl() will yield a number greater than or 30000.
+ */
+#define RPMB_MIN_SG_VERSION_NUM 30000
+
+/*
+ * CDB format of SECURITY PROTOCOL IN/OUT commands
+ * (JEDEC Standard No. 220D, Page 264)
+ */
+struct sec_proto_cdb {
+    /*
+     * OPERATION CODE = A2h for SECURITY PROTOCOL IN command,
+     * OPERATION CODE = B5h for SECURITY PROTOCOL OUT command.
+     */
+    uint8_t opcode;
+    /* SECURITY PROTOCOL = ECh (JEDEC Universal Flash Storage) */
+    uint8_t sec_proto;
+    /*
+     * The SECURITY PROTOCOL SPECIFIC field specifies the RPMB Protocol ID.
+     * CDB Byte 2 = 00h and CDB Byte 3 = 01h for RPMB Region 0.
+     */
+    uint8_t cdb_byte_2;
+    uint8_t cdb_byte_3;
+    /*
+     * Byte 4 and 5 are reserved.
+     */
+    uint8_t cdb_byte_4;
+    uint8_t cdb_byte_5;
+    /* ALLOCATION/TRANSFER LENGTH in big-endian */
+    uint32_t length;
+    /* Byte 9 is reserved. */
+    uint8_t cdb_byte_10;
+    /* CONTROL = 00h. */
+    uint8_t ctrl;
+} __packed;
+
 static int rpmb_fd = -1;
 static uint8_t read_buf[4096];
 static enum dev_type dev_type = UNKNOWN_RPMB;
@@ -71,6 +116,21 @@
 
 #endif
 
+static void set_sg_io_hdr(sg_io_hdr_t* io_hdrp, int dxfer_direction, unsigned char cmd_len,
+                          unsigned char mx_sb_len, unsigned int dxfer_len, void* dxferp,
+                          unsigned char* cmdp, void* sbp) {
+    memset(io_hdrp, 0, sizeof(sg_io_hdr_t));
+    io_hdrp->interface_id = 'S';
+    io_hdrp->dxfer_direction = dxfer_direction;
+    io_hdrp->cmd_len = cmd_len;
+    io_hdrp->mx_sb_len = mx_sb_len;
+    io_hdrp->dxfer_len = dxfer_len;
+    io_hdrp->dxferp = dxferp;
+    io_hdrp->cmdp = cmdp;
+    io_hdrp->sbp = sbp;
+    io_hdrp->timeout = TIMEOUT;
+}
+
 static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req) {
     struct {
         struct mmc_ioc_multi_cmd multi;
@@ -132,6 +192,57 @@
     return rc;
 }
 
+static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req) {
+    int rc;
+    const uint8_t* write_buf = req->payload;
+    /*
+     * Meaning of member values are stated on the definition of struct sec_proto_cdb.
+     */
+    struct sec_proto_cdb in_cdb = {0xA2, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
+    struct sec_proto_cdb out_cdb = {0xB5, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
+    unsigned char sense_buffer[32];
+
+    if (req->reliable_write_size) {
+        /* Prepare SECURITY PROTOCOL OUT command. */
+        out_cdb.length = __builtin_bswap32(req->reliable_write_size);
+        sg_io_hdr_t io_hdr;
+        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
+                      req->reliable_write_size, (void*)write_buf, (unsigned char*)&out_cdb,
+                      sense_buffer);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+        write_buf += req->reliable_write_size;
+    }
+
+    if (req->write_size) {
+        /* Prepare SECURITY PROTOCOL OUT command. */
+        out_cdb.length = __builtin_bswap32(req->write_size);
+        sg_io_hdr_t io_hdr;
+        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
+                      req->write_size, (void*)write_buf, (unsigned char*)&out_cdb, sense_buffer);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+        write_buf += req->write_size;
+    }
+
+    if (req->read_size) {
+        /* Prepare SECURITY PROTOCOL IN command. */
+        out_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);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+    }
+    return rc;
+}
+
 static int send_virt_rpmb_req(int rpmb_fd, void* read_buf, size_t read_size, const void* payload,
                               size_t payload_size) {
     int rc;
@@ -194,6 +305,13 @@
             msg->result = STORAGE_ERR_GENERIC;
             goto err_response;
         }
+    } else if (dev_type == UFS_RPMB) {
+        rc = send_ufs_rpmb_req(rpmb_fd, req);
+        if (rc < 0) {
+            ALOGE("send_ufs_rpmb_req failed: %d, %s\n", rc, strerror(errno));
+            msg->result = STORAGE_ERR_GENERIC;
+            goto err_response;
+        }
     } else if ((dev_type == VIRT_RPMB) || (dev_type == SOCK_RPMB)) {
         size_t payload_size = req->reliable_write_size + req->write_size;
         rc = send_virt_rpmb_req(rpmb_fd, read_buf, req->read_size, req->payload, payload_size);
@@ -233,7 +351,7 @@
 }
 
 int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) {
-    int rc;
+    int rc, sg_version_num;
     dev_type = open_dev_type;
 
     if (dev_type != SOCK_RPMB) {
@@ -263,6 +381,16 @@
             return rc;
         }
     }
+
+    /* For UFS, it is prudent to check we hava a sg device by calling an ioctl */
+    if (dev_type == UFS_RPMB) {
+        if ((ioctl(rc, SG_GET_VERSION_NUM, &sg_version_num) < 0) ||
+            (sg_version_num < RPMB_MIN_SG_VERSION_NUM)) {
+            ALOGE("%s is not a sg device, or old sg driver\n", rpmb_devname);
+            return -1;
+        }
+    }
+    rpmb_fd = rc;
     return 0;
 }
 
diff --git a/trusty/storage/proxy/rpmb.h b/trusty/storage/proxy/rpmb.h
index 09af3c5..f4e1b51 100644
--- a/trusty/storage/proxy/rpmb.h
+++ b/trusty/storage/proxy/rpmb.h
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <trusty/interface/storage.h>
 
-enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, SOCK_RPMB };
+enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, UFS_RPMB, SOCK_RPMB };
 
 int rpmb_open(const char* rpmb_devname, enum dev_type dev_type);
 int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len);