From patchwork Mon Nov 27 19:32:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Haines X-Patchwork-Id: 10080303 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 8D51A6056A for ; Tue, 28 Nov 2017 13:24:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7F07D28992 for ; Tue, 28 Nov 2017 13:24:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 72B2A290E0; Tue, 28 Nov 2017 13:24:50 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from UCOL19PA10.eemsg.mail.mil (ucol19pa10.eemsg.mail.mil [214.24.24.83]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B7DF128992 for ; Tue, 28 Nov 2017 13:24:48 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.44,468,1505779200"; d="scan'208";a="388173200" Received: from emsm-gh1-uea10.ncsc.mil ([214.29.60.2]) by UCOL19PA10.eemsg.mail.mil with ESMTP/TLS/AES256-SHA; 28 Nov 2017 13:24:43 +0000 X-IronPort-AV: E=Sophos;i="5.44,468,1505779200"; d="scan'208";a="6200092" IronPort-PHdr: =?us-ascii?q?9a23=3A1PB2HBL6JePzugIo3NmcpTZWNBhigK39O0sv0rFi?= =?us-ascii?q?tYgTIvv5rarrMEGX3/hxlliBBdydt6odzbKO+Pu6EUU7or+5+EgYd5JNUxJXwe?= =?us-ascii?q?43pCcHRPC/NEvgMfTxZDY7FskRHHVs/nW8LFQHUJ2mPw6arXK99yMdFQviPgRp?= =?us-ascii?q?OOv1BpTSj8Oq3Oyu5pHfeQpFiCagbb9oMBm6sQrdu8cIjYB/Nqs/1xzFr2dSde?= =?us-ascii?q?9L321oP1WTnxj95se04pFu9jlbtuwi+cBdT6j0Zrw0QrNEAjsoNWA1/9DrugLY?= =?us-ascii?q?TQST/HscU34ZnQRODgPY8Rz1RJbxsi/9tupgxCmXOND9QL4oVTi+6apgVRHniD?= =?us-ascii?q?0DNzUk7m/ZjMJ+h79frB64uhBz34vYbYeIP/R8Y6zdZ8sXS2pfUMhfVCJPBZ6y?= =?us-ascii?q?b5MNAuYcM+tXsZL9qkASoReiHwSgGPnixiNUinLwwKY00/4hEQbD3AE4A9wOsW?= =?us-ascii?q?jbrNXvO6cITO++0avGwi/Cb/NQxzj985XDfxc7ofGNQb1wcdDeyVMyGAzdklqf?= =?us-ascii?q?sYzlMCmU1uQLrWeb9PFtWvmzi24mrQFxviagxt0qiobXmoIZ0EzL9SJ8wIssI9?= =?us-ascii?q?CzVUB1YdmhEJRKtiGaMZN7Qts4TGF1vCY207gGuZm8fCgQ1psr3QLQa/uCc4WO?= =?us-ascii?q?/xntV/6RLC9liH9qd7+znRa//VW6xuHiWcS4zkxGojddntTPq3wBzQHf58aZRv?= =?us-ascii?q?dn8Uqs2yyD2x3d5+xEJ00/iLDVJIQ7wrEqk5oeqUHDHijrl0rolKKWbUAk+vSw?= =?us-ascii?q?6+Tgf7XmuoeQN49qhQH6NaQjgtC/Dv4iMggPQmib4v6w1KHj/ELlQLVKiec6kq?= =?us-ascii?q?/Fv5DBOcsXvKu5Aw5R0oo76ha/CSmp0MgAkHUaI19IdwiLgoj0N13UPvz1Aumz?= =?us-ascii?q?j06xnDtzwvDJJLzhApHDLnjZl7fheK5w61VCxwo3zNBf4Y9UC74YLP3oXU/xqd?= =?us-ascii?q?rYAQMnPAyv2OvnFNV82Z8eWWKIGKOZNrjSvkWS6uIgJOmMepcZuCzhJPg9+/7u?= =?us-ascii?q?kXg5lEcffamu25sYcmy4HvR8LEWfenfsgNABEWEPvgUkV+zqlEONUSRIZ3qoWK?= =?us-ascii?q?I8/D47Apq8DYjfXoCtnKCB3CCjE51UZGBJEEyDEXTzd4WDXfcMaTySL9RvkjwA?= =?us-ascii?q?SLigRJQu1QyotA/m1rprNO3U+jcXtZj7zth6+/XTlQ0u9TxzF8mc3WCNT2Vxnm?= =?us-ascii?q?wWXT87x65/rlJgxVeEy6h3meRYFcZU5/NLTAg1KYLcw/Z9C9DoVQLLZs2JR0q+?= =?us-ascii?q?QtW6HTExSco8zMISbEZ4HNWiiAzD0zexDr8LibOLHp0086Pb33j3Pcp9zWjJ1L?= =?us-ascii?q?U5hVk8XsRPLXGmhrJ49wXLGoHJj1+Wl7yxeKsA2y7N8XuMwnCVvEFESgJwV7vK?= =?us-ascii?q?XWwHbEvMsdv5/l/CT6OpCbk/MgpAyMmCKq1RZ93siVVKXfbjONLEb2K3gWiwHx?= =?us-ascii?q?WIxrKSbIX0YWkd2jvSCFQcmQAJ4XmGLRQ+Bjumo2/GAjxuD0jgY0Xw/ul/s3O2?= =?us-ascii?q?VUo0zxmLb0F4zLq09AUVieabS/MJ0bIOoD0hpClsHFahw9LWDMKNpwl7c6VfZt?= =?us-ascii?q?M9/UxK1WHDuAx+OZygMrpuhlkEcwR4p0nuzQl4Cp1ckcg2q3Mn1BB9Jr+C0FNA?= =?us-ascii?q?aTyYx4v9NafLJWn35hyvbLTW2l7G2taM5qgP8Og4q0nkvAyxDEot7mho3sJa03?= =?us-ascii?q?uZ6ZTGFgwSXoztUkwv7Rh1u6naYjUh54PTzXBsKqe0siXF29IyGOso0Q2gf9FY?= =?us-ascii?q?MKKKEQ/9CcsaC9KoKOM0h1ijdggEM/xK9K4oI8OmcOOL2aCxM+ZkgDKpk35H4J?= =?us-ascii?q?tm30KS6SV8UPXH34sAw/2C2QuHTTj8hk+7ss/rgYBEeS0SHm2nxCj4GYFee6xy?= =?us-ascii?q?cpwPCWq1P8K3wdB+iIL3VH5D6F6vHVUG19G1eRCKdVzywRVQ1VgLoXyggSa4yT?= =?us-ascii?q?10kzUtrqWBxyzD2P7tewQdOm5MXmViik3sIYeshdAAQEeodxQplAei5Uvi2ahb?= =?us-ascii?q?pbhwL3XUQUdSZST5M2FiUqy2trqNeMNP7JIosSNNX+SmZlCWULn9owEV0yn7BW?= =?us-ascii?q?tR2Cg7dy22upX+hxF6jGOdLG1vrHbAYsF/2xPf5N3aRf5M0TsLXzJ4iSHWBli6?= =?us-ascii?q?Ptmm4c6Um43Fsu+gS2KrTodTfjXzzYOcqCu74nVnAQe4n/C3nt3oDxI63jP819?= =?us-ascii?q?hkTijItwv8bZXw16igNuJnZEZoDkfm68VmAoF+jpcwhJYI1HgZmJqV+2EHnHzw?= =?us-ascii?q?MdpF36L+d3wNSiAXw9LP5wjlwkJjJGqTx43lTnWd3tdhZ96ib2MOwC098sRKB7?= =?us-ascii?q?mM7LNemyt1vkS3rRjKbPhghTcS1+Eu6GUAj+ESvwot0z+dDawMEklWOizsjRuI?= =?us-ascii?q?4M6koKVRemmvbaC61FBiktC5ELGCvgZcVW7nepckACB99dt/MFTR333z8I3kfs?= =?us-ascii?q?ffbc4LvB2OjxjAl/RVKI42lvcSnSpoI3/9vXk+xuEnjBxuwZG7sJGJK2p3+qK1?= =?us-ascii?q?GBlYNif6Z8kL4DHikb5entqK34CoBphhFC8EXJ30TfKvFTIfrvrnOBiTHz07sH?= =?us-ascii?q?eUA6LfHRWY6EdksX3AD4yrO2uQJHkDwtVoXAOdK1BHgAAIQDU6mYY0FgWwy8zl?= =?us-ascii?q?dEd2+CwR5kLipRRW0e9oMQfwUnvEpAi0cDg0UIaQIABQ7g5c+0ffKdae4f5rHy?= =?us-ascii?q?FE4p2hqxSAKnaBawVGF20JX1aLB1TkPriu/tTP6fSXBu+kI/vJe7WOpvRUV+2U?= =?us-ascii?q?ypK3zotm4zGMO92BPnl4EfI0x1FDUmp/G8TFnDUPUDcamDjRYM6evhu8/Td3rs?= =?us-ascii?q?+n+vTxRA3v/ZePC6dVMdh3/RC2m72MN/aIhCtiJzZY14kMxWTUyLgR3V4SjTth?= =?us-ascii?q?dz+xHrQBryHNSLjcmqhNDx4UcylzLtdH77og3glRPs7Wksv12aBjgfErDVdFVE?= =?us-ascii?q?DhmsayaMwLPW6yKk3ICFyMNLScKj3B29v3br+kSb1MkOVUsAW9ti2AHEPkOjSD?= =?us-ascii?q?liLpVwy0Me1WlyGUIgBRtJumchlzDWjjTdTmagC0MdJskTI3wac0hm7RNWIGPz?= =?us-ascii?q?lzaV9NrqaX7SNemPl/HHZB7nV9J+mehymZ9/XYKooRsfZzGSt0lu1a4HM8y7ZO?= =?us-ascii?q?8S5LWud6mCrIod5ouV2mlfOPyjV/WhpUtjlLnJ6LvVllOajB7JZAVmzL/AwT4m?= =?us-ascii?q?iLDBQKv8VqCtvqu69Ky9jPkLn8KDBN8t7O+sscHcfUItqdMHU9KRrpBCLUDAwd?= =?us-ascii?q?QD63MmHfglZRkOuV9nyUsJc6rIPjmIAJSrBFV1w4De8VCkNgHNMeOph3RS8kna?= =?us-ascii?q?SdjMEW+Xq0tAPRS9lCvpDbSvKSBu3iKDWZjLlAeRQF2rb4LYMdNo31xUNidkV6?= =?us-ascii?q?nITNG0rVQ99BuCthYREooE9V6nhxUnUz2175agOq+HITE+C7kQQyigZlYuQt8y?= =?us-ascii?q?zs40stKVrMvyswk0gxlc/jgT+PbD77NL2wUp1OCyroq0gxNYv2QxxrYg2pg0Nr?= =?us-ascii?q?Li3ESK5Rj7Z7bm9riRXctoZIGf5SVa1EegEfxPGNa/Uuz1tctj2txVVb6uvdFZ?= =?us-ascii?q?tiiAwqfIaxoHJH3QJjasM6KrLUJKpI1VVfnLyBvjWv1uwrxw8ePUkN+nuIeCEU?= =?us-ascii?q?oEwIKqUmJy2w8+Nx8wOChTpDd3UXV/cxuP1q7Fk9O+OOziL7zbFMNl2xN/aeL6?= =?us-ascii?q?OFu2nMj8iITU0s1kkQjUlK4aB20ds/c0qTT00vyLyRFw4XOsrEKABVaNFf9HfV?= =?us-ascii?q?fSaTq+nNxoh1P4qlHODyUeCOrLoUgl6jHAsxBIQD8MABHpiq0EHFIsbqN6IKyR?= =?us-ascii?q?Io5Av3PlqFF+hJdAiNkDgZv8G11IV30pVFJjEBHWV9Nj265qrWpg8vh/qDQNc2?= =?us-ascii?q?Y3cBU4QZN3I3WNe1lDVDs3RGEja3zvoTyBKe4D/kuiTQED78YsJ5a/eQZBNjFM?= =?us-ascii?q?+59i0686m2j17X9ZPeKHvhONt5u9/A8+Uaq4+JC/NJV7V9tVnTm5VATXywT2HP?= =?us-ascii?q?CcK1J4T3a4Q0dtP7FHC6X0elhD0oUcf+IsytLrOSjgHyRYdYqo6b3CosNcWlDD?= =?us-ascii?q?ERBw9wp/0f5KJ7fQADbIc7YR/stwQ6KaO/JRyV3ciwTGm2KDtZVf9fwf+9Z7xN?= =?us-ascii?q?wComdvW6x2c4TpEm0+m39lYARIsMjhHf2fmjZ45eUSzoGnJFYgvBuDA3mnRmOO?= =?us-ascii?q?sp3ug/xxbIvkUGPDCQaOxlcmpEsM8gBVmKO3V5FnI4R0OAjYrE+gOsxaod/zFa?= =?us-ascii?q?n9lPyuBFrGL+sYXBYD2yXKyrqJPVsyUkbdgnrK1xMZDjIsWcu5PEmzzTVp/QvR?= =?us-ascii?q?OZUCSiDfpVhsBQID5EQPlPgWwkN9YKtpZB6UowU8c+JqZACKo3q7CrdzVrEzAd?= =?us-ascii?q?wTUeV4Oa0zwImv281KfClheMbJQiNwQJsJBYjdsHUC55fD8epK6lV4XZjGKFRH?= =?us-ascii?q?IEIAEP4gRI4wIAi5J/fvv/7IrOUpBM1yZco+hoXSvTCplo61z7R3mMjljiVfWh?= =?us-ascii?q?lfal3QFJwfLt09kbWQJ/BlNHy+ZQiEQoNKl9K7MMsY7Srj+IaUT6sXrsyOugOF?= =?us-ascii?q?le18nUeEP9DIXbqWr8SC0d9GYTRY9X1n7fE5ESnBB4aKYvv1pMJ4+ndlz55zw+?= =?us-ascii?q?yIRjB6O4Wtyzx1Y5sXYGQD+nE8ZGC+Fjq1/XRCFpY5Wwp5n/PZVdXHNQ8oWHq1?= =?us-ascii?q?hFiEVtLzK5yZ1EJsFN+DEMRiJAoTGAs9apVcJMx9d2D4cSLdd7pXj9ArlIOJ+L?= =?us-ascii?q?o305orbv0GPW+yggsFemwzW+A624T+VH8GAFBwomOX+epVc1D+sw7Gjd70rBsl?= =?us-ascii?q?Zq8OdHHrKPl1l+oC5hHpBSATZEzWuqL1pvQ3VasehWNarYftdATPk1YB+gJwYx?= =?us-ascii?q?FeU630CT+0F7g2v5aTRotgRG4yDdQxU0VS4Nj7f3hzIRt8GnNiUGS59TaTUhaD?= =?us-ascii?q?nFJByFlS9LuxZQdl9lV4ofAtlb57ERxZFU8dbaSUawNSEFWwRvNhoj0fpDj0FM?= =?us-ascii?q?rVmYdDvGDQqvaPbPqAF4ctmXrM61NvT25gNHhpngsOAi+KUJX2emlhG1QdDCs4?= =?us-ascii?q?/8scWHtleUdKjmLeKzfGTMTCXIjRCsn7crFYfK/ynUMApfNZZ61WAoYZ/7CW7E?= =?us-ascii?q?JR5GPb4UJ1JHVaBmbtVLuuJaaNV+eKYO4q9tAgiIRg30FYyqsflGKkrTRTXCIC?= =?us-ascii?q?WA6OO/p5nT4abaSej6acyG32zHTL5vPpdm9Tn7HK/n0Y1E9Urw1Pdt7ER6RkXY?= =?us-ascii?q?PC2asNTuPAUL5NKldkf4uJ0mAy/WCo9qkHXx3kFAa9YXQyqy/ZQezJNU83fwSe?= =?us-ascii?q?R90kTpse1S8bdk6ZMt7LBy1ce0P7rSJuhGsU96GBibGB9m9pI3AGhwX2pRePMe?= =?us-ascii?q?KO/NfaQFisDjs+b3F60L5x2S/+xWc8DHK1vAmsm4DTGcUgdEkRwEqTMVIQqQzf?= =?us-ascii?q?mFm7V7Scy9v+j2xlot40SiLh4B1L1i+Z2L+q6Wq+/McxvQzb8EV7PxRszvr7Qj?= =?us-ascii?q?pUWS5eEllLEUYGB1ZROoEPQFXM4H2mjg1bwqzT4rE87bG7Lg4/tDWnIikzLuhZ?= =?us-ascii?q?9yAlIWGukOErqT54RemWU4lPLFOd0KaKxCnXyPFRG8GL8Y1XGr8zeXIHVighzW?= =?us-ascii?q?0RHwQGaz4UTzrSBmQSrD0c3jkktTVrm4H0tSWTSmOVNgujOVIAXorMb3ubgy7E?= =?us-ascii?q?wuM2zltciCm3G9N75MBM3wOsCcLjcoq14Ni50xXNOv05gBGdWhONcR7G1+bvzG?= =?us-ascii?q?5mywki9BuKlGiJDc4sGU5vXXBWOvj7Ceq7iW2D9YzWU3sk8l5dC9LPHO4MeKTO?= =?us-ascii?q?6y22YWVSd/tBPLXwSppbzDs1AUJUuL3V/TmIMQItFWwXk410/h5Og5Q9I/7R5e?= =?us-ascii?q?GZjEZ/MDozDzJTT1zE2HY90tSimRzztXH1zyEVliG6gwwmHws9zTlXfW5VIoQp?= =?us-ascii?q?N8d0v9hRx4F484M14i6EALwiofFggAcQybDKu2CkThN4QEU1YMZA+a07i7dac3?= =?us-ascii?q?3FFzzam05ODJd+x8GrABNvBDgQ6ShFJbAI4ZsbUCQLJgfF9Q7KHXqRL4C4f5Q/?= =?us-ascii?q?jmlWE9Nfm0QsBG788Zt2Et4hukRxa675dM8aobgoiSdqFYeZjMoNx870B/6D4A?= =?us-ascii?q?aCNNhgR/jxS+Uewbv+Ds/NzbsJuu6uazW6cgXOEX+AYuB2V+lZT8mlYjrs/L1+?= =?us-ascii?q?1EUI3alZz/8BxRI36NoIvVzxt8JvASJI+wYLlg8HEHJywfJ30QJ9qWd+cz7DNt?= =?us-ascii?q?MDnJ4FxCGMwMb8sCPMXRgQBUllHpWLZL+8reHV+YDZtzd8824GfszTA18IEzUu?= =?us-ascii?q?D+5z+qK5Hf6EtNP/BYjCl2ktLNuvQVy+LICCcL+XmZdwR1wiSaxpmCF/nw5v6M?= =?us-ascii?q?xMjJWV0JGCA2UoFdJCeN+AG8Seq1kY/mUgWK5cPph5I+bk2QTGSrnKsZqqZMDf?= =?us-ascii?q?JAiiLj0zhcEYD1h/SVv8Cw52tXsl1HDZt87BzEGKVZJZV7OhX4m9K1Rkh9GCvw?= =?us-ascii?q?YsXUeQcvuOaMwOcD/fl+PVPkZYAHOhIE16766X1NQwtvVr75pFCZUPkVZNt7Vf?= =?us-ascii?q?zEr3dV6Zl6J68IJlidq4Tgri1Up1AuHA8pdLgwoyRYdkbQkg1VVaL0taUOiwQG?= =?us-ascii?q?V952p1NMFXi2OG0g+zrNTb5Vg7WJCPwJ7jWTSbQDU0psMiN5TRK6xpFue7+ykP?= =?us-ascii?q?BctWNGmCJ9r+Qw3zxgWhS8pTXmp7gR1jI45LG4qDIBtGRHTuWekybIEVJDzPAL?= =?us-ascii?q?jacAFXnv8lm8YHgfbIvo/rZrP8Pg9ZMu434nexUsYzUGXfi8CyH3l66IHo2PsN?= =?us-ascii?q?dHiR6RucXBcbyzIjYWNrgnzxLsWWR92BDEnBl06GsLXimg7Ng8KYW4OMYlxSmo?= =?us-ascii?q?GW/AeVYO+KxJs8zxtVgVQ+swc19hxnts0tSfTC0XWMPPA3o1jhQjaWhca51M9x?= =?us-ascii?q?kaF7UzjzaTuqlG+R0UYCvKEou754bch8DI2WMyTd1y3GLZurWFho820H1ig950?= =?us-ascii?q?9imOuHAIeOzCXc5sBXzz1olExOz7YPWttfsHR5V6x7S7V/8CKdKj+Wqw2JVlQE?= =?us-ascii?q?Olwa4eH1WhOu8Z2rjbSzulSXGfWemTfWiDgTI5Mk/q5Ra2NVA2acZKr0o4MuTc?= =?us-ascii?q?nJ5ckxPuXalzRiWKql/R1HYjPv8CdwIqpIenfBQHTeAJZ+iGJOgh3OMxBUAJb3?= =?us-ascii?q?/IASt2EfG5vUSqnIhhNHVq+V/6bvj18gD6LNuSHQEJEYnerpFv4vG6XmaBNmV7?= =?us-ascii?q?zB1uPUl76/vfF04vueBCaZqRm8bfh8hj2+4fa/htKTE9usIUmo977YmU0cGKcQ?= =?us-ascii?q?zez5rrIdHVo+OYA+HEz0kxe2FVSLwZYQTv64U9JN45VKXZHaFFshQEGag6XJsh?= =?us-ascii?q?On/09K5uMAxzcg/RZLKzgsTxuOKLZ51UqGHS7lIxKifcphICxuazTQxhYJCgn2?= =?us-ascii?q?/yL4woRjJds91tDQNrHIlVFMMDqAqoGIWZmLy9i9+t+0N6vPIKsaXwCvDWzti5?= =?us-ascii?q?2Zt+X4RC70yRIDnRHLVrglhijumqgPfA157xCdn4edMFT+h2WWjFZaXDHoqhKz?= =?us-ascii?q?KCIMX8e1RJ87SEyrJ2Tg2RZDzlX6qBrCCkL/tk4UAnxYF5f+fe1yIt4K/B2Nvz?= =?us-ascii?q?ZmBboSGjoWSPNJRB8FyZTdDZCglZTfuD7XZNAbwcbYyy8vwHd9Ml3pzU5QRv4D?= =?us-ascii?q?lc+NWKLrLnrULW3E9/M5XBIw+h3yc/RJlPOx+jKWMyjmLD7HfQG3JRKo6jM8Yp?= =?us-ascii?q?yNKUCAH9olJ8knw3Z3JQX2/vScqVNEAF1M+kIg6H7gRGC5AEheHkV1Q/s/iISO?= =?us-ascii?q?JoM49J0cWjtbMKip49MSDERMFAMxbbG79/PzxcFc3FuFkufhMetbUpHIwyYM7d?= =?us-ascii?q?cws8LE6cxHaqnkP52krueonpjf6E?= X-IPAS-Result: =?us-ascii?q?A2C/AADMYh1a/wHyM5BdGgEBAQEBAgEBAQEIAQEBAYMQKQN?= =?us-ascii?q?mbieOH3SOIoJ7lXQQgX4lB4ogPxgBAQEBAQEBAQEBaiiCOCSCSwIXDRkBOAECA?= =?us-ascii?q?wkCBUMIAwFaEgWIFgM0gTcBAxUDAalAOoMKBYEChFCCHiYECIM8gTZTgz6CdYM?= =?us-ascii?q?OE4IZBIYPBYouDIkxjl6Hc40Nk1yXeR85gVEyGiOCeAmCOg8cgWd3iB4BJQeCG?= =?us-ascii?q?QEBAQ?= Received: from tarius.tycho.ncsc.mil ([144.51.242.1]) by EMSM-GH1-UEA10.NCSC.MIL with ESMTP; 28 Nov 2017 13:24:40 +0000 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 vASDO86P018710; Tue, 28 Nov 2017 08:24:16 -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 vAS3XrDg013441 for ; Mon, 27 Nov 2017 22:33:53 -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 vAS3Xogt027364; Mon, 27 Nov 2017 22:33:50 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A1AIAQAb2Bxaf3IYGNZcHAEBAQQBAQoBA?= =?us-ascii?q?YMQKWluJ44fdI4ggnuVbxCCAQ8ahRyEdj8YAQEBAQEBAQEBEwEBCxaGHQ0ZATg?= =?us-ascii?q?BFYEpEogbAzSBNwEDFQMBqHM6gwoFgQKES4IeAQEIHAQIgzqBNlGDPoJ1gw4Tg?= =?us-ascii?q?hYEhg8FiisMiTGOXodyjQ2TW5d0H4IJMhojgncJgjoPHIFnd4dcASUHghkBAQE?= X-IPAS-Result: =?us-ascii?q?A1AIAQAb2Bxaf3IYGNZcHAEBAQQBAQoBAYMQKWluJ44fdI4?= =?us-ascii?q?ggnuVbxCCAQ8ahRyEdj8YAQEBAQEBAQEBEwEBCxaGHQ0ZATgBFYEpEogbAzSBN?= =?us-ascii?q?wEDFQMBqHM6gwoFgQKES4IeAQEIHAQIgzqBNlGDPoJ1gw4TghYEhg8FiisMiTG?= =?us-ascii?q?OXodyjQ2TW5d0H4IJMhojgncJgjoPHIFnd4dcASUHghkBAQE?= X-IronPort-AV: E=Sophos;i="5.44,466,1505793600"; d="scan'208";a="128159" Received: from emsm-gh1-uea11.ncsc.mil ([214.29.60.35]) by goalie.tycho.ncsc.mil with ESMTP; 27 Nov 2017 22:33:49 -0500 IronPort-PHdr: =?us-ascii?q?9a23=3AUy/hWRAYtPLN7bpjHNRbUyQJP3N1i/DPJgcQr6Af?= =?us-ascii?q?oPdwSPX9oMbcNUDSrc9gkEXOFd2CrakV26yO6+jJYi8p2d65qncMcZhBBVcuqP?= =?us-ascii?q?49uEgeOvODElDxN/XwbiY3T4xoXV5h+GynYwAOQJ6tL1LdrWev4jEMBx7xKRR6?= =?us-ascii?q?JvjvGo7Vks+7y/2+94fdbghMhzexe69+IAmrpgjNq8cahpdvJLwswRXTuHtIfO?= =?us-ascii?q?pWxWJsJV2Nmhv3+9m98p1+/SlOovwt78FPX7n0cKQ+VrxYES8pM3sp683xtBnM?= =?us-ascii?q?VhWA630BWWgLiBVIAgzF7BbnXpfttybxq+Rw1DWGMcDwULs5Xymp4aV2Rx/ykC?= =?us-ascii?q?oJKj43/n/ZhMJzi6xWuw6tqwBlzoLIeoyZKOZyc6XAdt0aX2pBWcNRWjRdDIO9?= =?us-ascii?q?c4QPD/AOPfxFoILgpVUBtxq+BQ+yC+P01zRFgWX23awm3OQhCw7GxhEvEMoSv3?= =?us-ascii?q?vMrNX6LqYSUearw6nT1jjMdO9W2Tb76IjUbB8hu/eMUqxsccbL1UYvEAbFg0yW?= =?us-ascii?q?pIf4MT2V0eENvHKa7+pmTe+vk3Qoqxx1ojS2w8csjY7JhpgLxVze6Sp5x4M1KN?= =?us-ascii?q?ulQ0B4ed6pCIVcuzyVOodsXM8vTHtktDg1x7EcpJK3YScHxIwkyhLCcfCLboaF?= =?us-ascii?q?7gz5WOueIzp0nm9pdby/ihu07EOu0PfzVtOu31ZPtidFksfDtnQK1xHL98iIVv?= =?us-ascii?q?x9/kO81TuLzwDc8PxILEEumaXFNZEhx6UwlpUJvUTGBCD2mUH2gLWTdkUl/uik?= =?us-ascii?q?8+XnYrP4qZ+AL4J4lBzyP6s0lsChDuk0KBYCUmeB9eihybHu8lX1QLBQgf03lq?= =?us-ascii?q?nZvoraJcMepqOhGQ9V05os6xalADe8zdsXhWUII0pFeB2djojpPU/BIOvjAPik?= =?us-ascii?q?n1SskTFrx+zYMb37BJXCMGTDnK39crZ67k5Q0BAzwsxH55JIFrEBJ+r+WlTsu9?= =?us-ascii?q?zDFRI5Lwy1zPrnCNV6zI8eX3mPDbWDPKPdtl+I+PolI/OQa48NpDb9N/8l6ub1?= =?us-ascii?q?jXAnnV8dfK+p3YYYaX2jAvRnI1mWYXrrgtsbF2cKpRAxQPbliF2FTz4AL0q1Cr?= =?us-ascii?q?kx4jA9FZKOEZbIRofrhqeImii8ANkeYG1aBl2SOWnnep/CWPoWbi+WZMh7nXhM?= =?us-ascii?q?UbmnVp9kzhqyrCfkxLd9aOnZ4CsVsdTkztcxr+nSkwwisCd5BNmH0n2cCmRzkn?= =?us-ascii?q?4MShco061l509w0FGO1e5/mfMLO8ZU4qZzUww6PITQh8xzCtb/QUqVZNaCSF+8?= =?us-ascii?q?TuKtNjE4T9Q82PcEf0d7B9i4iB3fmSGtBulGxPSwGJUo//eEjDDKLMFnxiOe2Q?= =?us-ascii?q?=3D=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0AJAQCX1xxaf3IYGNZcHAEBAQQBAQoBA?= =?us-ascii?q?YMQKWluJ44fdI4ggnuVbxCCAQ8ahRyEdj8YAQEBAQEBAQEBARIBAQsWXYI4IoJ?= =?us-ascii?q?mDRkBOAEVgSkSiBsDNIE3AQMVAwGocjqDCgWBAoRLgh4BAQgcBAiDOoE2UYM+g?= =?us-ascii?q?nWDDhOCFgSCbwyDFAWKKwyJMY5eh3KNDZNbl3QfggkyGiOCdwmCOg8cgWd3h1w?= =?us-ascii?q?BJQeCGQEBAQ?= X-IPAS-Result: =?us-ascii?q?A0AJAQCX1xxaf3IYGNZcHAEBAQQBAQoBAYMQKWluJ44fdI4?= =?us-ascii?q?ggnuVbxCCAQ8ahRyEdj8YAQEBAQEBAQEBARIBAQsWXYI4IoJmDRkBOAEVgSkSi?= =?us-ascii?q?BsDNIE3AQMVAwGocjqDCgWBAoRLgh4BAQgcBAiDOoE2UYM+gnWDDhOCFgSCbwy?= =?us-ascii?q?DFAWKKwyJMY5eh3KNDZNbl3QfggkyGiOCdwmCOg8cgWd3h1wBJQeCGQEBAQ?= X-IronPort-AV: E=Sophos;i="5.44,466,1505779200"; d="scan'208";a="6395157" X-IronPort-Outbreak-Status: No, level 0, Unknown - Unknown Received: from ucol19pa16.eemsg.mail.mil ([214.24.24.114]) by emsm-gh1-uea11.NCSC.MIL with ESMTP; 28 Nov 2017 03:33:45 +0000 X-EEMSG-check-005: 0 X-EEMSG-check-006: 000-001;47d1c7c0-8210-4181-a05a-1e599e4ad2c4 Authentication-Results: ucol19pa06.eemsg.mail.mil; dkim=permerror (key too small [TEST]) header.i=@btinternet.com X-EEMSG-check-008: 384092475|UCOL19PA06_EEMSG_MP4.csd.disa.mil X-EEMSG-check-001: false X-EEMSG-SBRS: 3.5 X-EEMSG-ORIG-IP: 65.20.0.201 X-EEMSG-check-002: true X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0C0AAAeohxah8kAFEFcg0GBEm6POqcJEIIBD4U2hTUYAgEBAQEBAQETAQEBCA0JCCgvhUAmATgBFYEpiGSBNwEYBKk7gwoFgQKES4JEBAiDOoE2hwSFNwSCbwyDFAWKK4k9jl6Hco0Nk1uXdB+CCTIaI4VZgXOIXAElB4IZAQEB X-IPAS-Result: A0C0AAAeohxah8kAFEFcg0GBEm6POqcJEIIBD4U2hTUYAgEBAQEBAQETAQEBCA0JCCgvhUAmATgBFYEpiGSBNwEYBKk7gwoFgQKES4JEBAiDOoE2hwSFNwSCbwyDFAWKK4k9jl6Hco0Nk1uXdB+CCTIaI4VZgXOIXAElB4IZAQEB Received: from rgout0202.bt.lon5.cpcloud.co.uk (HELO rgout02.bt.lon5.cpcloud.co.uk) ([65.20.0.201]) by ucol19pa06.eemsg.mail.mil with ESMTP; 27 Nov 2017 19:32:36 +0000 X-OWM-Source-IP: 81.132.47.135 (GB) X-OWM-Env-Sender: richard_c_haines@btinternet.com X-Junkmail-Premium-Raw: score=10/50, refid=2.7.2:2017.11.27.190016:17:10.433, ip=, rules=__HAS_FROM, __FRAUD_WEBMAIL_FROM, __TO_MALFORMED_2, __TO_NO_NAME, __HAS_CC_HDR, __MULTIPLE_RCPTS_CC_X2, __CC_NAME, __CC_NAME_DIFF_FROM_ACC, __SUBJ_ALPHA_END, __HAS_MSGID, __SANE_MSGID, __HAS_X_MAILER, __FROM_DOMAIN_IN_ANY_CC1, __TO_IN_SUBJECT, __ANY_URI, __URI_WITH_PATH, __FRAUD_BODY_WEBMAIL, __CP_URI_IN_BODY, __URI_IN_BODY, __URI_NOT_IMG, __NO_HTML_TAG_RAW, BODY_SIZE_10000_PLUS, __MIME_TEXT_P1, __MIME_TEXT_ONLY, __URI_NS, HTML_00_01, HTML_00_10, __FRAUD_WEBMAIL, __FROM_DOMAIN_IN_RCPT, __CC_REAL_NAMES, MULTIPLE_RCPTS, __PHISH_SPEAR_STRUCTURE_1, TO_IN_SUBJECT, __MIME_TEXT_P, NO_URI_HTTPS, URI_WITH_PATH_ONLY Received: from localhost.localdomain (81.132.47.135) by rgout02.bt.lon5.cpcloud.co.uk (9.0.019.13-1) (authenticated as richard_c_haines@btinternet.com) id 59D91D94055AD842; Mon, 27 Nov 2017 19:32:24 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=btinternet.com; s=btcpcloud; t=1511811161; bh=eCmX4ubuvqYd7WHBK5jby3lDQQqLAA+EHP8hwgOPOKw=; h=From:To:Cc:Subject:Date:Message-Id:X-Mailer; b=mjA1PHCRff/LJttJ0WQhKP50CJkol8wkbekCOA87SRBWSRc79u5P/BsCujShGf64HCXVdcRV8eblq5jMOfHEGQKumf2UjdxD3mVQlTueBR91NKwwE2lqRj3/Q9PsQDCTAOuZVzoE5ZChfN2jzdRl7YY0Hnyv9umKgIBjX7qMHYA= X-EEMSG-check-009: 444-444 From: Richard Haines To: selinux@tycho.nsa.gov, netdev@vger.kernel.org, linux-sctp@vger.kernel.org, linux-security-module@vger.kernel.org Date: Mon, 27 Nov 2017 19:32:17 +0000 Message-Id: <20171127193217.2768-1-richard_c_haines@btinternet.com> X-Mailer: git-send-email 2.14.3 X-Mailman-Approved-At: Tue, 28 Nov 2017 08:24:06 -0500 Subject: [PATCH 4/4] selinux: Add SCTP support X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: Cc: marcelo.leitner@gmail.com, nhorman@tuxdriver.com, vyasevich@gmail.com, sds@tycho.nsa.gov Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP The SELinux SCTP implementation is explained in: Documentation/security/SELinux-sctp.rst Signed-off-by: Richard Haines --- Documentation/security/SELinux-sctp.rst | 104 ++++++++++++ security/selinux/hooks.c | 278 +++++++++++++++++++++++++++++--- security/selinux/include/classmap.h | 2 +- security/selinux/include/netlabel.h | 15 +- security/selinux/include/objsec.h | 4 + security/selinux/netlabel.c | 128 +++++++++++++-- 6 files changed, 499 insertions(+), 32 deletions(-) create mode 100644 Documentation/security/SELinux-sctp.rst diff --git a/Documentation/security/SELinux-sctp.rst b/Documentation/security/SELinux-sctp.rst new file mode 100644 index 0000000..f6a9162 --- /dev/null +++ b/Documentation/security/SELinux-sctp.rst @@ -0,0 +1,104 @@ +SCTP SELinux Support +===================== + +Security Hooks +=============== + +The ``Documentation/security/LSM-sctp.rst`` document describes how the +following sctp security hooks are utilised:: + + security_sctp_assoc_request() + security_sctp_bind_connect() + security_sctp_sk_clone() + security_inet_conn_established() + + +Policy Statements +================== +The following class and permissions to support SCTP are available within the +kernel:: + + class sctp_socket inherits socket { node_bind } + +whenever the following policy capability is enabled:: + + policycap extended_socket_class; + +SELinux SCTP support adds the ``name_connect`` permission for connecting +to a specific port type and the ``association`` permission that is explained +in the section below. + +If userspace tools have been updated, SCTP will support the ``portcon`` +statement as shown in the following example:: + + portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0 + + +SCTP Bind, Connect and ASCONF Chunk Parameter Permission Checks +================================================================ +The hook ``security_sctp_bind_connect()`` is called by SCTP to check +permissions required for ipv4/ipv6 addresses based on the ``@optname`` as +follows:: + + ------------------------------------------------------------------ + | BIND Permission Checks | + | @optname | @address contains | + |----------------------------|-----------------------------------| + | SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses | + | SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address | + | SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address | + ------------------------------------------------------------------ + + ------------------------------------------------------------------ + | CONNECT Permission Checks | + | @optname | @address contains | + |----------------------------|-----------------------------------| + | SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses | + | SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses | + | SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address | + | SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address | + ------------------------------------------------------------------ + + +SCTP Peer Labeling +=================== +An SCTP socket will only have one peer label assigned to it. This will be +assigned during the establishment of the first association. Once the peer +label has been assigned, any new associations will have the ``association`` +permission validated by checking the socket peer sid against the received +packets peer sid to determine whether the association should be allowed or +denied. + +NOTES: + 1) If peer labeling is not enabled, then the peer context will always be + ``SECINITSID_UNLABELED`` (``unlabeled_t`` in Reference Policy). + + 2) As SCTP can support more than one transport address per endpoint + (multi-homing) on a single socket, it is possible to configure policy + and NetLabel to provide different peer labels for each of these. As the + socket peer label is determined by the first associations transport + address, it is recommended that all peer labels are consistent. + + 3) **getpeercon**\(3) may be used by userspace to retrieve the sockets peer + context. + + 4) While not SCTP specific, be aware when using NetLabel that if a label + is assigned to a specific interface, and that interface 'goes down', + then the NetLabel service will remove the entry. Therefore ensure that + the network startup scripts call **netlabelctl**\(8) to set the required + label (see **netlabel-config**\(8) helper script for details). + + 5) The NetLabel SCTP peer labeling rules apply as discussed in the following + set of posts tagged "netlabel" at: http://www.paul-moore.com/blog/t. + + 6) CIPSO is only supported for IPv4 addressing: ``socket(AF_INET, ...)`` + CALIPSO is only supported for IPv6 addressing: ``socket(AF_INET6, ...)`` + + Note the following when testing CIPSO/CALIPSO: + a) CIPSO will send an ICMP packet if an SCTP packet cannot be + delivered because of an invalid label. + b) CALIPSO does not send an ICMP packet, just silently discards it. + + 7) IPSEC is not supported as RFC 3554 - sctp/ipsec support has not been + implemented in userspace (**racoon**\(8) or **ipsec_pluto**\(8)), + although the kernel supports SCTP/IPSEC. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0110bb5..7bd5886 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -67,6 +67,8 @@ #include #include #include +#include +#include #include #include /* for Unix socket types */ #include /* for Unix socket types */ @@ -4136,6 +4138,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, break; } +#if IS_ENABLED(CONFIG_IP_SCTP) + case IPPROTO_SCTP: { + struct sctphdr _sctph, *sh; + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + offset += ihlen; + sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); + if (sh == NULL) + break; + + ad->u.net->sport = sh->source; + ad->u.net->dport = sh->dest; + break; + } +#endif default: break; } @@ -4209,6 +4228,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, break; } +#if IS_ENABLED(CONFIG_IP_SCTP) + case IPPROTO_SCTP: { + struct sctphdr _sctph, *sh; + + sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); + if (sh == NULL) + break; + + ad->u.net->sport = sh->source; + ad->u.net->dport = sh->dest; + break; + } +#endif /* includes fragments */ default: break; @@ -4398,6 +4430,10 @@ static int selinux_socket_post_create(struct socket *sock, int family, sksec = sock->sk->sk_security; sksec->sclass = sclass; sksec->sid = sid; + /* Allows detection of the first association on this socket */ + if (sksec->sclass == SECCLASS_SCTP_SOCKET) + sksec->sctp_assoc_state = SCTP_ASSOC_UNSET; + err = selinux_netlbl_socket_post_create(sock->sk, family); } @@ -4418,11 +4454,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (err) goto out; - /* - * If PF_INET or PF_INET6, check name_bind permission for the port. - * Multiple address binding for SCTP is not supported yet: we just - * check the first address now. - */ + /* If PF_INET or PF_INET6, check name_bind permission for the port. */ family = sk->sk_family; if (family == PF_INET || family == PF_INET6) { char *addrp; @@ -4434,7 +4466,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in unsigned short snum; u32 sid, node_perm; - if (family == PF_INET) { + /* + * sctp_bindx(3) calls via selinux_sctp_bind_connect() + * that validates multiple binding addresses. Because of this + * need to check address->sa_family as it is possible to have + * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. + */ + if (address->sa_family == AF_INET) { if (addrlen < sizeof(struct sockaddr_in)) { err = -EINVAL; goto out; @@ -4488,6 +4526,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in node_perm = DCCP_SOCKET__NODE_BIND; break; + case SECCLASS_SCTP_SOCKET: + node_perm = SCTP_SOCKET__NODE_BIND; + break; + default: node_perm = RAWIP_SOCKET__NODE_BIND; break; @@ -4502,7 +4544,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ad.u.net->sport = htons(snum); ad.u.net->family = family; - if (family == PF_INET) + if (address->sa_family == AF_INET) ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; else ad.u.net->v6info.saddr = addr6->sin6_addr; @@ -4516,7 +4558,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in return err; } -static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) +/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) + * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt + */ +static int selinux_socket_connect_helper(struct socket *sock, + struct sockaddr *address, int addrlen) { struct sock *sk = sock->sk; struct sk_security_struct *sksec = sk->sk_security; @@ -4527,10 +4573,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, return err; /* - * If a TCP or DCCP socket, check name_connect permission for the port. + * If a TCP, DCCP or SCTP socket, check name_connect permission + * for the port. */ if (sksec->sclass == SECCLASS_TCP_SOCKET || - sksec->sclass == SECCLASS_DCCP_SOCKET) { + sksec->sclass == SECCLASS_DCCP_SOCKET || + sksec->sclass == SECCLASS_SCTP_SOCKET) { struct common_audit_data ad; struct lsm_network_audit net = {0,}; struct sockaddr_in *addr4 = NULL; @@ -4538,7 +4586,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, unsigned short snum; u32 sid, perm; - if (sk->sk_family == PF_INET) { + /* sctp_connectx(3) calls via selinux_sctp_bind_connect() + * that validates multiple connect addresses. Because of this + * need to check address->sa_family as it is possible to have + * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. + */ + if (address->sa_family == AF_INET) { addr4 = (struct sockaddr_in *)address; if (addrlen < sizeof(struct sockaddr_in)) return -EINVAL; @@ -4552,10 +4605,19 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, err = sel_netport_sid(sk->sk_protocol, snum, &sid); if (err) - goto out; + return err; - perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? - TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; + switch (sksec->sclass) { + case SECCLASS_TCP_SOCKET: + perm = TCP_SOCKET__NAME_CONNECT; + break; + case SECCLASS_DCCP_SOCKET: + perm = DCCP_SOCKET__NAME_CONNECT; + break; + case SECCLASS_SCTP_SOCKET: + perm = SCTP_SOCKET__NAME_CONNECT; + break; + } ad.type = LSM_AUDIT_DATA_NET; ad.u.net = &net; @@ -4563,13 +4625,24 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, ad.u.net->family = sk->sk_family; err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); if (err) - goto out; + return err; } - err = selinux_netlbl_socket_connect(sk, address); + return 0; +} -out: - return err; +/* Supports connect(2), see comments in selinux_socket_connect_helper() */ +static int selinux_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + int err; + struct sock *sk = sock->sk; + + err = selinux_socket_connect_helper(sock, address, addrlen); + if (err) + return err; + + return selinux_netlbl_socket_connect(sk, address); } static int selinux_socket_listen(struct socket *sock, int backlog) @@ -4832,7 +4905,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op u32 peer_sid = SECSID_NULL; if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || - sksec->sclass == SECCLASS_TCP_SOCKET) + sksec->sclass == SECCLASS_TCP_SOCKET || + sksec->sclass == SECCLASS_SCTP_SOCKET) peer_sid = sksec->peer_sid; if (peer_sid == SECSID_NULL) return -ENOPROTOOPT; @@ -4945,6 +5019,169 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) sksec->sclass = isec->sclass; } +/* Called whenever SCTP receives an INIT chunk. This happens when an incoming + * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association + * already present). + * The lock is to ensure sksec->sctp_assoc_state. + */ +static DEFINE_SPINLOCK(assoc_lock); +static int selinux_sctp_assoc_request(struct sctp_endpoint *ep, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec = ep->base.sk->sk_security; + struct common_audit_data ad; + struct lsm_network_audit net = {0,}; + u8 peerlbl_active; + u32 peer_sid = SECINITSID_UNLABELED; + u32 conn_sid; + int err = 0; + + if (!selinux_policycap_extsockclass) + return 0; + + spin_lock(&assoc_lock); + + peerlbl_active = selinux_peerlbl_enabled(); + + if (peerlbl_active) { + /* This will return peer_sid = SECSID_NULL if there are + * no peer labels, see security_net_peersid_resolve(). + */ + err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family, + &peer_sid); + if (err) + goto err; + + if (peer_sid == SECSID_NULL) + peer_sid = SECINITSID_UNLABELED; + } + + if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) { + sksec->sctp_assoc_state = SCTP_ASSOC_SET; + + /* Here as first association on socket. As the peer SID + * was allowed by peer recv (and the netif/node checks), + * then it is approved by policy and used as the primary + * peer SID for getpeercon(3). + */ + sksec->peer_sid = peer_sid; + } else if (sksec->peer_sid != peer_sid) { + /* Other association peer SIDs are checked to enforce + * consistency among the peer SIDs. + */ + ad.type = LSM_AUDIT_DATA_NET; + ad.u.net = &net; + ad.u.net->sk = ep->base.sk; + err = avc_has_perm(sksec->peer_sid, peer_sid, sksec->sclass, + SCTP_SOCKET__ASSOCIATION, &ad); + if (err) + goto err; + } + + /* Compute the MLS component for the connection and store + * the information in ep. This will be used by SCTP TCP type + * sockets and peeled off connections as they cause a new + * socket to be generated. selinux_sctp_sk_clone() will then + * plug this into the new socket. + */ + err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid); + if (err) + goto err; + + ep->secid = conn_sid; + ep->peer_secid = peer_sid; + + /* Set any NetLabel labels including CIPSO/CALIPSO options. */ + err = selinux_netlbl_sctp_assoc_request(ep, skb); + +err: + spin_unlock(&assoc_lock); + return err; +} + +/* + * Check if sctp IPv4/IPv6 addresses are valid for binding or connecting + * based on their @optname. + */ +static int selinux_sctp_bind_connect(struct sock *sk, int optname, + struct sockaddr *address, + int addrlen) +{ + int len, err = 0, walk_size = 0; + void *addr_buf; + struct sockaddr *addr; + struct socket *sock; + + if (!selinux_policycap_extsockclass) + return 0; + + /* Process one or more addresses that may be IPv4 or IPv6 */ + sock = sk->sk_socket; + addr_buf = address; + + while (walk_size < addrlen) { + addr = addr_buf; + switch (addr->sa_family) { + case AF_INET: + len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; + default: + return -EAFNOSUPPORT; + } + + err = -EINVAL; + switch (optname) { + /* Bind checks */ + case SCTP_PRIMARY_ADDR: + case SCTP_SET_PEER_PRIMARY_ADDR: + case SCTP_SOCKOPT_BINDX_ADD: + err = selinux_socket_bind(sock, addr, len); + break; + /* Connect checks */ + case SCTP_SOCKOPT_CONNECTX: + case SCTP_PARAM_SET_PRIMARY: + case SCTP_PARAM_ADD_IP: + case SCTP_SENDMSG_CONNECT: + err = selinux_socket_connect_helper(sock, addr, len); + if (err) + return err; + + err = selinux_netlbl_sctp_socket_connect(sk, addr); + break; + } + + if (err) + return err; + + addr_buf += len; + walk_size += len; + } + + return 0; +} + +/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */ +static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk, + struct sock *newsk) +{ + struct sk_security_struct *sksec = sk->sk_security; + struct sk_security_struct *newsksec = newsk->sk_security; + + /* If policy does not support SECCLASS_SCTP_SOCKET then call + * the non-sctp clone version. + */ + if (!selinux_policycap_extsockclass) + return selinux_sk_clone_security(sk, newsk); + + newsksec->sid = ep->secid; + newsksec->peer_sid = ep->peer_secid; + newsksec->sclass = sksec->sclass; + newsksec->nlbl_state = sksec->nlbl_state; +} + static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct request_sock *req) { @@ -6433,6 +6670,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), LSM_HOOK_INIT(sock_graft, selinux_sock_graft), + LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request), + LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone), + LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect), LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 35ffb29..099065e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -175,7 +175,7 @@ struct security_class_mapping secclass_map[] = { { COMMON_CAP2_PERMS, NULL } }, { "sctp_socket", { COMMON_SOCK_PERMS, - "node_bind", NULL } }, + "node_bind", "name_connect", "association", NULL } }, { "icmp_socket", { COMMON_SOCK_PERMS, "node_bind", NULL } }, diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 75686d5..313c8bd 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "avc.h" #include "objsec.h" @@ -53,7 +54,8 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, u16 family, u32 sid); - +int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, + struct sk_buff *skb); int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); @@ -65,6 +67,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, int level, int optname); int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); +int selinux_netlbl_sctp_socket_connect(struct sock *sk, struct sockaddr *addr); #else static inline void selinux_netlbl_cache_invalidate(void) @@ -114,6 +117,11 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk, return 0; } +static inline int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, + struct sk_buff *skb) +{ + return 0; +} static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) { @@ -146,6 +154,11 @@ static inline int selinux_netlbl_socket_connect(struct sock *sk, { return 0; } +static inline int selinux_netlbl_sctp_socket_connect(struct sock *sk, + struct sockaddr *addr) +{ + return 0; +} #endif /* CONFIG_NETLABEL */ #endif diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 6ebc61e..e319d5d 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -130,6 +130,10 @@ struct sk_security_struct { u32 sid; /* SID of this object */ u32 peer_sid; /* SID of peer */ u16 sclass; /* sock security class */ + enum { /* SCTP association state */ + SCTP_ASSOC_UNSET = 0, + SCTP_ASSOC_SET, + } sctp_assoc_state; }; struct tun_security_struct { diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index aaba667..ac23f29 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -250,6 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, sk = skb_to_full_sk(skb); if (sk != NULL) { struct sk_security_struct *sksec = sk->sk_security; + if (sksec->nlbl_state != NLBL_REQSKB) return 0; secattr = selinux_netlbl_sock_getattr(sk, sid); @@ -270,6 +271,61 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, return rc; } +/** + * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association. + * @ep: incoming association endpoint. + * @skb: the packet. + * + * Description: + * A new incoming connection is represented by @ep, ...... + * Returns zero on success, negative values on failure. + * + */ +int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, + struct sk_buff *skb) +{ + int rc; + struct netlbl_lsm_secattr secattr; + struct sk_security_struct *sksec = ep->base.sk->sk_security; + struct sockaddr *addr; + struct sockaddr_in addr4; +#if IS_ENABLED(CONFIG_IPV6) + struct sockaddr_in6 addr6; +#endif + + if (ep->base.sk->sk_family != PF_INET && + ep->base.sk->sk_family != PF_INET6) + return 0; + + netlbl_secattr_init(&secattr); + rc = security_netlbl_sid_to_secattr(ep->secid, &secattr); + if (rc != 0) + goto assoc_request_return; + + /* Move skb hdr address info to a struct sockaddr and then call + * netlbl_conn_setattr(). + */ + if (ip_hdr(skb)->version == 4) { + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; + addr = (struct sockaddr *)&addr4; +#if IS_ENABLED(CONFIG_IPV6) + } else { + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = ipv6_hdr(skb)->saddr; + addr = (struct sockaddr *)&addr6; +#endif + } + + rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr); + if (rc == 0) + sksec->nlbl_state = NLBL_LABELED; + +assoc_request_return: + netlbl_secattr_destroy(&secattr); + return rc; +} + /** * selinux_netlbl_inet_conn_request - Label an incoming stream connection * @req: incoming connection request socket @@ -470,7 +526,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, } /** - * selinux_netlbl_socket_connect - Label a client-side socket on connect + * selinux_netlbl_socket_connect_helper - Help label a client-side socket on + * connect * @sk: the socket to label * @addr: the destination address * @@ -479,18 +536,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, * Returns zero values on success, negative values on failure. * */ -int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) +static int selinux_netlbl_socket_connect_helper(struct sock *sk, + struct sockaddr *addr) { int rc; struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr *secattr; - if (sksec->nlbl_state != NLBL_REQSKB && - sksec->nlbl_state != NLBL_CONNLABELED) - return 0; - - lock_sock(sk); - /* connected sockets are allowed to disconnect when the address family * is set to AF_UNSPEC, if that is what is happening we want to reset * the socket */ @@ -498,18 +550,72 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) netlbl_sock_delattr(sk); sksec->nlbl_state = NLBL_REQSKB; rc = 0; - goto socket_connect_return; + return rc; } secattr = selinux_netlbl_sock_genattr(sk); if (secattr == NULL) { rc = -ENOMEM; - goto socket_connect_return; + return rc; } rc = netlbl_conn_setattr(sk, addr, secattr); if (rc == 0) sksec->nlbl_state = NLBL_CONNLABELED; -socket_connect_return: + return rc; +} + +/** + * selinux_netlbl_socket_connect - Label a client-side socket on connect + * @sk: the socket to label + * @addr: the destination address + * + * Description: + * Attempt to label a connected socket with NetLabel using the given address. + * Returns zero values on success, negative values on failure. + * + */ +int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) +{ + int rc; + struct sk_security_struct *sksec = sk->sk_security; + + if (sksec->nlbl_state != NLBL_REQSKB && + sksec->nlbl_state != NLBL_CONNLABELED) + return 0; + + lock_sock(sk); + rc = selinux_netlbl_socket_connect_helper(sk, addr); release_sock(sk); + + return rc; +} + +/** + * selinux_netlbl_sctp_socket_connect - Label an SCTP client-side socket on a + * connect + * @sk: the socket to label + * @addr: the destination address + * + * Description: + * Attempt to label a connected socket with NetLabel using the given address + * when called by the SCTP protocol layer. The situations handled are: + * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2), whenever a new IP address + * is added or when a new primary address is selected. Note that an SCTP + * connect(2) call happens before the SCTP protocol layer and is handled via + * selinux_netlbl_socket_connect() + * Returns zero values on success, negative values on failure. + * + */ +int selinux_netlbl_sctp_socket_connect(struct sock *sk, struct sockaddr *addr) +{ + int rc; + struct sk_security_struct *sksec = sk->sk_security; + + if (sksec->nlbl_state != NLBL_REQSKB && + sksec->nlbl_state != NLBL_CONNLABELED) + return 0; + + rc = selinux_netlbl_socket_connect_helper(sk, addr); + return rc; }