From 546fdd9f47ae3ee05f2ae27a1bbca6a61fde9380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Mr=C3=A1z?= Date: Thu, 1 Mar 2007 08:28:22 +0000 Subject: [PATCH] - reject connection if requested mls range is not obtained (#229278) --- openssh-4.5p1-mls.patch | 240 ++++++++++++++++++++++++++++++++-------- openssh.spec | 5 +- 2 files changed, 196 insertions(+), 49 deletions(-) diff --git a/openssh-4.5p1-mls.patch b/openssh-4.5p1-mls.patch index 0b56785..ccf15dc 100644 --- a/openssh-4.5p1-mls.patch +++ b/openssh-4.5p1-mls.patch @@ -1,6 +1,6 @@ ---- openssh-4.5p1/openbsd-compat/port-linux.c.mls 2007-01-16 22:08:06.000000000 +0100 -+++ openssh-4.5p1/openbsd-compat/port-linux.c 2007-01-16 22:11:05.000000000 +0100 -@@ -33,12 +33,22 @@ +--- openssh-4.5p1/openbsd-compat/port-linux.c.mls 2007-01-16 22:13:32.000000000 +0100 ++++ openssh-4.5p1/openbsd-compat/port-linux.c 2007-03-01 09:04:17.000000000 +0100 +@@ -33,12 +33,23 @@ #include "key.h" #include "hostfile.h" #include "auth.h" @@ -10,6 +10,7 @@ #include +#include #include ++#include +#include + +#ifdef HAVE_LINUX_AUDIT @@ -23,7 +24,7 @@ /* Wrapper around is_selinux_enabled() to log its return value once only */ static int -@@ -54,17 +64,107 @@ +@@ -54,17 +65,172 @@ return (enabled); } @@ -93,30 +94,99 @@ +get_user_context(const char *sename, const char *role, const char *lvl, + security_context_t *sc) { +#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (role != NULL && role[0]) -+ return get_default_context_with_rolelevel(sename, role, lvl, NULL, sc); -+ else -+ return get_default_context_with_level(sename, lvl, NULL, sc); -+#else -+ if (role != NULL && role[0]) -+ return get_default_context_with_role(sename, role, NULL, sc); -+ else -+ return get_default_context(sename, NULL, sc); ++ if (get_default_context_with_level(sename, lvl, NULL, sc) != 0) { ++ /* User may have requested a level completely outside of his ++ allowed range. We get a context just for auditing as the ++ range check below will certainly fail for default context. */ +#endif ++ if (get_default_context(sename, NULL, sc) != 0) { ++ *sc = NULL; ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ } ++#endif ++ if (role != NULL && role[0]) { ++ context_t con; ++ char *type=NULL; ++ if (get_default_type(role, &type) != 0) { ++ error("get_default_type: failed to get default type for '%s'", ++ role); ++ goto out; ++ } ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_role_set(con, role); ++ context_type_set(con, type); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ if (!*sc) ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ if (lvl != NULL && lvl[0]) { ++ /* verify that the requested range is obtained */ ++ context_t con; ++ security_context_t obtained_raw; ++ security_context_t requested_raw; ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_range_set(con, lvl); ++ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) { ++ context_free(con); ++ goto out; ++ } ++ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) { ++ freecon(obtained_raw); ++ context_free(con); ++ goto out; ++ } ++ ++ debug("get_user_context: obtained context '%s' requested context '%s'", ++ obtained_raw, requested_raw); ++ if (strcmp(obtained_raw, requested_raw)) { ++ /* set the context to the real requested one but fail */ ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ return -1; ++ } ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ context_free(con); ++ } ++#endif ++ return 0; ++ out: ++ freecon(*sc); ++ *sc = NULL; ++ return -1; +} + /* Return the default security context for the given username */ - static security_context_t - ssh_selinux_getctxbyname(char *pwname) +-static security_context_t +-ssh_selinux_getctxbyname(char *pwname) ++static int ++ssh_selinux_getctxbyname(char *pwname, ++ security_context_t *default_sc, security_context_t *user_sc) { - security_context_t sc = NULL; -+ security_context_t defsc = NULL; +- security_context_t sc = NULL; char *sename, *lvl; + const char *reqlvl = NULL; char *role = NULL; - int r = 0; +- int r = 0; ++ int r = -1; + context_t con = NULL; + ++ *default_sc = NULL; ++ *user_sc = NULL; + if (the_authctxt) { + if (the_authctxt->role != NULL) { + char *slash; @@ -133,7 +203,7 @@ #ifdef HAVE_GETSEUSERBYNAME if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { sename = NULL; -@@ -72,23 +172,49 @@ +@@ -72,37 +238,56 @@ } #else sename = pwname; @@ -142,60 +212,76 @@ #endif if (r == 0) { --#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL + #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL - if (role != NULL && role[0]) - r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc); - else - r = get_default_context_with_level(sename, lvl, NULL, &sc); --#else ++ r = get_default_context_with_level(sename, lvl, NULL, default_sc); + #else - if (role != NULL && role[0]) - r = get_default_context_with_role(sename, role, NULL, &sc); - else - r = get_default_context(sename, NULL, &sc); --#endif -+ r = get_user_context(sename, role, lvl, &defsc); ++ r = get_default_context(sename, NULL, default_sc); + #endif } +- if (r != 0) { +- switch (security_getenforce()) { +- case -1: +- fatal("%s: ssh_selinux_getctxbyname: " +- "security_getenforce() failed", __func__); +- case 0: +- error("%s: Failed to get default SELinux security " +- "context for %s", __func__, pwname); +- default: +- fatal("%s: Failed to get default SELinux security " +- "context for %s (in enforcing mode)", +- __func__, pwname); + if (r == 0) { + /* If launched from xinetd, we must use current level */ + if (inetd_flag && !rexeced_flag) { + security_context_t sshdsc=NULL; + -+ if (getcon(&sshdsc) < 0) ++ if (getcon_raw(&sshdsc) < 0) + fatal("failed to allocate security context"); + + if ((con=context_new(sshdsc)) == NULL) + fatal("failed to allocate selinux context"); + reqlvl = context_range_get(con); + freecon(sshdsc); ++ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) ++ /* we actually don't change level */ ++ reqlvl = ""; + + debug("%s: current connection level '%s'", __func__, reqlvl); + } + -+ if (reqlvl != NULL && reqlvl[0]) { -+ r = get_user_context(sename, role, reqlvl, &sc); ++ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) { ++ r = get_user_context(sename, role, reqlvl, user_sc); + -+ if (r == 0) { -+ if (mls_range_allowed(defsc, sc)) { -+ send_audit_message(1, defsc, sc); ++ if (r == 0 && reqlvl != NULL && reqlvl[0]) { ++ /* verify that the requested range is contained in the user range */ ++ if (mls_range_allowed(*default_sc, *user_sc)) { + logit("permit MLS level %s (user range %s)", reqlvl, lvl); + } else { -+ send_audit_message(0, defsc, sc); -+ if (security_getenforce() > 0) -+ fatal("deny MLS level %s (user range %s)", reqlvl, lvl); -+ else -+ error("deny MLS level %s (user range %s). Continuing in permissive mode", reqlvl, lvl); ++ r = -1; ++ error("deny MLS level %s (user range %s)", reqlvl, lvl); + } + } -+ freecon(defsc); + } else { -+ sc = defsc; -+ } ++ *user_sc = *default_sc; + } + } ++ if (r != 0) { ++ error("%s: Failed to get default SELinux security " ++ "context for %s", __func__, pwname); + } - if (r != 0) { - switch (security_getenforce()) { - case -1: -@@ -110,6 +236,10 @@ + + #ifdef HAVE_GETSEUSERBYNAME + if (sename != NULL) +@@ -110,14 +295,20 @@ if (lvl != NULL) xfree(lvl); #endif @@ -204,9 +290,67 @@ + if (con) + context_free(con); - return (sc); +- return (sc); ++ return (r); } -@@ -157,7 +287,10 @@ + + /* Set the execution context to the default for the specified user */ + void + ssh_selinux_setup_exec_context(char *pwname) + { ++ int r = 0; ++ security_context_t default_ctx = NULL; + security_context_t user_ctx = NULL; + + if (!ssh_selinux_enabled()) +@@ -125,21 +316,39 @@ + + debug3("%s: setting execution context", __func__); + +- user_ctx = ssh_selinux_getctxbyname(pwname); +- if (setexeccon(user_ctx) != 0) { ++ r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx); ++ if (r >= 0) { ++ r = setexeccon(user_ctx); ++ if (r < 0) { ++ error("%s: Failed to set SELinux execution context %s for %s", ++ __func__, user_ctx, pwname); ++ } ++ } ++ if (user_ctx == NULL) { ++ user_ctx = default_ctx; ++ } ++ if (r < 0 || user_ctx != default_ctx) { ++ /* audit just the case when user changed a role or there was ++ a failure */ ++ send_audit_message(r >= 0, default_ctx, user_ctx); ++ } ++ if (r < 0) { + switch (security_getenforce()) { + case -1: + fatal("%s: security_getenforce() failed", __func__); + case 0: +- error("%s: Failed to set SELinux execution " +- "context for %s", __func__, pwname); ++ error("%s: SELinux failure. Continuing in permissive mode.", ++ __func__); ++ break; + default: +- fatal("%s: Failed to set SELinux execution context " +- "for %s (in enforcing mode)", __func__, pwname); ++ fatal("%s: SELinux failure. Aborting connection.", ++ __func__); + } + } +- if (user_ctx != NULL) ++ if (user_ctx != NULL && user_ctx != default_ctx) + freecon(user_ctx); ++ if (default_ctx != NULL) ++ freecon(default_ctx); + + debug3("%s: done", __func__); + } +@@ -157,7 +366,10 @@ debug3("%s: setting TTY context on %s", __func__, tty); @@ -218,8 +362,8 @@ /* XXX: should these calls fatal() upon failure in enforcing mode? */ ---- openssh-4.5p1/sshd.c.mls 2007-01-16 21:43:11.000000000 +0100 -+++ openssh-4.5p1/sshd.c 2007-01-16 21:48:37.000000000 +0100 +--- openssh-4.5p1/sshd.c.mls 2007-01-16 22:13:32.000000000 +0100 ++++ openssh-4.5p1/sshd.c 2007-01-16 22:13:32.000000000 +0100 @@ -1833,6 +1833,9 @@ restore_uid(); } @@ -231,7 +375,7 @@ if (options.use_pam) { do_pam_setcred(1); --- openssh-4.5p1/misc.c.mls 2006-08-05 04:39:40.000000000 +0200 -+++ openssh-4.5p1/misc.c 2007-01-16 21:56:40.000000000 +0100 ++++ openssh-4.5p1/misc.c 2007-01-16 22:13:32.000000000 +0100 @@ -418,6 +418,7 @@ colon(char *cp) { @@ -256,8 +400,8 @@ } return (0); } ---- openssh-4.5p1/session.c.mls 2007-01-16 21:43:11.000000000 +0100 -+++ openssh-4.5p1/session.c 2007-01-16 21:46:35.000000000 +0100 +--- openssh-4.5p1/session.c.mls 2007-01-16 22:13:32.000000000 +0100 ++++ openssh-4.5p1/session.c 2007-01-16 22:13:32.000000000 +0100 @@ -1347,10 +1347,6 @@ #endif if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) diff --git a/openssh.spec b/openssh.spec index af53c3f..f8216bd 100644 --- a/openssh.spec +++ b/openssh.spec @@ -61,7 +61,7 @@ Summary: The OpenSSH implementation of SSH protocol versions 1 and 2 Name: openssh Version: 4.5p1 -Release: 3%{?dist}%{?rescue_rel} +Release: 4%{?dist}%{?rescue_rel} URL: http://www.openssh.com/portable.html #Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.sig @@ -459,6 +459,9 @@ fi %endif %changelog +* Thu Feb 27 2007 Tomas Mraz - 4.5p1-4 +- reject connection if requested mls range is not obtained (#229278) + * Wed Feb 22 2007 Tomas Mraz - 4.5p1-3 - improve Buildroot - remove duplicate /etc/ssh from files