platform_frameworks_native/cmds/installd/view_compiler.cpp
Nick Kralevich 9bb358f520 view_compiler.cpp: clean up file descriptor handling
For file descriptors which are explicitly passed across an exec()
boundary, mark them as // NOLINT(android-cloexec-open). This suppresses
clang-tidy link checks (intended to be added as part of b/129350825)

Don't call close(STDOUT_FILENO). The dup2() syscall atomically closes
this for us, so we don't need to do it ourselves. Additionally, this
also fixes a race condition where another thread may call open() and get
an FD corresponding to STDOUT_FILENO, which we will then close as part
of the dup2() call. Removing the close() makes file descriptor handling
atomic.

Set O_CLOEXEC on outfd. The pre-duped file descriptor should have
O_CLOEXEC set on it. Calling dup2() will dup the file descriptor, but
NOT preserve the O_CLOEXEC flag. Quoting "man dup2":

  The two file descriptors do not share file descriptor flags
  (the close-on-exec flag).  The close-on-exec flag (FD_CLOEXEC;
  see fcntl(2)) for the duplicate descriptor is off.

If we don't set the O_CLOEXEC flag on outfd, we'll be leaking the file
descriptor twice, once as STDOUT_FILENO, and once as outfd. The second
leak is undesirable although harmless.

Additional cleanup: Add missing newlines at end of file.

Bug: 129350825
Test: compiles
Change-Id: Ic83ad72ef8a38106ad95ec0202c5c09c61fcf3e7
2019-04-01 09:17:19 -07:00

95 lines
3.2 KiB
C++

/*
* Copyright (C) 2019 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 "view_compiler.h"
#include <string>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "utils.h"
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "android-base/unique_fd.h"
namespace android {
namespace installd {
using base::unique_fd;
bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
int uid) {
CHECK(apk_path != nullptr);
CHECK(package_name != nullptr);
CHECK(out_dex_file != nullptr);
// viewcompiler won't have permission to open anything, so we have to open the files first
// and pass file descriptors.
// Open input file
unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open)
if (infd.get() < 0) {
PLOG(ERROR) << "Could not open input file: " << apk_path;
return false;
}
// Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
// we close stdout and open it towards the right output.
unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)};
if (outfd.get() < 0) {
PLOG(ERROR) << "Could not open output file: " << out_dex_file;
return false;
}
if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
PLOG(ERROR) << "Could not change output file permissions";
return false;
}
if (dup2(outfd, STDOUT_FILENO) < 0) {
PLOG(ERROR) << "Could not duplicate output file descriptor";
return false;
}
// Prepare command line arguments for viewcompiler
std::string args[] = {"/system/bin/viewcompiler",
"--apk",
"--infd",
android::base::StringPrintf("%d", infd.get()),
"--dex",
"--package",
package_name};
char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
const_cast<char*>(args[6].c_str()), nullptr};
pid_t pid = fork();
if (pid == 0) {
// Now that we've opened the files we need, drop privileges.
drop_capabilities(uid);
execv("/system/bin/viewcompiler", argv);
_exit(1);
}
return wait_child(pid) == 0;
}
} // namespace installd
} // namespace android