[Libguestfs] [PATCH nbdkit 2/2] ip: Add filtering by process ID, user ID and group ID.

Richard W.M. Jones rjones at redhat.com
Sat Oct 3 12:01:41 UTC 2020


---
 filters/ip/nbdkit-ip-filter.pod | 54 ++++++++++++++++++++++----
 tests/Makefile.am               | 14 ++++++-
 filters/ip/ip.c                 | 67 ++++++++++++++++++++++++++++++---
 tests/test-ip-filter-gid.sh     | 51 +++++++++++++++++++++++++
 tests/test-ip-filter-pid.sh     | 52 +++++++++++++++++++++++++
 tests/test-ip-filter-uid.sh     | 51 +++++++++++++++++++++++++
 6 files changed, 274 insertions(+), 15 deletions(-)

diff --git a/filters/ip/nbdkit-ip-filter.pod b/filters/ip/nbdkit-ip-filter.pod
index 17108617..1f5a7e63 100644
--- a/filters/ip/nbdkit-ip-filter.pod
+++ b/filters/ip/nbdkit-ip-filter.pod
@@ -1,6 +1,7 @@
 =head1 NAME
 
-nbdkit-ip-filter - filter clients by IP address
+nbdkit-ip-filter - filter clients by IP address, process ID, user ID
+or group ID
 
 =head1 SYNOPSIS
 
@@ -14,6 +15,9 @@ address.  Usually it is better to control this outside nbdkit, for
 example using TCP wrappers or a firewall, but this filter can be used
 if these are not available.
 
+nbdkit E<ge> 1.24 added the ability to filter Unix domain sockets by
+process ID, user ID and group ID.  This currently only works on Linux.
+
 =head1 EXAMPLES
 
  nbdkit --filter=ip [...] allow=127.0.0.1,::1 deny=all
@@ -31,10 +35,22 @@ network.
 Allow IPv6 clients to connect from anywhere, deny all IPv4
 connections.
 
+ nbdkit -U /tmp/sock --filter=ip [...] allow=pid:1234 deny=all
+
+Only process ID 1234 can connect to the server over the local Unix
+domain socket.
+
+ nbdkit -U $tmpdir/sock --filter=ip [...] allow=uid:`id -u` deny=all
+
+Only allow the same user who runs nbdkit to connect over the socket.
+If you use this, it is better to use it as an additional line of
+defence: Also create a temporary directory, make sure it is only
+accessible by the user, and place the socket there.
+
 =head1 RULES
 
-When a client connects, this filter checks its IP address against the
-allow and deny lists as follows:
+When a client connects, this filter checks its source address against
+the allow and deny lists as follows:
 
 =over 4
 
@@ -66,8 +82,7 @@ list of any of the following:
 
 =item B<any>
 
-These keywords (which both have the same meaning) match any IP
-address.
+These keywords (which both have the same meaning) match any source.
 
 =item B<allipv4>
 
@@ -100,6 +115,26 @@ address representations can be used (see S<RFC 5952>).
 
 This matches a range of IPv6 addresses C<A:B:.../NN>.
 
+=item B<pid:>PID
+
+(nbdkit E<ge> 1.24, Linux only)
+
+This matches the process ID C<PID>.
+
+=item B<uid:>UID
+
+(nbdkit E<ge> 1.24, Linux only)
+
+This matches the user ID C<UID> (which must be numeric, you cannot use
+a user name).
+
+=item B<gid:>GID
+
+(nbdkit E<ge> 1.24, Linux only)
+
+This matches the group ID C<GID> (which must be numeric, you cannot
+use a group name).
+
 =back
 
 =head2 Not filtered
@@ -107,8 +142,11 @@ This matches a range of IPv6 addresses C<A:B:.../NN>.
 If neither the C<allow> nor the C<deny> parameter is given the filter
 does nothing.
 
-The filter permits non-IP connections, such as Unix domain sockets or
-AF_VSOCK.
+C<AF_VSOCK> connections are always unfiltered.
+
+Unix domain sockets were always unfiltered in S<nbdkit E<le> 1.22>.
+In S<nbdkit E<ge> 1.24> it is possible to apply filtering to them on
+Linux.
 
 =head1 PARAMETERS
 
@@ -155,4 +193,4 @@ Richard W.M. Jones
 
 =head1 COPYRIGHT
 
-Copyright (C) 2019 Red Hat Inc.
+Copyright (C) 2019-2020 Red Hat Inc.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b5b06810..cacbbce9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1437,8 +1437,18 @@ test_gzip_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
 test_gzip_LDADD = libtest.la $(LIBGUESTFS_LIBS)
 
 # ip filter test.
-TESTS += test-ip-filter.sh
-EXTRA_DIST += test-ip-filter.sh
+TESTS += \
+	test-ip-filter.sh \
+	test-ip-filter-pid.sh \
+	test-ip-filter-uid.sh \
+	test-ip-filter-gid.sh \
+	$(NULL)
+EXTRA_DIST += \
+	test-ip-filter.sh \
+	test-ip-filter-pid.sh \
+	test-ip-filter-uid.sh \
+	test-ip-filter-gid.sh \
+	$(NULL)
 
 # limit filter test.
 TESTS += test-limit.sh
diff --git a/filters/ip/ip.c b/filters/ip/ip.c
index 6e64042d..25a6c3a7 100644
--- a/filters/ip/ip.c
+++ b/filters/ip/ip.c
@@ -62,12 +62,13 @@ int ip_debug_rules;
 
 struct rule {
   struct rule *next;
-  enum { BAD = 0, ANY, ANYV4, ANYV6, IPV4, IPV6 } type;
+  enum { BAD = 0, ANY, ANYV4, ANYV6, IPV4, IPV6, PID, UID, GID } type;
   union {
-    struct in_addr ipv4;
+    struct in_addr ipv4;        /* for IPV4, IPV6 */
     struct in6_addr ipv6;
+    int id;                     /* for PID, UID and GID */
   } u;
-  unsigned prefixlen;
+  unsigned prefixlen;           /* for IPV4, IPV6 */
 };
 
 static struct rule *allow_rules, *allow_rules_last;
@@ -100,6 +101,16 @@ print_rule (const char *name, const struct rule *rule)
     nbdkit_debug ("%s=ipv6:[%s]/%u", name, u.addr6, rule->prefixlen);
     break;
 
+  case PID:
+    nbdkit_debug ("%s=pid:%d", name, rule->u.id);
+    break;
+  case UID:
+    nbdkit_debug ("%s=uid:%d", name, rule->u.id);
+    break;
+  case GID:
+    nbdkit_debug ("%s=gid:%d", name, rule->u.id);
+    break;
+
   case BAD:
     nbdkit_debug ("%s=BAD(!)", name);
     break;
@@ -227,6 +238,37 @@ parse_rule (const char *paramname,
     return 0;
   }
 
+  if (n >= 4 && ascii_strncasecmp (value, "pid:", 4) == 0) {
+    new_rule->type = PID;
+    if (nbdkit_parse_int ("pid:", &value[4], &new_rule->u.id) == -1)
+      return -1;
+    if (new_rule->u.id <= 0) {
+      nbdkit_error ("pid: parameter out of range");
+      return -1;
+    }
+    return 0;
+  }
+  if (n >= 4 && ascii_strncasecmp (value, "uid:", 4) == 0) {
+    new_rule->type = UID;
+    if (nbdkit_parse_int ("uid:", &value[4], &new_rule->u.id) == -1)
+      return -1;
+    if (new_rule->u.id < 0) {
+      nbdkit_error ("uid: parameter out of range");
+      return -1;
+    }
+    return 0;
+  }
+  if (n >= 4 && ascii_strncasecmp (value, "gid:", 4) == 0) {
+    new_rule->type = GID;
+    if (nbdkit_parse_int ("gid:", &value[4], &new_rule->u.id) == -1)
+      return -1;
+    if (new_rule->u.id < 0) {
+      nbdkit_error ("gid: parameter out of range");
+      return -1;
+    }
+    return 0;
+  }
+
   /* Address with prefixlen. */
   if ((p = strchr (value, '/')) != NULL) {
     size_t pllen = &value[n] - &p[1];
@@ -401,6 +443,19 @@ matches_rule (const struct rule *rule,
     sin6 = (struct sockaddr_in6 *) addr;
     return ipv6_equal (sin6->sin6_addr, rule->u.ipv6, rule->prefixlen);
 
+    /* Note these work even if the underlying nbdkit_peer_* call fails. */
+  case PID:
+    if (family != AF_UNIX) return false;
+    return nbdkit_peer_pid () == rule->u.id;
+
+  case UID:
+    if (family != AF_UNIX) return false;
+    return nbdkit_peer_uid () == rule->u.id;
+
+  case GID:
+    if (family != AF_UNIX) return false;
+    return nbdkit_peer_gid () == rule->u.id;
+
   case BAD:
   default:
     abort ();
@@ -432,8 +487,10 @@ check_if_allowed (const struct sockaddr *addr)
 {
   int family = ((struct sockaddr_in *)addr)->sin_family;
 
-  /* There's an implicit allow all for non-IP sockets, see the manual. */
-  if (family != AF_INET && family != AF_INET6)
+  /* There's an implicit allow all for non-IP, non-Unix sockets,
+   * see the manual.
+   */
+  if (family != AF_INET && family != AF_INET6 && family != AF_UNIX)
     return true;
 
   if (matches_rules_list (allow_rules, family, addr))
diff --git a/tests/test-ip-filter-gid.sh b/tests/test-ip-filter-gid.sh
new file mode 100755
index 00000000..d02407f3
--- /dev/null
+++ b/tests/test-ip-filter-gid.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test the ip filter with gid: parameter.
+
+source ./functions.sh
+set -e
+set -x
+
+requires qemu-img --version
+# This requires Linux.
+requires_linux_kernel_version 2.6
+
+nbdkit -U - -v -D ip.rules=1 --filter=ip null allow=gid:`id -g` deny=all \
+       --run 'qemu-img info $nbd'
+
+# This is expected to fail.
+if nbdkit -U - -v -D ip.rules=1 --filter=ip null deny=gid:`id -g` \
+          --run 'qemu-img info $nbd'; then
+    echo "$0: expected test to fail"
+    exit 1
+fi
diff --git a/tests/test-ip-filter-pid.sh b/tests/test-ip-filter-pid.sh
new file mode 100755
index 00000000..d14f3a42
--- /dev/null
+++ b/tests/test-ip-filter-pid.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test the ip filter with pid: parameter.
+
+source ./functions.sh
+set -e
+set -x
+
+requires qemu-img --version
+# This requires Linux.
+requires_linux_kernel_version 2.6
+
+# This is expected to fail.
+if nbdkit -U - -v -D ip.rules=1 --filter=ip null allow=pid:$$ deny=all \
+          --run 'qemu-img info $nbd'; then
+    echo "$0: expected test to fail"
+    exit 1
+fi
+
+# This is expected to work.
+nbdkit -U - -v -D ip.rules=1 --filter=ip null deny=pid:$$ \
+       --run 'qemu-img info $nbd'
diff --git a/tests/test-ip-filter-uid.sh b/tests/test-ip-filter-uid.sh
new file mode 100755
index 00000000..dc6ab679
--- /dev/null
+++ b/tests/test-ip-filter-uid.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2020 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test the ip filter with uid: parameter.
+
+source ./functions.sh
+set -e
+set -x
+
+requires qemu-img --version
+# This requires Linux.
+requires_linux_kernel_version 2.6
+
+nbdkit -U - -v -D ip.rules=1 --filter=ip null allow=uid:`id -u` deny=all \
+       --run 'qemu-img info $nbd'
+
+# This is expected to fail.
+if nbdkit -U - -v -D ip.rules=1 --filter=ip null deny=uid:`id -u` \
+          --run 'qemu-img info $nbd'; then
+    echo "$0: expected test to fail"
+    exit 1
+fi
-- 
2.27.0




More information about the Libguestfs mailing list