Skip to contentSkip to conversation

semanage: handle getprotobyname() failure case

PATCH Applied Topi Miettinen 2 participants 4 messages Jun 5, 2020 – Jun 25, 2020 SELinux security module

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 semanage: handle getprotobyname() failure case

At least on Debian, /etc/protocols, which is used by socket.getprotobyname() to resolve protocols to names, does not contain an entry for "ipv4". In that case, set the protocol number used by audit logs for "ipv4" to a fixed value. To ensure audit log compatibility, let's use the same numeric value as Fedora: 4, which is actually understood by kernel as IP over IP.

---
v2: don't change audit log format

---
 python/semanage/seobject.py | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)
python/semanage/seobject.py +19 -8
index 6e0b87f2..6a14f7b4 100644
@@ -1870,10 +1870,22 @@ class nodeRecords(semanageRecords):
         except:
             raise ValueError(_("Unknown or missing protocol"))
 
-        return newaddr, newmask, newprotocol
+        try:
+            audit_protocol = socket.getprotobyname(protocol)
+        except:
+            # Entry for "ipv4" not found in /etc/protocols on (at
+            # least) Debian? To ensure audit log compatibility, let's
+            # use the same numeric value as Fedora: 4, which is
+            # actually understood by kernel as IP over IP.
+            if (protocol == "ipv4"):
+                audit_protocol = socket.IPPROTO_IPIP
+            else:
+                raise ValueError(_("Unknown or missing protocol"))
+
+        return newaddr, newmask, newprotocol, audit_protocol
 
     def __add(self, addr, mask, proto, serange, ctype):
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         if is_mls_enabled == 1:
             if serange == "":
@@ -1942,7 +1954,7 @@ class nodeRecords(semanageRecords):
         semanage_node_key_free(k)
         semanage_node_free(node)
 
-        self.mylog.log_change("resrc=node op=add laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, socket.getprotobyname(self.protocol[proto]), "system_u", "object_r", ctype, serange))
+        self.mylog.log_change("resrc=node op=add laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, audit_proto, "system_u", "object_r", ctype, serange))
 
     def add(self, addr, mask, proto, serange, ctype):
         self.begin()
@@ -1950,7 +1962,7 @@ class nodeRecords(semanageRecords):
         self.commit()
 
     def __modify(self, addr, mask, proto, serange, setype):
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         if serange == "" and setype == "":
             raise ValueError(_("Requires setype or serange"))
@@ -1987,7 +1999,7 @@ class nodeRecords(semanageRecords):
         semanage_node_key_free(k)
         semanage_node_free(node)
 
-        self.mylog.log_change("resrc=node op=modify laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, socket.getprotobyname(self.protocol[proto]), "system_u", "object_r", setype, serange))
+        self.mylog.log_change("resrc=node op=modify laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, audit_proto, "system_u", "object_r", setype, serange))
 
     def modify(self, addr, mask, proto, serange, setype):
         self.begin()
@@ -1995,8 +2007,7 @@ class nodeRecords(semanageRecords):
         self.commit()
 
     def __delete(self, addr, mask, proto):
-
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         (rc, k) = semanage_node_key_create(self.sh, addr, mask, proto)
         if rc < 0:
@@ -2020,7 +2031,7 @@ class nodeRecords(semanageRecords):
 
         semanage_node_key_free(k)
 
-        self.mylog.log_change("resrc=node op=delete laddr=%s netmask=%s proto=%s" % (addr, mask, socket.getprotobyname(self.protocol[proto])))
+        self.mylog.log_change("resrc=node op=delete laddr=%s netmask=%s proto=%s" % (addr, mask, audit_proto))
 
     def delete(self, addr, mask, proto):
         self.begin()
Signature · 1 line
2.26.2
maintainer
#1 lore raw
Quoted 9 lines · Topi Miettinen

At least on Debian, /etc/protocols, which is used by socket.getprotobyname() to resolve protocols to names, does not contain an entry for "ipv4". In that case, set the protocol number used by audit logs for "ipv4" to a fixed value. To ensure audit log compatibility, let's use the same numeric value as Fedora: 4, which is actually understood by kernel as IP over IP.

This looks fine to me but adding linux-audit mailing list to see if they have any concerns. It appears to make no change to the audit messages on Fedora.

Quoted 84 lines

---
v2: don't change audit log format

---
 python/semanage/seobject.py | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)
python/semanage/seobject.py +19 -9
index 6e0b87f2..6a14f7b4 100644
@@ -1870,10 +1870,22 @@ class nodeRecords(semanageRecords):
         except:
             raise ValueError(_("Unknown or missing protocol"))
 
-        return newaddr, newmask, newprotocol
+        try:
+            audit_protocol = socket.getprotobyname(protocol)
+        except:
+            # Entry for "ipv4" not found in /etc/protocols on (at
+            # least) Debian? To ensure audit log compatibility, let's
+            # use the same numeric value as Fedora: 4, which is
+            # actually understood by kernel as IP over IP.
+            if (protocol == "ipv4"):
+                audit_protocol = socket.IPPROTO_IPIP
+            else:
+                raise ValueError(_("Unknown or missing protocol"))
+
+        return newaddr, newmask, newprotocol, audit_protocol
 
     def __add(self, addr, mask, proto, serange, ctype):
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         if is_mls_enabled == 1:
             if serange == "":
@@ -1942,7 +1954,7 @@ class nodeRecords(semanageRecords):
         semanage_node_key_free(k)
         semanage_node_free(node)
 
-        self.mylog.log_change("resrc=node op=add laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, socket.getprotobyname(self.protocol[proto]), "system_u", "object_r", ctype, serange))
+        self.mylog.log_change("resrc=node op=add laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, audit_proto, "system_u", "object_r", ctype, serange))
 
     def add(self, addr, mask, proto, serange, ctype):
         self.begin()
@@ -1950,7 +1962,7 @@ class nodeRecords(semanageRecords):
         self.commit()
 
     def __modify(self, addr, mask, proto, serange, setype):
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         if serange == "" and setype == "":
             raise ValueError(_("Requires setype or serange"))
@@ -1987,7 +1999,7 @@ class nodeRecords(semanageRecords):
         semanage_node_key_free(k)
         semanage_node_free(node)
 
-        self.mylog.log_change("resrc=node op=modify laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, socket.getprotobyname(self.protocol[proto]), "system_u", "object_r", setype, serange))
+        self.mylog.log_change("resrc=node op=modify laddr=%s netmask=%s proto=%s tcontext=%s:%s:%s:%s" % (addr, mask, audit_proto, "system_u", "object_r", setype, serange))
 
     def modify(self, addr, mask, proto, serange, setype):
         self.begin()
@@ -1995,8 +2007,7 @@ class nodeRecords(semanageRecords):
         self.commit()
 
     def __delete(self, addr, mask, proto):
-
-        addr, mask, proto = self.validate(addr, mask, proto)
+        addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
 
         (rc, k) = semanage_node_key_create(self.sh, addr, mask, proto)
         if rc < 0:
@@ -2020,7 +2031,7 @@ class nodeRecords(semanageRecords):
 
         semanage_node_key_free(k)
 
-        self.mylog.log_change("resrc=node op=delete laddr=%s netmask=%s proto=%s" % (addr, mask, socket.getprotobyname(self.protocol[proto])))
+        self.mylog.log_change("resrc=node op=delete laddr=%s netmask=%s proto=%s" % (addr, mask, audit_proto))
 
     def delete(self, addr, mask, proto):
         self.begin()
--

2.26.2

maintainer Acked-by
#2 lore raw
Quoted 10 lines · Stephen Smalley
Quoted 8 lines · Topi Miettinen

At least on Debian, /etc/protocols, which is used by socket.getprotobyname() to resolve protocols to names, does not contain an entry for "ipv4". In that case, set the protocol number used by audit logs for "ipv4" to a fixed value. To ensure audit log compatibility, let's use the same numeric value as Fedora: 4, which is actually understood by kernel as IP over IP.

Quoted 5 lines
Quoted 1 line

This looks fine to me but adding linux-audit mailing list to see if they have any concerns. It appears to make no change to the audit messages on Fedora.

Seeing no objections from linux-audit,

maintainer Applied
#3 lore raw
Quoted 15 lines · Stephen Smalley
Quoted 12 lines · Stephen Smalley
Quoted 9 lines · Topi Miettinen

At least on Debian, /etc/protocols, which is used by socket.getprotobyname() to resolve protocols to names, does not contain an entry for "ipv4". In that case, set the protocol number used by audit logs for "ipv4" to a fixed value. To ensure audit log compatibility, let's use the same numeric value as Fedora: 4, which is actually understood by kernel as IP over IP.

Quoted 7 lines
Quoted 3 lines

This looks fine to me but adding linux-audit mailing list to see if they have any concerns. It appears to make no change to the audit messages on Fedora.

Seeing no objections from linux-audit,

Applied.