From patchwork Wed Dec 14 13:39:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Haines X-Patchwork-Id: 9474181 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 6423C607EE for ; Wed, 14 Dec 2016 13:41:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 51A7628709 for ; Wed, 14 Dec 2016 13:41:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4605328726; Wed, 14 Dec 2016 13:41:57 +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=ham version=3.3.1 Received: from emsm-gh1-uea11.nsa.gov (emsm-gh1-uea11.nsa.gov [8.44.101.9]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 24B9E28709 for ; Wed, 14 Dec 2016 13:41:53 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.33,346,1477958400"; d="scan'208";a="1562709" IronPort-PHdr: =?us-ascii?q?9a23=3A3bPlSBAVoJHxIz/wVAiRUyQJP3N1i/DPJgcQr6Af?= =?us-ascii?q?oPdwSPr+rsWwAkXT6L1XgUPTWs2DsrQf2rGQ7f6rAzdIyK3CmUhKSIZLWR4BhJ?= =?us-ascii?q?detC0bK+nBN3fGKuX3ZTcxBsVIWQwt1Xi6NU9IBJS2PAWK8TW94jEIBxrwKxd+?= =?us-ascii?q?KPjrFY7OlcS30P2594HObwlSijewZb1/IA+3oAjQucUan4VvIbstxxXUpXdFZ/?= =?us-ascii?q?5Yzn5yK1KJmBb86Maw/Jp9/ClVpvks6c1OX7jkcqohVbBXAygoPG4z5M3wqBnM?= =?us-ascii?q?VhCP6WcGUmUXiRVHHQ7I5wznU5jrsyv6su192DSGPcDzULs5Vyiu47ttRRT1hi?= =?us-ascii?q?gHLTo5+3zJhMJ2gqxQvRatqwV/zoLRZoyeKfhwcb7Hfd4CRWRPQNtfWSJCDI27?= =?us-ascii?q?d4sCDfcNMOhXoIbhqFUBswC+CBKwBO7t0DJEmmX70bEk3+knDArI3BYgH9ULsH?= =?us-ascii?q?nMsNv1NbsdUeCvw6nS0DrIcvFY1i386IjObB8huuyHULVqccrQ1UYvFxnKjk+N?= =?us-ascii?q?poP9IzyazuQNvHKa7+pmS+2vkHUqpBptojiuwMcslpfGhpgTyl/a6SV12po6Jd?= =?us-ascii?q?q9SENiZ9OvDZVetyafN4RsQ8MiRXlluD0kxb0CuJ67ejUKyZs/xx7FbPyHcZaH?= =?us-ascii?q?7Q7/VOqLJjd4nn1ldKqkhxa17Eig0PHzWde60FZNtCpFncfDumoL1xPN9siLUv?= =?us-ascii?q?R9/ka92TaPygDc8ftILlwzlareM5Ih2qQ/locXsUjaGy/2n0L2jLWIeUk+5ueo?= =?us-ascii?q?7OHnb7P7rZGfL495khzyP6shl8ClAek0LxICU3aU9OiizrHv4FX1TbZXgvEsj6?= =?us-ascii?q?XUvo7WKd4Uq6O7GQNY1oku5hCiBDm8ytsYh2MILFdddRKCiIjmJk/BLejjDfe6?= =?us-ascii?q?n1SsiDBrx+3aPrH5ApXCMHzDkLD5cLZh8UFc0gszzc1E555OFrEAIO78Wk/2tN?= =?us-ascii?q?DCCB82Lxe0zPr9BNV414MeXXqDAq6fMKzMrV+F/v8jLuaDaYMPuDvxNuIp6+Dh?= =?us-ascii?q?gHMng1MRYLGl3Z4NZ3C5GvRmLV+ZYX3pgtoZCmcFoA4+TO3siF2fXj9ffm29X6?= =?us-ascii?q?Uh5jE9FI2pE5zDS5uxgL2BwCi7HppWanpAClCXC3jkbYqEW/ASaC6KOM9ujiQE?= =?us-ascii?q?VaS9S48mzRyvtA77y71hLufP/y0YsYvv1Nlz5+HJkxE97yZ0D8ec02GTUW54hG?= =?us-ascii?q?UISCEq3Kpnu0xy1k+D0bRkg/xfDdFc+etJXR0gNZ7d1Ox3EMjyVRjbfteIU1am?= =?us-ascii?q?WtGmDistQd0v2dMOZFx9G9q6hBDZwyWqG6MVl6CMBJEs/KLcxWL+J8BhxHbHz6?= =?us-ascii?q?kslFwmQtNONWG/na5++RPTC5TOk0WDmKagbb4c0zLV9Gef0WqOu1lVUA1qXqXG?= =?us-ascii?q?WnAfe1Dbrdfj6UPBSL+uFK4rMgxbyc6NMqFKcMHmjU1aRPf/P9TTe3i+lHqqBR?= =?us-ascii?q?aJ2LyMdpHndH8B0yXYEkQElBoT/XmePwgkGiihu37eDCBpFV/3Y0Pj7+1+qHe8?= =?us-ascii?q?TkIvywGKclFh172w+hEPn/CcTOkT3r0csic7tzp0BEq9387RC9eYvAphcr9cYd?= =?us-ascii?q?Qm4Fdbzm/ZrAp9PpuuLqBnnFEedR57v0Xw2BVrEo9Ai9QlrGs2zApuLqKVyF1A?= =?us-ascii?q?eCmc3ZDsJLLXMHLy8Quxa6HIwFHRy8uW+qIV5PQ/sVXjsxmjFlA+/HV/z9lVz3?= =?us-ascii?q?yc643WDAUPTJ3xU1w49xxhqr7GZSk94p/b2md3MamoqDPC3cwmBPc9wBa6Y9hf?= =?us-ascii?q?KL+EFBP1E8ACAciuKegqm1y3YRIfJ+1d7rA7P9mhd/ec366rJulgliq8jWtb+I?= =?us-ascii?q?B9zl6M9y1kR+HVxZkF3+uX0RWJVzbzl1qursD3lppeZTEOAGW/0zLoBIhPaa1u?= =?us-ascii?q?ZYwLE3uhI9WrxtVigJ7gQ2BY9F+/CFMa38+pYwCeYED93Q1X00QXrmeqmS+5zz?= =?us-ascii?q?xyiT4ptK2f0DbJw+T4exoNInRLS3V6jVfwPYi0iMgXXEypbwgyiBup/F36yLZf?= =?us-ascii?q?pKR+KWnTXEhJcjPtL2F6U6uwsLuCbNJU6J8ytyVYTvi8a0iASrHhuxsazz/jH2?= =?us-ascii?q?xGyTAhcDGqvpH5kAJgiG2BK3ZyomHUedptxRjD/9zQX/lR3iAJRCNgkznYGkC8?= =?us-ascii?q?P8W1/dWTj5rDqvqxV3+lVpFJaybn15iPtCy/5W12Bh2/meu+mtj7HQg81i/0y8?= =?us-ascii?q?NmVSPWoxbgeoPrzbi1Mfp7fkl0A1/x8896GoVnnoQugpEdwmYaiYuR/XoDj2jz?= =?us-ascii?q?K89X2aTgY3oRXTQL2cLa4BD52E1/KXKE34H5WWubwst6fNS6YX0Z2iQm78BMFq?= =?us-ascii?q?iU8KZInSxvolq3tQjRe+Ryni8Byfsy734Xm/8JuAwwwSiGHLASG1RXPSz2mxSO?= =?us-ascii?q?8d++sL1dZHyzfrioyEp+gdehAamaog5GRXb5fowvEjNx7sVjMFPAyXPz5ZvieN?= =?us-ascii?q?XKatITrBKUmQ/aj+dJMJIxiuYKhS1/NGLlp3Il1uo7ggJ23Z6guoiHN3ti/Lii?= =?us-ascii?q?Dx5FLT36edkT+ir3gaZFmcaWwpqvEYl/FTUFW5voV/2oHywIufThKQmODCU2qm?= =?us-ascii?q?2HFrrHAQ+f9EBmomrBE5+xMXGXOH4ZzdB5SRmTOkNQnQcUXC8gkZ4hDACqw87h?= =?us-ascii?q?f1ll6TAN/FL4rQFMyu1wPRnlTmjfvBuoaiszSJWHIxpW7h1N513VMMyG8uJzGD?= =?us-ascii?q?pV/pu/owyRMWyUex5HDXkXVUCeAVDsIKWu78Ha8+eEHuq+M+fOYbKWpOxbTfiI?= =?us-ascii?q?wZav3ZV6/zaQLMqAJGJvD/sl1UpfRnB2B97Wmy0RRCANkSLCcdKbrg+m+iJrts?= =?us-ascii?q?C/7OjrWAX36IuVEbdTP89j+xWsjqeHMO6RhD10JixE2ZMJ33PIz6If3FEKgSF0?= =?us-ascii?q?azatCagAtTLKTK/InK9XFQQUaztrNMZT4aI83xNNOdXHitP71754iOQ6C1FZWl?= =?us-ascii?q?zggM6pYdYGI2anNFPIHEyLLqiJJSXXw8HrZqOxUaVQg/tPuBKuvzabElPjPjOY?= =?us-ascii?q?mjnoSR+gL/9DgDucPBxEt4G3agxtBnT7TNL6dh27N8d6giYtzrEzgnPKNHUcMS?= =?us-ascii?q?Rnc09Xtb2f8z9Xju9kG2Nf6nplLO+EmzuW7uTDNpkXseFrAjlvl+5A7nU10adV?= =?us-ascii?q?7DpDRPxzgifSqcRuo16+mOmV1jVnSAZOqipMhI+TpkVtI7vZ+YNPWXna5xIA9n?= =?us-ascii?q?6QBA4Up9R/Bd3gpbtQxsLJlK3tNDdI68jU8tcEB8jINMKHN2IsPgHoGD7bCwsF?= =?us-ascii?q?SyWmOnzBiENGkfGd7HuVooI9qpj2l5oEUqVbW0AtFvMGFkRlG8QPL414Xjw+j7?= =?us-ascii?q?6UktUF5X2mrBbPQsVau4rIVvOWAfr0LzaYgqNIZxwSwbP3NY4TLJH021R+allm?= =?us-ascii?q?m4THA1bQXddIoiF7dA80p0RM/2Z4TmIowULlbR2i4HwIGPGomR42jxdxbv429D?= =?us-ascii?q?fw+Vs3IETFpDcomkkrhdrlmSyRcCL2LKqoXoFXCy70uFYqP5P+RAZ1YwOyklJ4?= =?us-ascii?q?NDfYR7JRiL5gen5xhA/ap5RPBeZWTbdYbx8I2fGXe/Io3ExdqiWh2U9I++/FBo?= =?us-ascii?q?VnlAQ0bZ6stXJB1hlkbN4tO6PQIq9JwUJRhqKKpSCo0e8wzBUZJ0YX/2OYYDQI?= =?us-ascii?q?t1AQNrk6Oyqo+fRh6QqclDRZfGgBTPkqovVx9kMhIeuAyTng071CKkyrMeyQMb?= =?us-ascii?q?+ZsXDalcGUWlMwyl8Il05d8Lhsz8gjaFSbWFo1zLSNFxQELtHNKQBPb8VP83jT?= =?us-ascii?q?cz6Osf/TzpN1JYm9EP7nTfOWvqYOnk2kBBopH5gL7skZA5as10fYLcH6I7EbzR?= =?us-ascii?q?Ut5R/mK0+bA/RTfxKHijAHo9uwzJVvx4lSOikdAXlhMSWw/rvYuxUlgOSCXNgr?= =?us-ascii?q?eXcXRZELNmgsWM29lS9ZpGpPAyWq0uIDyQiC8z/9qj7WDDbic9ppfO2Uag90CN?= =?us-ascii?q?Gq5TU/9LC7hkPM8prAPW76Os5itcXR6e4BvJaIEfBUTaRns0jGgYVYQ2GqU2jV?= =?us-ascii?q?Ht6vPpTwd44sbd/0C3a9SFC/jSw6T9vpNta3MqeImR3oRZpTsISD0jAjL9GyGS?= =?us-ascii?q?wFGxhqoeED+KV8ZRYYbpUhfRHosh4yN6ulIAeXyt+uWXqiKSNKT/lDyuW3f7hX?= =?us-ascii?q?zy02buCkznshT5Y6wvK48U4LWZEGlBbexeysZ4NGSyj8BmRdexnTpSo+j2VhLf?= =?us-ascii?q?g9wuM+wBPOrFkdPCuGe/BuaGxBo94zH0iSIWlsBmo+WVCckZLJ4hSw0LAK4ytd?= =?us-ascii?q?g9FU3PVGsHjkvp7QejSsWLCrqZjOvCogasAmrLFrPYzlPMSGqIvUnibDQ5nIrg?= =?us-ascii?q?2FTCm6GuJGmthRJSJYR+VImWElOMEdpIVB6EowWd0lKLBVDqkjuKyqYyJ+DSEO?= =?us-ascii?q?1S8ZS5+A3Dsaj+im37valwuff4o6PxwBsJRChNwdUyhsbS4Fv6CjVp/Zl2mdRm?= =?us-ascii?q?gFPQcf9wJM6xwcloVoZODq/JLITINQyz5Ru/97STXEFp9z+lThV26Wn0b3SO+6?= =?us-ascii?q?k+OzxwJTzOjg0t4BWB5wEUJd3fpZllM0KLFrLKkdpoHKsiKJdUP+uGLi1u6mKU?= =?us-ascii?q?JMxsLKbFL4DZDKtWzmXi0b430USpdFyGvDGpQKjwp5dKErqU1WIICge0bx+zwk?= =?us-ascii?q?x4NtH7mjTc6l3ksro2waSimtCNdOF+ZmsFfLVzJ/eJCrtI/pO5NMTW9M4JedsU?= =?us-ascii?q?tWkF1xMy6lzppRM9tN7SMRUzVUrjWdudSzRNdF2cBoE58GOs1/tGvlGKNYJJiR?= =?us-ascii?q?pGU7taDtynDD5z8xq0u1xDK3G6+8TuJW4XceGhk3KGuCqkkjFews8n3d8lrVqF?= =?us-ascii?q?B74/9bBqSTjUV2uDt9BIpBBixO1X++NFlzUGNGvP9EKKvLd8xcQv8yZRCrOxw/?= =?us-ascii?q?Gv4m31CJ/U9uknfjZix+rA1a9D7BXwMsTykanq/tmSECqsGgITIbS4hHbS47YC?= =?us-ascii?q?fAKgKbnztavBdDa05wQJAWHsxK96sd3YRK4srIUVysJj0dXBx+KgI41uJSlEBZ?= =?us-ascii?q?vEqEeSDdDA+odffVvR10ZsqRrdCmI+rn8wtdjYPnqu84/b0ZR3K6gQ2tXczer4?= =?us-ascii?q?jku9KQrEuOaaH4P/e/YXLaTTjMjBGwhas/AJXQ+SjcLhZbIYFgyXU4eZjhFXLL?= =?us-ascii?q?PRNeKqIUPUpUT6Z6acldr+BbYM9ldqAJ+bNtBh2ZRxPvHpCvo+dcLlrJQzTRMT?= =?us-ascii?q?mB+PSloY3P9bzdVfTgZsuUynbbRKJ3O4x36SXnF7fvyoBS4Ez21elx9kliU1jJ?= =?us-ascii?q?LziBrMj9JgMM/MSidlHtvoczEjPSHZh9i2fiyV9Yd8oPXSKq9IoXyIlD5Hb3U+?= =?us-ascii?q?J43VD5sPdO+Ll89Yk3/7dpxN+2JafVN/tXqlJoDQaPBgp07JUtHHZwSH1Lbu8X?= =?us-ascii?q?NvjRYbwTjdrypODvC6wX9BqV9vRCZtvJO07NhsuyBiySRBFfgAgBrjsaIReG2P?= =?us-ascii?q?6eh694U8Clqvbl2kg1+VixMgYGzKxx5YeD4qeIvvHYYAbRzbceRqjnXcfzrrMy?= =?us-ascii?q?u0yM+/EriLkOdXFrbAG9FugSSNIdzH/6za821SIsD9/DH7X49f5bTHI5gijvlI?= =?us-ascii?q?1hH1gNAfMUGqeL/Z5CkWgmnezZKscWfbpGmmqVEh6kCLACw2ax6ySLOGllng3O?= =?us-ascii?q?0xboTGOv9l/5szF3TjbXwtf+lkpVSqO3Cl1MXyqoPk94tC2APBbyuNrwo6Q141?= =?us-ascii?q?k8Mnb4u9KViGuhJLRXEtXiK9yaOyY5v08YjJsrSdC13oAbA9W9Ks8L8H5idvve?= =?us-ascii?q?93+rkyhZrqdFnYXe+MaV+u7THXa6ka2XsLCNxC1cyngkvFEw9tGgOevI592RWf?= =?us-ascii?q?io0HwRTyhnsQvbQxG1sqDbr0wTOUGT0kfEgooKPt9D3Xk/y07p+vMuQM4p+wVY?= =?us-ascii?q?DYbAYOkOpTbtNzvo2Vyfec44VjGC0ztLGVL4CV94GKwn1WLxusLJkG3c+1wuRo?= =?us-ascii?q?l+bUzonwd3D5kiKUIw9FcX3jcDERITZhyBC7GoH0vlJ5MeVUcfcRSHwKS6eqAv?= =?us-ascii?q?0E11w7Og+OjTbehmCKoWLPpdjwmOnF9AGpINqqAeRb1xelBH+K7QvAjiBJDtX+?= =?us-ascii?q?L6mnooKf21Xsda/NgFuHQ45gawWQGg6YtD7rYck52IbbJLYZnSs8B680dn5CQA?= =?us-ascii?q?ejZLgBdhkxOzSfocq/z74tjHrJqo7f6jVKI2R+US9xU5HGp+gIXtj1Aku9HYzf?= =?us-ascii?q?9cSpfSiYT97g9CP2KKtJzd0xlmJuoEM5irc6p493UbOygeIGoDPd+Sa/Yi5i9t?= =?us-ascii?q?Nyvc51hZD8MDe9wYO9HNmRhOhU31WbFc7M7bGl6eC4dvac8o6273yDE68ZQiVO?= =?us-ascii?q?bv9CG5KYrZ715TI/NJlD9sm87apOgJ3frSDzAa4XuYaxhw2S6CzoeCCvbu8uWW?= =?us-ascii?q?ydHUUVwGEjQwU4hDODqI4RanSfatlJX1TgOU7df+gJM/dU2KXHO+gL8Isr1SHu?= =?us-ascii?q?5clCr0wiJSFofvh/Kaq9Cs8ndYtkVbEIZv6h3IAL5QPpRgORX2jMarREl8Bjfn?= =?us-ascii?q?eM7OaxouvPGbyfsL4+pjKUTxf5IbIggDy7Lg83VZVAxuSKT5vlyBR+IeeMNmSO?= =?us-ascii?q?/YrnBS8Y9gM7UAPESBq5zqoDZIr0o2AAwwZL8rsDNackjOnAtIW6f7o7MAkhET?= =?us-ascii?q?UcJltk9MF2OwP3g+5zndWaRWkqaREvoV/SuXTqAUVEVoKCx+SQuv2JpyY7upge?= =?us-ascii?q?xHsmRekyNhuvglzThmSwG6uSLyvK8CxDMg+L65tDUdo3NFVf+Rkz3VCVlZyvQF?= =?us-ascii?q?k7scAW746VOgeHkDcJfy4L5/KMTv74Yh+WowYQkjfyAdWeSgCj3wgL2IAoOVrd?= =?us-ascii?q?JcnwSBuMPQYr+vNSISLKgyyQr/R3hh1QjThBlo/3UNQjW8698kI4KxOd07ySqs?= =?us-ascii?q?GGjbcksM46xSvcv1q1ELVus3Zkl7zGVlzMeHWjUHRNbTFGYtkggkdWJEfYpG6R?= =?us-ascii?q?8dEakonjmIsbdd8wERYTfbCIKl9ZfMncbG3nk9V9RqxnnMqq2DmJwqzGVvm8lo?= =?us-ascii?q?4S6WpHQSa+vYXtdjAnfvzYdf0vXyaeiivO4BSYtmzqmhUfAZP8ms/Gu5wpNqVV?= =?us-ascii?q?G/yrQZBVq5P/cJxq3HXCe9VW2YReOLfnCOnzY+Mk7y4wOkIUE3aMdOsk8yL+rD?= =?us-ascii?q?hp9alw36UrN0Rz6dpUHazGw9K+wacx85uIa9dwwMUuERe/CWJfIyz/0mFFsMc3?= =?us-ascii?q?jJEDN3C++oq1GtmpN2O3F94UrnYOTt9RvmPMGVGhkeHo7QtoRx9uCiRmKdJX9g?= =?us-ascii?q?ywV/PEtq+OfRGVQxsvRRcpiLktjWmdt7zfQJd/FzPi0hotQTgJ5s6ZGI0MeWdh?= =?us-ascii?q?Hc1pnyJdXSovmWHfLfy0Aqd3pBUroeZwP15pk1MsQ/W7LNAbtTpQ4cCrQiQJw9?= =?us-ascii?q?K2fx87l5LAFzcg/RfLS0hc3qpuOXZpRKvHLW61MwLDvGuxId0PC0ShZ7b5+yjX?= =?us-ascii?q?XoPJ8wXi5Br8FqChZ+AItPGsYAohG7A56VhK67iMG++0dgt+8Mr6XwFujA1M6l?= =?us-ascii?q?0IVpQ5ha+UuLMS7UBKlqgURljeOyj+zC0pbrCsPiftUEW/Z9QmLfbL/JAJm/IC?= =?us-ascii?q?qUOs3gY05G76Kc0LVhXxqKei/5WbaGuTa/NPVg5kU71pB4fPTNwzMw9b3b38Hy?= =?us-ascii?q?Z25DrCe5sXGJLIdf7EDNBeHGRxJUTv6F/3x/HawZaov08OkOPMcnwNib5Alz9y?= =?us-ascii?q?pN39efI6imtU/MwUN7dZTULEfz3CY5Q4YKKgylMUQwmW/ZtmjdAXNEI8iqN8Zt?= =?us-ascii?q?hNeVDgTz6ERqmGAtZ2tBGm/2SteLPWgUxdiyZAqQ9AJEF9wDhfK4eVYktq2uTu?= =?us-ascii?q?llIpVFmfmqtLUAlNZmMTrPSdNfPyHRML92JCReAv/IpFgybR4Oq6I1VZstZZiS?= =?us-ascii?q?PEMHN1+NyC3qzQvY0E37a8Kj2b2MICYX7nVH1azK3SJLpwmjtvaTmtfjX6zBbJ?= =?us-ascii?q?HqQP7SNzIoVjaeRTssCkup4VOktOAfvPqEIGcQvkwUYjiMBwENvKxvq8bfDnPL?= =?us-ascii?q?k+15YJIKnOyaWzz3SCBgkKoyByBLtV2DQvYaEQnWbmThgHZHuAG5J/9D53Tlb7?= =?us-ascii?q?qCyqpSQewWDZNGcueFTNvAZfBeOzAomy0COOmie93crrA50k/HTGceHKfI6F2e?= =?us-ascii?q?Q1CMQvOC3zLkR54Yv4sqtSoy/NLfgCt3HL/VP7aQvTKu9ZS4jCmAs+3ESmYte1?= =?us-ascii?q?A1gP4FAGSZxBlAKXoEC80OtUDsW66AYVxD2Ggvie1wxx8GYB5zXWF20n1KgPa9?= =?us-ascii?q?HdVUSVsOg2yyQP0GbVZ3DDQr8E+U4w3yZ8IPucTSR29Y67sNRpARLP4y6InYIK?= =?us-ascii?q?EQ2uom3Cp6oCwmtCWQF1FdgRiG86rXB61x3aBC5W8k//F2WUGPXjzfcmjbyoa8?= =?us-ascii?q?DcJA2ztuq2j+18XIpuBtKKdap4ZhDVcFGy15Pcrd/TFfXmHwwwayoRK7Ey6FID?= =?us-ascii?q?IY/TYHPyoFefhpz+VjqhbHas7B6V+Mt6ImsEarCwOLCr2u2JxRC8Hpzh61aS9R?= =?us-ascii?q?fjWuCZ92q+xBlNEIYaMofYK+GUzOLhDiDgKEvCAB7APqorquDcVWw2gTkb4hKM?= =?us-ascii?q?/3UIkQDNnY3TZ4w3BSyJoJ02KRHsvVZofl5MxgGXEOKp69RGHpYJLOOTXysOsO?= =?us-ascii?q?0pIwGEmPZuUaO3hbvIIomWvwaVOn55vwrWexKfSjeDi4PtweGIi5gGlJxKDaP8?= =?us-ascii?q?Xh4OIGQX4G+7UszNjLqWj2tDuRe5C0c2X4zxFvMQejLYyX+JdgIts3Yrh3C9p8?= =?us-ascii?q?SgcLtBEifv0fGc2jsn3o1A3FUOY5vyk4Kj3+GZb+64JYdDdp6diEilCV+Oq1Fa?= =?us-ascii?q?6YBMTZ+YHUMjdo16pzacS5oYCyyJyYGwhbmmyl4g2OquKwv+dGt6zBqE0JrNML?= =?us-ascii?q?50MxccCg?= X-IPAS-Result: =?us-ascii?q?A2EpAgARS1FY/wHyM5BdFgQBAQEBAgEBAQEIAQEBARUBAQE?= =?us-ascii?q?BAgEBAQEIAQEBAYMMAQEBAQEfWoEGjkCjCYltGyUiD4FrU4U1UwEBAQEBAQEBA?= =?us-ascii?q?gECXyiCMxoJBD0KAy4BAQEBAQEBAQEBAQEBAQEBGgIIBQ0LCiEBASACFwEMEwY?= =?us-ascii?q?BDSAMAgMJAgUSKQgIAwEtFRgHCwUYBIgvAQMXBAqrWDwqAoJhBYEChEqCVQQIh?= =?us-ascii?q?C+JIw+BUhEBAwOFdwWIWQMHhh6BQolgSIZQeYlXggFRh26GGIdsijdXYx5KgV6?= =?us-ascii?q?BYw8cgV1yAYV0AQ0XB4IQAQEB?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 14 Dec 2016 13:41:51 +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 uBEDfmfM023774; Wed, 14 Dec 2016 08:41:49 -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 uBEDeGWd179221 for ; Wed, 14 Dec 2016 08:40:16 -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 uBEDeGpP023496 for ; Wed, 14 Dec 2016 08:40:16 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1DQAAARS1FYh48AFEFdFgQBAQEBAgEBAQEIAQEBAYM3AQEBAQF5gQaxSYowDCKCPoM2gX9TAQIBAQEBAQITAQEBCA0JCR2FOQEMGQE4ARWBKRKIUAEDFwQKq1g8gw0FgQKESoIvASUECIQviSMPgWcDgmILgwoFiFkDB4YegUKJYEiGUHmJV4IBUY4Gh2yKN4FXSoFegWMPEQuBXXIBhXQBJAeCEAEBAQ X-IPAS-Result: A1DQAAARS1FYh48AFEFdFgQBAQEBAgEBAQEIAQEBAYM3AQEBAQF5gQaxSYowDCKCPoM2gX9TAQIBAQEBAQITAQEBCA0JCR2FOQEMGQE4ARWBKRKIUAEDFwQKq1g8gw0FgQKESoIvASUECIQviSMPgWcDgmILgwoFiFkDB4YegUKJYEiGUHmJV4IBUY4Gh2yKN4FXSoFegWMPEQuBXXIBhXQBJAeCEAEBAQ X-IronPort-AV: E=Sophos;i="5.33,346,1477972800"; d="scan'208";a="5878342" Received: from emsm-gh1-uea10.corp.nsa.gov (HELO emsm-gh1-uea10.nsa.gov) ([10.208.41.36]) by goalie.tycho.ncsc.mil with ESMTP; 14 Dec 2016 08:40:07 -0500 IronPort-PHdr: =?us-ascii?q?9a23=3A3zeeqBX98utkWYGzSqqeo+qxVnzV8LGtZVwlr6E/?= =?us-ascii?q?grcLSJyIuqrYbR2Bt8tkgFKBZ4jH8fUM07OQ6PG7HzJeqsza+Fk5M7V0Hycfjs?= =?us-ascii?q?sXmwFySOWkMmbcaMDQUiohAc5ZX0Vk9XzoeWJcGcL5ekGA6ibqtW1aFRrwLxd6?= =?us-ascii?q?KfroEYDOkcu3y/qy+5rOaAlUmTaxe71/IRG4oAnLt8QbgIRuJrg/xxDUvnZGZu?= =?us-ascii?q?NayH9yK1mOhRj8/MCw/JBi8yRUpf0s8tNLXLv5caolU7FWFSwqPG8p6sLlsxnD?= =?us-ascii?q?VhaP6WAHUmoKiBpIAhPK4w/8U5zsryb1rOt92C2dPc3rUbA5XCmp4ql3RBP0ji?= =?us-ascii?q?oMKjg0+3zVhMNtlqJWuBKvqQJizYDaY4+bM+Fzcr/Bcd4AWWZMRNpdWzBHD4ih?= =?us-ascii?q?b4UPFe0BPeNAoofhplsBsRu+ChO2BOzy1zRGhGX53aw80+s/CgHNwQstH8gPsH?= =?us-ascii?q?vIrNX6Lr0SXv2tw6bU1TrDb+lZ2Tb76IfWaRAsuuqDXa5xccrX1UkgCRnFjlOO?= =?us-ascii?q?poz5JT+ayuMNs22C4udmSOmhhWknqwRrrTiuwMchkpLJiZwRylDF8yV53Yk0Jc?= =?us-ascii?q?WiSE58Y96rDodftz2AO4txWMMiTHlkuD09yr0bo560YDYFyJogxx7FZPyIbZKE?= =?us-ascii?q?4hT9W+aNOTt4i3NleK6/hxav6kes0PHzVs6x0FpStipKiMTMtnQU2xzW7ciHTe?= =?us-ascii?q?F98Vm71TmT0ADT7+dJKl03m6rDM5Msw749moANvUjfBCP6hF/6gLKZe0gq4uSl?= =?us-ascii?q?6Pnrbq/7qpKSKYN4kA7zP6Y0lsG7Duk1NBUFUXKB9uSmzrLj+FX0QLVUgf0yla?= =?us-ascii?q?nUqIraJcscpq6kHw9ZzoQu5wqxAju8y9sYgWMLLFZCeBKBj4XlIU3BIOjkAve7?= =?us-ascii?q?hFSsjSpky+raMb3mGJnNM3vDnK/gfbZ79UFc1BI+wNFf6p5OFL0NPOj/VlPruN?= =?us-ascii?q?DFARI0PRS4w+P9B9V80oMeV3iPAqicMK7Kq1+I5/4gI+mWa48PpTnyM+Qq6Obu?= =?us-ascii?q?jXAjmF8de7em3YAMZX+jAvRmIkOZYWbyjdcbF2cFoBY+QPb2h12FVD5ff2yyUL?= =?us-ascii?q?4k5jEnFIKmCp/ORpuzj7yF3Se7GIBWZ29dB1CQEXbna4WEW/AWZCKUOc9uiCYI?= =?us-ascii?q?VbemS48/hlmSs1rhxr5mKPfE0jEJvpLkkt5u7qvckg92vTh1CdmNlnqGU3lcgG?= =?us-ascii?q?wFXXk10bp5rEg7zU2MleB8gvpFBZlI6vhUSAYmJNvZyOBnD93aRA3MZJGKRUyg?= =?us-ascii?q?T9HgBis+HfwrxNpbWUd2G9y4gljj1iusDqRdw6aKD5w96K7r1E/xLsd7xm3u3r?= =?us-ascii?q?UgiUUrWM1CKSutgasppFubPJLAj0jMz/XiTq8bxiOYrGo=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0HHAADzSlFYh48AFEFdFgQBAQEBAgEBA?= =?us-ascii?q?QEIAQEBARQBAQEBAQEBAQEBAQcBAQEBAYMMAQEBAQF5gQaxSYltGygMIoFrU4M?= =?us-ascii?q?2gX9TAQEBAQEBAQECAQIQAQEBCA0JCR0wgjMYCwQ9CgMuAQEBAQEBAQEBAQEBA?= =?us-ascii?q?QEBARoCCAUNCwohAToBDBkBOAEVgSkSiFABAxcECqtYPIMNBYEChEqCLwElBAi?= =?us-ascii?q?EL4kjD4FnA4JiC4MKBYhZAweGHoFCiWBIhlB5iVeCAVGOBodsijeBWEqBXoFjD?= =?us-ascii?q?xELgV1yAYV0ASQHghABAQE?= X-IPAS-Result: =?us-ascii?q?A0HHAADzSlFYh48AFEFdFgQBAQEBAgEBAQEIAQEBARQBAQE?= =?us-ascii?q?BAQEBAQEBAQcBAQEBAYMMAQEBAQF5gQaxSYltGygMIoFrU4M2gX9TAQEBAQEBA?= =?us-ascii?q?QECAQIQAQEBCA0JCR0wgjMYCwQ9CgMuAQEBAQEBAQEBAQEBAQEBARoCCAUNCwo?= =?us-ascii?q?hAToBDBkBOAEVgSkSiFABAxcECqtYPIMNBYEChEqCLwElBAiEL4kjD4FnA4JiC?= =?us-ascii?q?4MKBYhZAweGHoFCiWBIhlB5iVeCAVGOBodsijeBWEqBXoFjDxELgV1yAYV0ASQ?= =?us-ascii?q?HghABAQE?= X-IronPort-AV: E=Sophos;i="5.33,346,1477958400"; d="scan'208";a="1938181" Received: from rgout0703.bt.lon5.cpcloud.co.uk ([65.20.0.143]) by emsm-gh1-uea10.nsa.gov with ESMTP; 14 Dec 2016 13:40:04 +0000 X-OWM-Source-IP: 81.132.47.94 (GB) X-OWM-Env-Sender: richard_c_haines@btinternet.com X-Junkmail-Premium-Raw: score=9/50, refid=2.7.2:2016.12.14.123917:17:9.975, ip=, rules=__HAS_FROM, __FRAUD_WEBMAIL_FROM, __TO_MALFORMED_2, __TO_NO_NAME, __HAS_CC_HDR, __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, __FRAUD_REFNUM, __CP_NAME_BODY, __CP_URI_IN_BODY, __MULTIPLE_URI_TEXT, __URI_IN_BODY, __NO_HTML_TAG_RAW, BODY_SIZE_10000_PLUS, __MIME_TEXT_P1, __MIME_TEXT_ONLY, HTML_00_01, HTML_00_10, __FRAUD_WEBMAIL, __FRAUD_COMMON, __PHISH_SPEAR_STRUCTURE_1, __FROM_DOMAIN_IN_RCPT, TO_IN_SUBJECT, __MIME_TEXT_P, NO_URI_HTTPS, __CC_REAL_NAMES Received: from localhost.localdomain (81.132.47.94) by rgout07.bt.lon5.cpcloud.co.uk (9.0.019.13-1) (authenticated as richard_c_haines@btinternet.com) id 58482FD700919673; Wed, 14 Dec 2016 13:40:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=btinternet.com; s=btcpcloud; t=1481722804; bh=OdSFB4h2O3Ou1YGgOOL6GE0TB0sFt24j33dHewwHOk8=; h=From:To:Cc:Subject:Date:Message-Id:X-Mailer; b=BYAsf0zsqigHxkdHPTPh2kzgn1L7Nt3C1bJ1RaexQM4Two6mh5+0VEXCKlxUdr3YkyR8asOv5WXOiOynTv1icfU57K6AS2Fs0y35KQjgOdzkY/XijrIcl2qFy5W4psiX+kghS8L0cDNdfW1wSb7w5KkipFRfIBO+jYwh2r9GKXI= From: Richard Haines To: selinux@tycho.nsa.gov, linux-sctp@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [RFC PATCH 1/1] kernel: Add SELinux SCTP protocol support Date: Wed, 14 Dec 2016 13:39:59 +0000 Message-Id: <20161214133959.3078-1-richard_c_haines@btinternet.com> X-Mailer: git-send-email 2.9.3 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: MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP Add SELinux support for the SCTP protocol. The SELinux-sctp.txt document describes how the patch has been implemented with an example policy and tests using lkstcp-tools. Patches to assist the testing of this kernel patch are: 1) Support the new SCTP portcon statement used in the test CIL policy module shown in Documentation/security/SELinux-sctp.txt can be found at [1]. 2) Add SELinux support for the http://lksctp.sourceforge.net/ apps sctp_test.c and sctp_darn.c can be found at [2]. Built and tested on Fedora 25 with linux-4.8 kernel. [1] http://arctic.selinuxproject.org/~rhaines/selinux-sctp/selinux-Add-support-for-the-SCTP-portcon-keyword.patch [2] http://arctic.selinuxproject.org/~rhaines/selinux-sctp/lksctp-tools-Add-SELinux-support-to-sctp_test-and-sc.patch Signed-off-by: Richard Haines --- Documentation/security/SELinux-sctp.txt | 508 ++++++++++++++++++++++++++++++++ include/linux/lsm_hooks.h | 27 ++ include/linux/security.h | 16 + net/sctp/sm_statefuns.c | 12 + net/sctp/socket.c | 16 + security/security.c | 18 ++ security/selinux/Makefile | 2 + security/selinux/hooks.c | 124 +++++++- security/selinux/include/classmap.h | 4 + security/selinux/include/sctp.h | 50 ++++ security/selinux/include/sctp_private.h | 39 +++ security/selinux/netlabel.c | 3 + security/selinux/sctp.c | 194 ++++++++++++ 13 files changed, 1002 insertions(+), 11 deletions(-) create mode 100644 Documentation/security/SELinux-sctp.txt create mode 100644 security/selinux/include/sctp.h create mode 100644 security/selinux/include/sctp_private.h create mode 100644 security/selinux/sctp.c diff --git a/Documentation/security/SELinux-sctp.txt b/Documentation/security/SELinux-sctp.txt new file mode 100644 index 0000000..dcad4b2 --- /dev/null +++ b/Documentation/security/SELinux-sctp.txt @@ -0,0 +1,508 @@ + SCTP SELinux Support + ====================== + +Security Hooks +=============== +security_sk_setsockopt() +------------------------- +A new security hook security_sk_setsockopt() is introduced that checks +permissions before setting the options associated with sock @sk. +This is supported in security/selinux/hooks.c and net/sctp/socket.c + +An example usage is where sctp_getsockopt_connectx3() and +__sctp_setsockopt_connectx() manage the @optval data into a certain +state before security_sk_setsockopt is called for permission checks. This +means that the code to manage options does not need to be replicated in the +security module. See include/linux/lsm_hooks.h for details. + +security_sctp_assoc_request() +----------------------------- +security/selinux/hooks.c selinux_sctp_assoc_request() has been introduced to +support SCTP and obtains the sock peer context if first association and +also checks the association permission as shown in the "SCTP Peer Labeling +and Permission Checks" section below. + +The security_sctp_assoc_request() security hook has been added to +net/sctp/sm_statefuns.c where it passes the sk and chunk->skb to the security +module. + +security_sk_clone() +-------------------- +Added to net/sctp/socket.c sctp_sock_migrate() for cloning the security +context on a new socket. + + +Policy Statements +================== +A new object class "sctp_socket" has been introduced with the following SCTP +specific permissions: "association" "bindx_add" "bindx_rem" "connectx" +"peeloff" "set_addr" and "set_params". These are explained in the sections +below. + +Kernel policy language +----------------------- +class sctp_socket +class sctp_socket inherits socket { node_bind name_connect association + bindx_add bindx_rem connectx peeloff set_addr set_params } + +CIL policy language +-------------------- +(classcommon sctp_socket socket) +(class sctp_socket (node_bind name_connect association bindx_add bindx_rem + connectx peeloff set_addr set_params)) +(classorder (unordered sctp_socket)) + +If userspace tools have been updated (see "Testing" section), then the portcon +statement may be used as shown in the following example: +(portcon sctp (2000 20000) (system_u object_r port_test_t ((s0) (s0)))) + +Rule validation parameters used when 'network_peer_controls = 1': +------------------------------------------------------------------------------- +Rule Source Target Class Permissions +------------------------------------------------------------------------------- +allow domain_t self : sctp_socket {connectx peeloff set_addr set_params}; +allow domain_t socket_t : sctp_socket {bindx_add bindx_rem set_params peeloff}; +allow socket_t port_t : sctp_socket {name_bind name_connect}; +allow socket_t node_t : sctp_socket {node_bind}; +allow socket_t peer_t : sctp_socket {associate}; +allow peer_t netif_t : netif {ingress egress}; +allow peer_t node_t : node {recvfrom sendto}; +allow socket_t peer_t : peer {recv}; +allow domain_t packet_t : packet {send recv relabelto} + + +SCTP Socket Option Permissions +=============================== +The permissions consist of: "bindx_add" "bindx_rem" "connectx" "set_addr" and +"set_params" that are validated on setsockopt(2) calls, and "peeloff" that is +validated on getsockopt(2) calls. + +SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be + associated after (optionally) calling bind(2) + if given the "bind_add" permission. + +SCTP_SOCKOPT_CONNECTX - Allows the allocation of multiple + addresses for reaching a multi-homed peer + if given the "connectx" permission. + + Together they are used to form SCTP associations with information being + passed over the link to inform the peer of any changes. As these two options + can support multiple addresses, each address is checked via + selinux_socket_bind() or selinux_socket_connect() to determine whether they + have the correct permissions: + bindx_add: bind, name_bind, node_bind + node SID + port SID via the + (portcon sctp port ctx) policy statement. + connectx: connect, name_connect + port SID via the + (portcon sctp port ctx) policy statement. + +SCTP_SOCKOPT_BINDX_REM - Allows additional bind addresses to be removed + if given the "bind_rem" permission. + +SCTP_PEER_ADDR_PARAMS - Alter heartbeats and address max retransmissions. +SCTP_PEER_ADDR_THLDS - Alter the thresholds. +SCTP_ASSOCINFO - Alter association and endpoint parameters. + These require the "set_params" permission. + +SCTP_PRIMARY_ADDR - Set local primary address. +SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as association primary. + These require the "set_addr" permission. + +SCTP_SOCKOPT_PEELOFF - Branch off an association into a new socket that +will be a one-to-one style socket. As SELinux already handles the creation +of new sockets, only the "peeloff" permission is checked. + + +SCTP Peer Labeling and Permission Checks +========================================= +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, the "association" permission will be checked as follows: + + allow socket_t peer_t : sctp_socket { associate }; + +As SCTP supports multiple endpoints on a single socket it is possible that +each interface may be configured with a different peer label, however it is +recommended that the labels are consistent. + +NOTES: + 1) If peer labeling is not enabled, then the peer context will always be + SECINITSID_UNLABELED (unlabeled_t in Reference Policy). + + 2) If using NetLabel fallback labeling "netlabelctl unlbl ..." be aware + that if a label is assigned to a specific interface, and that interface + 'goes down' (as in the "Multi-homing Test" section), 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). + + 3) SCTP sockets inherit their labels from the creating process (unless + there are policy rules to change this). They do NOT follow the TCP + labeling method even for TCP-style sockets. For reference: TCP child + sockets take the TE information from the parent server socket, but the + MLS/MCS information from the connection when CIPSO is enabled. + + 4) getpeercon(3) may be used by userspace apps to retrieve the sockets + peer context. + + 5) The peer labeling rules apply as discussed in the following set of + posts tagged "netlabel" at: http://www.paul-moore.com/blog/t + + + SCTP endpoint "A" SCTP endpoint "Z" + ================= ================= + sctp_sf_do_prm_asoc() + Initiate an association to + SCTP peer endpoint "Z". + Send INIT first as we need to obtain + a peer label before checking whether + this is allowed or not. This will be + checked once the INIT ACK has been + received. + INIT ---------------------------------------------> + sctp_sf_do_5_1B_init() + Respond to an INIT chunk. + SCTP peer endpoint "A" is + asking for an association. Call + security_sctp_assoc_request() + to set the peer label if first + association, then check ASSOCIATE + permission: + allow socket_t peer_t : sctp_socket { associate }; + IF valid send: + <----------------------------------------------- INIT ACK + | ELSE audit event and silently + | discard the packet. + sctp_sf_do_5_1C_ack + Respond to an INIT ACK chunk. + SCTP peer endpoint"A" initiated + this association to SCTP peer + endpoint "Z". The security checks + are done now as we have a peer + label to check against, so call + security_sctp_assoc_request() + to set the peer label if first + association, then check ASSOCIATE + permission: + allow socket_t peer_t : sctp_socket { associate }; + IF valid send: + COOKIE ECHO ------------------------------------------------> + ELSE audit event and silently | + discard the packet. | + | + <----------------------------------------------- COOKIE ACK + | | + sctp_sf_do_5_1E_ca sctp_sf_do_5_1D_ce + ESTABLISHED ESTABLISHED + | | + ------------------------------------------------------------------ + | Association Established | + ------------------------------------------------------------------ + + +Testing +======== +Requirements: + 1) libsepol 2.5 or greater. If the sctp portcon statement is required, then + libsepol must be updated with the following patch: + http://arctic.selinuxproject.org/~rhaines/selinux-sctp/ + selinux-Add-support-for-the-SCTP-portcon-keyword.patch + + 2) A patched version of lksctp-tools (1.0.17 used for testing) to support + where sctp_test and sctp_darn have been modified to display the process, + peer and socket fd SELinux contexts using the -Z option. This patch is + available from: + http://arctic.selinuxproject.org/~rhaines/selinux-sctp/ + lksctp-tools-Add-SELinux-support-to-sctp_test-and-sc.patch + + lksctp-tools can be obtained by: + git clone git://github.com/sctp/lksctp-tools.git + + The tools can then be built by adding the patch first (as it modifies + Makefile.am and configure.ac), then: + ./bootstrap + ./configure + make + + +All lksctp-tools/src/func_tests run correctly in enforcing mode except when +specific permissions are denied (e.g. test_peeloff_v6 will fail with +"test_peeloff.c 1 BROK : sctp_peeloff: Permission denied"). + +Tests involving removal of the "association" permission will wait, simply +because the INIT or INIT ACK packets will be silently discarded, however as +with all AVC denials they are audited in the audit log. + +The following sections describe the tests run using a CIL module added to the +Fedora 'targeted' policy. The CIL policy is listed at the end of this document. + +During tests the audit.log should be monitored as there are 'auditallow' +statements in the policy to show packet labels. + +The tests cover: + 1) All the lksctp-tools/src/func_tests. To check that permissions are + correctly denied, use '(not ( ...' rules as shown in the + CIL policy "Define SCTP class and permissions" section. + + 2) Using lksctp-tools/src/apps/sctp_test and sctp_darn that has been modified + to display the process, peer and socket fd SELinux contexts using the -Z + option. + + 3) Running lksctp-tools/src/apps/sctp_darn for multi-homing tests between + client/server as shown in the following diagram: + + ------- Wireless Router ------- + / \ + / \ + / \ + 192.168.1.77 192.168.1.66 + / \ + ---------- Ethernet 193.168.1.67 ---------- + | CLIENT | <----------------------------> | SERVER | + ---------- 193.168.1.78 ---------- + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Testing Setup ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +Tested on Fedora 25 with kernel 4.8.11, only the client side results are shown. + +Initial setup before running any tests (modifying interfaces and addresses +as required): + +1) Create and add the CIL policy module (see the "CIL policy module" section): + semodule --priority 400 -i sctp_test_module.cil + +2) Update iptables to allow sctp traffic (MUST be run on client and server): + iptables -I INPUT 1 -p sctp -j ACCEPT + +3) Set the fallback peer labels: + netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_peer_lo_t:s0 + netlabelctl unlbl add interface:lo address:::1 label:system_u:object_r:netlabel_peer_lo_t:s0 + netlabelctl unlbl add interface:wlp6s0 address:192.168.1.0/24 label:system_u:object_r:netlabel_peer_wlan_t:s0 + netlabelctl unlbl add interface:enp7s0 address:193.168.1.0/24 label:system_u:object_r:netlabel_peer_eth_t:s0 + + The 'netlabelctl unlbl list' command can then be used to check the entries. + +4) Set SECMARK labels on SCTP packets. It is easier to paste the 'security' iptable + entries below into a script: + +############################ SECMARK IPTABLE ENTRIES ######################## +# +# Flush the security table first: +iptables -t security -F + +#-------------- INPUT IP Stream --------------------# +# This INPUT rule sets all packets to default_packet_t: +iptables -t security -A INPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A INPUT -i enp7s0 -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A INPUT -i wlp6s0 -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +#-------------- OUTPUT IP Stream --------------------# +# This OUTPUT rule sets all packets to default_packet_t: +iptables -t security -A OUTPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A OUTPUT -o enp7s0 -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A OUTPUT -o wlp6s0 -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +iptables -t security -L +# +#################### END OF IPTABLES SECURITY TABLE ################## + +; +;;;;;;;;;;;;;;;;;;;; Running func_tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +1) Paste below into script and run tests by passing over fqn path to lksctp-tools + All tests should pass. + + To test denial of permissions see the "Define SCTP class and permissions" + section in the sample CIL policy. + +#!/bin/bash + +list="test_1_to_1_accept_close test_1_to_1_addrs test_1_to_1_connect test_1_to_1_connectx test_1_to_1_events test_1_to_1_initmsg_connect test_1_to_1_nonblock test_1_to_1_recvfrom test_1_to_1_recvmsg test_1_to_1_rtoinfo test_1_to_1_send test_1_to_1_sendmsg test_1_to_1_sendto test_1_to_1_shutdown test_1_to_1_socket_bind_listen test_1_to_1_sockopt test_1_to_1_threads test_assoc_abort test_assoc_shutdown test_autoclose test_basic test_basic_v6 test_connect test_connectx test_fragments test_fragments_v6 test_getname test_getname_v6 test_inaddr_any test_inaddr_any_v6 test_peeloff test_peeloff_v6 test_recvmsg test_sctp_sendrecvmsg test_sctp_sendrecvmsg_v6 test_sockopt test_sockopt_v6 test_tcp_style test_tcp_style_v6 test_timetolive test_timetolive_v6" + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +for i in $list + do "$1/lksctp-tools/src/func_tests/$i" + if [ $? != 0 ]; then + echo -e "\nfunc_test $i FAILED\n" + exit + fi + done + +echo -e "\nAll func_tests passed.\n" + +; +;;;;;;;;;;;;;;;;;;; Running sctp_test to check Peer contexts ;;;;;;;;;;;;;;;;;; +; +1) To check peer contexts run the following on the Server: + /path/to/lksctp-tools/src/apps/sctp_test -H 192.168.1.66 -B 193.168.1.67 -P 1035 -l -Z + +2) To check WLAN peer context run the following on the Client: + /path/to/lksctp-tools/src/apps/sctp_test -H 192.168.1.77 -P 1024 -C 192.168.1.66 -p 1035 -a 1 -c 4 -x 1 -o 2 -m 65515 -s -Z + + The Client peer context should be: + sendmsg peer context=system_u:object_r:netlabel_peer_wlan_t:s0 + The Client SECMARK context from the audit log should be: + tcontext=system_u:object_r:sctp_packet_wlan_t:s0 tclass=packet + +3) To check ETH peer context run the following on the Client: + /path/to/lksctp-tools/src/apps/sctp_test -H 193.168.1.78 -P 1024 -C 193.168.1.67 -p 1035 -a 1 -c 4 -x 1 -o 2 -m 65515 -s -Z + + The Client peer context should be: + sendmsg peer context=system_u:object_r:netlabel_peer_eth_t:s0 + The Client SECMARK context from the audit log should be: + tcontext=system_u:object_r:sctp_packet_eth_t:s0 tclass=packet + + +;;;;;;;;;;;;;;;;;;;;; Running Multi-Homing Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +1) Run sctp_darn on server and client as follows: + Server: + /path/to/lksctp-tools/src/apps/sctp_darn -H 192.168.1.66 -B 193.168.1.67 -P 1035 -l -Z + Client: + /path/to/lksctp-tools/src/apps/sctp_darn -H 192.168.1.77 -B 193.168.1.78 -P 1024 -c 192.168.1.66 -c 193.168.1.67 -p 1035 -s -Z + +2) Send data from Client to Server - saddr 192.168.1.77 daddr 192.168.1.66 +3) Turn Server Wifi off (192.168.1.66) +4) Send data from Client to Server - saddr 192.168.1.77 daddr 193.168.1.67 + +Note that the peer context will be "netlabel_peer_wlan_t" even when the +Server side Wifi is turned off. This is because the first association +on the sctp socket sets the peer context to the first connection (in this +case from the Server's wireless lan addr (192.168.1.66). It is therefore +advised that the peer context is common across interfaces/addresses used +by SCTP, note however that the SECMARK packet contexts will reflect the +--selctx entry set in the iptables rules for interfaces/addresses. + +To set "netlabel_peer_eth_t", swap the peer socket 'connectx' (-c options) +addresses on the Client as follows: + + /path/to/lksctp-tools/src/apps/sctp_darn -H 192.168.1.77 -B 193.168.1.78 -P 1024 -c 193.168.1.67 -c 192.168.1.66 -p 1035 -s -Z + +The first connection will then be from the Server's ethernet addr (193.168.1.67). + +tcpdump(8) or tshark(1) may be used to monitor traffic on each interface, +for example: + tcpdump -v -x -i lo sctp + tshark -O SCTP -P -x -i enp7s0 + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CIL policy module ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +Paste the following CIL policy module into a file named "sctp_test_module.cil" +The policy needs to be modified if libsepol has NOT been updated to support the +new sctp portcon statement (see "Select SCTP portcon" section). +To load the policy use: + semodule --priority 400 -i sctp_test_module.cil + +The policy MUST be loaded before attempting to set any netlabel or iptables +entries. + +Once testing is complete the CIL policy module may be removed by: + semodule -r sctp_test_module + +; +;;;;;;;;;;;;;;;;;;;;;;;; CIL SCTP POLICY MODULE START ;;;;;;;;;;;;;;;;;;;;;;;;; +; +;;;;;;;;;;;;;;;;;;;;;;;; Define SCTP class and permissions ;;;;;;;;;;;;;;;;;;;; +; +; Add class for sctp_socket (requires libsepol 2.5+) +(classorder (unordered sctp_socket)) +(classcommon sctp_socket socket) +(class sctp_socket (node_bind name_connect association bindx_add bindx_rem + connectx peeloff set_addr set_params)) +; +; Add permission for testing (see notes below) +(classpermission sctp_socket_all_perms) +; +; For testing whether the "bindx_add bindx_rem connectx peeloff set_addr +; set_params" permissions deny access use (not ( ... rules, +; for example: +; (classpermissionset sctp_socket_all_perms (sctp_socket (not (set_params)))) +; +; Once completed use this to grant all required permissions: +(classpermissionset sctp_socket_all_perms (sctp_socket (all))) +; +; To test that "node_bind name_connect association" permissions deny access +; remove the permissions from the applicable allow rules below. +; +;;;;;;;;;;;;;;;;;;;;;;;; Define peer labels and rules ;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type netlabel_peer_lo_t) +(type netlabel_peer_wlan_t) +(type netlabel_peer_eth_t) +(roletype object_r netlabel_peer_wlan_t) +(roletype object_r netlabel_peer_eth_t) +(typeattribute sctp_peers) +(typeattributeset sctp_peers (netlabel_peer_lo_t netlabel_peer_wlan_t + netlabel_peer_eth_t)) + +(allow unconfined_t sctp_peers (sctp_socket (association))) +(allow unconfined_t sctp_peers (peer (recv))) +(allow sctp_peers netif_t (netif (ingress egress))) +(allow sctp_peers node_t (node (recvfrom))) + +; +;;;;;;;;;;;;;;;;;;; Define SECMARK packet labels and rules ;;;;;;;;;;;;;;;;;;;; +; +; All packets other than sctp with ports 1024 - 1035 are SECMARK'ed using +; iptables with default_packet_t. There is an 'allow' rule for this because +; SCTP func_tests try illegal addresses, so needed to pass tests, plus all +; other network traffic requires system access. +(type default_packet_t) +(type sctp_packet_lo_t) +(type sctp_packet_wlan_t) +(type sctp_packet_eth_t) +(roletype object_r default_packet_t) +(roletype object_r sctp_packet_lo_t) +(roletype object_r sctp_packet_wlan_t) +(roletype object_r sctp_packet_eth_t) +(typeattribute sctp_packets) +(typeattributeset sctp_packets (default_packet_t sctp_packet_lo_t + sctp_packet_wlan_t sctp_packet_eth_t)) + +(allow unconfined_t sctp_packets (packet(send recv relabelto))) + +; Add audit rule to monitor packet labeling: +(typeattribute audit_sctp_packets) +(typeattributeset audit_sctp_packets (sctp_packet_lo_t sctp_packet_wlan_t + sctp_packet_eth_t)) +(auditallow unconfined_t audit_sctp_packets (packet(send recv))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;; Select SCTP portcon ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; If libsepol has been updated to support the "sctp" portcon keyword then +; enable the TRUE set of statements, else use FALSE statement. +; +; TRUE: + (type sctp_port_t) + (roletype object_r sctp_port_t) + ; Set to (1024 1035) as func_tests start at 1024 with 10 clients (10 + 1). + (portcon sctp (1024 1035) (system_u object_r sctp_port_t ((s0) (s0)))) + ; This allows port 0 otherwise test_1_to_1_connectx will fail as it + ; tests illegal addr. + (portcon sctp 0 (system_u object_r sctp_port_t ((s0) (s0)))) + (allow unconfined_t sctp_port_t (sctp_socket (name_bind name_connect))) +; +; FALSE: +; ; need to allow port initial SID: +; (allow unconfined_t port_t (sctp_socket (name_bind name_connect))) + +; Common allow rules: +(allow unconfined_t self sctp_socket_all_perms) +(allow unconfined_t node_t (sctp_socket (node_bind))) + diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index f2af2af..6a7ddaf 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -813,6 +813,22 @@ * @level contains the protocol level to set options for. * @optname contains the name of the option to set. * Return 0 if permission is granted. + * @sk_setsockopt: + * Check permissions before setting the options associated with sock @sk. + * This is equivalent to @socket_setsockopt, except that it has the + * option parameters, as it is intended to support permission checking + * of options and their parameters within network services. + * An example usage is in net/sctp/socket.c where + * sctp_getsockopt_connectx3() manages the @optval data into a certain + * state before calling __sctp_setsockopt_connectx() that calls + * @sk_setsockopt for permission checks. This means the code to manage + * @optval does not need to be replicated in the security module. + * @sk contains the sock structure. + * @level contains the protocol level to set options for. + * @optname contains the name of the option to set. + * @optval contains the value(s) to set (already copied from userspace). + * @optlen contains the length of the value(s) to be set. + * Return 0 if permission is granted. * @socket_shutdown: * Checks permission before all or part of a connection on the socket * @sock is shut down. @@ -902,6 +918,12 @@ * This hook can be used by the module to update any security state * associated with the TUN device's security structure. * @security pointer to the TUN devices's security structure. + * @sctp_assoc_request: + * Update socket peer label if first association on @sk then check + * whether association allowed. + * @sk contains the sock structure. + * @skb skbuff of association packet (INIT or INIT ACK) being queried. + * Return 0 on success, error on failure. * * Security hooks for XFRM operations. * @@ -1582,6 +1604,8 @@ union security_list_options { int (*socket_getpeername)(struct socket *sock); int (*socket_getsockopt)(struct socket *sock, int level, int optname); int (*socket_setsockopt)(struct socket *sock, int level, int optname); + int (*sk_setsockopt)(struct sock *sk, int level, int optname, + char *optval, int optlen); int (*socket_shutdown)(struct socket *sock, int how); int (*socket_sock_rcv_skb)(struct sock *sk, struct sk_buff *skb); int (*socket_getpeersec_stream)(struct socket *sock, @@ -1610,6 +1634,7 @@ union security_list_options { int (*tun_dev_attach_queue)(void *security); int (*tun_dev_attach)(struct sock *sk, void *security); int (*tun_dev_open)(void *security); + int (*sctp_assoc_request)(struct sock *sk, struct sk_buff *skb); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM @@ -1819,6 +1844,7 @@ struct security_hook_heads { struct list_head socket_getpeername; struct list_head socket_getsockopt; struct list_head socket_setsockopt; + struct list_head sk_setsockopt; struct list_head socket_shutdown; struct list_head socket_sock_rcv_skb; struct list_head socket_getpeersec_stream; @@ -1841,6 +1867,7 @@ struct security_hook_heads { struct list_head tun_dev_attach_queue; struct list_head tun_dev_attach; struct list_head tun_dev_open; + struct list_head sctp_assoc_request; #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM struct list_head xfrm_policy_alloc_security; diff --git a/include/linux/security.h b/include/linux/security.h index a6c6d5d..9572b8b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1174,6 +1174,8 @@ int security_socket_getsockname(struct socket *sock); int security_socket_getpeername(struct socket *sock); int security_socket_getsockopt(struct socket *sock, int level, int optname); int security_socket_setsockopt(struct socket *sock, int level, int optname); +int security_sk_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen); int security_socket_shutdown(struct socket *sock, int how); int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb); int security_socket_getpeersec_stream(struct socket *sock, char __user *optval, @@ -1200,6 +1202,7 @@ int security_tun_dev_create(void); int security_tun_dev_attach_queue(void *security); int security_tun_dev_attach(struct sock *sk, void *security); int security_tun_dev_open(void *security); +int security_sctp_assoc_request(struct sock *sk, struct sk_buff *skb); #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct sock *sock, @@ -1289,6 +1292,13 @@ static inline int security_socket_setsockopt(struct socket *sock, return 0; } +static inline int security_sk_setsockopt(struct sock *sk, int level, + int optname, char *optval, + int optlen) +{ + return 0; +} + static inline int security_socket_shutdown(struct socket *sock, int how) { return 0; @@ -1392,6 +1402,12 @@ static inline int security_tun_dev_open(void *security) { return 0; } + +static inline int security_sctp_assoc_request(struct sock *sk, + struct sk_buff *skb) +{ + return 0; +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 920469e..920b101 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -315,6 +315,12 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net, sctp_unrecognized_param_t *unk_param; int len; + /* Update socket peer label if first association then check + * whether association allowed. + */ + if (security_sctp_assoc_request(ep->base.sk, chunk->skb)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. @@ -508,6 +514,12 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, struct sctp_chunk *err_chunk; struct sctp_packet *packet; + /* Update socket peer label if first association then check + * whether association allowed. + */ + if (security_sctp_assoc_request(ep->base.sk, chunk->skb)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7b0e059..ff4f1a8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1009,6 +1009,12 @@ static int sctp_setsockopt_bindx(struct sock *sk, /* Do the work. */ switch (op) { case SCTP_BINDX_ADD_ADDR: + /* Allow security module to validate bindx addresses. */ + err = security_sk_setsockopt(sk, SOL_SCTP, + SCTP_SOCKOPT_BINDX_ADD, + (char *)kaddrs, addrs_size); + if (err) + goto out; err = sctp_bindx_add(sk, kaddrs, addrcnt); if (err) goto out; @@ -1329,9 +1335,17 @@ static int __sctp_setsockopt_connectx(struct sock *sk, if (__copy_from_user(kaddrs, addrs, addrs_size)) { err = -EFAULT; } else { + /* Allow security module to validate connectx addresses. */ + err = security_sk_setsockopt(sk, SOL_SCTP, + SCTP_SOCKOPT_CONNECTX, + (char *)kaddrs, addrs_size); + if (err) + goto out_free; + err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); } +out_free: kfree(kaddrs); return err; @@ -7826,6 +7840,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->sk_state = SCTP_SS_ESTABLISHED; } + /* Ensure newsk has the same security attributes. */ + security_sk_clone(oldsk, newsk); release_sock(newsk); } diff --git a/security/security.c b/security/security.c index f825304..23ce9ea 100644 --- a/security/security.c +++ b/security/security.c @@ -1307,6 +1307,14 @@ int security_socket_setsockopt(struct socket *sock, int level, int optname) return call_int_hook(socket_setsockopt, 0, sock, level, optname); } +int security_sk_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + return call_int_hook(sk_setsockopt, 0, sk, level, optname, optval, + optlen); +} +EXPORT_SYMBOL(security_sk_setsockopt); + int security_socket_shutdown(struct socket *sock, int how) { return call_int_hook(socket_shutdown, 0, sock, how); @@ -1439,6 +1447,12 @@ int security_tun_dev_open(void *security) } EXPORT_SYMBOL(security_tun_dev_open); +int security_sctp_assoc_request(struct sock *sk, struct sk_buff *skb) +{ + return call_int_hook(sctp_assoc_request, 0, sk, skb); +} +EXPORT_SYMBOL(security_sctp_assoc_request); + #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM @@ -1856,6 +1870,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.socket_getsockopt), .socket_setsockopt = LIST_HEAD_INIT(security_hook_heads.socket_setsockopt), + .sk_setsockopt = + LIST_HEAD_INIT(security_hook_heads.sk_setsockopt), .socket_shutdown = LIST_HEAD_INIT(security_hook_heads.socket_shutdown), .socket_sock_rcv_skb = @@ -1897,6 +1913,8 @@ struct security_hook_heads security_hook_heads = { .tun_dev_attach = LIST_HEAD_INIT(security_hook_heads.tun_dev_attach), .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open), + .sctp_assoc_request = + LIST_HEAD_INIT(security_hook_heads.sctp_assoc_request), #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM .xfrm_policy_alloc_security = diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 3411c33..f60a8a3 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -13,6 +13,8 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o selinux-$(CONFIG_NETLABEL) += netlabel.o +selinux-$(subst m,y,$(CONFIG_IP_SCTP)) += sctp.o + ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e15e560..491599c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include /* for Unix socket types */ #include /* for Unix socket types */ @@ -93,6 +94,7 @@ #include "netlabel.h" #include "audit.h" #include "avc_ss.h" +#include "sctp.h" /* SECMARK reference count */ static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); @@ -1280,8 +1282,11 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc case PF_INET6: switch (type) { case SOCK_STREAM: + case SOCK_SEQPACKET: if (default_protocol_stream(protocol)) return SECCLASS_TCP_SOCKET; + else if (protocol == IPPROTO_SCTP) + return SECCLASS_SCTP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DGRAM: @@ -4034,6 +4039,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, break; } +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) + 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; } @@ -4107,6 +4129,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, break; } +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) + 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; @@ -4236,7 +4271,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, socksid); } -static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) +int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) { struct sk_security_struct *sksec = sk->sk_security; struct common_audit_data ad; @@ -4306,7 +4341,8 @@ static int selinux_socket_post_create(struct socket *sock, int family, Need to determine whether we should perform a name_bind permission check between the socket and the port number. */ -static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) +int selinux_socket_bind(struct socket *sock, struct sockaddr *address, + int addrlen) { struct sock *sk = sock->sk; u16 family; @@ -4318,8 +4354,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in /* * 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. + * Multiple address binding for SCTP is supported via + * selinux_sctp_setsockopt(). */ family = sk->sk_family; if (family == PF_INET || family == PF_INET6) { @@ -4377,6 +4413,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; @@ -4405,7 +4445,8 @@ out: return err; } -static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) +int selinux_socket_connect(struct socket *sock, struct sockaddr *address, + int addrlen) { struct sock *sk = sock->sk; struct sk_security_struct *sksec = sk->sk_security; @@ -4416,10 +4457,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; @@ -4443,8 +4486,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, if (err) goto out; - perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? - TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; + if (sksec->sclass == SECCLASS_TCP_SOCKET) + perm = TCP_SOCKET__NAME_CONNECT; + else if (sksec->sclass == SECCLASS_DCCP_SOCKET) + perm = DCCP_SOCKET__NAME_CONNECT; + else if (sksec->sclass == SECCLASS_SCTP_SOCKET) + perm = SCTP_SOCKET__NAME_CONNECT; ad.type = LSM_AUDIT_DATA_NET; ad.u.net = &net; @@ -4516,13 +4563,35 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname if (err) return err; + err = selinux_sctp_setsockopt(sock->sk, level, optname, NULL, 0); + if (err) + return err; + return selinux_netlbl_socket_setsockopt(sock, level, optname); } +static int selinux_sk_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + int err; + + err = sock_has_perm(current, sk, SOCKET__SETOPT); + if (err) + return err; + + return selinux_sctp_setsockopt(sk, level, optname, optval, optlen); +} + static int selinux_socket_getsockopt(struct socket *sock, int level, int optname) { - return sock_has_perm(current, sock->sk, SOCKET__GETOPT); + int err; + + err = sock_has_perm(current, sock->sk, SOCKET__GETOPT); + if (err) + return err; + + return selinux_sctp_getsockopt(sock->sk, level, optname); } static int selinux_socket_shutdown(struct socket *sock, int how) @@ -4715,7 +4784,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; @@ -4828,6 +4898,36 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) sksec->sclass = isec->sclass; } +static int selinux_sctp_assoc_request(struct sock *sk, struct sk_buff *skb) +{ + struct sk_security_struct *sksec = sk->sk_security; + struct common_audit_data ad; + struct lsm_network_audit net = {0,}; + u8 peerlbl_active; + int err; + + peerlbl_active = selinux_peerlbl_enabled(); + + if (sksec->peer_sid == SECINITSID_UNLABELED && peerlbl_active) { + /* Here because this is the first association on this + * socket that is always unlabeled, therefore set + * sksec->peer_sid to new peer ctx. For further info see: + * Documentation/security/SELinux-sctp.txt + */ + err = selinux_skb_peerlbl_sid(skb, sk->sk_family, + &sksec->peer_sid); + if (err) + return err; + } + + ad.type = LSM_AUDIT_DATA_NET; + ad.u.net = &net; + ad.u.net->sk = sk; + + return avc_has_perm(sksec->sid, sksec->peer_sid, sksec->sclass, + SCTP_SOCKET__ASSOCIATION, &ad); +} + static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct request_sock *req) { @@ -6243,6 +6343,7 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername), LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt), LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt), + LSM_HOOK_INIT(sk_setsockopt, selinux_sk_setsockopt), LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown), LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb), LSM_HOOK_INIT(socket_getpeersec_stream, @@ -6253,6 +6354,7 @@ static struct security_hook_list selinux_hooks[] = { 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(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 1f1f4b2..353183a 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -165,5 +165,9 @@ struct security_class_mapping secclass_map[] = { { COMMON_CAP_PERMS, NULL } }, { "cap2_userns", { COMMON_CAP2_PERMS, NULL } }, + { "sctp_socket", + { COMMON_SOCK_PERMS, "node_bind", "name_connect", "association", + "bindx_add", "bindx_rem", "connectx", "peeloff", "set_addr", + "set_params", NULL } }, { NULL } }; diff --git a/security/selinux/include/sctp.h b/security/selinux/include/sctp.h new file mode 100644 index 0000000..cee8e2d --- /dev/null +++ b/security/selinux/include/sctp.h @@ -0,0 +1,50 @@ +/* + * SELinux SCTP Support + * + * Provides security checks for the SCTP protocol. + * + * Author: Richard Haines + * + * 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. + * + */ + +#ifndef _SELINUX_SCTP_H_ +#define _SELINUX_SCTP_H_ + +#include +#include +#include +#include "objsec.h" + +#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) +int selinux_sctp_setsockopt(struct sock *sk, + int level, + int optname, + char *optval, + int optlen); + +int selinux_sctp_getsockopt(struct sock *sk, + int level, + int optname); +#else +static inline int selinux_sctp_setsockopt(struct sock *sk, + int level, + int optname, + char *optval, + int optlen) +{ + return 0; +} +static inline int selinux_sctp_getsockopt(struct sock *sk, + int level, + int optname) +{ + return 0; +} +#endif /* CONFIG_IP_SCTP */ + +#endif diff --git a/security/selinux/include/sctp_private.h b/security/selinux/include/sctp_private.h new file mode 100644 index 0000000..eaa9f4c --- /dev/null +++ b/security/selinux/include/sctp_private.h @@ -0,0 +1,39 @@ +/* + * SELinux SCTP Support + * + * Provides security checks for the SCTP protocol. + * + * Author: Richard Haines + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include /* For bindx setsocket option checks */ +#include +#include + +#include "security.h" +#include "avc.h" +#include "objsec.h" + +extern int sock_has_perm(struct task_struct *task, + struct sock *sk, u32 perms); + +extern int selinux_socket_bind(struct socket *sock, + struct sockaddr *address, + int addrlen); + +extern int selinux_socket_connect(struct socket *sock, + struct sockaddr *address, + int addrlen); + diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index aaba667..300a195 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -399,6 +399,9 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, case SECCLASS_TCP_SOCKET: perm = TCP_SOCKET__RECVFROM; break; + case SECCLASS_SCTP_SOCKET: + perm = SCTP_SOCKET__RECVFROM; + break; default: perm = RAWIP_SOCKET__RECVFROM; } diff --git a/security/selinux/sctp.c b/security/selinux/sctp.c new file mode 100644 index 0000000..bd25712 --- /dev/null +++ b/security/selinux/sctp.c @@ -0,0 +1,194 @@ +/* + * SELinux SCTP Support + * + * Provides security checks for the SCTP protocol. + * + * Author: Richard Haines + * + * 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. + * + */ + +#include "sctp_private.h" + +/** + * selinux_sctp_setsockopt - Check setsockopt values. + * @sk: the socket + * @level: contains the protocol level to validate + * @optname: contains the name of the option to validate + * @optval: contains the value(s) to set + * @optlen: contains the length of the value(s) to be set + * + * Description: + * Check whether SCTP socket options are allowed or not. Returns zero on + * success, negative values on failure. + * + * setsockopt(2) option support: + * + * SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be + * associated after (optionally) calling bind(3). + * sctp_bindx(3) adds or removes a set of bind + * addresses on a socket. + * + * SCTP_SOCKOPT_CONNECTX - Allows the allocation of multiple addresses for + * reaching a peer (multi-homed). + * sctp_connectx(3) initiates a connection on an + * SCTP socket using multiple destination addresses. + * May also return an association id. + * + * Together they form SCTP associations and will be passed over the + * link to inform peer of any changes. As these two options can support + * multiple addresses, each address is checked via selinux_socket_bind() or + * selinux_socket_connect() to determine whether they have the correct + * permissions: + * bindx_add: bind, name_bind, node_bind + node SID + port SID via the + * (portcon sctp port ctx) policy statement. + * connectx: connect, name_connect + port SID via the + * (portcon sctp port ctx) policy statement. + * + * These options require set_params permission: + * SCTP_SOCKOPT_BINDX_REM - As the addresses would have already been + * allowed, only the bindx_rem permission + * is checked. + * + * SCTP_PEER_ADDR_PARAMS - Set heartbeats and address max + * retransmissions. + * + * SCTP_PEER_ADDR_THLDS - Set thresholds. + * + * SCTP_ASSOCINFO - Set association and endpoint parameters. + * + * These options require the set_addr permission. + * SCTP_PRIMARY_ADDR - Set local primary address. + * + * SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as + * association primary. + */ +int selinux_sctp_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + int err, addrlen; + void *addr_buf; + struct sockaddr *address; + struct socket *sock; + int walk_size = 0; + + if (level != SOL_SCTP || level != IPPROTO_SCTP) + return 0; + + switch (optname) { + case SCTP_SOCKOPT_BINDX_ADD: + case SCTP_SOCKOPT_CONNECTX: + /* Note that for SCTP_SOCKOPT_BINDX_ADD and + * SCTP_SOCKOPT_CONNECTX the sctp kernel code has already + * copied the optval to kernel space. See net/sctp/socket.c + * security_sk_setsockopt() calls. + */ + err = sock_has_perm(current, sk, + (optname == SCTP_SOCKOPT_BINDX_ADD ? + SCTP_SOCKET__BINDX_ADD : + SCTP_SOCKET__CONNECTX)); + if (err) + return err; + + sock = sk->sk_socket; + addr_buf = optval; + /* Process list - may contain IPv4 or IPv6 addr's */ + while (walk_size < optlen) { + address = addr_buf; + + switch (address->sa_family) { + case PF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + case PF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; + default: + return -EINVAL; + } + + err = -EINVAL; + if (optname == SCTP_SOCKOPT_BINDX_ADD) { + err = selinux_socket_bind(sock, + address, addrlen); + } else if (optname == SCTP_SOCKOPT_CONNECTX) { + err = selinux_socket_connect(sock, + address, addrlen); + } + if (err) + return err; + + addr_buf += addrlen; + walk_size += addrlen; + } + break; + + case SCTP_SOCKOPT_BINDX_REM: + /* The addresses have been checked as they were + * added, so just see if allowed to be removed. + */ + err = sock_has_perm(current, sk, SCTP_SOCKET__BINDX_REM); + if (err) + return err; + break; + + /* Set heartbeats and address max retransmissions. */ + case SCTP_PEER_ADDR_PARAMS: + /* Set thresholds. */ + case SCTP_PEER_ADDR_THLDS: + /* Set association and endpoint parameters */ + case SCTP_ASSOCINFO: + err = sock_has_perm(current, sk, SCTP_SOCKET__SET_PARAMS); + if (err) + return err; + break; + + /* Set local primary address. */ + case SCTP_PRIMARY_ADDR: + /* Request peer sets address as association primary. */ + case SCTP_SET_PEER_PRIMARY_ADDR: + err = sock_has_perm(current, sk, SCTP_SOCKET__SET_ADDR); + if (err) + return err; + break; + } + + return 0; +} + +/** + * selinux_sctp_getsockopt - Check getsockopt values. + * @sk: the socket + * @level: contains the protocol level to validate + * @optname: contains the name of the option to validate + * + * Description: + * Check whether SCTP socket options are allowed or not. Returns zero on + * success, negative values on failure. + * + * SCTP_SOCKOPT_PEELOFF - Branch off an association into a new socket that + * will be a one-to-one style socket. As SELinux + * already handles the creation of new sockets, only + * the peeloff permission is checked. + */ +int selinux_sctp_getsockopt(struct sock *sk, int level, int optname) +{ + int err; + + if (level != SOL_SCTP || level != IPPROTO_SCTP) + return 0; + + switch (optname) { + case SCTP_SOCKOPT_PEELOFF: + err = sock_has_perm(current, sk, SCTP_SOCKET__PEELOFF); + if (err) + return err; + break; + } + + return 0; +}