Currently, cgexec has suid flag and runs as root because it needs to
communicate with cgrulesengd using /var/run/cgred.socket. This is generally
frowned upon, so let's add few options to cgrulesengd to set the socket
owner to someone else - cgexec does not need to run as powerful root, but
as some new harmless user or group.

Signed-off-by: Jan Safranek <[email protected]>
---

 doc/man/cgrulesengd.8    |    9 ++++++-
 src/daemon/cgrulesengd.c |   59 ++++++++++++++++++++++++++++++++++++++++++++--
 src/tools/cgexec.c       |   11 ++++++++-
 3 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/doc/man/cgrulesengd.8 b/doc/man/cgrulesengd.8
index 2e4f60c..10d1d09 100644
--- a/doc/man/cgrulesengd.8
+++ b/doc/man/cgrulesengd.8
@@ -16,6 +16,9 @@ the appropriate control group.
 The list of rules is read during the daemon startup and are cached in daemon's 
memory.
 The daemon reloads the list of rules when it receives SIGUSR2 signal.
 
+The daemon opens a standard unix socket to receive 'sticky' requests from
+cgexec tool.
+
 .SH OPTIONS
 .TP
 .B -h|--help
@@ -47,7 +50,11 @@ Disable logging.
 .B -d|--debug
 Equivalent to '-nvvf -', i.e. don't fork the daemon, display all log messages 
and
 write them to the standard output.
-
+.TP
+.B -u <user>|--socket-user=<user>
+.B -g <group>|--socket-group=<group>
+Set owner of cgrulesengd socket. It assumes that cgexec tool runs with proper
+suid permissions so it can write to the socket when cgexec --sticky is used.
 .SH FILES
 .LP
 .PD .1v
diff --git a/src/daemon/cgrulesengd.c b/src/daemon/cgrulesengd.c
index dc3febc..69165bf 100644
--- a/src/daemon/cgrulesengd.c
+++ b/src/daemon/cgrulesengd.c
@@ -54,6 +54,8 @@
 #include <linux/connector.h>
 #include <linux/cn_proc.h>
 #include <linux/un.h>
+#include <pwd.h>
+#include <grp.h>
 
 #define NUM_PER_REALLOCATIOM   (100)
 
@@ -66,6 +68,12 @@ int logfacility;
 /* Current log level */
 int loglevel;
 
+/* Owner of the socket, -1 means no change */
+uid_t socket_user = -1;
+
+/* Owner of the socket, -1 means no change */
+gid_t socket_group = -1;
+
 /**
  * Prints the usage information for this program and, optionally, an error
  * message.  This function uses vfprintf.
@@ -94,6 +102,10 @@ static void usage(FILE* fd, const char* msg, ...)
                "    -n           | --nodaemom          don't fork daemon\n"
                "    -d           | --debug             same as -v -v -n -f -\n"
                "    -Q           | --nolog             disable logging\n"
+               "    -u <user>    | --socket-user=<user> set "
+                       CGRULE_CGRED_SOCKET_PATH " socket user\n"
+               "    -g <group>   | --socket-group=<group> set "
+                       CGRULE_CGRED_SOCKET_PATH " socket group\n"
                "    -h           | --help              show this help\n\n"
                );
        va_end(ap);
@@ -650,6 +662,23 @@ static int cgre_create_netlink_socket_process_msg(void)
                cgroup_dbg("listening sk_unix error: %s\n", strerror(errno));
                goto close_and_exit;
        }
+
+       /* change the owner */
+       if (chown(CGRULE_CGRED_SOCKET_PATH, socket_user, socket_group) < 0) {
+               cgroup_dbg("Error changing socket owner: %s\n",
+                               strerror(errno));
+               goto close_and_exit;
+       }
+       cgroup_dbg("Socket %s owner successfully set to %d:%d\n",
+                       CGRULE_CGRED_SOCKET_PATH, (int) socket_user,
+                       (int) socket_group);
+
+       if (chmod(CGRULE_CGRED_SOCKET_PATH, 0660) < 0) {
+               cgroup_dbg("Error changing socket owner: %s\n",
+                               strerror(errno));
+               goto close_and_exit;
+       }
+
        FD_ZERO(&readfds);
        FD_SET(sk_nl, &readfds);
        FD_SET(sk_unix, &readfds);
@@ -927,8 +956,11 @@ int main(int argc, char *argv[])
        /* Return codes */
        int ret = 0;
 
+       struct passwd *pw;
+       struct group *gr;
+
        /* Command line arguments */
-       const char *short_options = "hvqf:s::ndQ";
+       const char *short_options = "hvqf:s::ndQu:g:";
        struct option long_options[] = {
                {"help", no_argument, NULL, 'h'},
                {"verbose", no_argument, NULL, 'v'},
@@ -938,6 +970,8 @@ int main(int argc, char *argv[])
                {"nodaemon", no_argument, NULL, 'n'},
                {"debug", no_argument, NULL, 'd'},
                {"nolog", no_argument, NULL, 'Q'},
+               {"socket-user", required_argument, NULL, 'u'},
+               {"socket-group", required_argument, NULL, 'g'},
                {NULL, 0, NULL, 0}
        };
 
@@ -1003,7 +1037,28 @@ int main(int argc, char *argv[])
                        verbosity = 4;
                        logp = "-";
                        break;
-
+               case 'u': /* --socket-user */
+                       pw = getpwnam(optarg);
+                       if (pw == NULL) {
+                               usage(stderr, "Cannot find user %s", optarg);
+                               ret = 3;
+                               goto finished;
+                       }
+                       socket_user = pw->pw_uid;
+                       cgroup_dbg("Using socket user %s id %d\n",
+                                       optarg, (int)socket_user);
+                       break;
+               case 'g': /* --socket-group */
+                       gr = getgrnam(optarg);
+                       if (gr == NULL) {
+                               usage(stderr, "Cannot find group %s", optarg);
+                               ret = 3;
+                               goto finished;
+                       }
+                       socket_group = gr->gr_gid;
+                       cgroup_dbg("Using socket group %s id %d\n",
+                                       optarg, (int)socket_group);
+                       break;
                default:
                        usage(stderr, "");
                        ret = 2;
diff --git a/src/tools/cgexec.c b/src/tools/cgexec.c
index 07af199..7552fd9 100644
--- a/src/tools/cgexec.c
+++ b/src/tools/cgexec.c
@@ -92,6 +92,11 @@ int main(int argc, char *argv[])
                return ret;
        }
 
+       /* Just for debugging purposes. */
+       uid = geteuid();
+       gid = getegid();
+       cgroup_dbg("My euid and eguid is: %d,%d\n", (int) uid, (int) gid);
+
        uid = getuid();
        gid = getgid();
        pid = getpid();
@@ -105,13 +110,17 @@ int main(int argc, char *argv[])
        /*
         * 'cgexec' command file needs the root privilege for executing
         * a cgroup_register_unchanged_process() by using unix domain
-        * socket, and an euid should be changed to the executing user
+        * socket, and an euid/egid should be changed to the executing user
         * from a root user.
         */
        if (seteuid(uid)) {
                fprintf(stderr, "%s", strerror(errno));
                return -1;
        }
+       if (setegid(gid)) {
+               fprintf(stderr, "%s", strerror(errno));
+               return -1;
+       }
        if (cg_specified) {
                /*
                 * User has specified the list of control group and


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev
_______________________________________________
Libcg-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to