login: fix check for file descriptor validity

LoginScreenStorage was incorrectly checking a file descriptor against
zero, but it should check against -1. Fixed by using
ScopedFD::is_valid instead of ScopedFD::get.

Added a new RetrieveInvalidData test that verifies that Retrieve
properly returns false if the file associated with the key is
empty. This required modifying
FakeSharedMemoryUtil::WriteDataToSharedMemory to return an invalid
file descriptor if the input vector is empty, which matches the
behavior of base::SharedMemory::Create.

BUG=b:159942676
TEST=cros_workon_make --test chromeos-login

Change-Id: I4b33b54426880f47b297c2e4d431ed7a608fdce0
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2281102
Reviewed-by: Mattias Nissler <mnissler@chromium.org>
Tested-by: Alexander Hendrich <hendrich@chromium.org>
Tested-by: Nicholas Bishop <nbishop@neverware.com>
Commit-Queue: Alexander Hendrich <hendrich@chromium.org>
diff --git a/login_manager/fake_secret_util.cc b/login_manager/fake_secret_util.cc
index 35b506c..e65aa36 100644
--- a/login_manager/fake_secret_util.cc
+++ b/login_manager/fake_secret_util.cc
@@ -12,6 +12,12 @@
 
 base::ScopedFD FakeSharedMemoryUtil::WriteDataToSharedMemory(
     const std::vector<uint8_t>& data) {
+  // Return an invalid file descriptor if the input is empty to match
+  // the behavior of base::SharedMemory::Create.
+  if (data.empty()) {
+    return base::ScopedFD();
+  }
+
   base::ScopedFD fd(open("/dev/null", O_RDONLY));
   data_[fd.get()] = data;
   return fd;
diff --git a/login_manager/login_screen_storage.cc b/login_manager/login_screen_storage.cc
index 0e80c75..42cde6e 100644
--- a/login_manager/login_screen_storage.cc
+++ b/login_manager/login_screen_storage.cc
@@ -161,7 +161,7 @@
     const std::vector<uint8_t>& data,
     base::ScopedFD* out_shared_memory_fd) {
   *out_shared_memory_fd = shared_memory_util_->WriteDataToSharedMemory(data);
-  if (!out_shared_memory_fd->get()) {
+  if (!out_shared_memory_fd->is_valid()) {
     *error = CreateError(DBUS_ERROR_IO_ERROR, "couldn't create shared memory.");
     return false;
   }
diff --git a/login_manager/login_screen_storage_test.cc b/login_manager/login_screen_storage_test.cc
index 4fabb0c..6c109f8 100644
--- a/login_manager/login_screen_storage_test.cc
+++ b/login_manager/login_screen_storage_test.cc
@@ -170,6 +170,27 @@
         testing::Values(std::vector<uint8_t>{0xb1, 0x0b},
                         GenerateLongTestValue())));
 
+TEST_F(LoginScreenStorageTestBase, RetrieveInvalidData) {
+  const base::FilePath path = GetKeyPath(kTestKey);
+
+  // Make the storage subdirectory
+  EXPECT_TRUE(base::CreateDirectory(path.DirName()));
+
+  // Create an empty file
+  base::ScopedFILE file(base::OpenFile(GetKeyPath(kTestKey), "w"));
+  EXPECT_NE(file, nullptr);
+  file.reset();
+
+  brillo::ErrorPtr error;
+  base::ScopedFD out_value_fd;
+  uint64_t value_size;
+  // CreateSharedMemoryWithData should fail because it can't create
+  // zero-sized shared memory, check that Retrieve propagates that
+  // failure.
+  EXPECT_FALSE(
+      storage_->Retrieve(&error, kTestKey, &value_size, &out_value_fd));
+}
+
 class LoginScreenStorageTestPersistent : public LoginScreenStorageTestBase {
  protected:
   const std::vector<uint8_t> test_value_{0xb1, 0x0b};