NFS shared over tunnel worked in Leap 15.6 but not in Leap 16

I was using NFS tunneled over SSH successfully in Leap 15.6 but attempting to do the same thing in leap 16 I get errors such as
my_tunnel.service: Unable to locate executable '/usr/bin/ssh': Permission denied
Service file looks like this:

[Unit]
Description=SSH tunnel service for NFS
#
After=network-online.target

[Service]
Restart=on-failure
RestartSec=5
ExecStart=/usr/bin/ssh -NTC -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L 3049:localhost:2049 user@server.lan

[Install]
WantedBy=multi-user.target

Is this an SELinux issue as web searches suggest?

@Richard_MQ likely, that is why if you use cockpit and install setroubleshoot-server it will provide details… or you can do the steps as detailed in Portal:SELinux - openSUSE Wiki

Thanks for the suggestions, I will take a look…

Show

ausearch -m avc -ts boot

I get multiple entries in the form


time->Sat Nov 29 16:37:52 2025
type=AVC msg=audit(1764434272.231:3092): avc:  denied  { execute } for  pid=19379 comm="(ssh)" name="ssh" dev="dm-1" ino=79238 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:ssh_exec_t:s0 tclass=file permissive=0

These match the denials in journactl -f

This means??

You need to decide whether you want to keep SELinux or not.

If you do, you have two options

  1. Sledgehammer approach - allow init_t to use /usr/bin/ssh (i.e. add SELinux policy module with the correct rules). This probably could be generated by the audit2allow. This effectively defeats the purpose of the SELinux as it allows any service to run ssh, including for calling home.
  2. Add new SELinux domain (context), make sure your service transitions into this domain when started and allow only this domain to execute /usr/bin/ssh. This is slightly more involved :slight_smile: and needs more than poor man AI tools.

The more I look at the various problems people have with SELinux the more I agree that SELinux is far too complicated to be useful on a general purpose system and that the right thing is isolation (that systemd supports quite well).

Lines like
...(ssh)[20184]: my_tunnel.service: Unable to locate executable '/usr/bin/ssh': Permission denied

So it looks like SELinux is blocking it, but I don’t understand what the correct solution looks like - I’m very new to SELinux.

Thanks, I understand your suggestions. As you say, (1) is defeating the object of SELinux. But indeed (2) looks like being a bit involved. I will try to do as you suggest in (2).

Somewhat roundabout way is to write a script and assign to it a suitable label that is less restricted. A bin_t looks like a good candidate because

bor@leap16:~> sesearch -A -s init_t -t bin_t -c file -p execute 
allow init_t base_ro_file_type:file { execute execute_no_trans map };
bor@leap16:~> 

so it should be executable and

bor@leap16:~> sesearch -T -s init_t -t bin_t -c process
type_transition init_t bin_t:process unconfined_service_t;
bor@leap16:~> 

executing it should transition into the unconfined_service_t which should have less restrictions. So, write a script and do

chcon -t bin_t /path/to/your/script

and use this script in the service. If it works, you need to add the rule to file contexts so it is not reset on (automatic) relabel.

If you put your script into /usr/bin it should inherit the bin_t automatically.

As example

leap16:~ # systemctl cat test-selinux.service
# /run/systemd/system/test-selinux.service
[Unit]
Description=SSH tunnel service for NFS
#
After=network-online.target

[Service]
Restart=on-failure
RestartSec=5
ExecStart=/usr/local/bin/test-selinux.sh

leap16:~ # cat /usr/local/bin/test-selinux.sh 
#!/bin/sh

exec /usr/bin/ssh -NTC -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L 3049:localhost:2049 user@server.lan
leap16:~ # ls -Z /usr/local/bin/test-selinux.sh
unconfined_u:object_r:bin_t:s0 /usr/local/bin/test-selinux.sh
leap16:~ # journalctl -b -u test-selinux.service --no-pager --full | tail -3
Nov 29 20:35:23 leap16 test-selinux.sh[2035]: ssh: Could not resolve hostname server.lan: Name or service not known
Nov 29 20:35:23 leap16 systemd[1]: test-selinux.service: Main process exited, code=exited, status=255/EXCEPTION
Nov 29 20:35:23 leap16 systemd[1]: test-selinux.service: Failed with result 'exit-code'.
leap16:~ # 

No chcon was needed, bin_t was set automatically.

Thanks, I’ll give this a go tomorrow (no more time this evening)

But surely I should use /usr/local/bin, I can’t see how to tell whether this also inherits bin_t?

ls -dZ /usr/local/bin

By default files inherit the label from the parent directory unless overridden by the policy.

$ ls -dZ /usr/local/bin
system_u:object_r:bin_t:s0 /usr/local/bin

And yes it seems to be able to execute the script, including ssh call.

I will test properly tomorrow but meanwhile many thanks for your help

Cheers
Richard

@Richard_MQ Sorry, I was mistaken. systemd does not explicitly transition a service to a SELinux domain, it relies on the magic during exec. While the target domain can be overridden with SELinuxContext, service binaries are launched while being in the default context (init_t) which means init_t must be allowed to execute binaries.

I tried to set init_t permission using sudo chcon -t init_t /usr/local/bin/* but get the response
chcon: failed to change context of '/usr/local/bin/my_tunnel.sh' to ‘unconfined_u:object_r:init_t:s0’: Permission denied

ls -dZ /usr/local/bin/ reports unconfined_u:object_r:usr_t:s0 /usr/local/bin/

Any suggestions please how to fix this?

PS also tried as root following su -, no difference

When I restart the systemd service I don’t see any errors, but attempting to mount the remote directory fails saying mount was refused:

$ sudo mount -vvv localhost:/home/data/shared  /home/shared

mount.nfs: timeout set for Sun Nov 30 15:58:17 2025
mount.nfs: trying text-based options 'vers=4.2,addr=::1,clientaddr=::1'
mount.nfs: mount(2): Connection refused
mount.nfs: trying text-based options 'vers=4.2,addr=127.0.0.1,clientaddr=127.0.0.1'
mount.nfs: mount(2): Connection refused
mount.nfs: trying text-based options 'addr=::1'
mount.nfs: prog 100003, trying vers=3, prot=6

This feels like a different problem, but essentially the same scripts are still working on my desktop machine with Leap 15.6, same server and SSH tunnel.

And the ssh process is running?

Hmm, maybe not, assuming I can trust ps aux | grep ssh which just shows /usr/bin/ssh-agent /usr/libexec/xinit/xintrc(and the query)

Thanks for the hint.

That is not how you show the command output. You copy and paste the command and its output verbatim. You do not tell stories about it.

Anyway

I have no idea how you got it.

bor@leap16:~> /usr/sbin/matchpathcon /usr/local/bin
/usr/local/bin	system_u:object_r:bin_t:s0
bor@leap16:~> ls -dZ /usr/local/bin
system_u:object_r:bin_t:s0 /usr/local/bin
bor@leap16:~> 

While it implies that you may have other problems, it should work for your particular case. I have shown you the working service and script.

Fix what? This?

I have never said to do it. Anyway, chcon is till not god almighty and what it does must be allowed by the current policy.

bor@leap16:~> sesearch -A -t init_t -c file -p relabelto
bor@leap16:~> 

Nothing is allowed to relabel file to the init_t. The init_t is used for processes, not for files. The very first PID 1 transitions into init_t when kernel launches it.

Thank you for clarifying. Unfortunately this episode is increasingly convincing me that Leap 16 is not a great match for my use case, a great shame after so many years with S.u.S.E. 5.2 and its successors.

For now I will revert to my original manually started tunnel script (which still works), if I ever have time and inclination to learn SE Linux I might try again to automate it.