FAQ
Hello,

Let's say you have something like this in C / C++:

main () {

    // Very beginning of main.
    int sockets[2];
    ... socketpair(... sockets);

    int process = fork();
    if (process != 0) {
      close(sockets[0]);

      chroot(...);
      dropAllRootPrivileges();
      RunWebServerForeverAndRequestActionsViaSocket(sockets[1]);
    } else {
      close(sockets[1]);

      keepSomeOfTheRootPrivileges(); // eg, CAP_SYS_ capabilities or similar.
      waitForRequestsOnSocketAndExecuteThem(sockets[0]);
    }
}

what would be the best implementation in golang?

It's a fairly common pattern to provide privilege separation: a more
privileged but very simple process accepts and executes a very limited
subset of operations based on input from pipe / socket, a much less
privileged and more disposable process implements complex interactions with
the user.

The issues I am running into are:

- fork() seems to be frowned upon. Easiest path seems to have two separate
binaries? and ForkAndExec the second one? any alternative?

I'd like to avoid that if possible as it comes with installation headaches
/ fragility (eg, figure out path of second binary, make sure it is correct
one ...).

- dropping posix capabilities ... although I have seen a few open source
libraries out there for golang.

- ipc via file descriptor - channels are great, but will need some code to
bridge channels and fd? need to look more into this.

Thank you for any suggestion,
Carlo

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Bakul Shah at Dec 14, 2015 at 10:12 pm

    On Mon, 14 Dec 2015 13:11:07 PST Carlo Contavalli wrote:

    Hello,

    Let's say you have something like this in C / C++:

    main () {

    // Very beginning of main.
    int sockets[2];
    ... socketpair(... sockets);

    int process = fork();
    if (process != 0) {
    close(sockets[0]);

    chroot(...);
    dropAllRootPrivileges();
    RunWebServerForeverAndRequestActionsViaSocket(sockets[1]);
    } else {
    close(sockets[1]);

    keepSomeOfTheRootPrivileges(); // eg, CAP_SYS_ capabilities or similar.
    waitForRequestsOnSocketAndExecuteThem(sockets[0]);
    }
    }

    what would be the best implementation in golang?
    May be connect the webserver to the privileged server via
    some sort of rpc or ipc since you can't have privilege
    isolation in the same process?
    It's a fairly common pattern to provide privilege separation: a more
    privileged but very simple process accepts and executes a very limited
    subset of operations based on input from pipe / socket, a much less
    privileged and more disposable process implements complex interactions with
    the user.

    The issues I am running into are:

    - fork() seems to be frowned upon. Easiest path seems to have two separate
    binaries? and ForkAndExec the second one? any alternative?
    I'd like to avoid that if possible as it comes with installation headaches
    / fragility (eg, figure out path of second binary, make sure it is correct
    one ...).
    You can fork-exec the same binary and run with different parameters.
    os.Argv[0] should point to the program file name.
    - dropping posix capabilities ... although I have seen a few open source
    libraries out there for golang.

    - ipc via file descriptor - channels are great, but will need some code to
    bridge channels and fd? need to look more into this.
    Channels are internal only. grpc/protobuf may do what you want
    though not exactly lightweight (may be capnproto is
    lighter weight but I haven't used it).

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Carlo Contavalli at Dec 15, 2015 at 12:59 am

    On Mon, Dec 14, 2015 at 2:12 PM, Bakul Shah wrote:
    On Mon, 14 Dec 2015 13:11:07 PST Carlo Contavalli wrote:

    Hello,

    Let's say you have something like this in C / C++:

    main () {

    // Very beginning of main.
    int sockets[2];
    ... socketpair(... sockets);

    int process = fork();
    if (process != 0) {
    close(sockets[0]);

    chroot(...);
    dropAllRootPrivileges();
    RunWebServerForeverAndRequestActionsViaSocket(sockets[1]);
    } else {
    close(sockets[1]);

    keepSomeOfTheRootPrivileges(); // eg, CAP_SYS_ capabilities or similar.
    waitForRequestsOnSocketAndExecuteThem(sockets[0]);
    }
    }

    what would be the best implementation in golang?
    May be connect the webserver to the privileged server via
    some sort of rpc or ipc since you can't have privilege
    isolation in the same process?
    It's a fairly common pattern to provide privilege separation: a more
    privileged but very simple process accepts and executes a very limited
    subset of operations based on input from pipe / socket, a much less
    privileged and more disposable process implements complex interactions with
    the user.

    The issues I am running into are:

    - fork() seems to be frowned upon. Easiest path seems to have two separate
    binaries? and ForkAndExec the second one? any alternative?
    I'd like to avoid that if possible as it comes with installation headaches
    / fragility (eg, figure out path of second binary, make sure it is correct
    one ...).
    You can fork-exec the same binary and run with different parameters.
    os.Argv[0] should point to the program file name.
    Note that os.Argv[0] is part of what makes this approach fragile: if
    the binary is in $PATH, for example, argv[0] may just be a binary name
    who knows where it comes from. It's easy to search in the $PATH, but
    I'd rather use something akin fork() if it was available.

    Are there projects you can think of in go that do something similar to
    what I need? How did they solve the problem?

    By googling further... seems like I'm yet another victim of
    https://github.com/golang/go/issues/227. Sounds like
    https://github.com/sevlyar/go-daemon may be an approach.

    Thank you all in any case,
    Carlo

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bakul Shah at Dec 15, 2015 at 1:57 am

    On Mon, 14 Dec 2015 16:58:56 PST Carlo Contavalli wrote:

    Note that os.Argv[0] is part of what makes this approach fragile: if
    the binary is in $PATH, for example, argv[0] may just be a binary name
    who knows where it comes from. It's easy to search in the $PATH, but
    I'd rather use something akin fork() if it was available.
    argv[0] contains command name or path, if you specified one in
    the command line. So why not specify a daemon's full path?

    $(which my-daemon) args...

    If you can't trust the shell or the filesystem where the executable
    is fetched from, you may have bigger problems to worry about:-)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • James Bardin at Dec 14, 2015 at 10:36 pm

    On Monday, December 14, 2015 at 4:49:08 PM UTC-5, Carlo Contavalli wrote:

    It's a fairly common pattern to provide privilege separation: a more
    privileged but very simple process accepts and executes a very limited
    subset of operations based on input from pipe / socket, a much less
    privileged and more disposable process implements complex interactions with
    the user.
    Starting as root and dropping privs was never the safest way, but it was
    historically all that was available.

    - fork() seems to be frowned upon. Easiest path seems to have two separate
    binaries? and ForkAndExec the second one? any alternative?
    You can't reliably fork a multithreaded program, and all go programs are
    multithreaded from the start, which is why it's not available.

    I think the best way current is to start as an unprivileged user, and use
    the system tools to add the needed capabilities (setcap).

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Manlio Perillo at Dec 15, 2015 at 4:29 pm
    Il giorno lunedì 14 dicembre 2015 23:36:54 UTC+1, James Bardin ha scritto:

    Starting as root and dropping privs was never the safest way, but it was
    historically all that was available.
    Note, however, that the more modern seccomp linux syscall use a similar
    approach.
    [...]
    Regards Manlio

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Konstantin Khomoutov at Dec 15, 2015 at 5:54 pm

    On Mon, 14 Dec 2015 13:11:07 -0800 Carlo Contavalli wrote: [...]
    what would be the best implementation in golang?

    It's a fairly common pattern to provide privilege separation: a more
    privileged but very simple process accepts and executes a very limited
    subset of operations based on input from pipe / socket, a much less
    privileged and more disposable process implements complex
    interactions with the user.

    The issues I am running into are:

    - fork() seems to be frowned upon. Easiest path seems to have two
    separate binaries? and ForkAndExec the second one? any alternative?

    I'd like to avoid that if possible as it comes with installation
    headaches / fragility (eg, figure out path of second binary, make
    sure it is correct one ...).

    - dropping posix capabilities ... although I have seen a few open
    source libraries out there for golang.

    - ipc via file descriptor - channels are great, but will need some
    code to bridge channels and fd? need to look more into this.
    I like re-executing of "/proc/self/exe" with lowered credentials
    and with a custom option to switch on in a newly executed command.

    Something like [1] (ripped off a real program).

    This example could be made more elaborate. For instance, you can
    attach a (Go) pipe to the stdin of the spawned process and write
    something there expecting it to read this and decode. This can be used
    for passing configuration bits to the copy running with lowered
    privileges, which that would otherwise unable to access (say, a
    configuration file with passwords which is root:root 0600). Or you can
    also attach another pipe to the process's stdout and have a
    bi-directional communication between them using any protocol you like
    (encoding/json, net/textproto, protobuf etc).

    1. http://play.golang.org/p/N7plnGf79z

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Manlio Perillo at Dec 15, 2015 at 6:59 pm
    Il giorno martedì 15 dicembre 2015 18:54:39 UTC+1, Konstantin Khomoutov ha
    scritto:
    [...]
    This example could be made more elaborate. For instance, you can
    attach a (Go) pipe to the stdin of the spawned process and write
    something there expecting it to read this and decode. This can be used
    for passing configuration bits to the copy running with lowered
    privileges, which that would otherwise unable to access (say, a
    configuration file with passwords which is root:root 0600). Or you can
    also attach another pipe to the process's stdout and have a
    bi-directional communication between them using any protocol you like
    (encoding/json, net/textproto, protobuf etc).

    1. http://play.golang.org/p/N7plnGf79z
    Why not using os.IsPerm(err), in line 34?


    Regards Manlio

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Konstantin Khomoutov at Dec 15, 2015 at 7:45 pm

    On Tue, 15 Dec 2015 10:58:55 -0800 (PST) Manlio Perillo wrote:
    This example could be made more elaborate. For instance, you can
    attach a (Go) pipe to the stdin of the spawned process and write
    something there expecting it to read this and decode. This can be
    used for passing configuration bits to the copy running with
    lowered privileges, which that would otherwise unable to access
    (say, a configuration file with passwords which is root:root
    0600). Or you can also attach another pipe to the process's stdout
    and have a bi-directional communication between them using any
    protocol you like (encoding/json, net/textproto, protobuf etc).

    1. http://play.golang.org/p/N7plnGf79z
    Why not using os.IsPerm(err), in line 34?
    I was not aware of its existence (and was using `syscall' anyway).

    Thanks for the heads up!

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedDec 14, '15 at 9:48p
activeDec 15, '15 at 7:45p
posts9
users5
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase