platform_system_core/init/snapuserd_transition.h
David Anderson 0e5ad5a093 snapuserd: Allow connecting to the first-stage daemon.
Currently there is no socket for daemon instances launched during the
selinux phase of init. We don't create any sockets due to the complexity
of the required sepolicy.

This workaround will allow us to create the socket with very minimal
sepolicy changes. init will launch a one-off instance of snapuserd in
"proxy" mode, and then the following steps will occur:

1. The proxy daemon will be given two sockets, the "normal" socket that
snapuserd clients would connect to, and a "proxy" socket.
2. The proxy daemon will listen on the proxy socket.
3. The first-stage daemon will wake up and connect to the proxy daemon
as a client.
4. The proxy will send the normal socket via SCM_RIGHTS, then exit.
5. The first-stage daemon can now listen and accept on the normal
socket.

Ordering of these events is achieved through a snapuserd.proxy_ready
property.

Some special-casing was needed in init to make this work. The snapuserd
socket owned by snapuserd_proxy is placed into a "persist" mode so it
doesn't get deleted when snapuserd_proxy exits. There's also a special
case method to create a Service object around a previously existing pid.

Finally, first-stage init is technically on a different updateable
partition than snapuserd. Thus, we add a way to query snapuserd to see
if it supports socket handoff. If it does, we communicate this
information through an environment variable to second-stage init.

Bug: 193833730
Test: manual test
Change-Id: I1950b31028980f0138bc03578cd455eb60ea4a58
2021-07-27 19:35:29 -07:00

90 lines
2.8 KiB
C++

/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <sys/types.h>
#include <optional>
#include <string>
#include <vector>
#include <libsnapshot/snapshot.h>
#include "block_dev_initializer.h"
namespace android {
namespace init {
// Fork and exec a new copy of snapuserd.
void LaunchFirstStageSnapuserd();
class SnapuserdSelinuxHelper final {
using SnapshotManager = android::snapshot::SnapshotManager;
public:
SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid);
void StartTransition();
void FinishTransition();
// Return a helper for facilitating the selinux transition of snapuserd.
// If snapuserd is not in use, null is returned. StartTransition() should
// be called after reading policy. FinishTransition() should be called
// after loading policy. In between, no reads of /system or other dynamic
// partitions are possible.
static std::unique_ptr<SnapuserdSelinuxHelper> CreateIfNeeded();
private:
void RelaunchFirstStageSnapuserd();
void ExecSnapuserd();
std::unique_ptr<SnapshotManager> sm_;
BlockDevInitializer block_dev_init_;
pid_t old_pid_;
std::vector<std::string> argv_;
};
// Remove /dev/socket/snapuserd. This ensures that (1) the existing snapuserd
// will receive no new requests, and (2) the next copy we transition to can
// own the socket.
void CleanupSnapuserdSocket();
// Kill an instance of snapuserd given a pid.
void KillFirstStageSnapuserd(pid_t pid);
// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
// used to later execveat() snapuserd.
void SaveRamdiskPathToSnapuserd();
// Returns true if first-stage snapuserd is running.
bool IsFirstStageSnapuserdRunning();
// Return the pid of the first-stage instances of snapuserd, if it was started.
std::optional<pid_t> GetSnapuserdFirstStagePid();
// Return snapuserd info strings that were set during first-stage init.
std::vector<std::string> GetSnapuserdFirstStageInfo();
// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
// used to later execveat() snapuserd.
void SaveRamdiskPathToSnapuserd();
// Returns true if first-stage snapuserd is running.
bool IsFirstStageSnapuserdRunning();
} // namespace init
} // namespace android