Giter Site home page Giter Site logo

sudo-rs's Introduction

sudo-rs

A safety oriented and memory safe implementation of sudo and su written in Rust.

Status of this project

Sudo-rs is being developed further; features you might expect from original sudo may still be unimplemented or not planned. If there is an important one you need, please request it using the issue tracker. If you encounter any usability bugs, also please report them on the issue tracker. Suspected vulnerabilities can be reported on our security page.

An audit of sudo-rs version 0.2.0 has been performed in August 2023. The findings from that audit are addressed in the current version.

Sudo-rs currently is targeted for Linux-based operating systems only; Linux kernel 5.9 or newer is necessary to run sudo-rs.

Installing sudo-rs

The recommended way to start using sudo-rs is via the package manager of your Linux distribution.

Arch Linux

Arch Linux can be installed via AUR sudo-rs or sudo-rs-git.

Note: AUR usage help

yay -Syu sudo-rs

Debian/Ubuntu

If you are running Debian 13 (trixie) or later, or Ubuntu 24.04 (Noble Numbat) or later, you can use:

sudo apt-get install sudo-rs

This will offer the functionality using the commands su-rs and sudo-rs. If you want to invoke sudo-rs via the usual commands sudo and su instead, prepend /usr/lib/cargo/bin to your current $PATH variable.

Fedora

If you are running Fedora 38 or later, you can use:

sudo dnf install sudo-rs

This will offer the functionality using the commands su-rs and sudo-rs.

Installing our pre-compiled x86-64 binaries

You can also switch to sudo-rs manually by using our pre-compiled tarballs. We currently only offer these for x86-64 systems.

We recommend installing sudo-rs and su-s in your /usr/local hierarchy using the commands:

sudo tar -C /usr/local -xvf sudo-VERSION.tar.gz

and for su-rs:

sudo tar -C /usr/local -xvf su-VERSION.tar.gz

This will install sudo-rs and su-rs in /usr/local/bin using the usual commands sudo and su.

Building from source

Sudo-rs is written in Rust. The minimum required Rust version is 1.70. If your Linux distribution does not package that version (or a later one), you can always install the most recent version through rustup. You also need the C development files for PAM (libpam0g-dev on Debian, pam-devel on Fedora).

On Ubuntu or Debian-based systems, use the following command to install the PAM development library:

sudo apt-get install libpam0g-dev

On Fedora, CentOS and other Red Hat-based systems, you can use the following command:

sudo yum install pam-devel

With dependencies installed, building sudo-rs is a simple matter of:

cargo build --release

This produces a binary target/release/sudo. However, this binary must have the setuid flag set and must be owned by the root user in order to provide any useful functionality. Consult your operating system manual for details.

Sudo-rs needs the sudoers configuration file. The sudoers configuration file will be loaded from /etc/sudoers-rs if that file exists, otherwise the original /etc/sudoers location will be used. You must make sure that a valid sudoers configuration exists at that location. For an explanation of the sudoers syntax you can look at the original sudo man page.

Differences from original sudo

sudo-rs supports less functionality than sudo. Some of this is by design. In most cases you will get a clear error if you try something that is not supported (e.g. use a configuration flag or command line option that is not implemented).

Exceptions to the above, with respect to your /etc/sudoers configuration:

  • use_pty is enabled by default, but can be disabled.
  • env_reset is ignored --- this is always enabled.
  • visiblepw is ignored --- this is always disabled.
  • verifypw is currently ignored; a password is always necessary for sudo -v.
  • mail_badpass, always_set_home, always_query_group_plugin and match_group_by_gid are not applicable to our implementation, but ignored for compatibility reasons.

Some other notable restrictions to be aware of:

  • Some functionality is not yet supported; in particular sudoedit and preventing shell escapes using NOEXEC and NOINTERCEPT.
  • Per-user, per-command, per-host Defaults sudoers entries for finer-grained control are not (yet) supported.
  • Sudo-rs always uses PAM for authentication at this time, your system must be set up for PAM. Sudo-rs will use the sudo service configuration. This also means that resource limits, umasks, etc have to be configured via PAM and not through the sudoers file.
  • sudo-rs will not include the sendmail support of original sudo.
  • The sudoers file must be valid UTF-8.
  • To prevent a common configuration mistake in the sudoers file, wildcards are not supported in argument positions for a command. E.g., %sudoers ALL = /sbin/fsck* will allow sudo fsck and sudo fsck_exfat as expected, but %sudoers ALL = /bin/rm *.txt will not allow an operator to run sudo rm README.txt, nor sudo rm -rf /home .txt, as with original sudo.

If you find a common use case for original sudo missing, please create a feature request for it in our issue tracker.

Aim of the project

Our current target is to build a drop-in replacement for all common use cases of sudo. For the sudoers config syntax this means that we support the default configuration files of common Linux distributions. Our implementation should support all commonly used command line options from the original sudo implementation.

Some parts of the original sudo are explicitly not in scope. Sudo has a large and rich history and some of the features available in the original sudo implementation are largely unused or only available for legacy platforms. In order to determine which features make it we both consider whether the feature is relevant for modern systems, and whether it will receive at very least decent usage. Finally, of course, a feature should not compromise the safety of the whole program.

Our su implementation is made using the building blocks we created for our sudo implementation. It will be suitable replacement for the su distributed by util-linux.

Future work

While our initial target is a drop-in replacement for most basic use cases of sudo, our work may evolve beyond that target. We are also looking into alternative ways to configure sudo without the sudoers config file syntax and to extract parts of our work in usable crates for other people.

Sponsors

The initial development of sudo-rs was started and funded by the Internet Security Research Group as part of the Prossimo project.

An independent security audit of sudo-rs was made possible by the NLNet Foundation.

sudo-rs's People

Contributors

allaboutevemirolive avatar atalii avatar avleen avatar bdaehlie avatar briocheberlin avatar certainlach avatar dd-dreams avatar divagant-martian avatar dlorenc avatar eltociear avatar github-merge-queue[bot] avatar ianchanning avatar jacobkapitein avatar japaric avatar jsoref avatar marlonbaeten avatar oneelectron avatar pohlm01 avatar pvdrz avatar r-vdp avatar rnijveld avatar shellheim avatar squell avatar sweetliquid avatar sylvestre avatar taotieren avatar tortoaster avatar xy2i avatar zhanghandong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sudo-rs's Issues

Be pedantic about disrecommended practices

There are some well-known anti-patterns in sudo, that the man page warns about; for instance using the negation operator with commands in rules like:

user machine = (ALL:ALL) ALL,!/bin/ls

We can detect those after parsing, during the semantical analysis (where also already complain about alias definitions that appear to be cyclical, etc), and emit a diagnostic about them (while still supporting said behaviour)

This has some subtasks:

  • Inventorise all the disrecommended sudoer-practices (either from the manpage or the wider internet)
  • Implement them during the analysis phase

Infrastructure for general logging and handling warning messages

Serious errors will either panic or be passed upwards via Result<>'s, but sometimes a part of the program will just need to warn or nag the user about something. Of course this can be done directly via eprintln! directly, but it's nicer to have some light-weight interface for this, like a warn! macro (that right now can just pass everything right on to eprintln)

Implement `-k` `--reset-timestamp` CLI flag

From sudo man page:

When used without a command, invalidates the user's cached credentials. In other words, the next time sudo is run a password will be required. This option does not require a password, and was added to allow a user to revoke sudo permissions from a .logout file.
When used in conjunction with a command or an option that may require a password, this option will cause sudo to ignore the user's cached credentials. As a result, sudo will prompt for a password (if one is required by the security policy) and will not update the user's cached credentials.

Not all security policies support credential caching.

Integration tests TODO list

Milestone 2

command line flags

sudoers tags

sudoers defaults

sudoers user specification

  • user_list e.g. <user_list> ALL(ALL:ALL) ALL #98
  • restricted runas user: e.g. root ALL=(<specific-user>:ALL) ALL #133
  • restricted runas group: e.g. root ALL=(ALL:<specific-group>) ALL #133
  • restricted command: e.g. root ALL=(ALL:ALL) /usr/bin/ls #144
  • restricted hostname, e.g. ALL remotehost = (ALL:ALL) ALL #145
  • User_Alias e.g. User_Alias ADMINS = root, ferris #178
  • Runas_Alias (see also #13)
  • Host_Alias e.g. Host_Alias SERVERS = main, www, mail #361
  • Cmnd_Alias e.g. Cmnd_Alias CMDSGROUP = /bin/true, /bin/ls #385

password authentication

  • with -S flag #98
  • without -S flag #109

child process

  • stdin, stdout, stderr, exit status redirection #132
  • signal handling #111

third party integration

miscellaneous

su

command line options

inter-operation

misc

Milestone 3

command line options

  • -e, --edit
  • -l, --list #530
  • -R, --chroot=directory
  • -U, --other-user=user
  • "accepts full syntax sudoers, including options that are no-ops" -- possibly in connection to visudo (-c)

visudo

incomplete list:

Code stats

Add a bot/website/something similar by which we can see the dependencies that we used, the number of tests in the compliance suite (and failed tests percentage) and similar metrics, such that we get a better understanding of our progress.

`sudo -u someone-else` preserves original user group

whereas the original sudo does not. test in question:

https://github.com/memorysafety/sudo-rs/blob/47bfda33252da0aaa66806951419ee47617be9ff/test-framework/sudo-compliance-tests/src/lib.rs#L478-L491

sudo -u someone_else id prints

uid=1000(someone_else) gid=1000(someone_else) groups=1000(someone_else)

the same as running id as someone_else

whereas sudo-rs prints

uid=1000(someone_else) gid=1000(someone_else) groups=1000(someone_else),1001(ferris)

Safe PAM binding setup

We'll at the very least need to have support for (interactive) authentication of users as a start

env_reset: sudo-rs sets less env vars than sudo

test in question:

https://github.com/memorysafety/sudo-rs/blob/16b948a6274bde1fe8011d9400f8b81383ba373c/test-framework/sudo-compliance-tests/src/env_reset.rs#L22-L31

the original sudo sets these env vars (in JSON syntax):

{
    "USER": "root",
    "TERM": "unknown",
    "SUDO_COMMAND": "/usr/bin/env",
    "SUDO_GID": "0",
    "SUDO_UID": "0",
    "MAIL": "/var/mail/root",
    "SHELL": "/bin/bash",
    "HOME": "/root",
    "PATH": "/usr/bin:/bin:/usr/sbin:/sbin",
    "SUDO_USER": "root",
    "LOGNAME": "root",
}

sudo-rs only sets:

{
    "SUDO_UID": "0",
    "SHELL": "/bin/bash",
    "SUDO_COMMAND": "/usr/bin/env",
    "SUDO_GID": "0",
    "MAIL": "/var/mail/root",
    "SUDO_USER": "root",
}

Setup of CI pipeline

  • Run unit tests
  • Clippy
  • Unused dependencies
  • Formatting
  • Code coverage
  • Audit
  • Miri for unsafe heavy crates
  • Show core indicators in PR's, like code-coverage, # of dependencies, # of tests (if feasible)

sudoers parser fails when sudoers file does not contain a trailing newline

Steps to reproduce: (note the -n flag passed to echo)

# echo -n 'root    ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers
# sudo true
Parse error: missing line terminator at end of file

the original sudo accepts this sudoers file.

adding a new line to the end of the file works

# echo 'root    ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers
# sudo true
# echo $?
0

Authentication and policy architecture

We'll need to think up of a way to setup the authentication and policy controls before we run the given commands.

Questions:

  • Do we want plugins? What is the interface for those plugins?
  • How to ensure security here? Can we use the typesystem to enforce application flow?

Setup testing framework

We want to have a compliance testing framework that can compare sudo-rs with original sudo.

Specific Defaults parser+checking

Right now the Defaults parser/checker only supports global settings, but the sudoers file supports setting them on a per-host, per-user, per-command basis. This will require some changes.

sudo-test: support password input without the `-S` flag

currently compliance tests that require password authentication use pass the -S flag to sudo so that the password can be piped via stdin.

we also want to support password input without the -S flag to cover more scenarios. this likely needs to be implemented in the sudo-test crate.

Use command contract in `check_permissions`

Use the command struct (or something similar) in the check_permissions of the sudoers crate:

pub struct CommandAndArguments<'a> {
    pub command: PathBuf,
    pub arguments: Vec<&'a str>,
}

Process configuration + options into context

  • We want to support these flags for the sudo cli
    • --user, --group, --login, --set-home, --shell, --help, --version, --chdir, --remove-timestamp, --reset-timestamp
  • NOPASSWD, PASSWD, CHDIR tags
  • Defaults:
    • env_reset (only true), env_keep, lecture_file, env_check, secure_path, visiblepw, always_set_home, match_group_by_gid, use_pty, always_query_group_plugin, insults, mail_bad_pass (low priority)

Parse CLI arguments

  • We would like to be able to parse (all?) the arguments that the original sudo implementation already does.
  • We have to evaluate if clap (or any other crate) is adequate for this or if we should roll our own, we have to consider:
    • Binary size
    • Minimizing the number of dependencies
    • Compilation time
    • Flexibility

Accumulate tag_spec's

Tag_spec's in sudoers accumulate, i.e. "NOPASSWD: /bin/dd, NOEXEC: /bin/ls", then NOPASSWD also applies to /bin/ls (until somewhere "PASSWD") is encountered.

This can't really be fixed in the grammar as the above example shows. so this requires find_item to accumulate a list of tags instead of just returning the last one. Actually changing this in find_item isn't a good idea since that is used to first build a set of matching rules, and then select the last rule, and tags don't accumulate across rules.

Support line continuation

I.e. "" followed by a newline character should merge the two lines for the parser. This is probably best done in concert with #14

Parsing of "Defaults" settings in sudoers

  • Add directives to parser
  • Have a classification of all the settings (and: what their defaults are according to the man page)
  • Add settings the Sudoers type to allow the outside world to access the settings that were parsed
  • Make a prioritization of which Defaults are most commonly used

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.