From patchwork Mon Nov 23 15:36:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Bigonville X-Patchwork-Id: 7683241 Return-Path: X-Original-To: patchwork-selinux@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 25EAABF90C for ; Mon, 23 Nov 2015 15:42:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E2D7D206EF for ; Mon, 23 Nov 2015 15:42:24 +0000 (UTC) Received: from emvm-gh1-uea08.nsa.gov (emvm-gh1-uea08.nsa.gov [63.239.67.9]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 17BF8206EE for ; Mon, 23 Nov 2015 15:42:23 +0000 (UTC) X-TM-IMSS-Message-ID: <50e0dadc000318ef@nsa.gov> Received: from tarius.tycho.ncsc.mil ([144.51.242.1]) by nsa.gov ([63.239.67.9]) with ESMTP (TREND IMSS SMTP Service 7.1) id 50e0dadc000318ef ; Mon, 23 Nov 2015 10:40:27 -0500 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id tANFePPd004736; Mon, 23 Nov 2015 10:40:29 -0500 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id tANFajOe009539 for ; Mon, 23 Nov 2015 10:36:45 -0500 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id tANFajvo004301 for ; Mon, 23 Nov 2015 10:36:45 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1CuBQD9MVNW/2OteVteGQEBAQEPAQEBAYJfLFNvgmepFwwGBpR7JYVqAoFDTAEBAQEBAYU/AQEBAQMMFwRREQkCEQMBAgoWCwICCQMCAQIBPQgQAwYCAogqAQMJkRWdNZAEAQEIAQEBAQEVCYYNhUWEKBMBAT6CeoFEBYdCAoVagTOHf4JZgkuIDYFbSYcckwkCY4IRHYFXcQEEg1wJF4EqAQEB X-IPAS-Result: A1CuBQD9MVNW/2OteVteGQEBAQEPAQEBAYJfLFNvgmepFwwGBpR7JYVqAoFDTAEBAQEBAYU/AQEBAQMMFwRREQkCEQMBAgoWCwICCQMCAQIBPQgQAwYCAogqAQMJkRWdNZAEAQEIAQEBAQEVCYYNhUWEKBMBAT6CeoFEBYdCAoVagTOHf4JZgkuIDYFbSYcckwkCY4IRHYFXcQEEg1wJF4EqAQEB X-IronPort-AV: E=Sophos; i="5.20,337,1444708800"; d="scan'208,223"; a="4957692" Received: from emvm-gh1-uea08.nsa.gov ([63.239.67.9]) by goalie.tycho.ncsc.mil with ESMTP; 23 Nov 2015 10:36:44 -0500 X-TM-IMSS-Message-ID: <50dd33b5000317c7@nsa.gov> Received: from anor.bigon.be (anor.bigon.be [91.121.173.99]) by nsa.gov ([63.239.67.9]) with ESMTP (TREND IMSS SMTP Service 7.1; TLSv1/SSLv3 ADH-AES256-SHA (256/256)) id 50dd33b5000317c7 ; Mon, 23 Nov 2015 10:36:27 -0500 Received: from anor.bigon.be (localhost.localdomain [127.0.0.1]) by anor.bigon.be (Postfix) with ESMTP id 6C5CE1A1D8 for ; Mon, 23 Nov 2015 16:36:41 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at bigon.be Received: from anor.bigon.be ([127.0.0.1]) by anor.bigon.be (anor.bigon.be [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id lUOE8OAI0VtX for ; Mon, 23 Nov 2015 16:36:32 +0100 (CET) Received: from [IPv6:2a02:578:85fc:1:c84e:489:bf64:5e4f] (unknown [IPv6:2a02:578:85fc:1:c84e:489:bf64:5e4f]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client did not present a certificate) (Authenticated sender: bigon) by anor.bigon.be (Postfix) with ESMTPSA id EBF3B1A070 for ; Mon, 23 Nov 2015 16:36:31 +0100 (CET) Subject: Re: (Userspace) AVC denial generated even if allowed by the policy? To: selinux@tycho.nsa.gov References: <5652636F.2060609@debian.org> <56533218.7090601@debian.org> From: Laurent Bigonville Message-ID: <5653327F.9010609@debian.org> Date: Mon, 23 Nov 2015 16:36:31 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Icedove/38.3.0 Mime-Version: 1.0 In-Reply-To: <56533218.7090601@debian.org> X-TM-AS-MML: disable X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Le 23/11/15 16:34, Laurent Bigonville a écrit : > Le 23/11/15 01:53, Laurent Bigonville a écrit : >> Hi, >> >> I'm still looking at adding SELinux support in the "at" daemon and I >> now have the following patch[0]. >> >> With this patch, at seems to behave like the cron daemon, as >> explained in the commit log: >> >> - When cron_userdomain_transition is set to off, a process for an >> unconfined user will transition to unconfined_cronjob_t. For >> confined >> user, the job is run as cronjob_t. >> >> - When cron_userdomain_transition is set to on, the processes are >> run >> under the user default context. >> >> But every time an AVC denial is generated (with >> cron_userdomain_transition set to off and the user running as >> staff_u, in permissive with unmodified refpolicy): >> >> avc: denied { entrypoint } for >> scontext=staff_u:staff_r:cronjob_t:s0 >> tcontext=staff_u:object_r:user_cron_spool_t:s0 tclass=file >> >> The job runs as (id -Z): staff_u:staff_r:cronjob_t:s0 >> >> But audit2{allow,why} are saying that this is already allowed in the >> policy >> >> Setting the cron_userdomain_transition boolean to on, I have the >> following avc: >> >> avc: denied { entrypoint } for >> scontext=staff_u:sysadm_r:sysadm_t:s0 >> tcontext=staff_u:object_r:user_cron_spool_t:s0 tclass=file >> >> The job runs as (id -Z): staff_u:sysadm_r:sysadm_t:s0 >> >> So as said it seems to work, but I'm not sure why this AVC denial is >> generated. >> >> sesearch shows: >> >> $ sesearch -ATSC -t user_cron_spool_t -c file -p entrypoint >> Found 6 semantic av rules: >> allow files_unconfined_type file_type : file { ioctl read write >> create getattr setattr lock relabelfrom relabelto append unlink link >> rename execute swapon quotaon mounton execute_no_trans entrypoint >> open audit_access } ; >> DT allow unconfined_t user_cron_spool_t : file entrypoint ; [ >> cron_userdomain_transition ] >> DT allow user_t user_cron_spool_t : file entrypoint ; [ >> cron_userdomain_transition ] >> EF allow cronjob_t user_cron_spool_t : file entrypoint ; [ >> cron_userdomain_transition ] >> DT allow staff_t user_cron_spool_t : file entrypoint ; [ >> cron_userdomain_transition ] >> DT allow sysadm_t user_cron_spool_t : file entrypoint ; [ >> cron_userdomain_transition ] >> >> Did I overlooked something? >> >> Cheers, >> >> Laurent Bigonville >> >> [0] >> https://anonscm.debian.org/cgit/users/bigon/at.git/commit/?h=selinux&id=0112f006b74a36f7200e315575fd25d78e11b170 > > I'm attaching the patch to this mail for the people that cannot access > the website and FTR. And it was of course the wrong one... From 0112f006b74a36f7200e315575fd25d78e11b170 Mon Sep 17 00:00:00 2001 From: Laurent Bigonville Date: Thu, 16 Jul 2015 01:06:06 +0200 Subject: [PATCH] Add SELinux support to run jobs in the proper domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, jobs run by at are run in the crond_t domain and not transitioned outside of it. With this patch, the jobs are transitioned in the same domain as the jobs that are run by the cron daemon: - When cron_userdomain_transition is set to off, a process for an unconfined user will transition to unconfined_cronjob_t. For confined user, the job is run as cronjob_t. - When cron_userdomain_transition is set to on, the processes are run under the user default context. This patch is based on Marcela Mašlá?ová work --- Makefile.in | 3 ++- atd.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.h.in | 3 +++ configure.ac | 8 ++++++ daemon.c | 16 +++++++++++ daemon.h | 3 +++ 6 files changed, 119 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 06544f9..dd3c2f8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -40,6 +40,7 @@ LIBS = @LIBS@ LIBOBJS = @LIBOBJS@ INSTALL = @INSTALL@ PAMLIB = @PAMLIB@ +SELINUXLIB = @SELINUXLIB@ CLONES = atq atrm ATOBJECTS = at.o panic.o perm.o posixtm.o y.tab.o lex.yy.o @@ -73,7 +74,7 @@ at: $(ATOBJECTS) $(LN_S) -f at atrm atd: $(RUNOBJECTS) - $(CC) $(LDFLAGS) -o atd $(RUNOBJECTS) $(LIBS) $(PAMLIB) + $(CC) $(LDFLAGS) -o atd $(RUNOBJECTS) $(LIBS) $(PAMLIB) $(SELINUXLIB) y.tab.c y.tab.h: parsetime.y $(YACC) -d parsetime.y diff --git a/atd.c b/atd.c index d0b422e..abb860e 100644 --- a/atd.c +++ b/atd.c @@ -83,6 +83,12 @@ #include "getloadavg.h" #endif +#ifdef WITH_SELINUX +#include +#include +int selinux_enabled = 0; +#endif + /* Macros */ #define BATCH_INTERVAL_DEFAULT 60 @@ -195,6 +201,72 @@ myfork() #define fork myfork #endif +#ifdef WITH_SELINUX +static int +set_selinux_context(const char *name, const char *filename) { + security_context_t user_context = NULL; + security_context_t file_context = NULL; + int retval = 0; + char *seuser = NULL; + char *level = NULL; + + if (getseuserbyname(name, &seuser, &level) == 0) { + retval = get_default_context_with_level(seuser, level, NULL, &user_context); + free(seuser); + free(level); + if (retval < 0) { + lerr("get_default_context_with_level: couldn't get security context for user %s", name); + retval = -1; + goto err; + } + } + + /* + * Since crontab files are not directly executed, + * crond must ensure that the crontab file has + * a context that is appropriate for the context of + * the user cron job. It performs an entrypoint + * permission check for this purpose. + */ + if (fgetfilecon(STDIN_FILENO, &file_context) < 0) { + lerr("fgetfilecon FAILED %s", filename); + retval = -1; + goto err; + } + + retval = selinux_check_access(user_context, file_context, "file", "entrypoint", NULL); + freecon(file_context); + if (retval < 0) { + lerr("Not allowed to set exec context to %s for user %s", user_context, name); + retval = -1; + goto err; + } + if (setexeccon(user_context) < 0) { + lerr("Could not set exec context to %s for user %s", user_context, name); + retval = -1; + goto err; + } +err: + if (retval < 0 && security_getenforce() != 1) + retval = 0; + if (user_context) + freecon(user_context); + return retval; +} + +static int +selinux_log_callback (int type, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog (LOG_ERR, fmt, ap); + va_end(ap); + return 0; +} + +#endif + static void run_file(const char *filename, uid_t uid, gid_t gid) { @@ -424,6 +496,13 @@ run_file(const char *filename, uid_t uid, gid_t gid) nice((tolower((int) queue) - 'a' + 1) * 2); +#ifdef WITH_SELINUX + if (selinux_enabled > 0) { + if (set_selinux_context(pentry->pw_name, filename) < 0) + perr("SELinux Failed to set context\n"); + } +#endif + if (initgroups(pentry->pw_name, pentry->pw_gid)) perr("Cannot initialize the supplementary group access list"); @@ -707,6 +786,14 @@ main(int argc, char *argv[]) struct passwd *pwe; struct group *ge; +#ifdef WITH_SELINUX + selinux_enabled=is_selinux_enabled(); + + if (selinux_enabled) { + selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) selinux_log_callback); + } +#endif + /* We don't need root privileges all the time; running under uid and gid * daemon is fine. */ diff --git a/config.h.in b/config.h.in index 4d7dc91..681d68e 100644 --- a/config.h.in +++ b/config.h.in @@ -192,6 +192,9 @@ . */ #undef UMAX4_3 +/* Define if you are building with_selinux */ +#undef WITH_SELINUX + /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER diff --git a/configure.ac b/configure.ac index bcd3ec6..0321a02 100644 --- a/configure.ac +++ b/configure.ac @@ -239,6 +239,14 @@ AC_ARG_WITH(daemon_username, ) AC_SUBST(DAEMON_USERNAME) +AC_ARG_WITH(selinux, +[ --with-selinux Define to run with selinux], +AC_DEFINE(WITH_SELINUX, 1, [Define if you are building with_selinux]), +) +AC_CHECK_LIB(selinux, is_selinux_enabled, SELINUXLIB=-lselinux) +AC_SUBST(SELINUXLIB) +AC_SUBST(WITH_SELINUX) + AC_MSG_CHECKING(groupname to run under) AC_ARG_WITH(daemon_groupname, [ --with-daemon_groupname=DAEMON_GROUPNAME Groupname to run under (default daemon) ], diff --git a/daemon.c b/daemon.c index 8be40d4..f9d25e7 100644 --- a/daemon.c +++ b/daemon.c @@ -83,6 +83,22 @@ perr(const char *fmt,...) } void +lerr(const char *fmt,...) +{ + char buf[1024]; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (daemon_debug) { + perror(buf); + } else + syslog(LOG_ERR, "%s: %m", buf); +} + +void pabort(const char *fmt,...) { char buf[1024]; diff --git a/daemon.h b/daemon.h index c4507ae..f44ccd1 100644 --- a/daemon.h +++ b/daemon.h @@ -13,5 +13,8 @@ __attribute__((noreturn)) #endif perr (const char *fmt, ...); +void +lerr (const char *fmt, ...); + extern int daemon_debug; extern int daemon_foreground; -- 2.6.2