nether internal logic follow up 74/63574/6
authorr.kubiak <r.kubiak@samsung.com>
Thu, 24 Mar 2016 13:37:14 +0000 (14:37 +0100)
committerZbigniew Jasinski <z.jasinski@samsung.com>
Wed, 6 Apr 2016 10:05:57 +0000 (12:05 +0200)
- mark is always int32_t and -1 means that
  no packet marking is done, and the packet
  should go through normal iptables rules

- when not copying packet, address and port
  are zeroed to indicate this in logs

- the builtin privilege for cynara is used
  unless specified in the policy file or
  on the command line NETHER_CYNARA_INTERNET_PRIVILEGE

- new command line parameters for cynara
  backend are "policy" - defines the path
  of the policy file  and "privname" - defines
  the default privilege to use when doing
  cynara checks

Change-Id: I1b4a91685af7f27fff162317a63e15a2d1b7319c
Signed-off-by: Zbigniew Jasinski <z.jasinski@samsung.com>
12 files changed:
conf/CMakeLists.txt
conf/file.policy [new file with mode: 0644]
conf/nether.policy [deleted file]
conf/systemd/nether.service
conf/systemd/nether.service.in
include/nether_CynaraBackend.h
include/nether_Netlink.h
include/nether_Types.h
packaging/nether.spec
src/CMakeLists.txt
src/nether_CynaraBackend.cpp
src/nether_Netlink.cpp

index 9479e08ff4867a2bc71fa4338c46cec05978853a..26ddd727e098f373c78ab8866d9112e071eca2b0 100644 (file)
@@ -20,7 +20,7 @@ MESSAGE(STATUS "Installing config files")
 
 CONFIGURE_FILE(systemd/nether.service.in systemd/nether.service)
 
-INSTALL(FILES nether.policy DESTINATION ${SYSCONF_INSTALL_DIR}/nether)
+INSTALL(FILES file.policy DESTINATION ${SYSCONF_INSTALL_DIR}/nether)
 INSTALL(FILES cynara.policy DESTINATION ${SYSCONF_INSTALL_DIR}/nether)
 INSTALL(FILES nether.rules DESTINATION ${SYSCONF_INSTALL_DIR}/nether)
 INSTALL(FILES systemd/nether.service DESTINATION ${SYSTEMD_UNIT_DIR})
diff --git a/conf/file.policy b/conf/file.policy
new file mode 100644 (file)
index 0000000..bc8ff10
--- /dev/null
@@ -0,0 +1,29 @@
+#
+#  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#  Contact: Roman Kubiak (r.kubiak@samsung.com)
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License
+#
+
+#
+# Nether file policy backend configuration
+# $UID:$GID:$SECCTX ALLOW|DENY|ALLOW_LOG
+# If no match is found for a pcket
+# the default verdict is used (can be set via
+# command line)
+#
+
+0::_:ALLOW
+5002::_:DENY
+1354787703::_:ALLOW
diff --git a/conf/nether.policy b/conf/nether.policy
deleted file mode 100644 (file)
index bc8ff10..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-#  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
-#
-#  Contact: Roman Kubiak (r.kubiak@samsung.com)
-#
-#  Licensed under the Apache License, Version 2.0 (the "License");
-#  you may not use this file except in compliance with the License.
-#  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License
-#
-
-#
-# Nether file policy backend configuration
-# $UID:$GID:$SECCTX ALLOW|DENY|ALLOW_LOG
-# If no match is found for a pcket
-# the default verdict is used (can be set via
-# command line)
-#
-
-0::_:ALLOW
-5002::_:DENY
-1354787703::_:ALLOW
index 6c2ca1f2d7c2f1a13a2283ac5346d8f9b7dd3753..f845dbea97e4acc45a129027461904d9d71cd165 100644 (file)
@@ -21,7 +21,7 @@ Description=nether service
 
 [Service]
 Type=simple
-ExecStart=/usr/local/bin/nether -d -l JOURNAL -B /etc/nether/nether.policy -r /etc/nether/nether.rules
+ExecStart=/usr/local/bin/nether -d -l JOURNAL -P policy=/etc/nether/cynara.policy -B /etc/nether/file.policy -r /etc/nether/nether.rules
 Restart=on-failure
 ExecReload=/bin/kill -HUP $MAINPID
 
index ab44b04055aa35b0cf21fe91af9f5aaeb63c5d67..41923cd96dcb5c59ce742322cd26b64e0ea3cc8a 100644 (file)
@@ -21,7 +21,7 @@ Description=nether service
 
 [Service]
 Type=simple
-ExecStart=${CMAKE_INSTALL_PREFIX}/bin/nether -l JOURNAL -B ${SYSCONF_INSTALL_DIR}/nether/nether.policy -r ${SYSCONF_INSTALL_DIR}/nether/nether.rules
+ExecStart=${CMAKE_INSTALL_PREFIX}/bin/nether -l JOURNAL -P policy=${SYSCONF_INSTALL_DIR}/nether/cynara.policy -B ${SYSCONF_INSTALL_DIR}/nether/file.policy -r ${SYSCONF_INSTALL_DIR}/nether/nether.rules
 Restart=on-failure
 ExecReload=/bin/kill -HUP $MAINPID
 
index 164e76d09afd7d22eaf38761fa48a753b49fc0b9..4208ee4bfad722b35936080b3c1d9a08b9d61d9b 100644 (file)
  * @brief   Cynara policy backend for nether
  */
 
-#ifndef NETHER_CYNARA_BACKEND_H
+#ifndef NETHER_CYNARA_BACKEND_H // NETHER_CYNARA_BACKEND_H
 #define NETHER_CYNARA_BACKEND_H
 
-// #ifdef HAVE_CYNARA
+#ifdef HAVE_CYNARA // HAVE_CYNARA
 
 #include <cynara-client-async.h>
 #include "nether_PolicyBackend.h"
+
 #include <vector>
-#include <fstream>
 #include <map>
 
 #ifndef NETHER_CYNARA_INTERNET_PRIVILEGE
 class NetherManager;
 
 const std::string cynaraErrorCodeToString(int cynaraErrorCode);
-typedef std::pair<std::string, u_int32_t> PrivilegePair;
+typedef std::pair<std::string, int32_t> PrivilegePair;
 
 struct NetherCynaraCheckInfo
 {
        NetherCynaraCheckInfo() {}
-       NetherCynaraCheckInfo(NetherPacket _packet, u_int32_t _privilegeId)
+       NetherCynaraCheckInfo(NetherPacket _packet, u_int32_t _privilegeId, cynara_check_id _checkId = -1)
                : packet(_packet),
-                 privilegeId(_privilegeId){}
+                 privilegeId(_privilegeId),
+                 checkId(_checkId){}
 
        NetherCynaraCheckInfo& operator=(const NetherCynaraCheckInfo &other)
        {
                packet = other.packet;
                privilegeId = other.privilegeId;
-
+               checkId = other.checkId;;
                return *this;
        }
 
        NetherPacket packet;
        u_int32_t privilegeId = -1;
+       cynara_check_id checkId;
 };
 
 class NetherCynaraBackend : public NetherPolicyBackend
@@ -92,5 +94,5 @@ class NetherCynaraBackend : public NetherPolicyBackend
                u_int32_t allPrivilegesToCheck;
 };
 
-// #endif // HAVE_CYNARA
+#endif // HAVE_CYNARA
 #endif // NETHER_CYNARA_BACKEND_H
index 679fc3e3b5efcba5fdd1cbc2d71f35cbac7b2aa5..9c3898195a1a3b67796c65681b4ac9875a0a6839 100644 (file)
@@ -39,7 +39,7 @@ class NetherNetlink : public NetherPacketProcessor
                bool reload();
                static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data);
                bool processPacket(char *packetBuffer, const int packetReadSize);
-               void setVerdict(const u_int32_t packetId, const NetherVerdict verdict, int mark = -1);
+               void setVerdict(const u_int32_t packetId, const NetherVerdict verdict, int32_t mark = -1);
                int getDescriptor();
                const NetherConfig &getNetherConfig();
                void getInterfaceInfo(struct nfq_data *nfa, NetherPacket &netherPacket);
index 5aeea5cb59e19973bdb6cbd770bcd3383f2fe44c..07c6edf9cc70396837d929a6c6a94a0698c3d167 100644 (file)
@@ -86,7 +86,7 @@
 #endif // NETHER_RULES_PATH
 
 #ifndef NETHER_POLICY_FILE
-#define NETHER_POLICY_FILE                             "/etc/nether/nether.policy"
+#define NETHER_POLICY_FILE                             "/etc/nether/file.policy"
 #endif // NETHER_POLICY_FILE
 
 
@@ -158,15 +158,15 @@ struct NetherPacket
        uid_t uid;
        u_int32_t id;
        std::string securityContext;
-       int remotePort;
-       int localPort;
+       int32_t remotePort                                                              = -1;
+       int32_t localPort                                                               = -1;
        gid_t gid;
        pid_t pid;
-       char localAddress[NETHER_NETWORK_ADDR_LEN];
-       char remoteAddress[NETHER_NETWORK_ADDR_LEN];
+       char localAddress[NETHER_NETWORK_ADDR_LEN]              = {0};
+       char remoteAddress[NETHER_NETWORK_ADDR_LEN]             = {0};
        NetherTransportType transportType;
        NetherProtocolType protocolType;
-       char outdevName[IFNAMSIZ];
+       char outdevName[IFNAMSIZ]                                               = {0};
 };
 
 struct NetherConfig
@@ -212,14 +212,14 @@ class NetherVerdictCaster
                        verdictListener = listenerToSet;
                }
 
-               bool castVerdict(const NetherPacket &packet, const NetherVerdict verdict, const int mark = -1)
+               bool castVerdict(const NetherPacket &packet, const NetherVerdict verdict, const int32_t mark = -1)
                {
                        if(verdictListener)
                                return (verdictListener->verdictCast(packet.id, verdict, mark));
                        return (false);
                }
 
-               bool castVerdict(const u_int32_t packetId, const NetherVerdict verdict, const int mark = -1)
+               bool castVerdict(const u_int32_t packetId, const NetherVerdict verdict, const int32_t mark = -1)
                {
                        if(verdictListener)
                                return (verdictListener->verdictCast(packetId, verdict, mark));
@@ -257,7 +257,7 @@ class NetherPacketProcessor
                        if(packetListener) packetListener->packetReceived(packetInfoToWrite);
                }
 
-               virtual void setVerdict(const u_int32_t packetId, const NetherVerdict verdict, int mark = -1) = 0;
+               virtual void setVerdict(const u_int32_t packetId, const NetherVerdict verdict, const int32_t mark = -1) = 0;
 
        protected:
                NetherProcessedPacketListener *packetListener;
index b460b76d11d98694d9ac888ffb18b5576e659020..0c2d3f76edab9e834523c0cc5c86ea94fb938174 100644 (file)
@@ -17,7 +17,7 @@ This is a network privilege enforcing service.
 %defattr(644,root,root,755)
 %caps(cap_sys_admin,cap_mac_override=ei) %attr(755,root,root) %{_bindir}/nether
 %dir %{_sysconfdir}/nether
-%config %{_sysconfdir}/nether/nether.policy
+%config %{_sysconfdir}/nether/file.policy
 %config %{_sysconfdir}/nether/nether.rules
 %config %{_sysconfdir}/nether/cynara.policy
 %{_unitdir}/nether.service
index f4e2920a26f86a2fc834cd9e1f11897b660637a3..169d0cdfb8f3a308df6c578451b928b3053ba173 100644 (file)
@@ -78,6 +78,6 @@ TARGET_LINK_LIBRARIES (nether
 )
 
 ADD_DEFINITIONS (-DNETHER_RULES_PATH="${CMAKE_INSTALL_DIR}/etc/nether/nether.rules"
-               -DNETHER_POLICY_FILE="${CMAKE_INSTALL_DIR}/etc/nether/nether.policy")
+               -DNETHER_POLICY_FILE="${CMAKE_INSTALL_DIR}/etc/nether/file.policy")
 
 INSTALL (TARGETS nether RUNTIME DESTINATION bin)
index 0f498c18e6c2afa4b6ea177becde809cf170c24a..3934e339ffeac81649f4f96b6993e59133b32a26 100644 (file)
 #include "nether_CynaraBackend.h"
 #include "nether_Utils.h"
 
+#include <fstream>
+
 using namespace std;
 
-// #ifdef HAVE_CYNARA
+#ifdef HAVE_CYNARA
 
 const std::string cynaraErrorCodeToString(int cynaraErrorCode)
 {
@@ -45,14 +47,16 @@ NetherCynaraBackend::NetherCynaraBackend(const NetherConfig &netherConfig)
                cynaraLastResult(CYNARA_API_UNKNOWN_ERROR), cynaraConfig(nullptr),
                allPrivilegesToCheck(1) /* if there is no additional policy, only one check is done */
 {
+       /* This is the default, if no policy is defined in the file or no
+               privilege name is passed in the command line, the built in
+               or the one defined at build time will be used
+               -1 is the mark that means, ACCEPT (don't mark the packet at all) */
+       privilegeChain.push_back (PrivilegePair (NETHER_CYNARA_INTERNET_PRIVILEGE, -1));
+
        if (netherConfig.primaryBackendArgs.length() != 0)
        {
                parseBackendArgs();
        }
-       else
-       {
-               privilegeChain.push_back (PrivilegePair (NETHER_CYNARA_INTERNET_PRIVILEGE, 0));
-       }
 }
 
 NetherCynaraBackend::~NetherCynaraBackend()
@@ -98,8 +102,6 @@ void NetherCynaraBackend::checkCallback(cynara_check_id check_id,
 
 bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
 {
-       cynara_check_id checkId;
-
        cynaraLastResult = cynara_async_check_cache(cynaraContext,
                                                                                                checkInfo.packet.securityContext.c_str(),
                                                                                                "",
@@ -112,33 +114,45 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
                                                                                 << " privilege="
                                                                                 << privilegeChain[checkInfo.privilegeId].first
                                                                                 << " mark="
-                                                                                << privilegeChain[checkInfo.privilegeId].second);
+                                                                                << privilegeChain[checkInfo.privilegeId].second
+                                                                                << " result string=\""
+                                                                                << cynaraErrorCodeToString(cynaraLastResult)
+                                                                                << "\""
+                                                                                << " packetId="
+                                                                                << checkInfo.packet.id);
 
        switch(cynaraLastResult)
        {
                case CYNARA_API_ACCESS_ALLOWED:
-                       LOGD(cynaraErrorCodeToString(cynaraLastResult).c_str());
-                       return (castVerdict(checkInfo.packet, NetherVerdict::allow, privilegeChain[checkInfo.privilegeId].second));
+                       return (castVerdict(checkInfo.packet,
+                                                               NetherVerdict::allow,
+                                                               privilegeChain[checkInfo.privilegeId].second));
 
                case CYNARA_API_ACCESS_DENIED:
+                       /* We need to copy this into the queue
+                               other checks might be needed
+                               and this information will be necessary */
+
+                       responseQueue[checkInfo.checkId] = checkInfo;
+                       return (reEnqueVerdict(checkInfo.checkId));
+
                case CYNARA_API_CACHE_MISS:
-                       LOGD(cynaraErrorCodeToString(cynaraLastResult).c_str());
                        cynaraLastResult = cynara_async_create_request(cynaraContext,
                                                           checkInfo.packet.securityContext.c_str(),
                                                           "",
                                                           std::to_string(checkInfo.packet.uid).c_str(),
                                                           privilegeChain[checkInfo.privilegeId].first.c_str(),
-                                                          &checkId,
+                                                          &checkInfo.checkId,
                                                           &checkCallback,
                                                           this);
 
                        if(cynaraLastResult == CYNARA_API_SUCCESS)
                        {
-                               responseQueue[checkId] = checkInfo;
-
+                               responseQueue[checkInfo.checkId] = checkInfo;
                                return (true);
                        }
                        else
+                       {
                                if(cynaraLastResult == CYNARA_API_SERVICE_NOT_AVAILABLE)
                                {
                                        LOGW("Cynara offline, fall back to another backend");
@@ -149,6 +163,7 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
                                        LOGW("Error on cynara request create after CYNARA_API_CACHE_MISS " << cynaraErrorCodeToString(cynaraLastResult));
                                        return (false);
                                }
+                       }
 
                default:
                        LOGW("Error on cynara request create unhandled result from cynara_async_check_cache "<<cynaraErrorCodeToString(cynaraLastResult));
@@ -160,26 +175,27 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
 
 bool NetherCynaraBackend::enqueueVerdict(const NetherPacket &packet)
 {
-       return (cynaraCheck ( NetherCynaraCheckInfo(packet, 0) ));
+       LOGD("packet id=" << packet.id);
+       return (cynaraCheck (NetherCynaraCheckInfo(packet, 0)));
 }
 
 bool NetherCynaraBackend::reEnqueVerdict(cynara_check_id checkId)
 {
        NetherCynaraCheckInfo checkInfo = responseQueue[checkId];
 
-       /* We goa deny from cynara, we need to check
-               if our internal (BAD, SATANIC, EVIL) policy
+       /* We got deny from cynara, we need to check
+               if our internal policy
                has other entries and try them too */
        if (++checkInfo.privilegeId < allPrivilegesToCheck)
        {
+               LOGD("more privileges in policy, keep checking id=" << checkInfo.packet.id);
                return (cynaraCheck(checkInfo));
        }
        else
        {
-               castVerdict(checkInfo.packet.id, NetherVerdict::deny);
+               LOGD("policy exhausted, deny packet id=" << checkInfo.packet.id);
+               return (castVerdict(checkInfo.packet.id, NetherVerdict::deny));
        }
-
-       return (true);
 }
 
 void NetherCynaraBackend::setCynaraVerdict(cynara_check_id checkId, int cynaraResult)
@@ -263,6 +279,12 @@ void NetherCynaraBackend::parseBackendArgs()
                {
                        parseInternalPolicy (valueNamePair[1]);
                }
+
+               if (valueNamePair[0] == "privname")
+               {
+                       privilegeChain.clear();
+                       privilegeChain.push_back (PrivilegePair (valueNamePair[1], -1));
+               }
        }
 }
 
@@ -273,9 +295,11 @@ bool NetherCynaraBackend::parseInternalPolicy(const std::string &policyFile)
 
        std::ifstream policyStream (policyFile);
 
-       if (!policyStream.good()) {
-               LOGE("Cynara policy file: " << policyFile << " failed to open");
-               return false;
+       if (!policyStream.good())
+       {
+               LOGE("Cynara policy file: " << policyFile << " failed to open. Using default privilege: \""
+                                                                       << privilegeChain[0].first << "\" for security checks");
+               return (false);
        }
 
        std::string s, privname, mark;
@@ -305,11 +329,16 @@ bool NetherCynaraBackend::parseInternalPolicy(const std::string &policyFile)
                mark = s.substr( begin, end - begin );
 
                // Insert the properly extracted (key, value) pair into the map
-               std::cout << mark;
+               LOGD("cynara policy add privilege: " << privname << " mark:" << mark);
                privilegeChain.push_back(PrivilegePair(privname, std::stoi(mark, 0, 16)));
        }
 
+       /* In case we didn't get at least ONE privilege from the file
+               fall back to default */
+       if (privilegeChain.size() == 0)
+               privilegeChain.push_back (PrivilegePair (NETHER_CYNARA_INTERNET_PRIVILEGE, -1));
+
        allPrivilegesToCheck = privilegeChain.size();
        return (true);
 }
-// #endif
+#endif
index 6d5d51433a21f1d1f2ba18b424d1ae4e211d2b10..8a1f5927b6b4233584aeb42a260a49893d8773c9 100644 (file)
@@ -169,7 +169,7 @@ int NetherNetlink::callback(struct nfq_q_handle *, struct nfgenmsg *, struct nfq
        else
                LOGD("Failed to get security context for packet id=" << packet.id);
 
-       if(nfq_get_payload(nfa, &payload) > 0)
+       if(me->netherConfig.copyPackets && nfq_get_payload(nfa, &payload) > 0)
                decodePacket(packet, payload);
 
        me->processNetherPacket(packet);  /* this call if from the NetherPacketProcessor class */
@@ -177,7 +177,7 @@ int NetherNetlink::callback(struct nfq_q_handle *, struct nfgenmsg *, struct nfq
        return (0);
 }
 
-void NetherNetlink::setVerdict(const u_int32_t packetId, const NetherVerdict verdict, int mark)
+void NetherNetlink::setVerdict(const u_int32_t packetId, const NetherVerdict verdict, int32_t mark)
 {
        int ret = 0;
        LOGD("id=" << packetId << " verdict=" << verdictToString(verdict) << " mark=" << mark);