1*7ba4dab5SXin Li /*
2*7ba4dab5SXin Li * Copyright (C) 2016 The Android Open Source Project
3*7ba4dab5SXin Li *
4*7ba4dab5SXin Li * Licensed under the Apache License, Version 2.0 (the "License");
5*7ba4dab5SXin Li * you may not use this file except in compliance with the License.
6*7ba4dab5SXin Li * You may obtain a copy of the License at
7*7ba4dab5SXin Li *
8*7ba4dab5SXin Li * http://www.apache.org/licenses/LICENSE-2.0
9*7ba4dab5SXin Li *
10*7ba4dab5SXin Li * Unless required by applicable law or agreed to in writing, software
11*7ba4dab5SXin Li * distributed under the License is distributed on an "AS IS" BASIS,
12*7ba4dab5SXin Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*7ba4dab5SXin Li * See the License for the specific language governing permissions and
14*7ba4dab5SXin Li * limitations under the License.
15*7ba4dab5SXin Li */
16*7ba4dab5SXin Li
17*7ba4dab5SXin Li #include <errno.h>
18*7ba4dab5SXin Li #include <fcntl.h>
19*7ba4dab5SXin Li #include <getopt.h>
20*7ba4dab5SXin Li #include <poll.h>
21*7ba4dab5SXin Li #include <string.h>
22*7ba4dab5SXin Li #include <sys/socket.h>
23*7ba4dab5SXin Li #include <sys/stat.h>
24*7ba4dab5SXin Li #include <sys/types.h>
25*7ba4dab5SXin Li #include <unistd.h>
26*7ba4dab5SXin Li
27*7ba4dab5SXin Li #include <memory>
28*7ba4dab5SXin Li
29*7ba4dab5SXin Li #include <android-base/logging.h>
30*7ba4dab5SXin Li #include <cutils/sockets.h>
31*7ba4dab5SXin Li #include <libminijail.h>
32*7ba4dab5SXin Li
33*7ba4dab5SXin Li #include <nvram/core/nvram_manager.h>
34*7ba4dab5SXin Li #include <nvram/messages/nvram_messages.h>
35*7ba4dab5SXin Li
36*7ba4dab5SXin Li // This is defined in fake_nvram_storage.h
37*7ba4dab5SXin Li void InitStorage(int data_dir_fd);
38*7ba4dab5SXin Li
39*7ba4dab5SXin Li namespace {
40*7ba4dab5SXin Li
41*7ba4dab5SXin Li // Minijail parameters.
42*7ba4dab5SXin Li constexpr char kNvramUser[] = "nvram";
43*7ba4dab5SXin Li constexpr char kNvramGroup[] = "nvram";
44*7ba4dab5SXin Li constexpr char kNvramSeccompPolicyPath[] =
45*7ba4dab5SXin Li "/system/usr/share/policy/fake-nvram-seccomp.policy";
46*7ba4dab5SXin Li
47*7ba4dab5SXin Li // Name of the control socket served by this daemon.
48*7ba4dab5SXin Li constexpr char kNvramControlSocketName[] = "nvram";
49*7ba4dab5SXin Li
50*7ba4dab5SXin Li // The default data directory.
51*7ba4dab5SXin Li constexpr char kNvramDataDirectory[] = "/data/misc/fake-nvram/";
52*7ba4dab5SXin Li
53*7ba4dab5SXin Li // Connection backlog on control socket.
54*7ba4dab5SXin Li constexpr int kControlSocketBacklog = 20;
55*7ba4dab5SXin Li
56*7ba4dab5SXin Li // Maximum number of client sockets supported.
57*7ba4dab5SXin Li constexpr int kMaxClientSockets = 32;
58*7ba4dab5SXin Li
59*7ba4dab5SXin Li // Size of the NVRAM message buffer for reading and writing serialized NVRAM
60*7ba4dab5SXin Li // command messages from and to the control socket.
61*7ba4dab5SXin Li constexpr int kNvramMessageBufferSize = 4096;
62*7ba4dab5SXin Li
63*7ba4dab5SXin Li // Variables holding command-line flags.
64*7ba4dab5SXin Li const char* g_data_directory_path = kNvramDataDirectory;
65*7ba4dab5SXin Li const char* g_control_socket_name = kNvramControlSocketName;
66*7ba4dab5SXin Li
67*7ba4dab5SXin Li // Parses the command line. Returns true if successful.
ParseCommandLine(int argc,char ** argv)68*7ba4dab5SXin Li bool ParseCommandLine(int argc, char** argv) {
69*7ba4dab5SXin Li while (true) {
70*7ba4dab5SXin Li static const struct option options[] = {
71*7ba4dab5SXin Li {"data_directory", required_argument, nullptr, 'd'},
72*7ba4dab5SXin Li {"control_socket", required_argument, nullptr, 's'},
73*7ba4dab5SXin Li };
74*7ba4dab5SXin Li
75*7ba4dab5SXin Li int option_index = 0;
76*7ba4dab5SXin Li int c = getopt_long(argc, argv, "", options, &option_index);
77*7ba4dab5SXin Li if (c == -1) {
78*7ba4dab5SXin Li break;
79*7ba4dab5SXin Li }
80*7ba4dab5SXin Li
81*7ba4dab5SXin Li switch (c) {
82*7ba4dab5SXin Li case 'd':
83*7ba4dab5SXin Li g_data_directory_path = optarg;
84*7ba4dab5SXin Li break;
85*7ba4dab5SXin Li case 's':
86*7ba4dab5SXin Li g_control_socket_name = optarg;
87*7ba4dab5SXin Li break;
88*7ba4dab5SXin Li default:
89*7ba4dab5SXin Li return false;
90*7ba4dab5SXin Li }
91*7ba4dab5SXin Li }
92*7ba4dab5SXin Li
93*7ba4dab5SXin Li return true;
94*7ba4dab5SXin Li }
95*7ba4dab5SXin Li
96*7ba4dab5SXin Li // Sets up a restricted environment using minijail and enters it.
InitMinijail()97*7ba4dab5SXin Li bool InitMinijail() {
98*7ba4dab5SXin Li std::unique_ptr<struct minijail, void (*)(struct minijail*)> minijail(
99*7ba4dab5SXin Li minijail_new(), &minijail_destroy);
100*7ba4dab5SXin Li if (minijail_change_user(minijail.get(), kNvramUser) ||
101*7ba4dab5SXin Li minijail_change_group(minijail.get(), kNvramGroup)) {
102*7ba4dab5SXin Li return false;
103*7ba4dab5SXin Li }
104*7ba4dab5SXin Li minijail_use_seccomp_filter(minijail.get());
105*7ba4dab5SXin Li minijail_no_new_privs(minijail.get());
106*7ba4dab5SXin Li minijail_parse_seccomp_filters(minijail.get(), kNvramSeccompPolicyPath);
107*7ba4dab5SXin Li minijail_enter(minijail.get());
108*7ba4dab5SXin Li return true;
109*7ba4dab5SXin Li }
110*7ba4dab5SXin Li
111*7ba4dab5SXin Li // Reads a single command from |socket|, decodes the command, executes it on
112*7ba4dab5SXin Li // |nvram_manager|, encodes the response, and writes the reply back to |socket|.
113*7ba4dab5SXin Li // Returns true on success, false on errors (in which case the caller is
114*7ba4dab5SXin Li // expected the close the |socket|).
ProcessCommand(int socket,nvram::NvramManager * nvram_manager)115*7ba4dab5SXin Li bool ProcessCommand(int socket, nvram::NvramManager* nvram_manager) {
116*7ba4dab5SXin Li uint8_t command_buffer[kNvramMessageBufferSize];
117*7ba4dab5SXin Li ssize_t bytes_read =
118*7ba4dab5SXin Li TEMP_FAILURE_RETRY(read(socket, command_buffer, sizeof(command_buffer)));
119*7ba4dab5SXin Li if (bytes_read == 0) {
120*7ba4dab5SXin Li return false;
121*7ba4dab5SXin Li }
122*7ba4dab5SXin Li
123*7ba4dab5SXin Li if (bytes_read < 0) {
124*7ba4dab5SXin Li PLOG(ERROR) << "Failed to read command from client socket";
125*7ba4dab5SXin Li return false;
126*7ba4dab5SXin Li }
127*7ba4dab5SXin Li
128*7ba4dab5SXin Li nvram::Request request;
129*7ba4dab5SXin Li if (!nvram::Decode(command_buffer, bytes_read, &request)) {
130*7ba4dab5SXin Li LOG(WARNING) << "Failed to decode command request!";
131*7ba4dab5SXin Li return false;
132*7ba4dab5SXin Li }
133*7ba4dab5SXin Li
134*7ba4dab5SXin Li nvram::Response response;
135*7ba4dab5SXin Li nvram_manager->Dispatch(request, &response);
136*7ba4dab5SXin Li size_t response_size = sizeof(command_buffer);
137*7ba4dab5SXin Li if (!nvram::Encode(response, command_buffer, &response_size)) {
138*7ba4dab5SXin Li LOG(WARNING) << "Failed to encode command response!";
139*7ba4dab5SXin Li return false;
140*7ba4dab5SXin Li }
141*7ba4dab5SXin Li
142*7ba4dab5SXin Li if (TEMP_FAILURE_RETRY(write(socket, command_buffer, response_size)) < 0) {
143*7ba4dab5SXin Li PLOG(ERROR) << "Failed to write response to client socket";
144*7ba4dab5SXin Li return false;
145*7ba4dab5SXin Li }
146*7ba4dab5SXin Li
147*7ba4dab5SXin Li return true;
148*7ba4dab5SXin Li }
149*7ba4dab5SXin Li
150*7ba4dab5SXin Li // Listens for incoming connections or data, accepts connections and processes
151*7ba4dab5SXin Li // data as needed.
ProcessMessages(int control_socket_fd,nvram::NvramManager * nvram_manager)152*7ba4dab5SXin Li int ProcessMessages(int control_socket_fd, nvram::NvramManager* nvram_manager) {
153*7ba4dab5SXin Li struct pollfd poll_fds[kMaxClientSockets];
154*7ba4dab5SXin Li memset(poll_fds, 0, sizeof(poll_fds));
155*7ba4dab5SXin Li poll_fds[0].fd = control_socket_fd;
156*7ba4dab5SXin Li poll_fds[0].events = POLLIN;
157*7ba4dab5SXin Li poll_fds[0].revents = 0;
158*7ba4dab5SXin Li nfds_t poll_fds_count = 1;
159*7ba4dab5SXin Li while (TEMP_FAILURE_RETRY(poll(poll_fds, poll_fds_count, -1)) >= 0) {
160*7ba4dab5SXin Li if (poll_fds[0].revents & POLLIN) {
161*7ba4dab5SXin Li // Accept a new connection.
162*7ba4dab5SXin Li int client_socket = accept(control_socket_fd, NULL, 0);
163*7ba4dab5SXin Li if (client_socket < 0) {
164*7ba4dab5SXin Li PLOG(ERROR) << "Error accepting connection";
165*7ba4dab5SXin Li return errno;
166*7ba4dab5SXin Li }
167*7ba4dab5SXin Li
168*7ba4dab5SXin Li // Add |client_socket| to |poll_fds|.
169*7ba4dab5SXin Li if (poll_fds_count < kMaxClientSockets) {
170*7ba4dab5SXin Li poll_fds[poll_fds_count].fd = client_socket;
171*7ba4dab5SXin Li poll_fds[poll_fds_count].events = POLLIN;
172*7ba4dab5SXin Li poll_fds[poll_fds_count].revents = 0;
173*7ba4dab5SXin Li ++poll_fds_count;
174*7ba4dab5SXin Li } else {
175*7ba4dab5SXin Li LOG(WARNING) << "Too many open client sockets, rejecting connection.";
176*7ba4dab5SXin Li // No need to handle EINTR specially here as bionic filters it out.
177*7ba4dab5SXin Li if (close(client_socket)) {
178*7ba4dab5SXin Li PLOG(ERROR) << "Failed to close connection socket after error";
179*7ba4dab5SXin Li }
180*7ba4dab5SXin Li }
181*7ba4dab5SXin Li }
182*7ba4dab5SXin Li
183*7ba4dab5SXin Li // Walk the connection fds backwards. This way, we can remove fds by
184*7ba4dab5SXin Li // replacing the slot with the last array element, which we have processed
185*7ba4dab5SXin Li // already.
186*7ba4dab5SXin Li for (int i = poll_fds_count - 1; i > 0; --i) {
187*7ba4dab5SXin Li if (poll_fds[i].revents & POLLIN) {
188*7ba4dab5SXin Li if (!ProcessCommand(poll_fds[i].fd, nvram_manager)) {
189*7ba4dab5SXin Li // No need to handle EINTR specially here as bionic filters it out.
190*7ba4dab5SXin Li if (close(poll_fds[i].fd)) {
191*7ba4dab5SXin Li PLOG(ERROR) << "Failed to close connection socket after error";
192*7ba4dab5SXin Li }
193*7ba4dab5SXin Li --poll_fds_count;
194*7ba4dab5SXin Li poll_fds[i] = poll_fds[poll_fds_count];
195*7ba4dab5SXin Li }
196*7ba4dab5SXin Li }
197*7ba4dab5SXin Li poll_fds[i].revents = 0;
198*7ba4dab5SXin Li }
199*7ba4dab5SXin Li }
200*7ba4dab5SXin Li
201*7ba4dab5SXin Li // poll error.
202*7ba4dab5SXin Li PLOG(ERROR) << "Failed to poll control socket";
203*7ba4dab5SXin Li return errno;
204*7ba4dab5SXin Li };
205*7ba4dab5SXin Li
206*7ba4dab5SXin Li } // namespace
207*7ba4dab5SXin Li
main(int argc,char ** argv)208*7ba4dab5SXin Li int main(int argc, char** argv) {
209*7ba4dab5SXin Li if (!ParseCommandLine(argc, argv)) {
210*7ba4dab5SXin Li return EINVAL;
211*7ba4dab5SXin Li }
212*7ba4dab5SXin Li
213*7ba4dab5SXin Li int control_socket_fd = android_get_control_socket(g_control_socket_name);
214*7ba4dab5SXin Li if (control_socket_fd < 0) {
215*7ba4dab5SXin Li LOG(ERROR) << "Failed to get control socket.";
216*7ba4dab5SXin Li return EINVAL;
217*7ba4dab5SXin Li }
218*7ba4dab5SXin Li
219*7ba4dab5SXin Li if (listen(control_socket_fd, kControlSocketBacklog)) {
220*7ba4dab5SXin Li PLOG(ERROR) << "Failed to listen on control socket";
221*7ba4dab5SXin Li return errno;
222*7ba4dab5SXin Li }
223*7ba4dab5SXin Li
224*7ba4dab5SXin Li if (!InitMinijail()) {
225*7ba4dab5SXin Li LOG(ERROR) << "Failed to drop privileges.";
226*7ba4dab5SXin Li return -1;
227*7ba4dab5SXin Li }
228*7ba4dab5SXin Li
229*7ba4dab5SXin Li int data_dir_fd =
230*7ba4dab5SXin Li TEMP_FAILURE_RETRY(open(g_data_directory_path, O_RDONLY | O_DIRECTORY));
231*7ba4dab5SXin Li if (data_dir_fd < 0) {
232*7ba4dab5SXin Li PLOG(ERROR) << "Failed to open data directory";
233*7ba4dab5SXin Li return errno;
234*7ba4dab5SXin Li }
235*7ba4dab5SXin Li
236*7ba4dab5SXin Li InitStorage(data_dir_fd);
237*7ba4dab5SXin Li
238*7ba4dab5SXin Li nvram::NvramManager nvram_manager;
239*7ba4dab5SXin Li return ProcessMessages(control_socket_fd, &nvram_manager);
240*7ba4dab5SXin Li }
241