Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-21778

Disable system commands in mysql/mariadb client

Details

    Description

      There may be circumstances where it makes sense to disable the system command in the mysql client. See https://mariadb.com/kb/en/how-to-disable-system-command-on-mariadb-shell, https://stackoverflow.com/questions/40958372/how-to-make-the-system-command-unavailable-in-mysql and https://bugs.mysql.com/bug.php?id=26941 for a MySQL patch that was never implemented.

      Attachments

        Issue Links

          Activity

            Hi I'm trying for GSOC 2020 . I would like to work on this issue to get familiar with the code base. I would require some guidance as I'm new in this org as well as Jira.

            amanbora Aman Alam Bora added a comment - Hi I'm trying for GSOC 2020 . I would like to work on this issue to get familiar with the code base. I would require some guidance as I'm new in this org as well as Jira.
            ralf.gebhardt Ralf Gebhardt added a comment - - edited

            To make the mariadb command line client "more secure" as requested, we do not only need to disable the system command, we also need to think about disabling for:

            • tee
            • load data local infile
            • source

            Another option would be to add chroot in the client and to be able to define a root directory for the client.

            ralf.gebhardt Ralf Gebhardt added a comment - - edited To make the mariadb command line client "more secure" as requested, we do not only need to disable the system command, we also need to think about disabling for: tee load data local infile source Another option would be to add chroot in the client and to be able to define a root directory for the client.
            ralf.gebhardt Ralf Gebhardt added a comment - - edited

            serg, to follow up on this. Do we really need the system command in the client, I am not sure if it is used that much. Do you have an opinion on that? chroot would of course also be a good option with the directory to be defined in the config file (and a good default).

            ralf.gebhardt Ralf Gebhardt added a comment - - edited serg , to follow up on this. Do we really need the system command in the client, I am not sure if it is used that much. Do you have an opinion on that? chroot would of course also be a good option with the directory to be defined in the config file (and a good default).

            I've used it myself for backups. Like

            mysql <<EEE
            flush tables with read lock;
            \! copy -r /var/lib/mysql /path/to/backup
            EEE
            

            that was, admittedly, long time ago and doesn't work all too well with InnoDB. Still, I suppose people use it.

            serg Sergei Golubchik added a comment - I've used it myself for backups. Like mysql <<EEE flush tables with read lock; \! copy -r /var/lib/mysql /path/to/backup EEE that was, admittedly, long time ago and doesn't work all too well with InnoDB. Still, I suppose people use it.

            System command is also useful while importing InnoDB tables, see http://mysqlentomologist.blogspot.com/2016/11/how-to-recover-corrupted-innodb.html for a typical way to use cp etc from inside mysql session.

            valerii Valerii Kravchuk added a comment - System command is also useful while importing InnoDB tables, see http://mysqlentomologist.blogspot.com/2016/11/how-to-recover-corrupted-innodb.html for a typical way to use cp etc from inside mysql session.
            ralf.gebhardt Ralf Gebhardt added a comment - - edited

            serg, so it looks like using chroot is a good approach here. If you agree, does it need more details before somebody could work on this?

            ralf.gebhardt Ralf Gebhardt added a comment - - edited serg , so it looks like using chroot is a good approach here. If you agree, does it need more details before somebody could work on this?

            anyone, it's a trivial patch. But it'll mean that mariadb client will need to be run as root. Is it acceptable?

            serg Sergei Golubchik added a comment - anyone, it's a trivial patch. But it'll mean that mariadb client will need to be run as root. Is it acceptable?
            laurentb-v Laurent Blume added a comment -

            Hello, I'd just would like to know, what does "need to be run as root" mean here? Enabling the setuid bit?

            My original concern with system stems from this: when using unix_socket to authenticate MariaDB's root (something which is now the default setting in at least Ubuntu), then giving somebody root access to the database also means giving them root access to the system, which is not always desirable.

            Laurent

            laurentb-v Laurent Blume added a comment - Hello, I'd just would like to know, what does "need to be run as root" mean here? Enabling the setuid bit? My original concern with system stems from this: when using unix_socket to authenticate MariaDB's root (something which is now the default setting in at least Ubuntu), then giving somebody root access to the database also means giving them root access to the system, which is not always desirable. Laurent

            I mean that only system root user can do chroot(). So for mariadb command client to do it, it must either be run by root or be setuid root.

            But let's get to your original concern. system command can only run commands as the user who started mariadb command line client. If root has started it, then those commands will be run as root. If non-root starts it, they'll be run as that user.

            When using unix_socket to authenticate MariaDB's root, then only system root will be able to connect as MariaDB root. But you can give anyone access to MariaDB root via a password, without giving system root privileges. Just login as root and issue

            SET PASSWORD = "...whatever...";
            

            and you'll be able to connect with a password if you aren't system root. Connecting as system root will still work without a password (good for scripts and for resetting the password when needed).

            serg Sergei Golubchik added a comment - I mean that only system root user can do chroot() . So for mariadb command client to do it, it must either be run by root or be setuid root. But let's get to your original concern. system command can only run commands as the user who started mariadb command line client. If root has started it, then those commands will be run as root. If non-root starts it, they'll be run as that user. When using unix_socket to authenticate MariaDB's root, then only system root will be able to connect as MariaDB root. But you can give anyone access to MariaDB root via a password, without giving system root privileges. Just login as root and issue SET PASSWORD = "...whatever..." ; and you'll be able to connect with a password if you aren't system root. Connecting as system root will still work without a password (good for scripts and for resetting the password when needed).
            laurentb-v Laurent Blume added a comment -

            That's where I'm coming from
            The idea for me is to get rid of passwords wherever possible for local access. Passwords are a pain, because due to rigorous compliance constraints, they imply a lot of administrative tasks, such as handling their secure storage and periodic rotation. As for scripts, storing an application user password on disk needs a business need and evidence of safety, storing a root password on disk is definitely forbidden.
            It's much easier in my context to allow MariaDB root access via sudo. It's usually not a problem, but there is the possibility that somebody need root access to the DB, but not the system's root.
            Compliance auditors are specifically focusing on applications that allow escaping to a shell, so I'm making sure they're all under control.

            laurentb-v Laurent Blume added a comment - That's where I'm coming from The idea for me is to get rid of passwords wherever possible for local access. Passwords are a pain, because due to rigorous compliance constraints, they imply a lot of administrative tasks, such as handling their secure storage and periodic rotation. As for scripts, storing an application user password on disk needs a business need and evidence of safety, storing a root password on disk is definitely forbidden. It's much easier in my context to allow MariaDB root access via sudo. It's usually not a problem, but there is the possibility that somebody need root access to the DB, but not the system's root. Compliance auditors are specifically focusing on applications that allow escaping to a shell, so I'm making sure they're all under control.

            So, you want to have only system root access to mariadb root, and you configure /etc/sudoers so that other users will be able to run mysql client as root, but not any other commands?

            Yes, in this case chroot approach will work and will do what you need.

            A more database centric approach would be to create a role, say, "admin" and grant it to those users that you want to be root-like. Say,

            CREATE ROLE admin;
            GRANT ALL PRIVILEGES ON *.* TO admin;
            GRANT admin TO tom, dick, harry;
            

            After that, say, Tom will be able to login without a password as tom, and then he'll be able to set the admin role to do root stuff:

            tom ~ $ mysql
            MariaDB> SHOW BINARY LOGS;
            ERROR ... permission denied to user `tom`@`localhost`
            MariaDB> SET ROLE admin;
            MariaDB> SHOW BINARY LOGS
            +--------------------------+
            ...
            

            That is, a user can login without a password as himself — just as you like. And then the user can assume the superuser role if needed, but can also work as non-superuser normally, so it doesn't mean that Tom becomes a superuser. Pretty much like you'd have with sudo and /etc/sudoers approach. But without a dangerous system root access.

            serg Sergei Golubchik added a comment - So, you want to have only system root access to mariadb root, and you configure /etc/sudoers so that other users will be able to run mysql client as root, but not any other commands? Yes, in this case chroot approach will work and will do what you need. A more database centric approach would be to create a role , say, "admin" and grant it to those users that you want to be root-like. Say, CREATE ROLE admin; GRANT ALL PRIVILEGES ON *.* TO admin; GRANT admin TO tom, dick, harry; After that, say, Tom will be able to login without a password as tom, and then he'll be able to set the admin role to do root stuff: tom ~ $ mysql MariaDB> SHOW BINARY LOGS; ERROR ... permission denied to user `tom`@`localhost` MariaDB> SET ROLE admin; MariaDB> SHOW BINARY LOGS +--------------------------+ ... That is, a user can login without a password as himself — just as you like. And then the user can assume the superuser role if needed, but can also work as non-superuser normally, so it doesn't mean that Tom becomes a superuser. Pretty much like you'd have with sudo and /etc/sudoers approach. But without a dangerous system root access.
            danblack Daniel Black added a comment -

            Less invasive than chroot that doesn't require elevated privs, set the process rlimit to 1

            rlimit PROC

            diff --git a/client/mysql.cc b/client/mysql.cc
            index 15325aec69d..c161d8b0f8b 100644
            --- a/client/mysql.cc
            +++ b/client/mysql.cc
            @@ -45,6 +45,7 @@
             #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H)
             #include <locale.h>
             #endif
            +#include <sys/resource.h>
             
             const char *VER= "15.1";
             
            @@ -1121,6 +1122,11 @@ int main(int argc,char *argv[])
               DBUG_ENTER("main");
               DBUG_PROCESS(argv[0]);
               
            +  struct rlimit rlimit;
            +
            +  rlimit.rlim_cur= rlimit.rlim_max= 1;
            +  setrlimit(RLIMIT_NPROC, &rlimit);
            

            effect of client

            MariaDB [(none)]> \! ls
            MariaDB [(none)]> \! ls
            MariaDB [(none)]> \! echo ya
            

            Sure some error handling is needed here.

            strace

            clone3({flags=CLONE_VM|CLONE_VFORK, exit_signal=SIGCHLD, stack=0x7fd064f46000, stack_size=0x9000}, 88) = -1 EAGAIN (Resource temporarily unavailable)
            ...
            

            danblack Daniel Black added a comment - Less invasive than chroot that doesn't require elevated privs, set the process rlimit to 1 rlimit PROC diff --git a/client/mysql.cc b/client/mysql.cc index 15325aec69d..c161d8b0f8b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -45,6 +45,7 @@ #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H) #include <locale.h> #endif +#include <sys/resource.h> const char *VER= "15.1"; @@ -1121,6 +1122,11 @@ int main(int argc,char *argv[]) DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); + struct rlimit rlimit; + + rlimit.rlim_cur= rlimit.rlim_max= 1; + setrlimit(RLIMIT_NPROC, &rlimit); effect of client MariaDB [(none)]> \! ls MariaDB [(none)]> \! ls MariaDB [(none)]> \! echo ya Sure some error handling is needed here. strace clone3({flags=CLONE_VM|CLONE_VFORK, exit_signal=SIGCHLD, stack=0x7fd064f46000, stack_size=0x9000}, 88) = -1 EAGAIN (Resource temporarily unavailable) ...
            danblack Daniel Black added a comment -

            Other non-code solutions:

            • Custom selinux/apparmor profile for the mariadb client
            • run under restricted shell (if the remaining privs are acceptable)
            • firejail
            • run mariadb client in container podman run -v /var/run/mysqld:/run/mysqld --rm mariadb:10.5 mariadb
            danblack Daniel Black added a comment - Other non-code solutions: Custom selinux/apparmor profile for the mariadb client run under restricted shell (if the remaining privs are acceptable) firejail run mariadb client in container podman run -v /var/run/mysqld:/run/mysqld --rm mariadb:10.5 mariadb
            • nice trick with rlimit. Doesn't protect against \T overwriting system files. And against load data local reading them.
            • I don't see how restricted shell can help
            • custom selinux profile might work
            • haven't used firejail or podman, but likely will have the same issue as using chroot for a non-code solution (that is, running chroot /restricted mysql) — it needs a complete execution environment in /restricted with all needed libraries and config files. So, awkward to use.
            serg Sergei Golubchik added a comment - nice trick with rlimit. Doesn't protect against \T overwriting system files. And against load data local reading them. I don't see how restricted shell can help custom selinux profile might work haven't used firejail or podman, but likely will have the same issue as using chroot for a non-code solution (that is, running chroot /restricted mysql ) — it needs a complete execution environment in /restricted with all needed libraries and config files. So, awkward to use.
            serg Sergei Golubchik added a comment - - edited

            Implemented

            • new mariadb client command line option: --sandbox which enables the sandbox mode
            • new mariadb command sandbox (short form \-) which enables the sandbox mode

            Sandbox mode

            In the sandbox mode, all mariadb commands that reach out into the file system are not allowed. These commands are: system (short form \!), tee (\T), pager with an argument(\P foo), source (\.), an attempt to use them causes an error. This error can be ignored with --force.

            Note that commands pager without an argument (\P) and edit (\e) are still allowed. To prevent the break-out from the sandbox they should be configured to use a safe pager (e.g. with PAGER=less LESSSECURE=1) and a safe editor (e.g. with EDITOR=rnano) or disabled whatsoever with PAGES=/bin/false EDITOR=/bin/false.

            There is no command to disable the sandbox mode. If it's enabled in the sql script, it'll be in force until the end of the script, then it'll be automatically disabled.

            serg Sergei Golubchik added a comment - - edited Implemented new mariadb client command line option: --sandbox which enables the sandbox mode new mariadb command sandbox (short form \- ) which enables the sandbox mode Sandbox mode In the sandbox mode , all mariadb commands that reach out into the file system are not allowed. These commands are: system (short form \! ), tee ( \T ), pager with an argument( \P foo ), source ( \. ), an attempt to use them causes an error. This error can be ignored with --force . Note that commands pager without an argument ( \P ) and edit ( \e ) are still allowed . To prevent the break-out from the sandbox they should be configured to use a safe pager (e.g. with PAGER=less LESSSECURE=1 ) and a safe editor (e.g. with EDITOR=rnano ) or disabled whatsoever with PAGES=/bin/false EDITOR=/bin/false . There is no command to disable the sandbox mode. If it's enabled in the sql script, it'll be in force until the end of the script, then it'll be automatically disabled.

            People

              serg Sergei Golubchik
              greenman Ian Gilfillan
              Votes:
              2 Vote for this issue
              Watchers:
              13 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.