---
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