NetBSD Problem Report #58438

From www@netbsd.org  Thu Jul 18 08:02:23 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 167001A9239
	for <gnats-bugs@gnats.NetBSD.org>; Thu, 18 Jul 2024 08:02:23 +0000 (UTC)
Message-Id: <20240718080221.B33781A923A@mollari.NetBSD.org>
Date: Thu, 18 Jul 2024 08:02:21 +0000 (UTC)
From: 13mdf@fege.net
Reply-To: 13mdf@fege.net
To: gnats-bugs@NetBSD.org
Subject: Compatibility issues with per-user-temp [described security(7) man page]
X-Send-Pr-Version: www-1.0

>Number:         58438
>Category:       kern
>Synopsis:       Compatibility issues with per-user-temp [described security(7) man page]
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people
>State:          analyzed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 18 08:05:00 +0000 2024
>Closed-Date:    
>Last-Modified:  Fri Dec 27 17:19:22 +0000 2024
>Originator:     Marc Fege
>Release:        10.0
>Organization:
>Environment:
NetBSD rpi.familie.fege.local 10.0 NetBSD 10.0 (GENERIC64) #0: Thu Mar 28 08:33:33 UTC 2024  mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/evbarm/compile/GENERIC64 evbarm
>Description:
Dear NetBSD community,

there seems to be a problem with the per-user-temp-function in the kernel, which seems to be incompatible with certain system-softwares like X(1) or even tmux(1), which expect to write their magic cookies and temp files directly to /tmp.  Those softwares might have a problem with those symlinks which relocates /tmp per-user-wise to a separate /private/tmp as stated in the security(7) man page.  Other programs like ed(1) or vi(1) do not have a problem to write to this symlinked temp directory on the other hand.

As I undertook correspondence in advance with the original author of this security enhancement from back in the day of 2006 and following, Elad Efrat, before opening this bug report, he recommended personally I should write here.
He says "it wouldn’t surprise [him] if some programs use a syscall or library function that prevents symlinks from working".

What did I do? I tested on arm64, amd64, i386 and vax the following steps with identical results as described above:

As root:
1.: mkdir -p /private/tmp

2.: chmod -R 755 /private

3.: Added in /etc/rc.conf:
    per_user_tmp="YES"

4.: Replaced /tmp mount point in /etc/fstab with following lines:
    #tmpfs        /tmp             tmpfs   rw,-m1777,-sram%65
    tmpfs         /private/tmp     tmpfs   rw,-m1755,-sram%65

5.: Rebooted.

I tried even to mess around with the file permissions of the directories (chmod -R 777 for example).  No effect what so ever for me.  Maybe one tries to reproduce that behaviour.  Does anyone has a clue, what might be the issue here in my procedures?  Maybe I forgot something or did something wrong, that Elad did not anticipated when he wrote this man page back in the day.

A propos man page: as an ordinary user in the field I would recommend to exemplificate the necessary steps in the man page a bit broader and give a few more examples or a detailed list of steps, what users should do to activate this feature successfully.  As you see, I took five steps to activate this feature whatsoever.  As mentioned: maybe I forgot something or did something wrong what was not anticipated when writing this man page.

Thank you in advance for an reply and
best regards -
Marc Fege
>How-To-Repeat:
As root:
1.: mkdir -p /private/tmp

2.: chmod -R 755 /private

3.: Added in /etc/rc.conf:
    per_user_tmp="YES"

4.: Replaced /tmp mount point in /etc/fstab with following lines:
    #tmpfs        /tmp             tmpfs   rw,-m1777,-sram%65
    tmpfs         /private/tmp     tmpfs   rw,-m1755,-sram%65

5.: Reboot.

6. Try to launch X(1) or tmux(1).
>Fix:

>Release-Note:

>Audit-Trail:
From: "David H. Gutteridge" <david@gutteridge.ca>
To: Gnats Bugs <gnats-bugs@netbsd.org>
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Sat, 26 Oct 2024 20:41:33 -0400

 I've never used this feature, but from looking at what's documented in
 security(7) and what /etc/rc.d/perusertmp does, I can't see how it
 would work at all as-is. According to the steps you've listed, you'd
 end up with a /tmp link that points to /private/tmp/@ruid. But nothing
 has populated the actual per-user directories at this point. If you're
 root, it would expect /private/tmp/0 as a directory, for example. Each
 UID-specific directory would need (secured) permissions appropriate to
 that account, of course. I see nothing in the rc.d infrastructure that
 would create this (nor is it mentioned in the man page).

 So you'd need to also create each directory that @ruid would
 contextually point to under /private/tmp before it will work. Since
 you're using tmpfs, you'd have to redo this each time after boot (or
 otherwise initiating the feature). You'd need to figure out which UIDs
 are relevant for you, presumably at least two. (I'm not sure there'd be
 any point applying a sticky bit to these directories, given they're
 supposed to be isolated per-user anyway.)

 (Well, if you were using a non-volatile tmp, by default, you'd still
 have to recreate each user's directory every time, as from what I see
 /etc/rc.d/cleartmp also doesn't take this concept into account and
 would remove all the per-UID directories each time, too. In that case
 you could disable it via rc.conf(5), of course. If you just tweaked
 perusertmp to create the extra directories, cleartmp would immediately
 remove them out from under you, too, since it runs afterwards.)

 You wrote "Other programs like ed(1) or vi(1) do not have a problem to
 write to this symlinked temp directory on the other hand." Are you
 certain that those actually tried to use /tmp in the first place, and
 successfully wrote there? vi(1) uses /var/tmp, not /tmp, for its
 recovery files. (Yes, it can use /tmp for other purposes.) Based on
 what you shared, I can't follow how vi(1) would have written to "/tmp"
 successfully either.

 It seems there are functional and probably documentation issues with
 this feature. (I suppose if it really "just worked" the man page
 wouldn't need to spell out that there are dedicated per-user
 directories, but there'd still need to be a facility provided to
 specify which ones to create, so that would be documented as well.)

 Regards,

 Dave

From: "David H. Gutteridge" <david@gutteridge.ca>
To: Gnats Bugs <gnats-bugs@netbsd.org>
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Sat, 26 Oct 2024 21:17:11 -0400

 Several web search tries eventually turned up that this is evidently a
 known issue that someone already proposed a patch to address, which is
 here: https://gist.github.com/nonakap/3802982

 I haven't actually found a mailing list discussion about any of this
 specific context yet (including that patch), nor did initial attempts
 at searching GNATS turn up anything. That patch lines up pretty much
 exactly with what my take on this was.

 Regards,

 Dave

From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: "David H. Gutteridge" <gutteridge@netbsd.org>
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Sun, 27 Oct 2024 11:38:42 +0000 (UTC)

 On Sun, 27 Oct 2024, David H. Gutteridge via gnats wrote:

 > I've never used this feature, but from looking at what's documented in
 > security(7) and what /etc/rc.d/perusertmp does, I can't see how it
 > would work at all as-is. According to the steps you've listed, you'd
 > end up with a /tmp link that points to /private/tmp/@ruid. But nothing
 > has populated the actual per-user directories at this point. If you're
 > root, it would expect /private/tmp/0 as a directory, for example. Each
 > UID-specific directory would need (secured) permissions appropriate to
 > that account, of course. I see nothing in the rc.d infrastructure that
 > would create this (nor is it mentioned in the man page).
 >

 There's a very obscure trick which makes per-user-tmp dirs work. See
 the code in setusercontext() which every login-type program (eg. sshd)
 ends up calling:

 https://github.com/NetBSD/src/blob/trunk/lib/libutil/login_cap.c#L624

 This creates the /private/tmp/NNNN dirs for each user logging into the
 system.

 > You wrote "Other programs like ed(1) or vi(1) do not have a problem to
 > write to this symlinked temp directory on the other hand."
 >

 Programs like ed(1) and vi(1) work because they don't apply realpath(3)
 to their temp. filenames. tmux(1), however, uses realpath() on its socket
 pathname. And, the way realpath() works, testing each component for a
 symlink, then using readlink(2) on symlinks, is what causes this failure
 because what readlink() returns contains `@ruid' which is _not_ expanded
 because that's _not_ a symlink. The kernel only expands magic tokens in
 _symlinks_ and no where else.  This is easily seen; to wit:

 $ realpath /tmp
 /private/tmp/@ruid		# <--- note: @ruid, not 1000 or whatever
 $ realpath /private/tmp/@ruid
 /private/tmp/@ruid		# <--- no expansion as not a symlink
 $ readlink /tmp
 /private/tmp/@ruid		# as expected
 $ readlink -v /private/tmp/@ruid
 readlink: /private/tmp/@ruid: lstat: No such file or directory
 $

 I made a hacky patch (duplicating the entire symlink_magic() machinery 
 present in kern/vfs_lookup.c) awhile back for do_sys_readlinkat() which
 expands these magic tokens, but, that then needed a lot more elsewhere
 (because of the expansion removing the tokens). I've given up for the
 time-being.

 -RVP

 -RVP

From: "David H. Gutteridge" <david@gutteridge.ca>
To: RVP <rvp@SDF.ORG>, gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Sun, 27 Oct 2024 17:53:59 -0400

 On Sun, 2024-10-27 at 11:38 +0000, RVP wrote:
 > On Sun, 27 Oct 2024, David H. Gutteridge via gnats wrote:
 >=20
 > > I've never used this feature, but from looking at what's documented
 > > in
 > > security(7) and what /etc/rc.d/perusertmp does, I can't see how it
 > > would work at all as-is. According to the steps you've listed, you'd
 > > end up with a /tmp link that points to /private/tmp/@ruid. But
 > > nothing
 > > has populated the actual per-user directories at this point. If
 > > you're
 > > root, it would expect /private/tmp/0 as a directory, for example.
 > > Each
 > > UID-specific directory would need (secured) permissions appropriate
 > > to
 > > that account, of course. I see nothing in the rc.d infrastructure
 > > that
 > > would create this (nor is it mentioned in the man page).
 > >=20
 >=20
 > There's a very obscure trick which makes per-user-tmp dirs work. See
 > the code in setusercontext() which every login-type program (eg. sshd)
 > ends up calling:
 >=20
 > https://github.com/NetBSD/src/blob/trunk/lib/libutil/login_cap.c#L624
 >=20
 > This creates the /private/tmp/NNNN dirs for each user logging into the
 > system.
 >=20

 Well, I guess that teaches me not to rely on code inspection instead of
 turning the feature on to check! Heh. I looked into login(1) itself, but
 not there.

 I wonder what nonaka@ intended to address with that GitHub gist patch,
 then. It was created five years after the code you reference was added.
 Perhaps in attempted response to this very type of issue.

 > > You wrote "Other programs like ed(1) or vi(1) do not have a problem
 > > to
 > > write to this symlinked temp directory on the other hand."
 > >=20
 >=20
 > Programs like ed(1) and vi(1) work because they don't apply
 > realpath(3)
 > to their temp. filenames. tmux(1), however, uses realpath() on its
 > socket
 > pathname. And, the way realpath() works, testing each component for a
 > symlink, then using readlink(2) on symlinks, is what causes this
 > failure
 > because what readlink() returns contains `@ruid' which is _not_
 > expanded
 > because that's _not_ a symlink. The kernel only expands magic tokens
 > in
 > _symlinks_ and no where else.=C2=A0 This is easily seen; to wit:
 >=20
 > $ realpath /tmp
 > /private/tmp/@ruid		# <--- note: @ruid, not 1000 or
 > whatever
 > $ realpath /private/tmp/@ruid
 > /private/tmp/@ruid		# <--- no expansion as not a symlink
 > $ readlink /tmp
 > /private/tmp/@ruid		# as expected
 > $ readlink -v /private/tmp/@ruid
 > readlink: /private/tmp/@ruid: lstat: No such file or directory
 > $
 >=20
 > I made a hacky patch (duplicating the entire symlink_magic() machinery
 > present in kern/vfs_lookup.c) awhile back for do_sys_readlinkat()
 > which
 > expands these magic tokens, but, that then needed a lot more elsewhere
 > (because of the expansion removing the tokens). I've given up for the
 > time-being.

 I guess I find it a bit concerning that this feature was added which (1)
 doesn't work with some basic use cases and (2) doesn't document this
 limitation. #2 is easy enough to remedy.

 Thanks,

 Dave

From: "David H. Gutteridge" <gutteridge@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/58438 CVS commit: src/share/man/man7
Date: Wed, 30 Oct 2024 01:44:43 +0000

 Module Name:	src
 Committed By:	gutteridge
 Date:		Wed Oct 30 01:44:43 UTC 2024

 Modified Files:
 	src/share/man/man7: security.7

 Log Message:
 security.7: note some programs won't work with per-user-tmp

 Addresses a documentation aspect of PR kern/58438.


 To generate a diff of this commit:
 cvs rdiff -u -r1.16 -r1.17 src/share/man/man7/security.7

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->feedback
State-Changed-By: gutteridge@NetBSD.org
State-Changed-When: Thu, 31 Oct 2024 01:24:32 +0000
State-Changed-Why:
You stated this is "incompatible with certain system-softwares like
X(1) or even tmux(1)". I'm able to reproduce the issue with tmux(1), as
RVP has explained in detail. I'm not able to reproduce with an X
session, that works fine for me. Can you give more specific details
about what is failing for you in an X11 context, please?

From: Marc Daniel Fege <13mdf@fege.net>
To: kern-bug-people@netbsd.org, netbsd-bugs@netbsd.org,
 gnats-admin@netbsd.org, gutteridge@netbsd.org, gnats-bugs@netbsd.org
Cc: 
Subject:  Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Thu, 31 Oct 2024 07:29:11 +0100

 Hello,

 Of course. X in terms of xdm session manager won't start up for me=20
 (booted via xdm=3D"YES" in /etc/rc.conf), neither on a Raspberry PI 4, nor=
 =20
 on an old x86 machine, whatsoever if I activate per-user-temp. I could=20
 not see, whether xdm itself produces some session files within temp or=20
 expects certain folders to be writable in a certain way at least, but=20
 once the per-user-temp-feature is deactivated and rebooted, xdm comes up=20
 again as it should be.

 I hope this hint helps a bit.

 Best regards =E2=80=93
 Marc.

 Am Donnerstag, 31. Oktober 2024, 02:24:32 Mitteleurop=C3=A4ische Normalzeit=
 =20
 schrieb gutteridge@NetBSD.org:
 > Synopsis: Compatibility issues with per-user-temp [described
 > security(7) man page]
 >=20
 > State-Changed-From-To: open->feedback
 > State-Changed-By: gutteridge@NetBSD.org
 > State-Changed-When: Thu, 31 Oct 2024 01:24:32 +0000
 > State-Changed-Why:
 > You stated this is "incompatible with certain system-softwares like
 > X(1) or even tmux(1)". I'm able to reproduce the issue with tmux(1),
 > as RVP has explained in detail. I'm not able to reproduce with an X
 > session, that works fine for me. Can you give more specific details
 > about what is failing for you in an X11 context, please?


From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: "David H. Gutteridge" <gutteridge@netbsd.org>
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Fri, 1 Nov 2024 00:49:06 +0000 (UTC)

 On Sun, 27 Oct 2024, David H. Gutteridge via gnats wrote:

 > I guess I find it a bit concerning that this feature was added which (1)
 > doesn't work with some basic use cases and (2) doesn't document this
 > limitation. #2 is easy enough to remedy.
 >

 Since userspace needs to see the @magic tokens (as we've seen), and realpath(3)
 seems to the cause of all this, I think we should just fix it to expand those
 tokens when magic-symlinks are active. That should take care of 1)--even though
 this means duplicating the expansion already being done in the kernel.

 Shouldn't be hard. I'll do it--but, prolly only next week.

 Thx,

 -RVP

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Fri, 1 Nov 2024 08:29:33 +0100

 On Fri, Nov 01, 2024 at 12:50:01AM +0000, RVP via gnats wrote:
 >  Since userspace needs to see the @magic tokens (as we've seen), and realpath(3)
 >  seems to the cause of all this, I think we should just fix it to expand those
 >  tokens when magic-symlinks are active. That should take care of 1)--even though
 >  this means duplicating the expansion already being done in the kernel.
 >  
 >  Shouldn't be hard. I'll do it--but, prolly only next week.

 I agree with the aproach, but it is not as trivial as it sounds, see
 PR kern/58801.

 I wonder if we should make the mapping table the kernel uses available
 (read only) to userland via a sysctl, so besides realpath(3) it could
 also be used in the ATF tests. The ATF tests also should grow a realpath
 test.

 Or we define (and document) a fixed mapping/semantics for
 machine/machine_arch that we can hardcode in both places.

 Martin

From: mlelstv@serpens.de (Michael van Elst)
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described security(7) man page])
Date: Fri, 1 Nov 2024 07:55:04 -0000 (UTC)

 gnats-admin@NetBSD.org ("Martin Husemann via gnats") writes:

 > Or we define (and document) a fixed mapping/semantics for
 > machine/machine_arch that we can hardcode in both places.

 sysctl does the mapping, so you can just query the kernel
 and cache the result.

State-Changed-From-To: feedback->open
State-Changed-By: gutteridge@NetBSD.org
State-Changed-When: Sat, 02 Nov 2024 01:51:37 +0000
State-Changed-Why:
Feedback provided. I'll take a look at xdm(8).

From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: gutteridge@NetBSD.org
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Sat, 2 Nov 2024 08:28:12 +0000 (UTC)

 OK, this patch seems to work.

 When xdm is started using the rc(8) framework, setusercontext(3) never gets
 called (this is only called in xdm _after_ user authentication), so the X
 server can't start without /private/tmp/0 existing. Do a bogus su(1) in
 /etc/rc.d/xdm to create this.

 Next, do the same for each user before _their_ X session is started; _and_
 since now X is running as root and the user is not, and there's no shared
 /tmp anymore, link root's X11 lock-file and socket into the user's per-user
 /tmp dir.

 Thankfully, both files are normally world-readable and -writable by default.

 This is a terrible hack... (note that if you change xdm-config to use a
 different DisplayManager._0.startup, you'll have to put that hack in the new
 file.)

 -RVP

 ```
 --- etc/rc.d/xdm.orig	2024-01-29 23:14:46.000000000 +0000
 +++ etc/rc.d/xdm	2024-11-02 07:40:02.031867487 +0000
 @@ -17,4 +17,9 @@
   extra_commands="reload"

   load_rc_config $name
 +
 +if readlink /tmp | grep -q @ruid && [ $1 = start ]
 +then	su root -c 'echo "Bogus su(1) to create /private/tmp/0"'
 +fi
 +
   run_rc_command "$1"
 --- etc/X11/xdm/GiveConsole.orig	2024-01-29 23:14:46.000000000 +0000
 +++ etc/X11/xdm/GiveConsole	2024-11-02 07:35:40.902195347 +0000
 @@ -7,3 +7,18 @@
   # causing serious grief.
   #
   chown $USER /dev/console
 +
 +UID=$(id -u $USER)
 +if readlink /tmp | grep -q @ruid && [ $UID -ne 0 ]
 +then
 +	# First, do a bogus su(1) to create $USER's "/tmp" dir.;
 +	# then force create _hard-links_ to root's X socket and
 +	# lock-file _every time_--as the inodes of root's files
 +	# could change with every session.
 +
 +	su "$USER" -c "echo 'This creates /private/tmp/$UID'"
 +	cd /private/tmp/$UID || exit 1		# sanity chk.
 +	test -d .X11-unix || install -dm 700 -o $USER .X11-unix
 +	ln -f /private/tmp/0/.X0-lock .X0-lock
 +	ln -f /private/tmp/0/.X11-unix/X0 .X11-unix/X0
 +fi
 ```

From: "David H. Gutteridge" <david@gutteridge.ca>
To: RVP <rvp@SDF.ORG>, gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58438 (Compatibility issues with per-user-temp [described
 security(7) man page])
Date: Thu, 07 Nov 2024 00:47:01 -0500

 On Sat, 2024-11-02 at 08:28 +0000, RVP wrote:
 > OK, this patch seems to work.
 >=20
 > When xdm is started using the rc(8) framework, setusercontext(3) never
 > gets
 > called (this is only called in xdm _after_ user authentication), so
 > the X
 > server can't start without /private/tmp/0 existing. Do a bogus su(1)
 > in
 > /etc/rc.d/xdm to create this.
 >=20
 > Next, do the same for each user before _their_ X session is started;
 > _and_
 > since now X is running as root and the user is not, and there's no
 > shared
 > /tmp anymore, link root's X11 lock-file and socket into the user's
 > per-user
 > /tmp dir.
 >=20
 > Thankfully, both files are normally world-readable and -writable by
 > default.
 >=20
 > This is a terrible hack... (note that if you change xdm-config to use
 > a
 > different DisplayManager._0.startup, you'll have to put that hack in
 > the new
 > file.)

 Thanks for doing all this!

 This makes me wonder if the patch I'd found from nonaka@ existed for
 reasons somewhat like this; if there are various programs that have
 issues here if there's no /private/tmp/0 or what-have-you created
 without recourse to that login trick. Seems like it wouldn't have
 fully helped here, mind you, given the assumptions xdm makes.

 Dave

State-Changed-From-To: open->analyzed
State-Changed-By: gutteridge@NetBSD.org
State-Changed-When: Fri, 27 Dec 2024 17:19:22 +0000
State-Changed-Why:
Issue is understood, and fix under discussion.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.