diff mbox series

[net-next] tun: fix group permission check

Message ID 20241117090514.9386-1-stsp2@yandex.ru (mailing list archive)
State Deferred
Delegated to: Netdev Maintainers
Headers show
Series [net-next] tun: fix group permission check | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4 this patch: 4
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 30 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline warning Was 1 now: 1
netdev/contest success net-next-2024-11-17--12-00 (tests: 789)

Commit Message

stsp Nov. 17, 2024, 9:05 a.m. UTC
Currently tun checks the group permission even if the user have matched.
Besides going against the usual permission semantic, this has a
very interesting implication: if the tun group is not among the
supplementary groups of the tun user, then effectively no one can
access the tun device. CAP_SYS_ADMIN still can, but its the same as
not setting the tun ownership.

This patch relaxes the group checking so that either the user match
or the group match is enough. This avoids the situation when no one
can access the device even though the ownership is properly set.

Also I simplified the logic by removing the redundant inversions:
tun_not_capable() --> !tun_capable()

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>

CC: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
CC: Jason Wang <jasowang@redhat.com>
CC: Andrew Lunn <andrew+netdev@lunn.ch>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jakub Kicinski <kuba@kernel.org>
CC: Paolo Abeni <pabeni@redhat.com>
CC: netdev@vger.kernel.org
CC: linux-kernel@vger.kernel.org
---
 drivers/net/tun.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

Comments

Willem de Bruijn Nov. 17, 2024, 3:04 p.m. UTC | #1
Stas Sergeev wrote:
> Currently tun checks the group permission even if the user have matched.
> Besides going against the usual permission semantic, this has a
> very interesting implication: if the tun group is not among the
> supplementary groups of the tun user, then effectively no one can
> access the tun device. CAP_SYS_ADMIN still can, but its the same as
> not setting the tun ownership.
> 
> This patch relaxes the group checking so that either the user match
> or the group match is enough. This avoids the situation when no one
> can access the device even though the ownership is properly set.
> 
> Also I simplified the logic by removing the redundant inversions:
> tun_not_capable() --> !tun_capable()
> 
> Signed-off-by: Stas Sergeev <stsp2@yandex.ru>

This behavior goes back through many patches to commit 8c644623fe7e:

    [NET]: Allow group ownership of TUN/TAP devices.

    Introduce a new syscall TUNSETGROUP for group ownership setting of tap
    devices. The user now is allowed to send packages if either his euid or
    his egid matches the one specified via tunctl (via -u or -g
    respecitvely). If both, gid and uid, are set via tunctl, both have to
    match.

The choice evidently was on purpose. Even if indeed non-standard.
Willem de Bruijn Nov. 18, 2024, 9:40 p.m. UTC | #2
Willem de Bruijn wrote:
> Stas Sergeev wrote:
> > Currently tun checks the group permission even if the user have matched.
> > Besides going against the usual permission semantic, this has a
> > very interesting implication: if the tun group is not among the
> > supplementary groups of the tun user, then effectively no one can
> > access the tun device. CAP_SYS_ADMIN still can, but its the same as
> > not setting the tun ownership.
> > 
> > This patch relaxes the group checking so that either the user match
> > or the group match is enough. This avoids the situation when no one
> > can access the device even though the ownership is properly set.
> > 
> > Also I simplified the logic by removing the redundant inversions:
> > tun_not_capable() --> !tun_capable()
> > 
> > Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
> 
> This behavior goes back through many patches to commit 8c644623fe7e:
> 
>     [NET]: Allow group ownership of TUN/TAP devices.
> 
>     Introduce a new syscall TUNSETGROUP for group ownership setting of tap
>     devices. The user now is allowed to send packages if either his euid or
>     his egid matches the one specified via tunctl (via -u or -g
>     respecitvely). If both, gid and uid, are set via tunctl, both have to
>     match.
> 
> The choice evidently was on purpose. Even if indeed non-standard.

I should clarify that I'm not against bringing this file in line with
normal user/group behavior.

Just want to give anyone a chance to speak up if they disagree and/or
recall why the code was originally written as it is.
stsp Nov. 19, 2024, 9:42 a.m. UTC | #3
17.11.2024 18:04, Willem de Bruijn пишет:
> Stas Sergeev wrote:
>> Currently tun checks the group permission even if the user have matched.
>> Besides going against the usual permission semantic, this has a
>> very interesting implication: if the tun group is not among the
>> supplementary groups of the tun user, then effectively no one can
>> access the tun device. CAP_SYS_ADMIN still can, but its the same as
>> not setting the tun ownership.
>>
>> This patch relaxes the group checking so that either the user match
>> or the group match is enough. This avoids the situation when no one
>> can access the device even though the ownership is properly set.
>>
>> Also I simplified the logic by removing the redundant inversions:
>> tun_not_capable() --> !tun_capable()
>>
>> Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
> This behavior goes back through many patches to commit 8c644623fe7e:
>
>      [NET]: Allow group ownership of TUN/TAP devices.
>
>      Introduce a new syscall TUNSETGROUP for group ownership setting of tap
>      devices. The user now is allowed to send packages if either his euid or
>      his egid matches the one specified via tunctl (via -u or -g
>      respecitvely). If both, gid and uid, are set via tunctl, both have to
>      match.
>
> The choice evidently was on purpose. Even if indeed non-standard.

So what would you suggest?
Added Guido Guenther <agx@sigxcpu.org> to CC
for an opinion.
The main problem here is that by
setting user and group properly, you
end up with device inaccessible by
anyone, unless the user belongs to
the tun group. I don't think someone
wants to set up inaccessible devices,
so this property doesn't seem useful.
OTOH if the user does have that group
in his list, then, AFAICT, adding such
group to tun changes nothing: neither
limits nor extends the scope.
If you had group already set and you
set also user, then you limit the scope,
but its the same as just setting user alone.
So I really can't think of any valid usage
scenario of setting both tun user and tun
group.
Paolo Abeni Nov. 19, 2024, 10:51 a.m. UTC | #4
On 11/18/24 22:40, Willem de Bruijn wrote:
> Willem de Bruijn wrote:
>> Stas Sergeev wrote:
>>> Currently tun checks the group permission even if the user have matched.
>>> Besides going against the usual permission semantic, this has a
>>> very interesting implication: if the tun group is not among the
>>> supplementary groups of the tun user, then effectively no one can
>>> access the tun device. CAP_SYS_ADMIN still can, but its the same as
>>> not setting the tun ownership.
>>>
>>> This patch relaxes the group checking so that either the user match
>>> or the group match is enough. This avoids the situation when no one
>>> can access the device even though the ownership is properly set.
>>>
>>> Also I simplified the logic by removing the redundant inversions:
>>> tun_not_capable() --> !tun_capable()
>>>
>>> Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
>>
>> This behavior goes back through many patches to commit 8c644623fe7e:
>>
>>     [NET]: Allow group ownership of TUN/TAP devices.
>>
>>     Introduce a new syscall TUNSETGROUP for group ownership setting of tap
>>     devices. The user now is allowed to send packages if either his euid or
>>     his egid matches the one specified via tunctl (via -u or -g
>>     respecitvely). If both, gid and uid, are set via tunctl, both have to
>>     match.
>>
>> The choice evidently was on purpose. Even if indeed non-standard.
> 
> I should clarify that I'm not against bringing this file in line with
> normal user/group behavior.
> 
> Just want to give anyone a chance to speak up if they disagree and/or
> recall why the code was originally written as it is.

I think we can't accept a behaviour changing patch this late in the
cycle. If an agreement is reached it should be reposted after the merge
window.

/P
stsp Nov. 19, 2024, 10:54 a.m. UTC | #5
19.11.2024 13:51, Paolo Abeni пишет:
> I think we can't accept a behaviour changing patch this late in the
> cycle. If an agreement is reached it should be reposted after the merge
> window.
>
> /P
Noted, thanks.
Willem de Bruijn Nov. 19, 2024, 2:56 p.m. UTC | #6
stsp wrote:
> 17.11.2024 18:04, Willem de Bruijn пишет:
> > Stas Sergeev wrote:
> >> Currently tun checks the group permission even if the user have matched.
> >> Besides going against the usual permission semantic, this has a
> >> very interesting implication: if the tun group is not among the
> >> supplementary groups of the tun user, then effectively no one can
> >> access the tun device. CAP_SYS_ADMIN still can, but its the same as
> >> not setting the tun ownership.
> >>
> >> This patch relaxes the group checking so that either the user match
> >> or the group match is enough. This avoids the situation when no one
> >> can access the device even though the ownership is properly set.
> >>
> >> Also I simplified the logic by removing the redundant inversions:
> >> tun_not_capable() --> !tun_capable()
> >>
> >> Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
> > This behavior goes back through many patches to commit 8c644623fe7e:
> >
> >      [NET]: Allow group ownership of TUN/TAP devices.
> >
> >      Introduce a new syscall TUNSETGROUP for group ownership setting of tap
> >      devices. The user now is allowed to send packages if either his euid or
> >      his egid matches the one specified via tunctl (via -u or -g
> >      respecitvely). If both, gid and uid, are set via tunctl, both have to
> >      match.
> >
> > The choice evidently was on purpose. Even if indeed non-standard.
> 
> So what would you suggest?
> Added Guido Guenther <agx@sigxcpu.org> to CC
> for an opinion.
> The main problem here is that by
> setting user and group properly, you
> end up with device inaccessible by
> anyone, unless the user belongs to
> the tun group. I don't think someone
> wants to set up inaccessible devices,
> so this property doesn't seem useful.
> OTOH if the user does have that group
> in his list, then, AFAICT, adding such
> group to tun changes nothing: neither
> limits nor extends the scope.
> If you had group already set and you
> set also user, then you limit the scope,
> but its the same as just setting user alone.
> So I really can't think of any valid usage
> scenario of setting both tun user and tun
> group.

Understood. If no one comments before the window reopens, I think it's
fine to just resubmit.
diff mbox series

Patch

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9a0f6eb32016..d35b6a48d138 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -574,14 +574,18 @@  static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
 	return ret;
 }
 
-static inline bool tun_not_capable(struct tun_struct *tun)
+static inline bool tun_capable(struct tun_struct *tun)
 {
 	const struct cred *cred = current_cred();
 	struct net *net = dev_net(tun->dev);
 
-	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);
+	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;
 }
 
 static void tun_set_real_num_queues(struct tun_struct *tun)
@@ -2778,7 +2782,7 @@  static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 		    !!(tun->flags & IFF_MULTI_QUEUE))
 			return -EINVAL;
 
-		if (tun_not_capable(tun))
+		if (!tun_capable(tun))
 			return -EPERM;
 		err = security_tun_dev_open(tun->security);
 		if (err < 0)