1
//! Code to adjust process-related parameters.
2

            
3
use tracing::error;
4

            
5
use crate::ArtiConfig;
6

            
7
/// Set our current maximum-file limit to a large value, if we can.
8
///
9
/// Since we're going to be used as a proxy, we're likely to need a
10
/// _lot_ of simultaneous sockets.
11
///
12
/// # Limitations
13
///
14
/// This doesn't actually do anything on windows.
15
#[cfg_attr(feature = "experimental-api", visibility::make(pub))]
16
pub(crate) fn use_max_file_limit(config: &ArtiConfig) {
17
    match rlimit::increase_nofile_limit(config.system.max_files) {
18
        Ok(n) => tracing::debug!("Increased process file limit to {}", n),
19
        Err(e) => tor_error::warn_report!(e, "Error while increasing file limit"),
20
    }
21
}
22

            
23
/// Enable process hardening, to make it harder for low-privilege users to
24
/// extract information from Arti.
25
///
26
/// This function only has effect the first time it is called.  If it returns an
27
/// error, the caller should probably exit the process.
28
///
29
/// # Limitations
30
///
31
/// See notes from the [`secmem_proc`] crate: this is a best-effort defense, and
32
/// only makes these attacks _harder_.  It can interfere with debugging.
33
306
#[cfg_attr(feature = "experimental-api", visibility::make(pub))]
34
306
#[cfg(feature = "harden")]
35
306
pub(crate) fn enable_process_hardening() -> anyhow::Result<()> {
36
    use anyhow::Context as _;
37
    use std::sync::atomic::{AtomicBool, Ordering};
38
    /// Have we called this method before?
39
    static ENABLED: AtomicBool = AtomicBool::new(false);
40

            
41
306
    if ENABLED.swap(true, Ordering::SeqCst) {
42
        // Already enabled, or tried to enable.
43
        return Ok(());
44
306
    }
45

            
46
306
    secmem_proc::harden_process().context("Problem while hardening process")?;
47

            
48
306
    Ok(())
49
306
}
50

            
51
/// Check that we are not running as "root".
52
///
53
/// If we are, give an error message, and exit.
54
pub(crate) fn exit_if_root() {
55
    if running_as_root() {
56
        error!(
57
            "You are running Arti as root. You don't need to, and \
58
             you probably shouldn't. \
59
             To run as root anyway, set application.allow_running_as_root."
60
        );
61
        std::process::exit(1);
62
    }
63
}
64

            
65
/// Return true if we seem to be running as root.
66
fn running_as_root() -> bool {
67
    #[cfg(target_family = "unix")]
68
    unsafe {
69
        libc::geteuid() == 0
70
    }
71
    #[cfg(not(target_family = "unix"))]
72
    false
73
}
74

            
75
/// Return an async stream that reports an event whenever we get a `SIGHUP`
76
/// signal.
77
///
78
/// Note that the signal-handling backend can coalesce signals; this is normal.
79
#[cfg(target_family = "unix")]
80
pub(crate) fn sighup_stream() -> crate::Result<impl futures::Stream<Item = ()>> {
81
    cfg_if::cfg_if! {
82
        if #[cfg(feature="tokio")] {
83
            use tokio_crate::signal::unix as s;
84
            let mut signal = s::signal(s::SignalKind::hangup())?;
85
            Ok(futures::stream::poll_fn(move |ctx| signal.poll_recv(ctx)))
86
        } else if #[cfg(feature="async-std")] {
87
            use async_signal::{Signal, Signals};
88
            use futures::stream::StreamExt as _;
89
            let signals = Signals::new(&[Signal::Hup])?;
90
            Ok(signals.map(|_| ()))
91
        } else {
92
            // Not backend, so we won't ever get a SIGHUP.
93
            Ok(futures::stream::pending())
94
        }
95
    }
96
}