From patchwork Fri Jun 9 13:22:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mimi Zohar X-Patchwork-Id: 9778429 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3D2C36034B for ; Fri, 9 Jun 2017 13:22:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2C322285DC for ; Fri, 9 Jun 2017 13:22:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 211D32861A; Fri, 9 Jun 2017 13:22:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8AEB12861C for ; Fri, 9 Jun 2017 13:22:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751538AbdFINWX (ORCPT ); Fri, 9 Jun 2017 09:22:23 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:49013 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751527AbdFINWW (ORCPT ); Fri, 9 Jun 2017 09:22:22 -0400 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v59DJS2P119621 for ; Fri, 9 Jun 2017 09:22:22 -0400 Received: from e23smtp06.au.ibm.com (e23smtp06.au.ibm.com [202.81.31.148]) by mx0a-001b2d01.pphosted.com with ESMTP id 2aytdtxpj4-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Fri, 09 Jun 2017 09:22:22 -0400 Received: from localhost by e23smtp06.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 9 Jun 2017 23:22:19 +1000 Received: from d23relay07.au.ibm.com (202.81.31.226) by e23smtp06.au.ibm.com (202.81.31.212) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 9 Jun 2017 23:22:17 +1000 Received: from d23av01.au.ibm.com (d23av01.au.ibm.com [9.190.234.96]) by d23relay07.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v59DMGZG1048944 for ; Fri, 9 Jun 2017 23:22:16 +1000 Received: from d23av01.au.ibm.com (localhost [127.0.0.1]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id v59DMFaR002239 for ; Fri, 9 Jun 2017 23:22:16 +1000 Received: from localhost.localdomain ([9.80.110.47]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id v59DMC03002145; Fri, 9 Jun 2017 23:22:14 +1000 Subject: [PATCH v1] shebang: restrict python interactive prompt/interpreter From: Mimi Zohar To: linux-security-module Cc: Kees Cook , Matt Brown Date: Fri, 09 Jun 2017 09:22:08 -0400 X-Mailer: Evolution 3.20.5 (3.20.5-1.fc24) Mime-Version: 1.0 X-TM-AS-MML: disable x-cbid: 17060913-0040-0000-0000-0000032B5A43 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17060913-0041-0000-0000-00000CA56A22 Message-Id: <1497014528.21594.190.camel@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-06-09_07:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=0 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000 definitions=main-1706090235 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This patch defines a new, minor LSM named "shebang", that restricts python such that scripts are allowed to execute, while the interactive prompt/interpreter is not available. When used in conjunction with an IMA appraise execute policy requiring files signatures, only signed python scripts would be allowed to execute. (A separate method for identifying "imported" code would need to be defined in order to verify their file signatures.) A blank/comma delimited list of interpreter pathnames is converted to a list of inodes, which is used to detect and prevent the interactive prompt/interpreter's usage. Mimi Zohar --- security/Kconfig | 1 + security/Makefile | 2 + security/shebang/Kconfig | 16 ++++++ security/shebang/Makefile | 3 + security/shebang/shebang_python.c | 117 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 security/shebang/Kconfig create mode 100644 security/shebang/Makefile create mode 100644 security/shebang/shebang_python.c diff --git a/security/Kconfig b/security/Kconfig index bdcbb92927ab..4453299c430e 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -195,6 +195,7 @@ source security/tomoyo/Kconfig source security/apparmor/Kconfig source security/loadpin/Kconfig source security/yama/Kconfig +source security/shebang/Kconfig source security/integrity/Kconfig diff --git a/security/Makefile b/security/Makefile index f2d71cdb8e19..00a8dbebb07f 100644 --- a/security/Makefile +++ b/security/Makefile @@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin +subdir-$(CONFIG_SECURITY_SHEBANG) += shebang # always enable default capabilities obj-y += commoncap.o @@ -24,6 +25,7 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ +obj-$(CONFIG_SECURITY_SHEBANG) += shebang/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/shebang/Kconfig b/security/shebang/Kconfig new file mode 100644 index 000000000000..1b977b266413 --- /dev/null +++ b/security/shebang/Kconfig @@ -0,0 +1,16 @@ +config SECURITY_SHEBANG + bool "Restrict python interactive prompt/interpreter" + depends on SECURITY + help + Restrict python so that python scripts are allowed to execute, + while the interactive prompt/interpreter is not available. When + used in conjunction with an IMA appraise policy requiring files + signatures, only signed scripts will be executed. + +config SECURITY_SHEBANG_PATHNAME + string "interactive prompt/interpreter pathname" + depends on SECURITY_SHEBANG + default "/usr/bin/python2, /usr/bin/python3" + help + This option defines a blank/comma delimited list of + interpreter pathnames. diff --git a/security/shebang/Makefile b/security/shebang/Makefile new file mode 100644 index 000000000000..f1b83dcb96d1 --- /dev/null +++ b/security/shebang/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_SHEBANG) += shebang.o + +shebang-y := shebang_python.o diff --git a/security/shebang/shebang_python.c b/security/shebang/shebang_python.c new file mode 100644 index 000000000000..6f98cce38ea4 --- /dev/null +++ b/security/shebang/shebang_python.c @@ -0,0 +1,117 @@ +/* + * shebang security module + * + * Copyright (C) 2017 IBM Corporation + * + * Authors: + * Mimi Zohar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define pr_fmt(fmt) "shebang: " fmt + +#include +#include +#include +#include + +static int initialized; + +#define MAX_INODES 6 +static char *pathnames; +static int pathnames_len; +static unsigned long inode_list[MAX_INODES]; +static int total; + +/* + * Get the inodes associated with the list of pathnames, as specified + * on CONFIG_SECURITY_SHEBANG_PATHNAME. + */ +static void init_inode_list(void) +{ + char *tmp_pathnames = pathnames; + char *p; + struct path path; + int i; + int ret; + + total = 0; + while ((p = strsep(&tmp_pathnames, " ,")) != NULL) { + if ((*p == '\0') || (*p == ' ') || (*p == ',')) + continue; + + if (total > MAX_INODES - 1) { + pr_info("too many interpreters\n"); + break; + } + + ret = kern_path(p, LOOKUP_FOLLOW, &path); + if (!ret) { + struct inode *inode = d_backing_inode(path.dentry); + + inode_list[total] = inode->i_ino; + pr_info("pathname:%s i_ino: %lu\n", + p, inode_list[total]); + initialized = 1; + total++; + } + } + + /* cleanup in case we need to lookup the inodes again. */ + tmp_pathnames = pathnames; + for (i = 0; i < pathnames_len; i++) + if (tmp_pathnames[i] == '\0') + tmp_pathnames[i] = ' '; +} + +/** + * shebang_bprm_check - prevent python interactive prompt/interpreter + * @bprm: contains the linux_binprm structure + * + * Restrict python such that scripts are allowed to execute, while the + * interactive prompt/interpreter is not available. + */ +static int shebang_bprm_check(struct linux_binprm *bprm) +{ + struct inode *inode = file_inode(bprm->file); + int i = 0; + + if (bprm->interp != bprm->filename) /* allow scripts */ + return 0; + + if (!initialized) + init_inode_list(); + + while (i < total) { + if (inode_list[i++] != inode->i_ino) + continue; + + pr_info("prevent executing %s (ino=%lu)\n", + bprm->interp, inode->i_ino); + return -EPERM; + } + return 0; +} + +static struct security_hook_list shebang_hooks[] = { + LSM_HOOK_INIT(bprm_check_security, shebang_bprm_check) +}; + +static int __init init_shebang(void) +{ + pathnames = kstrdup(CONFIG_SECURITY_SHEBANG_PATHNAME, GFP_KERNEL); + if (!pathnames) + return -ENOMEM; + pathnames_len = strlen(pathnames); + + security_add_hooks(shebang_hooks, ARRAY_SIZE(shebang_hooks), "shebang"); + pr_info("initialized\n"); + return 0; +} + +late_initcall(init_shebang); +MODULE_LICENSE("GPL");