Accepting request 888794 from network:samba:STABLE

- cifs.upcall: fix regression in kerberos mount; (bsc#1184815).
  * add 0001-cifs.upcall-fix-regression-in-kerberos-mount.patch

- CVE-2021-20208: cifs-utils: cifs.upcall kerberos auth leak in
  container; (bsc#1183239); CVE-2021-20208.
  * add 0001-cifs.upcall-try-to-use-container-ipc-uts-net-pid-mnt.patch

- Make cifs-idmap plugin (idmapwb.so) use update-alternatives
  mechanism to be able to switch between cifs-utils and sssd;
  (bsc#1182682).

OBS-URL: https://build.opensuse.org/request/show/888794
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/cifs-utils?expand=0&rev=67
This commit is contained in:
Dominique Leuenberger 2021-04-27 19:34:18 +00:00 committed by Git OBS Bridge
commit 07c5d3dc0c
4 changed files with 816 additions and 6 deletions

View File

@ -0,0 +1,493 @@
From 4ca235223d948fe4f3392da28b1471bce36e88d4 Mon Sep 17 00:00:00 2001
From: Aurelien Aptel <aaptel@suse.com>
Date: Wed, 21 Apr 2021 16:22:15 +0200
Subject: [PATCH v4] cifs.upcall: fix regression in kerberos mount
The fix for CVE-2021-20208 in commit e461afd ("cifs.upcall: try to use
container ipc/uts/net/pid/mnt/user namespaces") introduced a
regression for kerberos mounts when cifs-utils is built with
libcap-ng. It makes mount fail with ENOKEY "Required key not
available".
Current state:
mount.cifs
'---> mount() ---> kernel
negprot, session setup (need security blob for krb)
request_key("cifs.spnego", payload="pid=%d;username=...")
upcall
/sbin/request-key <--------------'
reads /etc/request-keys.conf
dispatch cifs.spnego request
calls /usr/sbin/cifs.upcall <key id>
- drop privileges (capabilities)
- fetch keyid
- parse payload
- switch to mount.cifs namespaces
- call krb5_xxx() funcs
- generate security blob
- set key value to security blob
'-----------------------------------> kernel
put blob in session setup packet
continue auth
open tcon
get share root
setup superblock
mount.cifs mount() returns <-----------'
By the time cifs.upcall tries to switch to namespaces, enough
capabilities have dropped in trim_capabilities() that it makes setns()
fail with EPERM.
setns() requires CAP_SYS_ADMIN.
With libcap trim_capabilities() is a no-op.
This fix:
- moves the namespace switch earlier so that operations like
setgroups(), setgid(), scanning of pid environment, ... happens in the
contained namespaces.
- moves trim_capabilities() after the namespace switch
- moves the string processing to decode the key request payload in a
child process with minimum capabilities. the decoded data is shared
with the parent process via shared memory obtained with mmap().
Fixes: e461afd ("cifs.upcall: try to use container ipc/uts/net/pid/mnt/user namespaces")
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
---
cifs.upcall.c | 214 ++++++++++++++++++++++++++++++++------------------
1 file changed, 139 insertions(+), 75 deletions(-)
diff --git a/cifs.upcall.c b/cifs.upcall.c
index e413934..ad04301 100644
--- a/cifs.upcall.c
+++ b/cifs.upcall.c
@@ -52,6 +52,9 @@
#include <stdbool.h>
#include <errno.h>
#include <sched.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include "data_blob.h"
#include "spnego.h"
@@ -787,6 +790,25 @@ handle_krb5_mech(const char *oid, const char *host, DATA_BLOB * secblob,
return retval;
}
+
+
+struct decoded_args {
+ int ver;
+ char hostname[NI_MAXHOST + 1];
+ char ip[NI_MAXHOST + 1];
+
+/* Max user name length. */
+#define MAX_USERNAME_SIZE 256
+ char username[MAX_USERNAME_SIZE + 1];
+
+ uid_t uid;
+ uid_t creduid;
+ pid_t pid;
+ sectype_t sec;
+
+/*
+ * Flags to keep track of what was provided
+ */
#define DKD_HAVE_HOSTNAME 0x1
#define DKD_HAVE_VERSION 0x2
#define DKD_HAVE_SEC 0x4
@@ -796,23 +818,13 @@ handle_krb5_mech(const char *oid, const char *host, DATA_BLOB * secblob,
#define DKD_HAVE_CREDUID 0x40
#define DKD_HAVE_USERNAME 0x80
#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
-
-struct decoded_args {
- int ver;
- char *hostname;
- char *ip;
- char *username;
- uid_t uid;
- uid_t creduid;
- pid_t pid;
- sectype_t sec;
+ int have;
};
static unsigned int
-decode_key_description(const char *desc, struct decoded_args *arg)
+__decode_key_description(const char *desc, struct decoded_args *arg)
{
- int len;
- int retval = 0;
+ size_t len;
char *pos;
const char *tkn = desc;
@@ -826,13 +838,13 @@ decode_key_description(const char *desc, struct decoded_args *arg)
len = pos - tkn;
len -= 5;
- free(arg->hostname);
- arg->hostname = strndup(tkn + 5, len);
- if (arg->hostname == NULL) {
- syslog(LOG_ERR, "Unable to allocate memory");
+ if (len > sizeof(arg->hostname)-1) {
+ syslog(LOG_ERR, "host= value too long for buffer");
return 1;
}
- retval |= DKD_HAVE_HOSTNAME;
+ memset(arg->hostname, 0, sizeof(arg->hostname));
+ strncpy(arg->hostname, tkn + 5, len);
+ arg->have |= DKD_HAVE_HOSTNAME;
syslog(LOG_DEBUG, "host=%s", arg->hostname);
} else if (!strncmp(tkn, "ip4=", 4) || !strncmp(tkn, "ip6=", 4)) {
if (pos == NULL)
@@ -841,13 +853,13 @@ decode_key_description(const char *desc, struct decoded_args *arg)
len = pos - tkn;
len -= 4;
- free(arg->ip);
- arg->ip = strndup(tkn + 4, len);
- if (arg->ip == NULL) {
- syslog(LOG_ERR, "Unable to allocate memory");
+ if (len > sizeof(arg->ip)-1) {
+ syslog(LOG_ERR, "ip[46]= value too long for buffer");
return 1;
}
- retval |= DKD_HAVE_IP;
+ memset(arg->ip, 0, sizeof(arg->ip));
+ strncpy(arg->ip, tkn + 4, len);
+ arg->have |= DKD_HAVE_IP;
syslog(LOG_DEBUG, "ip=%s", arg->ip);
} else if (strncmp(tkn, "user=", 5) == 0) {
if (pos == NULL)
@@ -856,13 +868,13 @@ decode_key_description(const char *desc, struct decoded_args *arg)
len = pos - tkn;
len -= 5;
- free(arg->username);
- arg->username = strndup(tkn + 5, len);
- if (arg->username == NULL) {
- syslog(LOG_ERR, "Unable to allocate memory");
+ if (len > sizeof(arg->username)-1) {
+ syslog(LOG_ERR, "user= value too long for buffer");
return 1;
}
- retval |= DKD_HAVE_USERNAME;
+ memset(arg->username, 0, sizeof(arg->username));
+ strncpy(arg->username, tkn + 5, len);
+ arg->have |= DKD_HAVE_USERNAME;
syslog(LOG_DEBUG, "user=%s", arg->username);
} else if (strncmp(tkn, "pid=", 4) == 0) {
errno = 0;
@@ -873,13 +885,13 @@ decode_key_description(const char *desc, struct decoded_args *arg)
return 1;
}
syslog(LOG_DEBUG, "pid=%u", arg->pid);
- retval |= DKD_HAVE_PID;
+ arg->have |= DKD_HAVE_PID;
} else if (strncmp(tkn, "sec=", 4) == 0) {
if (strncmp(tkn + 4, "krb5", 4) == 0) {
- retval |= DKD_HAVE_SEC;
+ arg->have |= DKD_HAVE_SEC;
arg->sec = KRB5;
} else if (strncmp(tkn + 4, "mskrb5", 6) == 0) {
- retval |= DKD_HAVE_SEC;
+ arg->have |= DKD_HAVE_SEC;
arg->sec = MS_KRB5;
}
syslog(LOG_DEBUG, "sec=%d", arg->sec);
@@ -891,7 +903,7 @@ decode_key_description(const char *desc, struct decoded_args *arg)
strerror(errno));
return 1;
}
- retval |= DKD_HAVE_UID;
+ arg->have |= DKD_HAVE_UID;
syslog(LOG_DEBUG, "uid=%u", arg->uid);
} else if (strncmp(tkn, "creduid=", 8) == 0) {
errno = 0;
@@ -901,7 +913,7 @@ decode_key_description(const char *desc, struct decoded_args *arg)
strerror(errno));
return 1;
}
- retval |= DKD_HAVE_CREDUID;
+ arg->have |= DKD_HAVE_CREDUID;
syslog(LOG_DEBUG, "creduid=%u", arg->creduid);
} else if (strncmp(tkn, "ver=", 4) == 0) { /* if version */
errno = 0;
@@ -911,14 +923,56 @@ decode_key_description(const char *desc, struct decoded_args *arg)
strerror(errno));
return 1;
}
- retval |= DKD_HAVE_VERSION;
+ arg->have |= DKD_HAVE_VERSION;
syslog(LOG_DEBUG, "ver=%d", arg->ver);
}
if (pos == NULL)
break;
tkn = pos + 1;
} while (tkn);
- return retval;
+ return 0;
+}
+
+static unsigned int
+decode_key_description(const char *desc, struct decoded_args **arg)
+{
+ pid_t pid;
+ pid_t rc;
+ int status;
+
+ /*
+ * Do all the decoding/string processing in a child process
+ * with low privileges.
+ */
+
+ *arg = mmap(NULL, sizeof(struct decoded_args), PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if (*arg == MAP_FAILED) {
+ syslog(LOG_ERR, "%s: mmap failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ syslog(LOG_ERR, "%s: fork failed: %s", __func__, strerror(errno));
+ munmap(*arg, sizeof(struct decoded_args));
+ *arg = NULL;
+ return -1;
+ }
+ if (pid == 0) {
+ /* do the parsing in child */
+ drop_all_capabilities();
+ exit(__decode_key_description(desc, *arg));
+ }
+
+ rc = waitpid(pid, &status, 0);
+ if (rc < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ munmap(*arg, sizeof(struct decoded_args));
+ *arg = NULL;
+ return 1;
+ }
+
+ return 0;
}
static int setup_key(const key_serial_t key, const void *data, size_t datalen)
@@ -1098,7 +1152,7 @@ int main(const int argc, char *const argv[])
bool try_dns = false, legacy_uid = false , env_probe = true;
char *buf;
char hostbuf[NI_MAXHOST], *host;
- struct decoded_args arg;
+ struct decoded_args *arg = NULL;
const char *oid;
uid_t uid;
char *keytab_name = NULL;
@@ -1109,7 +1163,6 @@ int main(const int argc, char *const argv[])
const char *key_descr = NULL;
hostbuf[0] = '\0';
- memset(&arg, 0, sizeof(arg));
openlog(prog, 0, LOG_DAEMON);
@@ -1150,9 +1203,6 @@ int main(const int argc, char *const argv[])
}
}
- if (trim_capabilities(env_probe))
- goto out;
-
/* is there a key? */
if (argc <= optind) {
usage();
@@ -1178,6 +1228,10 @@ int main(const int argc, char *const argv[])
syslog(LOG_DEBUG, "key description: %s", buf);
+ /*
+ * If we are requested a simple DNS query, do it and exit
+ */
+
if (strncmp(buf, "cifs.resolver", sizeof("cifs.resolver") - 1) == 0)
key_descr = ".cifs.resolver";
else if (strncmp(buf, "dns_resolver", sizeof("dns_resolver") - 1) == 0)
@@ -1187,33 +1241,42 @@ int main(const int argc, char *const argv[])
goto out;
}
- have = decode_key_description(buf, &arg);
+ /*
+ * Otherwise, it's a spnego key request
+ */
+
+ rc = decode_key_description(buf, &arg);
free(buf);
- if ((have & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
+ if (rc) {
+ syslog(LOG_ERR, "failed to decode key description");
+ goto out;
+ }
+
+ if ((arg->have & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
syslog(LOG_ERR, "unable to get necessary params from key "
"description (0x%x)", have);
rc = 1;
goto out;
}
- if (arg.ver > CIFS_SPNEGO_UPCALL_VERSION) {
+ if (arg->ver > CIFS_SPNEGO_UPCALL_VERSION) {
syslog(LOG_ERR, "incompatible kernel upcall version: 0x%x",
- arg.ver);
+ arg->ver);
rc = 1;
goto out;
}
- if (strlen(arg.hostname) >= NI_MAXHOST) {
+ if (strlen(arg->hostname) >= NI_MAXHOST) {
syslog(LOG_ERR, "hostname provided by kernel is too long");
rc = 1;
goto out;
}
- if (!legacy_uid && (have & DKD_HAVE_CREDUID))
- uid = arg.creduid;
- else if (have & DKD_HAVE_UID)
- uid = arg.uid;
+ if (!legacy_uid && (arg->have & DKD_HAVE_CREDUID))
+ uid = arg->creduid;
+ else if (arg->have & DKD_HAVE_UID)
+ uid = arg->uid;
else {
/* no uid= or creduid= parm -- something is wrong */
syslog(LOG_ERR, "No uid= or creduid= parm specified");
@@ -1221,6 +1284,21 @@ int main(const int argc, char *const argv[])
goto out;
}
+ /*
+ * Change to the process's namespace. This means that things will work
+ * acceptably in containers, because we'll be looking at the correct
+ * filesystem and have the correct network configuration.
+ */
+ rc = switch_to_process_ns(arg->pid);
+ if (rc == -1) {
+ syslog(LOG_ERR, "unable to switch to process namespace: %s", strerror(errno));
+ rc = 1;
+ goto out;
+ }
+
+ if (trim_capabilities(env_probe))
+ goto out;
+
/*
* The kernel doesn't pass down the gid, so we resort here to scraping
* one out of the passwd nss db. Note that this might not reflect the
@@ -1266,20 +1344,7 @@ int main(const int argc, char *const argv[])
* look at the environ file.
*/
env_cachename =
- get_cachename_from_process_env(env_probe ? arg.pid : 0);
-
- /*
- * Change to the process's namespace. This means that things will work
- * acceptably in containers, because we'll be looking at the correct
- * filesystem and have the correct network configuration.
- */
- rc = switch_to_process_ns(arg.pid);
- if (rc == -1) {
- syslog(LOG_ERR, "unable to switch to process namespace: %s",
- strerror(errno));
- rc = 1;
- goto out;
- }
+ get_cachename_from_process_env(env_probe ? arg->pid : 0);
rc = setuid(uid);
if (rc == -1) {
@@ -1301,18 +1366,18 @@ int main(const int argc, char *const argv[])
ccache = get_existing_cc(env_cachename);
/* Couldn't find credcache? Try to use keytab */
- if (ccache == NULL && arg.username != NULL)
- ccache = init_cc_from_keytab(keytab_name, arg.username);
+ if (ccache == NULL && arg->username[0] != '\0')
+ ccache = init_cc_from_keytab(keytab_name, arg->username);
if (ccache == NULL) {
rc = 1;
goto out;
}
- host = arg.hostname;
+ host = arg->hostname;
// do mech specific authorization
- switch (arg.sec) {
+ switch (arg->sec) {
case MS_KRB5:
case KRB5:
/*
@@ -1328,7 +1393,7 @@ int main(const int argc, char *const argv[])
* TRY only:
* cifs/bar.example.com@REALM
*/
- if (arg.sec == MS_KRB5)
+ if (arg->sec == MS_KRB5)
oid = OID_KERBEROS5_OLD;
else
oid = OID_KERBEROS5;
@@ -1385,10 +1450,10 @@ retry_new_hostname:
break;
}
- if (!try_dns || !(have & DKD_HAVE_IP))
+ if (!try_dns || !(arg->have & DKD_HAVE_IP))
break;
- rc = ip_to_fqdn(arg.ip, hostbuf, sizeof(hostbuf));
+ rc = ip_to_fqdn(arg->ip, hostbuf, sizeof(hostbuf));
if (rc)
break;
@@ -1396,7 +1461,7 @@ retry_new_hostname:
host = hostbuf;
goto retry_new_hostname;
default:
- syslog(LOG_ERR, "sectype: %d is not implemented", arg.sec);
+ syslog(LOG_ERR, "sectype: %d is not implemented", arg->sec);
rc = 1;
break;
}
@@ -1414,7 +1479,7 @@ retry_new_hostname:
rc = 1;
goto out;
}
- keydata->version = arg.ver;
+ keydata->version = arg->ver;
keydata->flags = 0;
keydata->sesskey_len = sess_key.length;
keydata->secblob_len = secblob.length;
@@ -1440,11 +1505,10 @@ out:
krb5_cc_close(context, ccache);
if (context)
krb5_free_context(context);
- free(arg.hostname);
- free(arg.ip);
- free(arg.username);
free(keydata);
free(env_cachename);
+ if (arg)
+ munmap(arg, sizeof(*arg));
syslog(LOG_DEBUG, "Exit status %ld", rc);
return rc;
}
--
2.30.0

View File

@ -0,0 +1,264 @@
From e461afd8cfa6d0781ae0c5c10e89b6ef1ca6da32 Mon Sep 17 00:00:00 2001
From: Alastair Houghton <alastair@alastairs-place.net>
Date: Tue, 29 Dec 2020 14:02:39 +0000
Subject: [PATCH] cifs.upcall: try to use container ipc/uts/net/pid/mnt/user
namespaces
In certain scenarios (e.g. kerberos multimount), when a process does
syscalls, the kernel sometimes has to query information or trigger
some actions in userspace. To do so it calls the cifs.upcall binary
with information on the process that triggered the syscall in the
first place.
ls(pid=10) ====> open("foo") ====> kernel
that user doesn't have an SMB
session, lets create one using his
kerberos credential cache
call cifs.upcall and ask for krb info
for whoever owns pid=10
|
cifs.upcall --pid 10 <=================+
...gather info...
return binary blob used
when establishing SMB session
===================> kernel
open SMB session, handle
open() syscall
ls <=================================== return open() result to ls
On a system using containers, the kernel is still calling the host
cifs.upcall and using the host configuration (for network, pid, etc).
This patch changes the behaviour of cifs.upcall so that it uses the
calling process namespaces (ls in the example) when doing its
job.
Note that the kernel still calls the binary in the host, but the
binary will place itself the contexts of the calling process
namespaces.
This code makes use of (but shouldn't require) the following kernel
config options and syscall flags:
approx. year |
introduced | config/flags
---------------+----------------
2008 | CONFIG_NAMESPACES=y
2007 | CONFIG_UTS_NS=y
2020 | CONFIG_TIME_NS=y
2006 | CONFIG_IPC_NS=y
2007 | CONFIG_USER_NS
2008 | CONFIG_PID_NS=y
2007 | CONFIG_NET_NS=y
2007 | CONFIG_CGROUPS
2016 | CLONE_NEWCGROUP setns() flag
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
---
cifs.upcall.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+)
diff --git a/cifs.upcall.c b/cifs.upcall.c
index 400b42d..e413934 100644
--- a/cifs.upcall.c
+++ b/cifs.upcall.c
@@ -51,6 +51,7 @@
#include <grp.h>
#include <stdbool.h>
#include <errno.h>
+#include <sched.h>
#include "data_blob.h"
#include "spnego.h"
@@ -240,6 +241,164 @@ err_cache:
return credtime;
}
+static struct namespace_file {
+ int nstype;
+ const char *name;
+ int fd;
+} namespace_files[] = {
+
+#ifdef CLONE_NEWCGROUP
+ { CLONE_NEWCGROUP, "cgroup", -1 },
+#endif
+
+#ifdef CLONE_NEWIPC
+ { CLONE_NEWIPC, "ipc", -1 },
+#endif
+
+#ifdef CLONE_NEWUTS
+ { CLONE_NEWUTS, "uts", -1 },
+#endif
+
+#ifdef CLONE_NEWNET
+ { CLONE_NEWNET, "net", -1 },
+#endif
+
+#ifdef CLONE_NEWPID
+ { CLONE_NEWPID, "pid", -1 },
+#endif
+
+#ifdef CLONE_NEWTIME
+ { CLONE_NEWTIME, "time", -1 },
+#endif
+
+#ifdef CLONE_NEWNS
+ { CLONE_NEWNS, "mnt", -1 },
+#endif
+
+#ifdef CLONE_NEWUSER
+ { CLONE_NEWUSER, "user", -1 },
+#endif
+};
+
+#define NS_PATH_FMT "/proc/%d/ns/%s"
+#define NS_PATH_MAXLEN (6 + 10 + 4 + 6 + 1)
+
+/**
+ * in_same_user_ns - return true if two processes are in the same user
+ * namespace.
+ * @pid_a: the pid of the first process
+ * @pid_b: the pid of the second process
+ *
+ * Works by comparing the inode numbers for /proc/<pid>/user.
+ */
+static int
+in_same_user_ns(pid_t pid_a, pid_t pid_b)
+{
+ char path[NS_PATH_MAXLEN];
+ ino_t a_ino, b_ino;
+ struct stat st;
+
+ snprintf(path, sizeof(path), NS_PATH_FMT, pid_a, "user");
+ if (stat(path, &st) != 0)
+ return 0;
+ a_ino = st.st_ino;
+
+ snprintf(path, sizeof(path), NS_PATH_FMT, pid_b, "user");
+ if (stat(path, &st) != 0)
+ return 0;
+ b_ino = st.st_ino;
+
+ return a_ino == b_ino;
+}
+
+/**
+ * switch_to_process_ns - change the namespace to the one for the specified
+ * process.
+ * @pid: initiating pid value from the upcall string
+ *
+ * Uses setns() to switch process namespace.
+ * This ensures that we have the same access and configuration as the
+ * process that triggered the lookup.
+ */
+static int
+switch_to_process_ns(pid_t pid)
+{
+ int count = sizeof(namespace_files) / sizeof(struct namespace_file);
+ int n, err = 0;
+ int rc = 0;
+
+ /* First, open all the namespace fds. We do this first because
+ the namespace changes might prohibit us from opening them. */
+ for (n = 0; n < count; ++n) {
+ char nspath[NS_PATH_MAXLEN];
+ int ret, fd;
+
+#ifdef CLONE_NEWUSER
+ if (namespace_files[n].nstype == CLONE_NEWUSER
+ && in_same_user_ns(getpid(), pid)) {
+ /* Switching to the same user namespace is forbidden,
+ because switching to a user namespace grants all
+ capabilities in that namespace regardless of uid. */
+ namespace_files[n].fd = -1;
+ continue;
+ }
+#endif
+
+ ret = snprintf(nspath, NS_PATH_MAXLEN, NS_PATH_FMT,
+ pid, namespace_files[n].name);
+ if (ret >= NS_PATH_MAXLEN) {
+ syslog(LOG_DEBUG, "%s: unterminated path!\n", __func__);
+ err = ENAMETOOLONG;
+ rc = -1;
+ goto out;
+ }
+
+ fd = open(nspath, O_RDONLY);
+ if (fd < 0 && errno != ENOENT) {
+ /*
+ * don't stop on non-existing ns
+ * but stop for other errors
+ */
+ err = errno;
+ rc = -1;
+ goto out;
+ }
+
+ namespace_files[n].fd = fd;
+ }
+
+ /* Next, call setns for each of them */
+ for (n = 0; n < count; ++n) {
+ /* skip non-existing ns */
+ if (namespace_files[n].fd < 0)
+ continue;
+
+ rc = setns(namespace_files[n].fd, namespace_files[n].nstype);
+
+ if (rc < 0) {
+ syslog(LOG_DEBUG, "%s: setns() failed for %s\n",
+ __func__, namespace_files[n].name);
+ err = errno;
+ goto out;
+ }
+ }
+
+out:
+ /* Finally, close all the fds */
+ for (n = 0; n < count; ++n) {
+ if (namespace_files[n].fd != -1) {
+ close(namespace_files[n].fd);
+ namespace_files[n].fd = -1;
+ }
+ }
+
+ if (rc != 0) {
+ errno = err;
+ }
+
+ return rc;
+}
+
#define ENV_PATH_FMT "/proc/%d/environ"
#define ENV_PATH_MAXLEN (6 + 10 + 8 + 1)
@@ -1109,6 +1268,19 @@ int main(const int argc, char *const argv[])
env_cachename =
get_cachename_from_process_env(env_probe ? arg.pid : 0);
+ /*
+ * Change to the process's namespace. This means that things will work
+ * acceptably in containers, because we'll be looking at the correct
+ * filesystem and have the correct network configuration.
+ */
+ rc = switch_to_process_ns(arg.pid);
+ if (rc == -1) {
+ syslog(LOG_ERR, "unable to switch to process namespace: %s",
+ strerror(errno));
+ rc = 1;
+ goto out;
+ }
+
rc = setuid(uid);
if (rc == -1) {
syslog(LOG_ERR, "setuid: %s", strerror(errno));
--
2.30.0

View File

@ -1,3 +1,16 @@
-------------------------------------------------------------------
Fri Apr 23 10:41:59 UTC 2021 - Aurelien Aptel <aaptel@suse.com>
- cifs.upcall: fix regression in kerberos mount; (bsc#1184815).
* add 0001-cifs.upcall-fix-regression-in-kerberos-mount.patch
-------------------------------------------------------------------
Tue Mar 9 17:17:59 UTC 2021 - palcantara@suse.de
- CVE-2021-20208: cifs-utils: cifs.upcall kerberos auth leak in
container; (bsc#1183239); CVE-2021-20208.
* add 0001-cifs.upcall-try-to-use-container-ipc-uts-net-pid-mnt.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Tue Feb 23 12:15:39 UTC 2021 - Aurelien Aptel <aaptel@suse.com> Tue Feb 23 12:15:39 UTC 2021 - Aurelien Aptel <aaptel@suse.com>
@ -53,6 +66,13 @@ Tue Nov 17 13:42:23 UTC 2020 - Ludwig Nussel <lnussel@suse.de>
- prepare usrmerge (boo#1029961) - prepare usrmerge (boo#1029961)
-------------------------------------------------------------------
Tue Aug 11 12:45:15 UTC 2020 - Aurelien Aptel <aaptel@suse.com>
- Make cifs-idmap plugin (idmapwb.so) use update-alternatives
mechanism to be able to switch between cifs-utils and sssd;
(bsc#1182682).
------------------------------------------------------------------- -------------------------------------------------------------------
Mon Aug 10 06:56:11 UTC 2020 - Aurelien Aptel <aaptel@suse.com> Mon Aug 10 06:56:11 UTC 2020 - Aurelien Aptel <aaptel@suse.com>

View File

@ -37,6 +37,20 @@ Source100: README.cifstab.migration
Source1: cifs.init Source1: cifs.init
Patch1: fix-sbin-install-error.patch Patch1: fix-sbin-install-error.patch
Patch2: 0001-cifs.upcall-try-to-use-container-ipc-uts-net-pid-mnt.patch
Patch3: 0001-cifs.upcall-fix-regression-in-kerberos-mount.patch
# Both SSSD and cifs-utils provide an idmap plugin for cifs.ko
# /etc/cifs-utils/idmap-plugin should be a symlink to one of the 2 idmap plugins
# * cifs-utils one is the default (priority 20)
# * installing SSSD should NOT switch to SSSD plugin (priority 10)
%define cifs_idmap_plugin %{_sysconfdir}/cifs-utils/idmap-plugin
%define cifs_idmap_lib %{_libdir}/cifs-utils/idmapwb.so
%define cifs_idmap_name cifs-idmap-plugin
%define cifs_idmap_priority 20
BuildRequires: update-alternatives
Requires(post): update-alternatives
Requires(preun): update-alternatives
# cifs-utils 6.8 switched to python for man page generation # cifs-utils 6.8 switched to python for man page generation
# we need to require either py2 or py3 package # we need to require either py2 or py3 package
@ -121,6 +135,8 @@ for i in $pyscripts; do
done done
%patch1 -p1 %patch1 -p1
%patch2 -p1
%patch3 -p1
%build %build
export CFLAGS="%{optflags} -D_GNU_SOURCE -fpie" export CFLAGS="%{optflags} -D_GNU_SOURCE -fpie"
@ -139,8 +155,6 @@ mkdir -p %{buildroot}/%{_sysconfdir}/init.d
%endif %endif
%make_install %make_install
mkdir -p %{buildroot}%{_sysconfdir}/%{name}
ln -s %{_libdir}/%{name}/idmapwb.so %{buildroot}%{_sysconfdir}/%{name}/idmap-plugin
mkdir -p %{buildroot}%{_sysconfdir}/request-key.d mkdir -p %{buildroot}%{_sysconfdir}/request-key.d
install -m 644 -p contrib/request-key.d/cifs.idmap.conf %{buildroot}%{_sysconfdir}/request-key.d install -m 644 -p contrib/request-key.d/cifs.idmap.conf %{buildroot}%{_sysconfdir}/request-key.d
install -m 644 -p contrib/request-key.d/cifs.spnego.conf %{buildroot}%{_sysconfdir}/request-key.d install -m 644 -p contrib/request-key.d/cifs.spnego.conf %{buildroot}%{_sysconfdir}/request-key.d
@ -156,6 +170,10 @@ install -m 0755 -p ${RPM_SOURCE_DIR}/cifs.init %{buildroot}/%{_sysconfdir}/init.
ln -s service %{buildroot}/%{_sbindir}/rccifs ln -s service %{buildroot}/%{_sbindir}/rccifs
%endif %endif
# dummy target for cifs-idmap-plugin
mkdir -p %{buildroot}%{_sysconfdir}/alternatives %{buildroot}%{_sysconfdir}/cifs-utils
ln -s -f %{_sysconfdir}/alternatives/%{cifs_idmap_name} %{buildroot}%{cifs_idmap_plugin}
touch %{buildroot}/%{_sysconfdir}/sysconfig/network/if-{down,up}.d/${script} \ touch %{buildroot}/%{_sysconfdir}/sysconfig/network/if-{down,up}.d/${script} \
%{buildroot}%{_rundir}/cifs %{buildroot}%{_rundir}/cifs
%endif %endif
@ -164,6 +182,15 @@ touch %{buildroot}/%{_sysconfdir}/sysconfig/network/if-{down,up}.d/${script} \
%fdupes %{buildroot} %fdupes %{buildroot}
%endif %endif
%post
# install cifs-utils cifs-idmap plugin using alternatives system
update-alternatives --install %{cifs_idmap_plugin} %{cifs_idmap_name} %{cifs_idmap_lib} %{cifs_idmap_priority}
%postun
if [ ! -f %{cifs_idmap_lib} ] ; then
update-alternatives --remove %{cifs_idmap_name} %{cifs_idmap_lib}
fi
%files %files
%if 0%{?usrmerged} %if 0%{?usrmerged}
%{_sbindir}/mount.cifs %{_sbindir}/mount.cifs
@ -188,14 +215,20 @@ touch %{buildroot}/%{_sysconfdir}/sysconfig/network/if-{down,up}.d/${script} \
%{_mandir}/man8/cifs.upcall.8%{ext_man} %{_mandir}/man8/cifs.upcall.8%{ext_man}
%{_mandir}/man8/mount.cifs.8%{ext_man} %{_mandir}/man8/mount.cifs.8%{ext_man}
%{_mandir}/man8/mount.smb3.8%{ext_man} %{_mandir}/man8/mount.smb3.8%{ext_man}
# request keys
%dir %{_sysconfdir}/request-key.d %dir %{_sysconfdir}/request-key.d
%config(noreplace) %{_sysconfdir}/request-key.d/cifs.idmap.conf %config(noreplace) %{_sysconfdir}/request-key.d/cifs.idmap.conf
%config(noreplace) %{_sysconfdir}/request-key.d/cifs.spnego.conf %config(noreplace) %{_sysconfdir}/request-key.d/cifs.spnego.conf
%dir %{_libdir}/cifs-utils
%dir %{_sysconfdir}/cifs-utils # idmap plugin
%config(noreplace) %{_sysconfdir}/cifs-utils/idmap-plugin %dir %_sysconfdir/cifs-utils
%{_libdir}/%{name}/idmapwb.so %{cifs_idmap_plugin}
%dir %_libdir/cifs-utils
%{cifs_idmap_lib}
%ghost %_sysconfdir/alternatives/%{cifs_idmap_name}
%{_mandir}/man8/idmapwb.8%{ext_man} %{_mandir}/man8/idmapwb.8%{ext_man}
%if 0%{?suse_version} > 1221 %if 0%{?suse_version} > 1221
%if ! %{systemd} %if ! %{systemd}
%attr(0754,root,root) %config %{_sysconfdir}/init.d/cifs %attr(0754,root,root) %config %{_sysconfdir}/init.d/cifs