Package: cifs-utils
Version: 7.1

Description:

The Linux SMB client kernel filesystem today depends on the upcall
mechanism (request_key) to get stuff done in userspace (which is
difficult in the kernel. For example: DNS resolutions, Kerberos
authentication etc) and then use a binary in the userspace (which is
part of cifs-utils) to do that work. The kernel upcall mechanism today
does not have a way to upcall to specific user namespace and can do
so only to the root namespace. So, we have the user space utility that
does the switch to the "correct" namespace. With the parameters that
are supplied today with the upcall, this correct namespace cannot be
decided by the utility for a specific set of use cases, which is why
we needed to introduce a new mount option. The idea is that we'll let
the users decide what type of upcalling mechanism they need by passing
this mount option differently.
Once the kernel upcall mechanism has a way to upcall a specific
namespace, we will use this mount option to make this decision in the
kernel itself.
Without this mount option, the upcall can go to a "wrong" namespace,
and may not find what it needs or (worse) find something wrong (for
example krb5 credentials of a wrong user).


In some cases, like described below, the cifs.upcall program from the
cifs-utils package makes an upcall to the wrong namespace in
containerized environments.

Consider the following scenario:
A CIFS/SMB file share is mounted on a host node using Kerberos authentication.
During the session setup phase, the Linux kernel's cifs.ko module
makes an upcall to user space to retrieve the Kerberos service ticket
from the credential cache.
In typical (non-container) environments, this process works correctly,
but in containerized environments, the upcall may be directed to a
different namespace than intended, leading to issues. For example:
    (1) The file share is mounted on the host node at /mnt/testshare1,
meaning the Kerberos credential cache is stored in the host's
namespace.
    (2) Docker container is created, and the file share path
/mnt/testshare1 is exported to the container at /sharedpath.
    (3) When the service ticket expires and the SMB connection is
lost, before the ticket is refreshed in the credential cache, an
application inside the container performs a file operation. This
triggers the kernel to attempt a session reconnect.
    (4) During the session setup, a Kerberos ticket is needed, so the
kernel invokes the cifs.upcall binary using the request_key function.
However, cifs.upcall switches to the namespace of the caller (i.e.,
the container), causing it to attempt to read the credential cache
from the container's namespace. But since the original
mount happened in the host namespace, the credential cache is located
on the host, not in the container. This results in the upcall failing
to access the correct credential cache or accessing credential cache
which doesn't belong to the correct user.

I have attached the bug simulation logs, can you please take a look at
this issue
and backport this fix to all the affected distros.? We are in the
process of publishing
CVE for this issue.

It fixed here by adding a new mount option in Linux kernel, based on
that updating namespaces in user space cifs-utils:
cifs-utils commits:
    Fix: 
https://git.samba.org/?p=cifs-utils.git;a=commit;h=89b679228cc1be9739d54203d28289b03352c174
    Documentation:
https://git.samba.org/?p=cifs-utils.git;a=commit;h=cf63240489431e98033e599a7c9437b59494a2e4

Linux kernel commit:
    
https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/smb?id=db363b0a1d9e6b9dc556296f1b1007aeb496a8cf



Thanks,
Bharath
Simulation/Repro steps:

>> At the time of mount, Credential cache located at /tmp/krb5cc_0 file the 
>> host name space was used because by default kerberos looks for cache in 
>> /tmp/krb5cc_{uid}, since share is mounted as uid=0.

Feb 22 12:08:06 localaadvm kernel: [ 4035.333167] CIFS: Attempting to mount 
//teststorageaccount.file.core.windows.net/share
Feb 22 12:08:06 localaadvm cifs.upcall: key description: 
cifs.spnego;0;0;39010000;ver=0x2;host=teststorageaccount.file.core.windows.net;ip4=XX.239.XXX.203;sec=krb5;uid=0x0;creduid=0x0;user=root;pid=0x2dad
Feb 22 12:08:06 localaadvm cifs.upcall: ver=2
Feb 22 12:08:06 localaadvm cifs.upcall: 
host=teststorageaccount.file.core.windows.net
Feb 22 12:08:06 localaadvm cifs.upcall: ip=XX.239.XXX.203
Feb 22 12:08:06 localaadvm cifs.upcall: sec=1
Feb 22 12:08:06 localaadvm cifs.upcall: uid=0
Feb 22 12:08:06 localaadvm cifs.upcall: creduid=0
Feb 22 12:08:06 localaadvm cifs.upcall: user=root
Feb 22 12:08:06 localaadvm cifs.upcall: pid=11693
Feb 22 12:08:06 localaadvm cifs.upcall: get_cachename_from_process_env: pid == 0
Feb 22 12:08:06 localaadvm cifs.upcall: get_existing_cc: default ccache is 
FILE:/tmp/krb5cc_0   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Feb 22 12:08:06 localaadvm cifs.upcall: main: valid service ticket exists in 
credential cache
Feb 22 12:08:06 localaadvm cifs.upcall: handle_krb5_mech: getting service 
ticket for teststorageaccount.file.core.windows.net
Feb 22 12:08:06 localaadvm cifs.upcall: handle_krb5_mech: using native krb5
Feb 22 12:08:06 localaadvm cifs.upcall: handle_krb5_mech: obtained service 
ticket
Feb 22 12:08:06 localaadvm cifs.upcall: Exit status 0




>> Share mounted.
root@localaadvm:/home/azureuser/# mount -t cifs
//teststorageaccount.file.core.windows.net/testshare1 on /mnt/testshare1 type 
cifs 
(rw,relatime,vers=3.1.1,sec=krb5,cruid=0,cache=strict,username=root,uid=0,noforceuid,gid=0,noforcegid,addr=XX.239.XXX.203,file_mode=0777,dir_mode=0777,soft,persistenthandles,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,bsize=1048576,retrans=1,echo_interval=60,nosharesock,actimeo=30,closetimeo=1)
root@localaadvm:/home/azureuser# klist


root@localaadvm:/home/azureuser# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: localadminu...@azuretestdomain.onmicrosoft.com

Valid starting     Expires            Service principal
02/22/25 12:03:45  02/22/25 22:03:45  
krbtgt/azuretestdomain.onmicrosoft....@azuretestdomain.onmicrosoft.com
        renew until 03/01/25 12:03:45
02/22/25 12:03:45  02/22/25 22:03:45  
LOCALAADVM$@AZURETESTDOMAIN.ONMICROSOFT.COM
02/22/25 12:04:59  02/22/25 22:03:45  
cifs/teststorageaccount.file.core.windows.net@
        renew until 03/01/25 12:03:45
        Ticket server: 
cifs/teststorageaccount.file.core.windows....@azuretestdomain.onmicrosoft.com




root@localaadvm:/home/azureuser# stat /mnt/testshare1
  File: /mnt/testshare1
  Size: 0               Blocks: 0          IO Block: 1048576 directory
Device: 2fh/47d Inode: 13403049305088161085  Links: 2
Access: (0777/drwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-12-30 04:36:51.813053200 +0000
Modify: 2021-12-30 04:36:51.813053200 +0000
Change: 2021-12-30 04:36:51.813053200 +0000
 Birth: 2021-12-30 04:36:51.813053200 +0000
root@localaadvm:/home/azureuser#





>> Run docker container and share the host path with container:

root@localaadvm:/home/azureuser/my-debian-container#
root@localaadvm:/home/azureuser/my-debian-container# docker run -it -v 
/mnt/testshare1:/mnt/shared --name my-debian-container 
my-debian-with-syslog-cifs
root@12d9c615199e:/#


root@12d9c615199e:/# stat /mnt/shared
  File: /mnt/shared
  Size: 0               Blocks: 0          IO Block: 1048576 directory
Device: 2fh/47d Inode: 13403049305088161085  Links: 2
Access: (0777/drwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-12-30 04:36:51.813053200 +0000
Modify: 2021-12-30 04:36:51.813053200 +0000
Change: 2021-12-30 04:36:51.813053200 +0000
 Birth: 2021-12-30 04:36:51.813053200 +0000
root@12d9c615199e:/# ls /mnt/shared



>> Now to simulate bug I removed the credentials from the host and triggered 
>> the SMB connection disconnect.

>> Then I tried performing operation on container mounted path like stat 
>> operation on a file, which resulted upcall into container and accessing file 
>> /tmp/krb5cc_000 located in container.
Earlier, I explicitly made a change in container's /etc/krb5.conf for a 
default_cache_name paramater to point to /tmp/krb5cc_000 to actually notice 
that upcall came to container instead of host. 
Note that configuration at the host is unchnaged and remained same.


Feb 22 12:22:27 localaadvm kernel: [ 4896.304927] CIFS: VFS: Verify user has a 
krb5 ticket and keyutils is installed
Feb 22 12:22:27 localaadvm kernel: [ 4896.310332] CIFS: VFS: 
\\teststorageaccount.file.core.windows.net Send error in SessSetup = -126
Feb 22 12:22:28 localaadvm cifs.upcall: key description: 
cifs.spnego;0;0;39010000;ver=0x2;host=teststorageaccount.file.core.windows.net;ip4=XX.239.XXX.203;sec=krb5;uid=0x0;creduid=0x0;user=root;pid=0x3201
Feb 22 12:22:28 localaadvm cifs.upcall: ver=2
Feb 22 12:22:28 localaadvm cifs.upcall: 
host=teststorageaccount.file.core.windows.net
Feb 22 12:22:28 localaadvm cifs.upcall: ip=XX.239.XXX.203
Feb 22 12:22:28 localaadvm cifs.upcall: sec=1
Feb 22 12:22:28 localaadvm cifs.upcall: uid=0
Feb 22 12:22:28 localaadvm cifs.upcall: creduid=0
Feb 22 12:22:28 localaadvm cifs.upcall: user=root
Feb 22 12:22:28 localaadvm cifs.upcall: pid=12801
Feb 22 12:22:28 localaadvm cifs.upcall: get_cachename_from_process_env: pid == 0
Feb 22 12:22:28 localaadvm cifs.upcall: get_existing_cc: default ccache is 
FILE:/tmp/krb5cc_000  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Feb 22 12:22:28 localaadvm cifs.upcall: check_service_ticket_exists: unable to 
get client principal from cache: No credentials cache found (filename: 
/tmp/krb5cc_000)
Feb 22 12:22:28 localaadvm cifs.upcall: get_tgt_time: unable to get principal
Feb 22 12:22:28 localaadvm cifs.upcall: main: valid TGT is not present in 
credential cache
Feb 22 12:22:28 localaadvm cifs.upcall: krb5_parse_name: -1765328160
Feb 22 12:22:28 localaadvm cifs.upcall: handle_krb5_mech: getting service 
ticket for 

Reply via email to