rpms/vixie-cron/devel vixie-cron-4.1-_60-SELinux-contains-range.patch, NONE, 1.1

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Sat Dec 30 14:33:25 UTC 2006


Author: dwalsh

Update of /cvs/dist/rpms/vixie-cron/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv6701

Added Files:
	vixie-cron-4.1-_60-SELinux-contains-range.patch 
Log Message:
* Thu Dec 14 2006 Dan Walsh <dwalsh at redhat.com> - 4:4.1-68
- Patch to run vixie-cron with mls correctly


vixie-cron-4.1-_60-SELinux-contains-range.patch:
 crontab.c    |   22 ++++-
 do_command.c |    1 
 funcs.h      |    4 
 security.c   |  255 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 250 insertions(+), 32 deletions(-)

--- NEW FILE vixie-cron-4.1-_60-SELinux-contains-range.patch ---
--- vixie-cron-4.1/do_command.c.selinux-contains-range	2006-12-30 09:20:53.000000000 -0500
+++ vixie-cron-4.1/do_command.c	2006-12-30 09:20:53.000000000 -0500
@@ -238,6 +238,7 @@
 		}
 		break;
 	default:
+		cron_restore_default_security_context();
 		/* parent process */
 		break;
 	}
--- vixie-cron-4.1/security.c.selinux-contains-range	2006-12-30 09:20:53.000000000 -0500
+++ vixie-cron-4.1/security.c	2006-12-30 09:22:54.000000000 -0500
@@ -23,6 +23,7 @@
 
 #ifdef WITH_SELINUX
 #include <selinux/selinux.h>
+#include <selinux/context.h>
 #include <selinux/flask.h>
 #include <selinux/av_permissions.h>
 #include <selinux/get_context_list.h>
@@ -30,6 +31,15 @@
 
 static char ** build_env(char **cronenv);
 
+#ifdef WITH_SELINUX
+static int cron_change_selinux_range( user *u,
+                                      security_context_t ucontext );
+static int cron_get_job_range( user *u, security_context_t *ucontextp, char **jobenv );
+#endif
+
+int cron_restore_default_security_context() {
+	setexeccon(NULL);
+}
 int cron_set_job_security_context( entry *e, user *u, char ***jobenv )
 {
     time_t minutely_time = 0;
@@ -58,9 +68,9 @@
      * we'll not be permitted to read the cron spool directory :-)
      */
 
-    security_context_t scontext=0, file_context=0; 
+    security_context_t ucontext=0; 
 
-    if ( cron_get_job_context(u, &scontext, &file_context, *jobenv) < OK )
+    if ( cron_get_job_range(u, &ucontext, *jobenv) < OK )
     {
 	syslog(LOG_ERR, "CRON (%s) ERROR: failed to get selinux context: %s", 
 	       e->pwd->pw_name, strerror(errno)
@@ -68,38 +78,37 @@
 	return -1;
     }
 
+    if (cron_change_selinux_range(u, ucontext) != 0)
+    {
+        syslog(LOG_INFO,"CRON (%s) ERROR: failed to change SELinux context", 
+	       e->pwd->pw_name);
+	if ( ucontext )
+		freecon(ucontext);
+	return -1;
+    }
+    if ( ucontext )
+	freecon(ucontext);
 #endif
 
-    if ( cron_change_user( e->pwd ) != 0 )
+    if ( cron_start_security_session( e->pwd ) != 0 )
     {
 	syslog(LOG_INFO, "CRON (%s) ERROR: failed to open PAM security session: %s", 
 	       e->pwd->pw_name, strerror(errno)
 	      );
 	return -1;
-    }	
+    }
 
-#if WITH_SELINUX
-    if ( cron_change_selinux_context( u, scontext, file_context ) != 0 )
+    if ( cron_change_user( e->pwd, env_get("HOME", *jobenv)) != 0 )
     {
-        syslog(LOG_INFO,"CRON (%s) ERROR: failed to change SELinux context", 
-	       e->pwd->pw_name);
-	if ( file_context )
-		freecon(file_context);
+	syslog(LOG_INFO, "CRON (%s) ERROR: failed to open PAM security session: %s", 
+	       e->pwd->pw_name, strerror(errno)
+	      );
 	return -1;
-    }
-    if ( file_context )
-	freecon(file_context);
-#endif
+    }	
 
     log_close();
     openlog(ProgramName, LOG_PID, LOG_CRON);
 
-    if ( chdir(env_get("HOME", *jobenv)) == -1 )
-    {
-	log_it("CRON", getpid(), "chdir(HOME) failed:", strerror(errno));
-	return -1;
-    }
-
     time_t job_run_time = time(0L);
 
     if( (minutely_time > 0)
@@ -145,10 +154,20 @@
     PAM_FAIL_CHECK;
     retcode = pam_acct_mgmt(pamh, PAM_SILENT);
     PAM_FAIL_CHECK;
-    retcode = pam_open_session(pamh, PAM_SILENT);
-    PAM_FAIL_CHECK;
+#endif
+
+    return retcode;
+}
+
+int cron_start_security_session( struct passwd *pw )
+{
+    int	retcode = 0;
+
+#if defined(WITH_PAM)
     retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
     PAM_FAIL_CHECK;
+    retcode = pam_open_session(pamh, PAM_SILENT);
+    PAM_FAIL_CHECK;
     log_close(); /* PAM has now re-opened our log to auth.info ! */
     openlog(ProgramName, LOG_PID, LOG_CRON);
 #endif
@@ -165,7 +184,7 @@
 #endif
 }
 
-int cron_change_user( struct passwd *pw )
+int cron_change_user( struct passwd *pw, char *homedir )
 {    	
     /* set our directory, uid and gid.  Set gid first, since once
      * we set uid, we've lost root privledges.
@@ -176,6 +195,13 @@
 	return -1;
     }
 
+    if ( chdir(homedir) == -1 )
+    {
+	log_it("CRON", getpid(), "chdir(HOME) failed:", strerror(errno));
+	log_it("CRON", getpid(), homedir, strerror(errno));
+	return -1;
+    }
+
     if ( initgroups( pw->pw_name, pw->pw_gid ) != 0 )
     {
 	log_it("CRON", getpid(), "initgroups failed:", strerror(errno));
@@ -201,6 +227,7 @@
 #ifdef WITH_SELINUX
 	struct av_decision avd;
 	int retval;
+        unsigned int bit = FILE__ENTRYPOINT;
 	/*
 	 * Since crontab files are not directly executed,
 	 * crond must ensure that the crontab file has
@@ -208,13 +235,35 @@
 	 * the user cron job.  It performs an entrypoint
 	 * permission check for this purpose.
 	 */
-	retval = security_compute_av(scontext,
-				     file_context,
-				     SECCLASS_FILE,
-				     FILE__ENTRYPOINT,
-				     &avd);
+	retval = security_compute_av(scontext, file_context,
+				     SECCLASS_FILE, bit, &avd);
+
+	if (retval || ((bit & avd.allowed) != bit))
+		return 0;
+#endif
+	return 1;
+}
+
+static int 
+cron_authorize_range
+( 
+	security_context_t scontext,
+	security_context_t ucontext
+)	
+{
+#ifdef WITH_SELINUX
+	struct av_decision avd;
+	int retval;
+        unsigned int bit = CONTEXT__CONTAINS;
+	/*
+	 * Since crontab files are not directly executed,
+	 * so crond must ensure that any user specified range
+	 * falls within the seusers-specified range for that Linux user.
+	 */
+	retval = security_compute_av(scontext, ucontext,
+				     SECCLASS_CONTEXT, bit, &avd);
 
-	if (retval || ((FILE__ENTRYPOINT & avd.allowed) != FILE__ENTRYPOINT))
+	if (retval || ((bit & avd.allowed) != bit))
 		return 0;
 #endif
 	return 1;
@@ -265,6 +314,75 @@
 	return 0;
 }
 
+#if WITH_SELINUX
+/* always uses u->scontext as the default process context, then changes the
+   level, and retuns it in ucontextp (or NULL otherwise) */
+static int cron_get_job_range( user *u, security_context_t *ucontextp,
+                               char **jobenv )
+{
+	char *range;
+
+	if ( is_selinux_enabled() <= 0 )
+		return 0;
+	if ( ucontextp == 0L )
+		return -1;
+
+	*ucontextp = 0L;
+
+	if ( (range = env_get("MLS_LEVEL",jobenv)) != 0L )
+	{
+                context_t ccon;
+
+                if (!(ccon = context_new(u->scontext)))
+                {
+			log_it(u->name, 
+                               getpid(), "context_new FAILED for MLS_LEVEL", 
+                               range);
+                        return -1;
+                }                  
+
+                if (context_range_set(ccon, range))
+                {
+                        log_it(u->name, 
+                               getpid(), "context_range_set FAILED for MLS_LEVEL", 
+                               range);
+                        return -1;
+                }
+
+                if (!(*ucontextp = context_str(ccon)))
+                {
+                        log_it(u->name, 
+                               getpid(), "context_str FAILED for MLS_LEVEL", 
+                               range);
+                        return -1;
+                }
+
+                if (!(*ucontextp = strdup(*ucontextp)))
+                {
+                        log_it(u->name, 
+                               getpid(), "strdup FAILED for MLS_LEVEL", 
+                               range);
+                        return -1;
+                }
+
+                context_free(ccon);
+	}
+        else if (!u->scontext)
+        { /* cron_change_selinux_range() deals with this */
+                return 0;
+        }
+        else if (!(*ucontextp = strdup(u->scontext)))
+        {
+                log_it(u->name, 
+                       getpid(), "strdup FAILED for MLS_LEVEL", 
+                       range);
+                return -1;
+        }
+
+	return 0;
+}
+#endif
+
 int cron_change_selinux_context( user *u, void *scontext, void *file_context )
 {
 #ifdef WITH_SELINUX
@@ -332,6 +450,84 @@
 	return 0;
 }
 
+#ifdef WITH_SELINUX
+static int cron_change_selinux_range( user *u,
+                                      security_context_t ucontext )
+{
+	if ( is_selinux_enabled() <= 0 )
+		return 0;
+
+	if ( u->scontext == 0L )
+	{
+		if (security_getenforce() > 0) 
+		{
+			log_it( u->name, getpid(), 
+				"NULL security context for user", 
+				""
+			      );
+			return -1;
+		}else
+		{
+			log_it( u->name, getpid(), 
+				"NULL security context for user, "
+				"but SELinux in permissive mode, continuing",
+				""
+				);
+			return 0;
+		}
+	}
+
+	if ( strcmp(u->scontext, ucontext) )
+	{		
+                if ( ! cron_authorize_range( u->scontext, ucontext ))
+		{
+			if ( security_getenforce() > 0 ) 
+			{
+				syslog(LOG_ERR,
+				       "CRON (%s) ERROR:"
+				       "Unauthorized range %s in MLS_LEVEL for user %s ", 
+				       u->name, (char*)ucontext, u->scontext
+				      );
+				return -1;
+			} else
+			{
+				syslog(LOG_INFO,
+				       "CRON (%s) WARNING:"
+				       "Unauthorized range %s in MLS_LEVEL for user %s,"
+				       " but SELinux in permissive mode, continuing", 
+				       u->name, (char*)ucontext, u->scontext
+				      );
+			}
+		}
+	} 
+
+	if ( setexeccon(ucontext) < 0 ) 
+	{
+		if (security_getenforce() > 0) 
+		{
+			syslog(LOG_ERR,
+			       "CRON (%s) ERROR:"
+			       "Could not set exec context to %s for user", 
+			       u->name, (char*)ucontext
+			      );
+
+			return -1;
+		} else
+		{
+			syslog(LOG_ERR,
+			       "CRON (%s) ERROR:"
+			       "Could not set exec context to %s for user, "
+                               " but SELinux in permissive mode, continuing", 
+			       u->name, (char*)ucontext
+			      );
+
+			return 0;
+		}
+	}
+	return 0;
+}
+#endif
+
 int get_security_context( const char *name, 
 			  int crontab_fd, 
 			  security_context_t *rcontext, 
@@ -449,3 +645,4 @@
     return env_copy(cronenv);
 #endif
 }
+
--- vixie-cron-4.1/crontab.c.selinux-contains-range	2006-12-30 09:20:53.000000000 -0500
+++ vixie-cron-4.1/crontab.c	2006-12-30 09:20:53.000000000 -0500
@@ -33,6 +33,7 @@
 #include "cron.h"
 #ifdef WITH_SELINUX
 #include <selinux/selinux.h>
+#include <selinux/context.h>
 #include <selinux/av_permissions.h>
 #endif
 
@@ -415,8 +416,25 @@
 #ifdef WITH_SELINUX
 	if ( selinux_context )
 	{
-		fprintf(NewCrontab,"SELINUX_ROLE_TYPE=%s\n", selinux_context);
-		selinux_context = 0;
+                context_t ccon = NULL;
+                char *level = NULL;
+
+                if (!(ccon = context_new(selinux_context)))
+                {
+                        fprintf(stderr, "context_new failed\n");
+                        goto fatal;
+                }
+                
+                if (!(level = context_range_get(ccon)))
+                {
+                        fprintf(stderr, "context_range failed\n");
+                        goto fatal;
+                }
+                
+		fprintf(NewCrontab,"MLS_LEVEL=%s\n", level);
+                context_free(ccon);
+		freecon(selinux_context);
+                selinux_context = NULL;
 	}
 #endif
 
--- vixie-cron-4.1/funcs.h.selinux-contains-range	2006-12-30 09:20:53.000000000 -0500
+++ vixie-cron-4.1/funcs.h	2006-12-30 09:20:53.000000000 -0500
@@ -80,13 +80,15 @@
 
 /* Red Hat security stuff (security.c): 
  */
+int cron_restore_default_security_context( void );
+
 int cron_set_job_security_context( entry *e, user *u, char ***jobenvp );
 
 int cron_open_security_session( struct passwd *pw );
 
 void cron_close_security_session( void );
 
-int cron_change_user( struct passwd *pw );
+int cron_change_user( struct passwd *pw, char *homedir );
 
 int cron_get_job_context( user *u, void *scontextp, void *file_contextp, char **envp );
 




More information about the fedora-cvs-commits mailing list