// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SANDBOX_LINUX_SERVICES_LIBC_INTERCEPTOR_H_
#define SANDBOX_LINUX_SERVICES_LIBC_INTERCEPTOR_H_

#include <vector>

#include "base/files/scoped_file.h"
#include "base/pickle.h"
#include "build/build_config.h"
#include "sandbox/sandbox_export.h"

namespace sandbox {

// Sandbox interception of libc calls.
//
// When we are running in a namespace sandbox certain libc calls will fail
// (localtime being the motivating example - it needs to read /etc/localtime).
// We need to intercept these calls and proxy them to a parent process.
// However, these calls may come from us or from our third_party libraries, so
// in some cases we can't just change the code.
//
// It's for these cases that we have the following setup:
//
// We define global functions for those functions which we wish to override.
// Since we will be first in the dynamic resolution order, the dynamic linker
// will point callers to our versions of these functions. However, we have the
// same binary for both the browser and the renderers, which means that our
// overrides will apply in the browser too.
//
// Our replacement functions must handle both cases, and either proxy the call
// to the parent over the IPC back-channel (see
// https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md)
// or use dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in
// the current module. Use SetUseLocaltimeOverride() and SetAmZygoteOrRenderer()
// below to control the mode of operation, which defaults using the dlsym
// approach.
//
// Other avenues:
//
// Our first attempt involved some assembly to patch the GOT of the current
// module. This worked, but was platform specific and doesn't catch the case
// where a library makes a call rather than current module.
//
// We also considered patching the function in place, but this would again by
// platform specific and the above technique seems to work well enough.

// Methods supported over the back-channel to the parent.
// This isn't the full list, values < 32 are reserved for methods called from
// Skia, and values >= 64 are reserved for sandbox_ipc_linux.cc.
enum InterceptedIPCMethods {
  METHOD_LOCALTIME = 32,
};

// Currently, only METHOD_LOCALTIME, returns false if |kind| is otherwise.
SANDBOX_EXPORT bool HandleInterceptedCall(
    int kind,
    int fd,
    base::PickleIterator iter,
    const std::vector<base::ScopedFD>& fds);

// On Linux, localtime is overridden to use a synchronous IPC to the browser
// process to determine the locale. This can be disabled, which causes
// localtime to use UTC instead. https://crbug.com/772503.
SANDBOX_EXPORT void SetUseLocaltimeOverride(bool enable);

// Turns on/off the libc interception. Called by the zygote and inherited by it
// children. |backchannel_fd| must be the fd to use for proxying calls.
SANDBOX_EXPORT void SetAmZygoteOrRenderer(bool enable, int backchannel_fd);

}  // namespace sandbox

#endif  // SANDBOX_LINUX_SERVICES_LIBC_INTERCEPTOR_H_
