9bb358f520
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
95 lines
3.2 KiB
C++
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
|