From patchwork Mon Apr 24 13:09:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Haines X-Patchwork-Id: 9696115 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 E0A9C60113 for ; Mon, 24 Apr 2017 13:11:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CB1122074F for ; Mon, 24 Apr 2017 13:11:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BC53326B41; Mon, 24 Apr 2017 13:11:24 +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 (smtp.nsa.gov [8.44.101.9]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C54BC2074F for ; Mon, 24 Apr 2017 13:11:22 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.37,244,1488844800"; d="scan'208";a="5142115" IronPort-PHdr: =?us-ascii?q?9a23=3A3/PV1h0mRhKWRhXUsmDT+DRfVm0co7zxezQtwd8Z?= =?us-ascii?q?sewULPXxwZ3uMQTl6Ol3ixeRBMOAuqwC17Kd7vCocFdDyK7JiGoFfp1IWk1Nou?= =?us-ascii?q?QttCtkPvS4D1bmJuXhdS0wEZcKflZk+3amLRodQ56mNBXdrXKo8DEdBAj0OxZr?= =?us-ascii?q?KeTpAI7SiNm82/yv95HJbQhFgDuwbal9IRmqognctsobipZ+J6gszRfEvmFGcP?= =?us-ascii?q?lMy2NyIlKTkRf85sOu85Nm7i9dpfEv+dNeXKvjZ6g3QqBWAzogM2Au+c3krgLD?= =?us-ascii?q?QheV5nsdSWoZjBxFCBXY4R7gX5fxtiz6tvdh2CSfIMb7Q6w4VSik4qx2RhDoki?= =?us-ascii?q?MHPCMn/m/RhMJ7kaZXrAu8qxBjxoLZZpyeOvhjcaPHZd4URXRPUNtfWSJCBY28?= =?us-ascii?q?d4kCA/cPMOlGtInwvEcCoQekCAWwHu7j1iNEi3nr1qM6yeQhFgTG0RQ8EdIPrH?= =?us-ascii?q?vUrM/6NL0PXuuozqfH1zTDb/VI1jfm9YPFdQohofCQUrJwa8XR01QgGBvZgVqI?= =?us-ascii?q?qYzqJTKV1uITvGiA9OdvTv6vi28hqwFtvDev3MEshZfVho4P1l/E8iB5zZ8zKN?= =?us-ascii?q?alS0B7ecapHIZfuiyVLYd7Qt4uT3t2tCs11LEKo4O3cDAJxZkm3RLTdvOKfomS?= =?us-ascii?q?7h/iVuudOzV1iXZjdbminRi961Kgxff5VsSs1VZKqTdKncfUu3AW0hzT9tCHSv?= =?us-ascii?q?xg/ke9wTqP1x7c6uVDIU0siarUMYQhwr8tlpoIq0jDAi/3l1n2jK+RbEkk/PSn?= =?us-ascii?q?6//7bbn8o5+cNot0hhn/MqQohMO/Hfw1PhUBUmWU4+ix1KDv8VfnTLhFkPE6iL?= =?us-ascii?q?TVvIjfJcsBp665BwFV0pwk6xa6Fzqmy8oXnX0GLFJDZRKGgJHlNErJIPDlC/ew?= =?us-ascii?q?n0qjkCxwyvDaPrzuHpXNLn/ZnLfnZrZy8VRQyAU0zdBB/55UEK0OIOrvWk/ts9?= =?us-ascii?q?zVFh05Mwuyw+n9FNV91pkRWWSUD6+bN6PSt1qI6fg0I+mQeoAVoi39J+Ii5/70?= =?us-ascii?q?gn8zgUUdcrWx3ZsLdHC4GexrI0ebYXX2ntgBEnwKvg04TOzrll2PSjBTZ3KvX6?= =?us-ascii?q?Mz/T47FYSmDZveRoy3h7yBxii7FIVMZm9aElCMDWvod4KcVvcUdi2dOdFukjoF?= =?us-ascii?q?Vbi9TI8szhCuuxHkxLV5NObU/TcYtZ373thv++LTjQ0y9SBzD8mFzm6NSGd0nm?= =?us-ascii?q?UVSDAo2KB/oFdwxU2d3qhihPxUD9tT5+lGUg0iL57T0/R6C8zuWgLGZtqGVUqm?= =?us-ascii?q?Tc+8ATwqUt0xxNoObFpnFNW5khDPxSyqDKEJl7aTHpw77rrc32TtJ8Z603vG1a?= =?us-ascii?q?8hj0U4TctLK2Kmg7Bw9xTJB4/JiEiZkL6qeroa3C7I7miDzG6Os1pfUA9/S6nF?= =?us-ascii?q?WmofZkTOp9Tj+kzCV6OuCaggMgZZyc+DK6xKatvygFVDQPfvIdXeY2Srl2e2Hx?= =?us-ascii?q?mI3LCMbIv0e2oDxindDlYLkxwL93acKQc+Hjuho37ZDDF2Dl3geETg8e1/qHOg?= =?us-ascii?q?Uk801BuGb1Z/2LWp4BIVnuKTS/cS3rICpScgpC55E0q93tLMFtqAvBBtfatGbt?= =?us-ascii?q?Mh+1dH0mTZuxZ6Ppy6IKBonkQefBhvv0PyyxV3DZ1NntYyrHww1gpyKLmY3UhZ?= =?us-ascii?q?dzyCx5DwO6bXKnH2/B+1d6HZxEvS0NGM+qcA8P44sUnsvBm1Fko+9HVqy9dU03?= =?us-ascii?q?qY5pXPEgUSS4n8Ukgp+BdnoLHaeDMy55vO1X1rM6m7rCPN284zCOsi0BagcM9V?= =?us-ascii?q?MLmYGw/qD80aG8+uJfQkm1izdB0EOvxd9K8vP869cvuGwK+rMP97nDOolmRL+o?= =?us-ascii?q?d90liD9yBkUO7Hw44Fw+2E3guATzr8j02ussPwmYBZfjwSHXCwySvjBI5MfKFy?= =?us-ascii?q?epwLCWi2Kc2t2tp+n4LtW2Jf9FO7HVwJxdWpeRuMYFznxgBfz1gYoXm9lSu/1T?= =?us-ascii?q?x0nCkjrrCD0yzW3+TiaB0HN3ZXS2Z4iVfjP5O0j8waXUivdAUpjweq5UfkyKhd?= =?us-ascii?q?uKR/LnPcTV1OfyfoM2FoSrGwuaaaY85T9JMotj1aUP+yYVCATb79uAca3jj4H2?= =?us-ascii?q?tYwzA6eTSqtY//nxBgjmKSMmpzpmLDec5s3Rff+MDcRflJ0zsIXiZ4jSXXCUam?= =?us-ascii?q?P9my5tiUiYnMsvqlWGK8U51fay7rzZmPtCGj/21lHQW/n+yvmt3gCQU6zTL02M?= =?us-ascii?q?RrVSrSqBbxeZXk16O/Me17ZEZoH0P859B8Go5gjos6nIsQ1mQChpWJ4XoHln/+?= =?us-ascii?q?Mcta2a3icHoNQiQLz8TJ7wjl301jKH2Jypn9VnWcxMtufcO6YmQM1iI69cBKB7?= =?us-ascii?q?+e7KZYkittvlq4sQXRbOB5njcc0vsu9GcWg/oXtwopzyWdBK0SHEZDMCz3jxSI?= =?us-ascii?q?7ta+rKRLa2a0a7Sw0lRxncy5BrGYvg5cQGr5eoslHSJo9MV/N1bM0Hnt5YH+ZN?= =?us-ascii?q?bQatwSuwaPkxfdk+dVM4g9lv0QhSpoIWj9p2Eqy/YnjRxy2pG3pJCHJH9w/KK9?= =?us-ascii?q?GBJXLCf5aNgU+jHpkaZemcCW0puqHpl9HDULW4fnQeiuED0MqfTtLxyOHyEkqn?= =?us-ascii?q?eHBbrfGheS6ER4oHLJCJCmLHKXK2cfzdV5QhmSOlBfjBoTXDUgkZ4zDhqqy9D5?= =?us-ascii?q?cEdl+jAR4Ub1qgNWxeJ1MxnwTH/fqx2uajcoVpefNgFb7hxZ50jLK8ye9fh/Hz?= =?us-ascii?q?pf/p28tgyCNnKUZwpPDWETVUyLGUrvPr+w6tnc6+KYHPaxL+PSYbWSruxTT+mI?= =?us-ascii?q?xZSy3YZ94TaMMNiAPnl4A/09xEVDQWhzG97FlDUXVywXiyXNYtaDpBim5y13qt?= =?us-ascii?q?uy/+jqWALz5YqDErVSPs9p+xyshqeDLeGQjj5jKTlEzpMM2WPIyL8H0V4RiyBu?= =?us-ascii?q?cyeiHK8FtS7KQqLQlLFYDwIHayNzM8tI6rwz0hNLOcHFltP/zqR4geItC1dZSV?= =?us-ascii?q?zhndmkZcIQLGG7KFPHA0OLOa+IJTLV3s73Zrm8RqdIjOVOsB2wuyiUHFP/PjiZ?= =?us-ascii?q?kDnpTR+vO/lWjC6HJBxepJ29chF1BGj5Ud3pdwa2MNByjTw527E0gG3FNXIEOz?= =?us-ascii?q?hmb0xNtqGQ7T9fgvhnAWxN9HRkIfOBmymD6+nYLZYXvOBxDStokuJW+nM6y6Fa?= =?us-ascii?q?7CtcXvx6hDPSrsJyo1GhiuSPxCBnXwRTpTZQno2Lu1liOaLC9pRbQ3nL4BcN4X?= =?us-ascii?q?+XCxQQqNtvEsfvtLxIytjTiKLzLy9P89TO/cQGH8jUMNmKMHQgMRrzAz7UEAUF?= =?us-ascii?q?TT+tNW7FgUxSjPCS+WeRrpQgrZjsgpUOQKdBVFMpDvMaFlhlHNsaLZhqRTMrj6?= =?us-ascii?q?SUjMES5XWkshncX95asYrEVvKPG/XgMiyVjb1ZZxsO27z4N50fNpH820xhalh6?= =?us-ascii?q?m57GG0zOUtBRuidhdBM7oF1R8HhiSW0+w0TlagKp4H8XC/G0hQU7hRFgbuQ38z?= =?us-ascii?q?fg+VA3JkDFpCEoikk+hc3lgSyNcD72NKq/RoBWCyXzt0g3KZ70Xhh6YhaznUN+?= =?us-ascii?q?MjfIXbVRj6FvdWpzkg/TpYNPGeJATa1DeBIf3/6XaO820VtCsSinwldH6vXDCZ?= =?us-ascii?q?tnjgQqcJqsoGlH2wNsdtI1IrbQJKVRxFhKmq2OpjOo1vw2wAIGO0YN92aSdDQS?= =?us-ascii?q?uEwPN7gpOSyo8fd26QyFhTRDe3MBWOYtovJv6kwyIf+Azz76375FNE+xK/SVL7?= =?us-ascii?q?mFtGjYic6IXlQw21sOl0Zb57d21dwuc0mTV0A00LueDRIJNdHBKQFUdcZS8mbc?= =?us-ascii?q?fTqWu+XX3Z11J5m9FvzvTeKWrqYbnFmkExgzEIQW8ssBHoKh31rZLcf9MbEFzh?= =?us-ascii?q?st5BzxJFqbDPVFYhSLnykbo8un1p94wZFdJi0BAWV6KSi4+6zYphErgPWeR9c7?= =?us-ascii?q?eW0VXpEeNnIxVsy6gDBWsGhdDDmt0+IZ1AiD4yX6pivOEDn2d8Bja+uMZRNwFN?= =?us-ascii?q?G2/i0y86yxiV7N7JreIWD7NdN5t9/A7+MauoyLC/ROTblyq03cgZVXR2S2U27T?= =?us-ascii?q?Ft64P4PwZJcobdz1DHa6T1O+hikpQMf2OdaiMrKHgRr0RYpOtomUwiwjP9enFj?= =?us-ascii?q?4CAxdwu/0D5KVkaAIef5U7ZBnotwIiN6CiOwqYzMuhQ3ysKTpXSPlfy/+2Z7pJ?= =?us-ascii?q?wCowduW60mcvTokmz+mr9k4AXJIKjgvexPm5YYleTSjzF2dSewXIvSo2i3JtNu?= =?us-ascii?q?Aszecj2BnIq0UTMyiXdOx1b2xJp808BVKXIXVxFmo4R1+dgJHe7Q6t37Ed5TBS?= =?us-ascii?q?k8xS0eJbrHj0poXfby60WKy3tZXVtDItbdc8o6JrN4zjPtCLtJLZnj3RSpnQrg?= =?us-ascii?q?2FXzC7F/pchthfPjhYTONOmW47JcwMoZBB5lYpVsciO7xPD7EhqaquaTplESEd?= =?us-ascii?q?0zcWV4aA3TwEhee83aHVmwyLf5QjKhMEtoxOgtUAUyJsZCMRurOjXZ3Ml2CYUm?= =?us-ascii?q?gLPBsT7QNU6Q0biIBwePvo75DVQ59S1TFWuel0XTHRFpho7Vf7TXuWgVfgQvW7?= =?us-ascii?q?j+OpxR5SzO7r0tQDQh5/D0ldyPpWlksvLLF3MLEesJfXvDGSaU70u3ngx/ehJF?= =?us-ascii?q?lU1cLbbUb4DJbfuWr6TCIc5WUeRZVTx3HHCZQSjw15Zb43q1VOOo+pZl3z6CAj?= =?us-ascii?q?x4RtG7m4VN6kx0w5rXkYWyiqE8BNC+Z8sFLYQDdleYykqI35O5VORW9d4IedpE?= =?us-ascii?q?1DkEVqKCG00oZcK9tX7T4SQjdPpTSdvN29SM1H2M92AJ8MIstxu3jnAqNEPYKd?= =?us-ascii?q?o3sotbzz0nXZ4SwzsE+mxDWvHK+1V+xY83cCFQUpJmSer0gvAPEv8mrJ81DCrE?= =?us-ascii?q?578PlBCriIl0Vxry53HopSCTZRyXClM1NzQWFes+VdLKTaadZcQvc1ZR+rNRwz?= =?us-ascii?q?Dvsm30uO/UFvg3j2fzZytgxB+yDGXgk0UyYVjq3qmT0EpcGtISUaRI5QbTU9cy?= =?us-ascii?q?fFLBqWljpNvBZCbUFmQZMZD81E+7Ea3ItU4tHNRVyqKS4bQBxoLhg43uZHlU5f?= =?us-ascii?q?rEWYfjjQDRavdfbKqRB3YdudrMuyI/jj+gdIlJ/nuvgi96ofX32mhRGtQdfGoo?= =?us-ascii?q?/8rNKKrFGBdKPlPOCnfHDOUiDMjQiuircgEZbK5TLfMA1BK5l10XAke4TuCXbX?= =?us-ascii?q?PRRaIKIWP0hbVadkZthdv+9VedRkd7gT+a9xGB2IWwnjGIqxo/laNlzTXyjRLz?= =?us-ascii?q?2d8uyjpoLe9afSSeb8acCQxXvLXqx6M4xm5jn8HrflzZVR+lHq2vt38EN1V0TG?= =?us-ascii?q?OTibrNv9PgML+NWidkz6s50zAzzZHZdwn2Dxxkxbc8oXRDOq/4oGxJxF73b/VP?= =?us-ascii?q?x33lL1sOJM67lu8ZM37KxxyceoOafSLuxXsVd8AhiIHApl64ktDXNkR2BWf+8R?= =?us-ascii?q?MuvecrofjcDyseD4DagX5AeS++xDZtvNP1vBldWnCjGAVRxEmx8MqSIALgSCyf?= =?us-ascii?q?GKhrR5SduhpejlwEIi+Ua+Lh8BzLBp+4iE5rCEpOjNbxve1bIEQLTlRtvvrrQw?= =?us-ascii?q?vEOf/fgkm6QKemxxfQKnDPQdWdQHyWr7y6Al0z4sE9jfEL364P5MSWg1njT+lJ?= =?us-ascii?q?BhB18WAO8bHaKX/YRCmWc1g+7ZOccMcqBFgWaPEQSrEqEZxH6u9iuXJHVlghDS?= =?us-ascii?q?3BHxW2yz6kT2oTV/QSvWwNfpilBVWaWvBUdOQyqpPld1sDGVMwruutr3o6M141?= =?us-ascii?q?woPWH/qNKCjm2hOKhQH8HlItyTPzU0rkoNjJItXtyvxZwbGd2lLdce7XF+b//e?= =?us-ascii?q?62e1nC9EuKpImpTR7dqU+vrNG3mslaqaq6+CxDpA0Hg3oUk/6sy8NvHJ/9CKRf?= =?us-ascii?q?Co2n0QTyd5vgvNRR+1qrrVr1AOI0OLy1vLmJYXPt5FwXk4y1vm6/Y5TNI07gVe?= =?us-ascii?q?GZ7KZ+keqjDrJDv03VGfbsoyVimZ1TtXAl31HkdjFag52WL/psTJmmnM+1wmQY?= =?us-ascii?q?lwbU/nhQdtA4U+N00t9EAdwjAfHggVdRCbELaoCFzhLYsfUEgOaQ+K3Lakdagq?= =?us-ascii?q?2k1z2Kmg5PfJbex7BaoCKOpSjhKUkFhcAJIWvrUUQKhgdF9F6K7Xug/iBpD8X/?= =?us-ascii?q?f8i3o/L/K1Td5B8c0CrHst+Bi/SACv6Zhd9LYXkpaIebBYYZLUpsBz819n5SIT?= =?us-ascii?q?dixKmBV/jRK5UeUHqeDm/NfasISn6vyvVKYrSOUb7R40CHpij5HomlAsvcnX1/?= =?us-ascii?q?tASo3SkYn/8QFMLGSQt4nGyBR8MvQBK561c7l87XkHIDIeJ30WN9qMd/Y8+zNt?= =?us-ascii?q?MCnU51FaGcwMZMgYPcTXlgBWi03pRKlT+dDGGl+cEIp8a8co4Hfpxz8v7Js8SO?= =?us-ascii?q?Hg6CWsKpzF6FFNJfxDhj12lN3evOgV3ebSCC8P7HmBcRd13j+Ny5mDCvb35+WM?= =?us-ascii?q?y8jYV0gYES4yUoddIieC+AO8S+qtjprpTh+b6s/9gZI5bkKQRWa9nKcbvaZWF+?= =?us-ascii?q?5PlCH70iJZFoDviPKfq8Cs53dPtl1bDIZz6gXIGLlFPpplPRT3jM+rSVZnCyTi?= =?us-ascii?q?ecHUeRsuuPaMyecX+ep+LVb+aZUdIh0a17Lw8WBVQRd2SL7qolaZWvocZNR8R/?= =?us-ascii?q?PesH9V9YJgJrQLPFicuJzlsDdIp0orAA8ycrMwqCJVdlXWlg1PR6n0oKIAihcb?= =?us-ascii?q?UdNhtk9DB2SwOH455zrAUqhVl7eeCPgU8jWVU6wPXF5lMidgTBOv2JRhYaGlnf?= =?us-ascii?q?ZZvWNahil9uuQl0yR6RBugvi3hv6QN2TM897G/sDUOo2dFQv+fkyfPDlVD1+8K?= =?us-ascii?q?gLwZC3vt5l2wen4DbJH94LN/P8Tv6ZEh42gjYRUkZyAGUvivCzrrj6+RH4KBv9?= =?us-ascii?q?RShB+LuMXTYr6+NicSNrEnxhLlWXdxyA/enAxn8GETWDWv8MckJJmhOcYi3ieo?= =?us-ascii?q?G2/bdFYK4q9TrMTxtVoLTPYrZlJgwWVj1NOHRi4MRMHUBWY1jxYkZn9AcJ1e6B?= =?us-ascii?q?8WDa8ojSiUvqNe5AEbfC/UEpi5+onXhcrI2Gc9Qs1sxm/Noq2Fm44l0Hxim9Nv?= =?us-ascii?q?9CKOv24Sd+PAWc92HnfzzptfyfD5Z/i1sOAIVoVmyLqlUPIZPMis422214t2Wk?= =?us-ascii?q?O/wLQRAUa5OvcZxrjHSyelVXGYWeOTfmiDmzY5NUDz6gesLl0zc8pKtEg9Mu3D?= =?us-ascii?q?hpFAjQHhV617RjmIr1/B0GMjKf8adx4xuIq/eQwKTO4QZ/CbJegqwf0+FEUDYm?= =?us-ascii?q?TMHSt3F++2q0CikJJ8O3V67kXwef7t/Rz+MNuOBhkEFpbXrpFs+fy7W22BPmRt?= =?us-ascii?q?zAFoPEZq8effC04+tutGfJaXgdfQhs503fQDd/hzLS03osQTlZ576YmIzMeKdg?= =?us-ascii?q?nczorzJdHQufWYH/zfwFgpem5EVroVewX16JsmPtQhQb3cAaNZvQgABag9WJEh?= =?us-ascii?q?Mmbx9KJ3LAN0aQPRZq67gsrtpuKNeJRUoWXa7lQuIyfAoxcD0OC7TRRnb5C2gH?= =?us-ascii?q?X/OIs/SSxHr91xERZmB49PG8Qcrwq7HZ6bhry0h8W2+0NgtO8AqbDwBezS1NSl?= =?us-ascii?q?w4VxWIBX5UKVMzbVBalrmlpqg/+zg/fB15nxDN3teckAVOdlWGLFbaXGHoqnID?= =?us-ascii?q?KUJs38Y1JG86Kb0L9hXBSRfDr5X6uauyK6L/hk5EQ7ypBifOXN1jAt6Kvb2NTq?= =?us-ascii?q?bWFBuiijtWKJNIdY7FHSAuzeWwxbROGd8GZhB6IXdpf09OYSPtw+2tiT/Rd84C?= =?us-ascii?q?5E0MSbP6irtlXM1V5jdZLHMEvp3D40WY0LIBS5LEstjnbVqnDcAXRHMsikMtJg?= =?us-ascii?q?gNePARzr4El9g2YtZnROGmDwX9eeJXAb296iZA2N7A9LFMgMn+q2eU4+q62zRu?= =?us-ascii?q?5kNJpZmeWqqroHi8hmKznVS8VBPCHfMqV2PjxPAeXLv1cofxEEv6IyWocvapiE?= =?us-ascii?q?OFkHP1uYySPu0QvC1lX5d9m226mVICYW83NHz7Xe3DhSpgm5v+iWgsniULDfcZ?= =?us-ascii?q?H3U+TeMC0/VjGVXT4yC1qm+U+4u/oYu/qVOWUfrUoXYiKVEwEevb1vrd7MDm/T?= =?us-ascii?q?nu1jYZIKhPCGWyzqTi13irYyDD5RtU+QW/oDCRXWb3j5jWpTogOtPeVM/XP7YL?= =?us-ascii?q?2c3adVRegWDZFXcv2YXtvUY/ZeKCk0lj8BIuazY8Xcr6ol0lLPVWYZEazI9FqE?= =?us-ascii?q?TE6MQ/yc3CnmXYMPsIgxpCUo+8jcnihtE6THJ7yfvSKh8pakjCaEvu3TTnItY0?= =?us-ascii?q?IwgO0eAWSMwwJNKH8aBNEPuUHsQ6mAZ0BW2HIvl+1uxwcGeB5vXX12zn1WgPG9?= =?us-ascii?q?F9VbSV4TimOuROYLbFVpAzwt80+K5RfybsAetszJQW9R6KcMGsIhK6wz5Y3WPr?= =?us-ascii?q?YA6Oo41zJh5iohumOSCE0OoBiC9v/qHal8z6dOrUkx/vd7RQnbWTLUcmHdxr2t?= =?us-ascii?q?PMJGxCFjuljuy8vSou13MrZG4Yp+BQFZUmpNOtnB8GUZAinP0wyoskP+RWyT?= X-IPAS-Result: =?us-ascii?q?A2FQAgBf+P1Y/wHyM5BcHAEBBAEBCgEBFwEBBAEBCgEBgwA?= =?us-ascii?q?pgW2Ob5FkkBmGKEAkig5XAQEBAQEBAQECAQJoKIIzIg1GJjIBAQEBAQEBAQEBA?= =?us-ascii?q?QEBAQEaAghIAQEgAhcNGQE5AgMJAgUSMQgDAWwFiEyBMgEDFQStFDomAoJhBYE?= =?us-ascii?q?ChEOCbgQIhEODbYJlgwWBcIV7BYkwhluBUotkknmCDYkMDIY/SIgniypYWC4mH?= =?us-ascii?q?SCEcgELATQPHIFkdIk2AQEB?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 24 Apr 2017 13:11:20 +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 v3ODBIxE013878; Mon, 24 Apr 2017 09:11:18 -0400 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 v3OD9xKB092931 for ; Mon, 24 Apr 2017 09:09:59 -0400 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 v3OD9wMC012879 for ; Mon, 24 Apr 2017 09:09:58 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1BjAQAX+P1YhnkAFEFcHAEBBAEBCgEBgyuCFo5vkWSQGYZrDoYWhGIBAgEBAQEBAhMBAQEKCQsIKIVlDRkBOAEVgTuIUYEyAQMVBK0UOoMJBYEChEOCSCYECIRDg22CZYMFgXCCYgyDDQWJMIZbgVKLZJJ5gg2JGIY/SIgniyqBLy4mHSCEcgFADxAMgWR0iTYBAQE X-IPAS-Result: A1BjAQAX+P1YhnkAFEFcHAEBBAEBCgEBgyuCFo5vkWSQGYZrDoYWhGIBAgEBAQEBAhMBAQEKCQsIKIVlDRkBOAEVgTuIUYEyAQMVBK0UOoMJBYEChEOCSCYECIRDg22CZYMFgXCCYgyDDQWJMIZbgVKLZJJ5gg2JGIY/SIgniyqBLy4mHSCEcgFADxAMgWR0iTYBAQE X-IronPort-AV: E=Sophos;i="5.37,244,1488862800"; d="scan'208";a="6026936" Received: from emsm-gh1-uea11.corp.nsa.gov (HELO emsm-gh1-uea11.nsa.gov) ([10.208.41.37]) by goalie.tycho.ncsc.mil with ESMTP; 24 Apr 2017 09:09:55 -0400 IronPort-PHdr: =?us-ascii?q?9a23=3AFP8nSRYXHO6eDA1EH0DgoBr/LSx+4OfEezUN459i?= =?us-ascii?q?sYplN5qZoMS9bnLW6fgltlLVR4KTs6sC0LuI9fy4EjFQqb+681k6OKRWUBEEjc?= =?us-ascii?q?hE1ycBO+WiTXPBEfjxciYhF95DXlI2t1uyMExSBdqsLwaK+i764jEdAAjwOhRo?= =?us-ascii?q?LerpBIHSk9631+ev8JHPfglEnjSwbLdzIRmsogjdqsYajIthJ60s1hbHv3xEdv?= =?us-ascii?q?hMy2h1P1yThRH85smx/J5n7Stdvu8q+tBDX6vnYak2VKRUAzs6PW874s3rrgTD?= =?us-ascii?q?QhCU5nQASGUWkwFHDBbD4RrnQ5r+qCr6tu562CmHIc37SK0/VDq+46t3ThLjlS?= =?us-ascii?q?EKPCM7/m7KkMx9lKJVrgy8qRJxwIDaZ5qYOOZicq7HYd8XX3ZNUtpXWidcAo28?= =?us-ascii?q?dYwPD+8ZMOhEronyu1sOogGkBQaxGejhyCVHhn7w3aIkyOQqDAbL3BYhH90SsH?= =?us-ascii?q?Tbts/1O7oKXu+p1KbIzS/Mb/JQ2Tjj84jFaQsuoe2NXbJ2bcre11MvFwXbgVWM?= =?us-ascii?q?s4DqIzSV1uEUvmWd8uFuVvqvhnYmpgxxuDSj2NsghpPVio4P11zI6zh1zJ42KN?= =?us-ascii?q?C5UkJ3fNGpHZpKuyybNYZ6WMEvTmVutS0n0LMJo4S7czIPyJk/xx7QdfiHc4+Q?= =?us-ascii?q?7xL5W+aRJip4hG55dL6inRq96lSgxvf4Vsmz1lZHrjBJncXUtn8R0xzT7dWHRe?= =?us-ascii?q?Zn8ki93jaDzR3T6uJcLUA1k6rUNYIhz6Yxm5cTq0jPADP6lF/qgKOMa0ko5PWk?= =?us-ascii?q?5/ziYrr8p5+cM4F0ihv5MqQrgsG/G+U4PRQOX2eB4+SzyaXs8lHhT7VKlPI2k6?= =?us-ascii?q?/Zv47BJckAvaG5Hw5V0oA/6xmhFTem1soXnWUdIF1ZfxKHipDlO0vSL/DgEfe/?= =?us-ascii?q?n1OsnS9wx//YOr3hA5PNLmXMkbr6YbZ861JTyAo0zdxF4ZJUEasOLOj8Wk/2qt?= =?us-ascii?q?yLRiM+Zhe5x+fhFcVVypIVWWXJBLSQdqzVrwym/OUqdtONb48cojq1C/Ek4fP1?= =?us-ascii?q?xSsjmFQddLOl6pAgaHm5GPl9C0+FYHzwj80HHHtMtQ07Gr+5wGaeWCJeMi7hF5?= =?us-ascii?q?k34Ss2Xdqr?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0GzAABf+P1YhnkAFEFcHAEBBAEBCgEBF?= =?us-ascii?q?wEBBAEBCgEBgwCCFo5vkWSQGYYoQw6GFoRiAQEBAQEBAQECAQIQAQEBCgkLCCg?= =?us-ascii?q?vgjMgD0YmMgEBAQEBAQEBAQEBAQEBARoCCEgBOg0ZATgBFYE7iFGBMgEDFQStF?= =?us-ascii?q?DqDCQWBAoRDgkgmBAiEQ4NtgmWDBYFwgmIMgw0FiTCGW4FSi2SSeYINiRiGP0i?= =?us-ascii?q?IJ4sqgTAuJh0ghHIBQA8QDIFkdIk2AQEB?= X-IPAS-Result: =?us-ascii?q?A0GzAABf+P1YhnkAFEFcHAEBBAEBCgEBFwEBBAEBCgEBgwC?= =?us-ascii?q?CFo5vkWSQGYYoQw6GFoRiAQEBAQEBAQECAQIQAQEBCgkLCCgvgjMgD0YmMgEBA?= =?us-ascii?q?QEBAQEBAQEBAQEBARoCCEgBOg0ZATgBFYE7iFGBMgEDFQStFDqDCQWBAoRDgkg?= =?us-ascii?q?mBAiEQ4NtgmWDBYFwgmIMgw0FiTCGW4FSi2SSeYINiRiGP0iIJ4sqgTAuJh0gh?= =?us-ascii?q?HIBQA8QDIFkdIk2AQEB?= X-IronPort-AV: E=Sophos;i="5.37,244,1488844800"; d="scan'208";a="5142038" X-IronPort-Outbreak-Status: No, level 0, Unknown - Unknown Received: from rgout0101.bt.lon5.cpcloud.co.uk (HELO rgout01.bt.lon5.cpcloud.co.uk) ([65.20.0.121]) by emsm-gh1-uea11.nsa.gov with ESMTP; 24 Apr 2017 13:09:54 +0000 X-OWM-Source-IP: 86.146.67.79 (GB) X-OWM-Env-Sender: richard_c_haines@btinternet.com X-Junkmail-Premium-Raw: score=8/50, refid=2.7.2:2017.4.19.110016:17:8.707, ip=, rules=NO_URI_FOUND, NO_CTA_URI_FOUND, NO_MESSAGE_ID, NO_URI_HTTPS, TO_MALFORMED Received: from localhost.localdomain (86.146.67.79) by rgout01.bt.lon5.cpcloud.co.uk (9.0.019.13-1) (authenticated as richard_c_haines@btinternet.com) id 58F62BE300B06E7C; Mon, 24 Apr 2017 14:09:52 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=btinternet.com; s=btcpcloud; t=1493039394; bh=/Y4gdLBZqSTe0RqZtA78+/m52OD1mhF2wcvtIVLenDg=; h=From:To:Cc:Subject:Date:Message-Id:X-Mailer; b=dWKkzoFoSWpDSnGQFj8Vfp9g4QqSwg4QkGE0N0KLv03XCBr/uiwM/mRc7lsmrDzBYrixmMQ+IU0IwQPymv/dGm7KEEgbaKCUxxFVaPA+j6MkoZcnhVLarAnOvL6l629glbkW+qjYlgCQIisZ652vm1Ps6u7rXg8bGL/3T4xQrGE= From: Richard Haines To: selinux@tycho.nsa.gov Subject: [RFC PATCH 1/1] libselinux: Add support for selinux_check_access_flags Date: Mon, 24 Apr 2017 14:09:44 +0100 Message-Id: <20170424130944.5334-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: Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP Add function selinux_check_access_flags() that is the same as selinux_check_access() except that it will also return the avd flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE flag is used to signify that the source type is defined as permissive in policy. Because selinux_check_access_flags() can return before the AVC call, and also the AVC call may return with undefined avd flags, the returned flags should be checked for SELINUX_AVD_FLAGS_UNDEFINED, first. If set, the remaining flags are undefined. See the selinux_check_access_flags() man page entry for details. There is a utility for testing the functionality: utils/selinux_check_access -f scon tcon class perm As a consequence of implementing selinux_check_access_flags, additional calls have been added to avc.c: avc_has_perm_flags() and avc_has_perm_noaudit_flags(). The appropriate man pages have been updated. There is a utility for testing the avc_has_perm() and avc_has_perm_flags(): utils/avc_has_perm -f scon tcon class perm Signed-off-by: Richard Haines --- libselinux/include/selinux/avc.h | 68 +++++++ libselinux/include/selinux/selinux.h | 32 +++ libselinux/man/man3/avc_has_perm.3 | 37 +++- libselinux/man/man3/security_compute_av.3 | 21 +- libselinux/man/man3/selinux_check_access_flags.3 | 1 + libselinux/src/avc.c | 44 ++++- libselinux/src/avc_internal.h | 1 + libselinux/src/checkAccess.c | 63 +++--- libselinux/utils/.gitignore | 2 + libselinux/utils/avc_has_perm.c | 235 +++++++++++++++++++++++ libselinux/utils/selinux_check_access.c | 189 ++++++++++++++++++ 11 files changed, 660 insertions(+), 33 deletions(-) create mode 100644 libselinux/man/man3/selinux_check_access_flags.3 create mode 100644 libselinux/utils/avc_has_perm.c create mode 100644 libselinux/utils/selinux_check_access.c diff --git a/libselinux/include/selinux/avc.h b/libselinux/include/selinux/avc.h index b4bc6f3..89d75c3 100644 --- a/libselinux/include/selinux/avc.h +++ b/libselinux/include/selinux/avc.h @@ -264,6 +264,43 @@ int avc_has_perm_noaudit(security_id_t ssid, struct avc_entry_ref *aeref, struct av_decision *avd); /** + * avc_has_perm_noaudit_flags - Check permissions but perform no auditing, + * return avd flags. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @avd: access vector decisions + * @flags: returned avd flags. Currently two flags are supported: + * SELINUX_AVD_FLAGS_UNDEFINED This is typically set when the + * source or target context is not valid in policy, or the + * avc is in permissive mode, or the returned entry could not be + * inserted into the avc cache. + * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is + * computed on a policy defined permissive domain. + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions, and return a copy of the decisions + * in @avd. Return %0 if all @requested permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied, or to another value + * upon other errors. This function is typically called by avc_has_perm(), + * but may also be called directly to separate permission checking from + * auditing, e.g. in cases where a lock must be held for the check but + * should be released for the auditing. + */ +int avc_has_perm_noaudit_flags(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, + struct av_decision *avd, + unsigned int *flags); + +/** * avc_has_perm - Check permissions and perform any appropriate auditing. * @ssid: source security identifier * @tsid: target security identifier @@ -286,6 +323,37 @@ int avc_has_perm(security_id_t ssid, security_id_t tsid, struct avc_entry_ref *aeref, void *auditdata); /** + * avc_has_perm_flags - Check permissions, returning avd flags and perform any + * appropriate auditing. + * @ssid: source security identifier + * @tsid: target security identifier + * @tclass: target security class + * @requested: requested permissions, interpreted based on @tclass + * @aeref: AVC entry reference + * @auditdata: auxiliary audit data + * @flags: returned avd flags. Currently two flags are supported: + * SELINUX_AVD_FLAGS_UNDEFINED This is typically caused when the + * source or target context is not valid in policy, or the + * avc is in permissive mode, or the returned entry could not be + * inserted into the avc cache. + * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is + * computed on a policy defined permissive domain. + * + * Check the AVC to determine whether the @requested permissions are granted + * for the SID pair (@ssid, @tsid), interpreting the permissions + * based on @tclass, and call the security server on a cache miss to obtain + * a new decision and add it to the cache. Update @aeref to refer to an AVC + * entry with the resulting decisions. Audit the granting or denial of + * permissions in accordance with the policy. Return %0 if all @requested + * permissions are granted, -%1 with @errno set to %EACCES if any permissions + * are denied or to another value upon other errors. + */ +int avc_has_perm_flags(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata, + unsigned int *flags); + +/** * avc_audit - Audit the granting or denial of permissions. * @ssid: source security identifier * @tsid: target security identifier diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index 45dd6ca..4e9d209 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -136,6 +136,7 @@ struct av_decision { /* Definitions of av_decision.flags */ #define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 +#define SELINUX_AVD_FLAGS_UNDEFINED 0x8000 /* Structure for passing options, used by AVC and label subsystems */ struct selinux_opt { @@ -578,6 +579,37 @@ extern const char *selinux_path(void); */ extern int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata); +/** + * selinux_check_access_flags - Check permissions, returning avd flags and + * perform any appropriate auditing. + * @scon: source security context + * @tcon: target security context + * @tclass: target security class string + * @perm: requested permissions string, interpreted based on @tclass + * @auditdata: auxiliary audit data + * @flags: returned avd flags. Currently two flags are supported: + * SELINUX_AVD_FLAGS_UNDEFINED, which indicates that the remaining + * @flags should not be checked as the avd flags could not be read. + * SELINUX_AVD_FLAGS_PERMISSIVE, which indicates the decision is + * computed on a policy defined permissive domain. + * + * Check the AVC to determine whether the @perm permissions are granted + * for the SID pair (@scon, @tcon), interpreting the permissions + * based on @tclass. + * Return %0 if all @perm permissions are granted, -%1 with + * @errno set to %EACCES if any permissions are denied or to another + * value upon other errors. + * If auditing or logging is configured the appropriate callbacks will be + * called and passed the auditdata field. + * If selinux_check_access_flags() fails before calling the AVC, then @flags + * will be returned with a value of SELINUX_AVD_FLAGS_UNDEFINED as the avd + * flags could not be read. This will happen when either SELinux is disabled + * or there is an unknown class/permission. + */ +extern int selinux_check_access_flags(const char *scon, const char *tcon, + const char *tclass, const char *perm, + void *auditdata, unsigned int *flags); + /* Check a permission in the passwd class. Return 0 if granted or -1 otherwise. */ extern int selinux_check_passwd_access(access_vector_t requested); diff --git a/libselinux/man/man3/avc_has_perm.3 b/libselinux/man/man3/avc_has_perm.3 index 3e9fca8..74d3420 100644 --- a/libselinux/man/man3/avc_has_perm.3 +++ b/libselinux/man/man3/avc_has_perm.3 @@ -19,6 +19,13 @@ avc_has_perm, avc_has_perm_noaudit, avc_audit, avc_entry_ref_init \- obtain and .BI "struct avc_entry_ref *" aeref ", void *" auditdata ");" .in .sp +.BI "int avc_has_perm_flags(security_id_t " ssid ", security_id_t " tsid , +.in +\w'int avc_has_perm('u +.BI "security_class_t " tclass ", access_vector_t " requested , +.br +.BI "struct avc_entry_ref *" aeref ", void *" auditdata ", int *" flags ");" +.in +.sp .BI "int avc_has_perm_noaudit(security_id_t " ssid ", security_id_t " tsid , .in +\w'int avc_has_perm('u .BI "security_class_t " tclass ", access_vector_t " requested , @@ -60,6 +67,21 @@ parameter is for supplemental auditing; see .BR avc_audit () below. +.BR avc_has_perm_flags () +is identical to +.BR avc_has_perm () +but additionally sets the +.I flags +field. On return +.I flags +must be tested and if +.BR SELINUX_AVD_FLAGS_UNDEFINED , +then the remaining +.I flags +should not be checked. Currently one other flag is supported: +.BR SELINUX_AVD_FLAGS_PERMISSIVE , +which indicates the decision is computed on a policy defined permissive domain. + .BR avc_has_perm_noaudit () behaves as .BR avc_has_perm () @@ -69,6 +91,15 @@ and can be passed to .BR avc_audit () explicitly. +.BR avc_has_perm_noaudit_flags () +behaves as +.BR avc_has_perm_flags () +without producing an audit message. The access decision is returned in +.I avd +and can be passed to +.BR avc_audit () +explicitly. + .BR avc_audit () produces an audit message for the access query represented by .IR ssid , @@ -101,9 +132,11 @@ After declaring an structure, use .BR avc_entry_ref_init () to initialize it before passing it to -.BR avc_has_perm () +.BR avc_has_perm (), +.BR avc_has_perm_flags (), +.BR avc_has_perm_noaudit () or -.BR \%avc_has_perm_noaudit () +.BR avc_has_perm_noaudit_flags () for the first time. Using an uninitialized structure will produce undefined behavior. . diff --git a/libselinux/man/man3/security_compute_av.3 b/libselinux/man/man3/security_compute_av.3 index 2aade5f..2a9312f 100644 --- a/libselinux/man/man3/security_compute_av.3 +++ b/libselinux/man/man3/security_compute_av.3 @@ -39,7 +39,9 @@ the SELinux policy database in the kernel .sp .BI "int security_get_initial_context_raw(const char *" name ", char **" con ); .sp -.BI "int selinux_check_access(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata); +.BI "int selinux_check_access(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata ); +.sp +.BI "int selinux_check_access_flags(const char *" scon ", const char *" tcon ", const char *" class ", const char *" perm ", void *" auditdata ", int *" flags ); .sp .BI "int selinux_check_passwd_access(access_vector_t " requested ); .sp @@ -67,7 +69,7 @@ field of .IR avd . Currently one flag is supported: .BR SELINUX_AVD_FLAGS_PERMISSIVE , -which indicates the decision is computed on a permissive domain. +which indicates the decision is computed on a policy defined permissive domain. .BR security_compute_create () is used to compute a context to use for labeling a new object in a particular @@ -119,6 +121,21 @@ translation. .BR selinux_check_access () is used to check if the source context has the access permission for the specified class on the target context. +.BR selinux_check_access_flags () +is identical to +.BR selinux_check_access () +but additionally sets the +.I flags +field. On return +.I flags +must be tested and if +.BR SELINUX_AVD_FLAGS_UNDEFINED , +then the remaining +.I flags +should not be checked. Currently one other flag is supported: +.BR SELINUX_AVD_FLAGS_PERMISSIVE , +which indicates the decision is computed on a policy defined permissive domain. + .BR selinux_check_passwd_access () is used to check for a permission in the .I passwd diff --git a/libselinux/man/man3/selinux_check_access_flags.3 b/libselinux/man/man3/selinux_check_access_flags.3 new file mode 100644 index 0000000..a60bca4 --- /dev/null +++ b/libselinux/man/man3/selinux_check_access_flags.3 @@ -0,0 +1 @@ +.so man3/security_compute_av.3 diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c index b1ec57f..87f4c76 100644 --- a/libselinux/src/avc.c +++ b/libselinux/src/avc.c @@ -741,12 +741,27 @@ static void avd_init(struct av_decision *avd) avd->flags = 0; } + int avc_has_perm_noaudit(security_id_t ssid, security_id_t tsid, security_class_t tclass, access_vector_t requested, struct avc_entry_ref *aeref, struct av_decision *avd) { + return avc_has_perm_noaudit_flags(ssid, tsid, tclass, + requested, aeref, avd, NULL); +} + +hidden_def(avc_has_perm_noaudit) + +int avc_has_perm_noaudit_flags(security_id_t ssid, + security_id_t tsid, + security_class_t tclass, + access_vector_t requested, + struct avc_entry_ref *aeref, + struct av_decision *avd, + unsigned int *flags) +{ struct avc_entry *ae; int rc = 0; struct avc_entry entry; @@ -790,13 +805,13 @@ int avc_has_perm_noaudit(security_id_t ssid, &entry.avd); if (rc && errno == EINVAL && !avc_enforcing) { rc = errno = 0; - goto out; + goto set_undef; } if (rc) - goto out; + goto set_undef; rc = avc_insert(ssid, tsid, tclass, &entry, aeref); if (rc) - goto out; + goto set_undef; } ae = aeref->ae; } @@ -816,21 +831,38 @@ int avc_has_perm_noaudit(security_id_t ssid, } } - out: + if (flags) + *flags = ae->avd.flags; +out: avc_release_lock(avc_lock); return rc; + +set_undef: + if (flags) + *flags = SELINUX_AVD_FLAGS_UNDEFINED; + goto out; } -hidden_def(avc_has_perm_noaudit) +hidden_def(avc_has_perm_noaudit_flags) int avc_has_perm(security_id_t ssid, security_id_t tsid, security_class_t tclass, access_vector_t requested, struct avc_entry_ref *aeref, void *auditdata) { + return avc_has_perm_flags(ssid, tsid, tclass, requested, aeref, + auditdata, NULL); +} + +int avc_has_perm_flags(security_id_t ssid, security_id_t tsid, + security_class_t tclass, access_vector_t requested, + struct avc_entry_ref *aeref, void *auditdata, + unsigned int *flags) +{ struct av_decision avd; int errsave, rc; - rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd); + rc = avc_has_perm_noaudit_flags(ssid, tsid, tclass, + requested, aeref, &avd, flags); errsave = errno; avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); errno = errsave; diff --git a/libselinux/src/avc_internal.h b/libselinux/src/avc_internal.h index f851659..82781d1 100644 --- a/libselinux/src/avc_internal.h +++ b/libselinux/src/avc_internal.h @@ -179,4 +179,5 @@ hidden_proto(avc_av_stats) hidden_proto(avc_reset) hidden_proto(avc_audit) hidden_proto(avc_has_perm_noaudit) + hidden_proto(avc_has_perm_noaudit_flags) #endif /* _SELINUX_AVC_INTERNAL_H_ */ diff --git a/libselinux/src/checkAccess.c b/libselinux/src/checkAccess.c index 8de5747..0a3d79b 100644 --- a/libselinux/src/checkAccess.c +++ b/libselinux/src/checkAccess.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ #include #include #include @@ -32,7 +31,16 @@ static void avc_init_once(void) } } -int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) { +int selinux_check_access(const char *scon, const char *tcon, const char *class, + const char *perm, void *aux) +{ + return selinux_check_access_flags(scon, tcon, class, perm, aux, NULL); +} + +int selinux_check_access_flags(const char *scon, const char *tcon, + const char *class, const char *perm, + void *aux, unsigned int *flags) +{ int rc; security_id_t scon_id; security_id_t tcon_id; @@ -41,6 +49,13 @@ int selinux_check_access(const char *scon, const char *tcon, const char *class, __selinux_once(once, avc_init_once); + /* Set flags undefined as avc_has_perm_flags may never get called, + * as either SELinux is disabled or there is an unknown + * class/permission. + */ + if (flags) + *flags = SELINUX_AVD_FLAGS_UNDEFINED; + if (selinux_enabled != 1) return 0; @@ -54,27 +69,29 @@ int selinux_check_access(const char *scon, const char *tcon, const char *class, (void) avc_netlink_check_nb(); - sclass = string_to_security_class(class); - if (sclass == 0) { - rc = errno; - avc_log(SELINUX_ERROR, "Unknown class %s", class); - if (security_deny_unknown() == 0) - return 0; - errno = rc; - return -1; - } - - av = string_to_av_perm(sclass, perm); - if (av == 0) { - rc = errno; - avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", perm, class); - if (security_deny_unknown() == 0) - return 0; - errno = rc; - return -1; - } - - return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); + sclass = string_to_security_class(class); + if (sclass == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown class %s", class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + av = string_to_av_perm(sclass, perm); + if (av == 0) { + rc = errno; + avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", + perm, class); + if (security_deny_unknown() == 0) + return 0; + errno = rc; + return -1; + } + + return avc_has_perm_flags(scon_id, tcon_id, sclass, av, NULL, + aux, flags); } int selinux_check_passwd_access(access_vector_t requested) diff --git a/libselinux/utils/.gitignore b/libselinux/utils/.gitignore index ed3bf0b..07c0870 100644 --- a/libselinux/utils/.gitignore +++ b/libselinux/utils/.gitignore @@ -25,3 +25,5 @@ selinuxexeccon setenforce setfilecon togglesebool +avc_has_perm +selinux_check_access diff --git a/libselinux/utils/avc_has_perm.c b/libselinux/utils/avc_has_perm.c new file mode 100644 index 0000000..c144674 --- /dev/null +++ b/libselinux/utils/avc_has_perm.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(char *progname) +{ + fprintf(stderr, "usage: %s [-f] [-i] [-p] scon tcon class perm\n" + "\nWhere:\n\t" + "-f Call avc_has_perm_flags(3) to obtain the avd\n\t" + " flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE\n\t" + " flag is defined. If set, signifies the source type is\n\t" + " defined in policy as a PERMISSIVE type.\n\t" + " The default is to call avc_has_perm(3) that\n\t" + " does not request the avd flags.\n\t" + "-i Interactive mode. Once displayed first result, can\n\t" + " enter additional entries and display AVC cache info.\n" + "-p Set avc_open to permissive mode.\n", + progname); + exit(1); +} + +static void get_entry(char **buffer) +{ + char *buf; + int len; +#define BUF_LEN 81 + + buf = malloc(BUF_LEN * sizeof(char)); + if (!buf) { + perror("malloc"); + exit(1); + } + + if (fgets(buf, BUF_LEN - 1, stdin) == NULL) { + perror("fgets"); + exit(1); + } + + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = 0; + + *buffer = buf; +} + +/* + * Function to print the AVC statistics. Because no audit logging call back + * has been set, the avc_cache_stats will be displayed on stderr. + */ +static void print_avc_stats(void) +{ + struct avc_cache_stats acs; + + avc_cache_stats(&acs); + printf("\nThe avc_cache_stats are as follows:\n"); + printf("entry_hits: %d\t(Decisions found in aeref)\n", + acs.entry_hits); + printf("entry_misses: %d\t(Decisions not found in aeref)\n", + acs.entry_misses); + printf("entry_discards: %d\t(Decisions not found in aeref that were " + "also non-NULL)\n", acs.entry_discards); + printf("entry_lookups: %d\t(Queries made)\n", acs.entry_lookups); + printf("cav_lookups: %d\t(Cache lookups)\n", acs.cav_lookups); + printf("cav_hits: %d\t(Cache hits)\n", acs.cav_hits); + printf("cav_probes: %d\t(Entries examined searching the cache)\n", + acs.cav_probes); + printf("cav_misses: %d\t(Cache misses)\n\n", acs.cav_misses); +} + +struct avc_entry_ref aeref; +static void exec_func(char *scon, char *tcon, char *class, char *perm, + bool get_flags) +{ + int rc; + unsigned int flags; + context_t context; + const char *type; + security_id_t scon_id; + security_id_t tcon_id; + security_class_t sclass; + access_vector_t av; + + rc = avc_context_to_sid(scon, &scon_id); + if (rc < 0) { + perror("Error scon avc_context_to_sid"); + exit(1); + } + + rc = avc_context_to_sid(tcon, &tcon_id); + if (rc < 0) { + perror("Error tcon avc_context_to_sid"); + exit(1); + } + + sclass = string_to_security_class(class); + av = string_to_av_perm(sclass, perm); + + context = context_new(scon); + if (!context) { + perror("Error context_new"); + exit(1); + } + type = context_type_get(context); + if (!type) { + perror("Error context_type_get"); + free(context); + exit(1); + } + + printf("\nAny avc_log error messages are shown on stderr:\n"); + if (get_flags) + rc = avc_has_perm_flags(scon_id, tcon_id, sclass, av, &aeref, + NULL, &flags); + else + rc = avc_has_perm(scon_id, tcon_id, sclass, av, &aeref, NULL); + printf("\nEnd of avc_log error messages.\n\n"); + + if (rc < 0) { + printf("Error %s: %s\n", + get_flags ? "avc_has_perm_flags" : "avc_has_perm", + strerror(errno)); + } else { + printf("Permission ALLOWED.\n"); + } + + if (get_flags) { + if (flags & SELINUX_AVD_FLAGS_UNDEFINED) + printf("AVD flags are undefined.\n"); + else if (flags & SELINUX_AVD_FLAGS_PERMISSIVE) + printf("%s is defined in policy as a PERMISSIVE " + "domain.\n", type); + else + printf("%s is NOT defined in policy as a PERMISSIVE " + "domain.\n", type); + } + context_free(context); +} + +int main(int argc, char **argv) +{ + int opt, rc; + bool get_flags = false, interactive = false; + char *scon, *tcon, *class, *perm; + struct selinux_opt avc_option; + + avc_option.type = AVC_OPT_SETENFORCE; + avc_option.value = (char *)1; + + while ((opt = getopt(argc, argv, "fip")) != -1) { + switch (opt) { + case 'f': + get_flags = true; + break; + case 'i': + interactive = true; + break; + case 'p': + avc_option.value = NULL; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 4) + usage(argv[0]); + + rc = is_selinux_enabled(); + if (rc == 0) { + printf("SELinux is not enabled.\n"); + exit(1); + } else if (rc == 1) { + printf("SELinux is enabled.\n"); + } else { + perror("Error is_selinux_enabled"); + exit(1); + } + + rc = security_getenforce(); + if (rc == 0) + printf("SELinux running in PERMISSIVE mode.\n"); + else if (rc == 1) + printf("SELinux running in ENFORCING mode.\n"); + else { + perror("Error security_getenforce"); + exit(1); + } + + rc = security_deny_unknown(); + if (rc == 0) + printf("Undefined object classes or permissions: ALLOWED.\n"); + else if (rc == 1) + printf("Undefined object classes or permissions: DENIED.\n"); + else { + perror("Error security_deny_unknown"); + exit(1); + } + + if (avc_open(&avc_option, 1)) { + perror("Error avc_open"); + exit(1); + } + + if (avc_option.value == NULL) + printf("avc_open - PERMISSIVE mode.\n"); + else + printf("avc_open - ENFORCING mode.\n"); + + avc_entry_ref_init(&aeref); + + exec_func(argv[optind], argv[optind + 1], argv[optind + 2], + argv[optind + 3], get_flags); + + while (interactive) { + printf("\nEnter scon: "); + get_entry(&scon); + printf("Enter tcon: "); + get_entry(&tcon); + printf("Enter class: "); + get_entry(&class); + printf("Enter perm: "); + get_entry(&perm); + + exec_func(scon, tcon, class, perm, get_flags); + print_avc_stats(); + } + + exit(0); +} diff --git a/libselinux/utils/selinux_check_access.c b/libselinux/utils/selinux_check_access.c new file mode 100644 index 0000000..06cbaf5 --- /dev/null +++ b/libselinux/utils/selinux_check_access.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(char *progname) +{ + fprintf(stderr, "usage: %s [-f] [-i] scon tcon class perm\n" + "\nWhere:\n\t" + "-f Call selinux_check_access_flags(3) to obtain the avd\n\t" + " flags. Currently only the SELINUX_AVD_FLAGS_PERMISSIVE\n\t" + " flag is defined. If set, signifies the source type is\n\t" + " defined in policy as a PERMISSIVE type.\n\t" + " The default is to call selinux_check_access(3) that\n\t" + " does not request the avd flags.\n\t" + "-i Interactive mode. Once displayed first result, can\n\t" + " enter additional entries and display AVC cache info.\n", + progname); + exit(1); +} + +static void get_entry(char **buffer) +{ + char *buf; + int len; +#define BUF_LEN 81 + + buf = malloc(BUF_LEN * sizeof(char)); + if (!buf) { + perror("malloc"); + exit(1); + } + + if (fgets(buf, BUF_LEN - 1, stdin) == NULL) { + perror("fgets"); + exit(1); + } + + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = 0; + + *buffer = buf; +} + +/* + * Function to print the AVC statistics. Because no audit logging call back + * has been set, the avc_cache_stats will be displayed on stderr. + * selinux_check_access* sets aeref = NULL, so do not print these stats. + */ +static void print_avc_stats(void) +{ + struct avc_cache_stats acs; + + avc_cache_stats(&acs); + printf("\nThe avc_cache_stats are as follows:\n"); + printf("entry_lookups: %d\t(Queries made)\n", acs.entry_lookups); + printf("cav_lookups: %d\t(Cache lookups)\n", acs.cav_lookups); + printf("cav_hits: %d\t(Cache hits)\n", acs.cav_hits); + printf("cav_probes: %d\t(Entries examined searching the cache)\n", + acs.cav_probes); + printf("cav_misses: %d\t(Cache misses)\n\n", acs.cav_misses); +} + +static void exec_func(char *scon, char *tcon, char *class, char *perm, + bool get_flags) +{ + int rc; + unsigned int flags; + context_t context; + const char *type; + + context = context_new(scon); + if (!context) { + perror("Error context_new"); + exit(1); + } + type = context_type_get(context); + if (!type) { + perror("Error context_type_get"); + free(context); + exit(1); + } + + printf("\nAny avc_log error messages are shown on stderr:\n"); + if (get_flags) + rc = selinux_check_access_flags(scon, tcon, class, perm, + NULL, &flags); + else + rc = selinux_check_access(scon, tcon, class, perm, NULL); + printf("\nEnd of avc_log error messages.\n\n"); + + if (rc < 0) + printf("Error %s: %s\n", + get_flags ? "selinux_check_access_flags" : + "selinux_check_access", strerror(errno)); + else + printf("Permission ALLOWED.\n"); + + if (get_flags) { + if (flags & SELINUX_AVD_FLAGS_UNDEFINED) + printf("AVD flags are undefined.\n"); + else if (flags & SELINUX_AVD_FLAGS_PERMISSIVE) + printf("%s is defined in policy as a PERMISSIVE " + "domain.\n", type); + else + printf("%s is NOT defined in policy as a PERMISSIVE " + "domain.\n", type); + } + context_free(context); +} + +int main(int argc, char **argv) +{ + int opt, rc; + bool get_flags = false, interactive = false; + char *scon, *tcon, *class, *perm; + + while ((opt = getopt(argc, argv, "fi")) != -1) { + switch (opt) { + case 'f': + get_flags = true; + break; + case 'i': + interactive = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 4) + usage(argv[0]); + + rc = is_selinux_enabled(); + if (rc == 0) { + printf("SELinux is not enabled.\n"); + exit(1); + } else if (rc == 1) { + printf("SELinux is enabled.\n"); + } else { + perror("Error is_selinux_enabled"); + exit(1); + } + + rc = security_getenforce(); + if (rc == 0) + printf("SELinux running in PERMISSIVE mode.\n"); + else if (rc == 1) + printf("SELinux running in ENFORCING mode.\n"); + else { + perror("Error security_getenforce"); + exit(1); + } + + rc = security_deny_unknown(); + if (rc == 0) + printf("Undefined object classes or permissions: ALLOWED.\n"); + else if (rc == 1) + printf("Undefined object classes or permissions: DENIED.\n"); + else { + perror("Error security_deny_unknown"); + exit(1); + } + + exec_func(argv[optind], argv[optind + 1], argv[optind + 2], + argv[optind + 3], get_flags); + + while (interactive) { + printf("\nEnter scon: "); + get_entry(&scon); + printf("Enter tcon: "); + get_entry(&tcon); + printf("Enter class: "); + get_entry(&class); + printf("Enter perm: "); + get_entry(&perm); + + exec_func(scon, tcon, class, perm, get_flags); + print_avc_stats(); + } + + exit(0); +}