Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to permit running as non-root #1018

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

monoidk
Copy link

@monoidk monoidk commented Sep 22, 2022

On a configured system, running as a non-privileged user is possible.

Keep bailing out when running as non-root for those who have not configured their systems, so they don't report #362,
but add an option to permit non-privileged use for those who have configured their systems.

In particular, one would need permission to run pppd (or equivalent), which is suid root on typical systems,
then setup pppd such that it handles ip, route, dns configuration. No need to split openfortivpn as proposed in #373, #650,
at least not for the functionality I have tested.

cat > /etc/ppp/peers/myconnection << 'EOF'
38400
:192.0.2.1
noipdefault
noaccomp
noauth
default-asyncmap
nopcomp
receive-all
nodefaultroute
nodetach
lcp-max-configure 40
mru 1354
ipparam myconnection
EOF

cat > /etc/ppp/ip-up.local << 'EOF'
case "$PPP_IPPARAM" in
    myconnection)
        # setup networking, dns, etc - run via ppp as root
        ip route add 1.2.3.4/24 dev "$PPP_IFACE"
        ;;
esac 2>&1 | logger -p daemon.debug -i -t "$0"
true
EOF
chmod a+x /etc/ppp/ip-up.local

for f in ip-down ipv6-down ipv6-up; do
    script="/etc/ppp/${f}.local"
    echo '#!/bin/sh' > "$script"
    chmod a+x "$script"
done

Then one could start the tunnel, unprivileged with a config like

cat > ~/zssk.conf << 'EOFCONF'
host = 1.2.3.4
port = 443
username = myuser
password = mypass
trusted-cert = 1234567890123456789345678456789034567890456789034567891234567890
set-routes = 0
set-dns = 0
pppd-call = myconnection
allow-nonroot = 1
EOFCONF

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 15, 2022

We can get rid of pppd (see #1048), but for now pppd must be started by root because option noauth is privileged (see #650).

If we get rid of pppd; setting routes and DNS parameters will require root privileges.

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

While I understand your plan of removing use of pppd and relying on internal encapsulation/decapsulation (seems required for DTLS), I would like to note for anyone interested, that the patch:

  • enables running openfortivpn as an unprivileged non-root user (Revisit running openfortivpn as root? #650), albeit for a narrow use case
  • enables one to configure the system such that only root code that runs is a system supported component with vendor updates and a long track record (pppd) instead of an entirety of an evolving code base of openfortivpn

Though it has drawbacks of

  • requires pppd, so no DTLS
  • pppd itself must be suitably configured by an administrator and invoking user does require privilege to invoke pppd (e.g. belong to dip group).
  • openfortivpn is likely to evolve away from support for this configuration (when it starts using internal ppp)

As such, it may be more suitable for some users, particularly system administrators who would not shy away from configuring pppd.

Rationale: Openfortivpn is implemented in a way that one could expect vulnerabilities to be present (memory-unsafe language, no privilege separation (I think?), evolving code base, no security audits (I think)), whereas pppd is at least stable and has had lots of time and eyes on it.

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 19, 2022

What about noauth?

By the way, pppd is also written in C, like openfortivpn. The openfortivpn code base is stable too. Not sure a different class of security audits has been applied to pppd. But you're right, pppd has had more time and eyes on it.

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

I'm not really sure what you mean by noauth, but I'm using the code as specified in the merge request, with pppd running as root and openfortivpn as a separate unprivileged user (unprivileged except permission to run pppd).

I see noauth specified in configuration - I believe pppd does not handle authentication, hence why I may have specified it - it has been a long time since I have configured openfortivpn and pppd.

I understand pppd is written in C, and sadly it has had a few vulnerabilities that have been discovered, but realistically - yes - it seems more widespread, has had a test of time and has automatic updates from the linux distro. It is also a form of privilege separation, as we are only using a part of pppd and it is not even exposed to the internet, only to the authenticated server (though I do not have implicit trust for the server).

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 19, 2022

openfortivpn is not directly exposed to internet either, is it?

Not sure what you mean "automatic updates from the linux distro". Most distributions have openfortivpn packages too.

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 19, 2022

For noauth, see:

"noauth",

Which distribution have you tested? At least on Ubuntu 16.04, 18.04 and 20.04, I seem to recall pppd needs to be started by root because of this - despite the SUID bit being set:

$ ls -l /usr/sbin/pppd
-rwsr-xr-- 1 root dip 378600 juil. 23  2020 /usr/sbin/pppd
$ 

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

Well.. it connects to a server over the internet, that it subsequently authenticates, so .. at least the TLS stack is exposed, not sure how much else runs before server authentication.

I believe I've tested both current debian and some version of ubuntu (maybe 18.04 or 16.04). The user is in dip group, though theoretically one could also change the group so the user only has privileges to pppd iself. Either way - much less exposure than root.

Checking the man page:

call name
              Read additional options from the file /etc/ppp/peers/name.  This file may contain privileged options, such as noauth, even if pppd is not being run by root.

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 19, 2022

Have you added anything under /etc/ppp/peers in your tests? If so, I would recommend documenting it – and removing the noauth option from the list when allow_nonroot is set.

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

Yes - it requires using --pppd-call=<name> and configuring the connection under /etc/ppp/peers/<name>, which in turn requires root, but only for configuration.

I have not added it to the documentation, though it's listed at the top comment of the merge request (/etc/ppp/peers/myconnection example).

@DimitriPapadopoulos
Copy link
Collaborator

I am asking because I had added myself to dip, but pppd would nevertheless refuse to be started because of noauth. I must have missed something. See #650:

$ pppd noauth
pppd: using the noauth option requires root privilege
$

So, what you are saying is that after adding noauth in /etc/ppp/peers/myconnection for example, it works?

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

Yes, noauth is specified in /etc/ppp/peers/myconnection, but not in the command line when using --pppd-call, and that is permitted by pppd, at least on my system.

@DimitriPapadopoulos
Copy link
Collaborator

DimitriPapadopoulos commented Dec 19, 2022

I get it now.

I feel Requires system/ppp configuration. is not sufficient. At least more information should be added to the man page – which should be updated any way. Cross-reference --pppd-call and --allow-nonroot in the man page?

Better yet, we could even allow openfortivpn to run as non-root any way if --pppd-call is used, in which case --allow-nonroot can be discarded. Your opinion?

@monoidk
Copy link
Author

monoidk commented Dec 19, 2022

I agree it requires better documentation :)

I guess non-root is only useful for --pppd-call, so yes, the switch would be redundant, though then the you're-not-root error message should probably mention --pppd-call, and documentation for --pppd-call should mention it allows use as non-root. Perhaps with a separate section for a sample configuration?

Sorry, I've got to go now. I will check back tomorrow.

On a configured system, running as a non-privileged user is possible.

Keep bailing out when running as non-root for those who have not
configured their systems, but add an option to permit it for those who
have configured their systems.

In particular, one would need permission to run pppd (or equivalent),
and setup ppp such that it handles ip, route, dns configuration.

cat > /etc/ppp/peers/myconnection << 'EOF'
38400
:192.0.2.1
noipdefault
noaccomp
noauth
default-asyncmap
nopcomp
receive-all
nodefaultroute
nodetach
lcp-max-configure 40
mru 1354
ipparam myconnection
EOF

cat > /etc/ppp/ip-up.local << 'EOF'
case "$PPP_IPPARAM" in
    myconnection)
        # setup networking, dns, etc - run via ppp as root
        ip route add 1.2.3.4/24 dev "$PPP_IFACE"
        ;;
esac 2>&1 | logger -p daemon.debug -i -t "$0"
true
EOF
chmod a+x /etc/ppp/ip-up.local

for f in ip-down ipv6-down ipv6-up; do
    script="/etc/ppp/${f}.local"
    echo '#!/bin/sh' > "$script"
    chmod a+x "$script"
done

Then one could start the tunnel, unprivileged with a config like
cat > ~/zssk.conf << 'EOFCONF'
host = 1.2.3.4
port = 443
username = myuser
password = mypass
trusted-cert = 1234567890123456789345678456789034567890456789034567891234567890
set-routes = 0
set-dns = 0
pppd-call = myconnection
allow-nonroot = 1
EOFCONF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants