]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tun: revert fix group permission check
authorWillem de Bruijn <willemb@google.com>
Tue, 4 Feb 2025 16:10:06 +0000 (11:10 -0500)
committerJakub Kicinski <kuba@kernel.org>
Thu, 6 Feb 2025 02:22:11 +0000 (18:22 -0800)
This reverts commit 3ca459eaba1bf96a8c7878de84fa8872259a01e3.

The blamed commit caused a regression when neither tun->owner nor
tun->group is set. This is intended to be allowed, but now requires
CAP_NET_ADMIN.

Discussion in the referenced thread pointed out that the original
issue that prompted this patch can be resolved in userspace.

The relaxed access control may also make a device accessible when it
previously wasn't, while existing users may depend on it to not be.

This is a clean pure git revert, except for fixing the indentation on
the gid_valid line that checkpatch correctly flagged.

Fixes: 3ca459eaba1b ("tun: fix group permission check")
Link: https://lore.kernel.org/netdev/CAFqZXNtkCBT4f+PwyVRmQGoT3p1eVa01fCG_aNtpt6dakXncUg@mail.gmail.com/
Signed-off-by: Willem de Bruijn <willemb@google.com>
Cc: Ondrej Mosnacek <omosnace@redhat.com>
Cc: Stas Sergeev <stsp2@yandex.ru>
Link: https://patch.msgid.link/20250204161015.739430-1-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/tun.c

index 28624cca91f8d124955dcd461573b758e60e36c5..acf96f26248873abe495c67b36727f3ca82f6164 100644 (file)
@@ -574,18 +574,14 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
        return ret;
 }
 
-static inline bool tun_capable(struct tun_struct *tun)
+static inline bool tun_not_capable(struct tun_struct *tun)
 {
        const struct cred *cred = current_cred();
        struct net *net = dev_net(tun->dev);
 
-       if (ns_capable(net->user_ns, CAP_NET_ADMIN))
-               return 1;
-       if (uid_valid(tun->owner) && uid_eq(cred->euid, tun->owner))
-               return 1;
-       if (gid_valid(tun->group) && in_egroup_p(tun->group))
-               return 1;
-       return 0;
+       return ((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) ||
+               (gid_valid(tun->group) && !in_egroup_p(tun->group))) &&
+               !ns_capable(net->user_ns, CAP_NET_ADMIN);
 }
 
 static void tun_set_real_num_queues(struct tun_struct *tun)
@@ -2782,7 +2778,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                    !!(tun->flags & IFF_MULTI_QUEUE))
                        return -EINVAL;
 
-               if (!tun_capable(tun))
+               if (tun_not_capable(tun))
                        return -EPERM;
                err = security_tun_dev_open(tun->security);
                if (err < 0)