import nfs-utils-2.3.3-46.el8

This commit is contained in:
CentOS Sources 2021-11-09 05:05:30 -05:00 committed by Stepan Oksanichenko
parent 0507dd6161
commit 39bd9e53dd
8 changed files with 1458 additions and 28 deletions

View File

@ -0,0 +1,43 @@
commit ac266e2edc4f40eef810d52c72657b645e4010db
Author: Ondrej Mosnacek <omosnace@redhat.com>
Date: Tue Apr 6 15:57:37 2021 -0400
exportfs: fix unexporting of '/'
The code that has been added to strip trailing slashes from path in
unexportfs_parsed() forgot to account for the case of the root
directory, which is simply '/'. In that case it accesses path[-1] and
reduces the path to an empty string, which then fails to match any
export.
Fix it by stopping the stripping when the path is just a single
character - it doesn't matter if it's a '/' or not, we want to keep it
either way in that case.
Reproducer:
exportfs localhost:/
exportfs -u localhost:/
Without this patch, the unexport step fails with "exportfs: Could not
find 'localhost:/' to unexport."
Fixes: a9a7728d8743 ("exportfs: Deal with path's trailing "/" in unexportfs_parsed()")
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1941171
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 262dd19a..25d757d8 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -383,7 +383,7 @@ unexportfs_parsed(char *hname, char *path, int verbose)
* so need to deal with it.
*/
size_t nlen = strlen(path);
- while (path[nlen - 1] == '/')
+ while ((nlen > 1) && (path[nlen - 1] == '/'))
nlen--;
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {

View File

@ -0,0 +1,290 @@
diff -up nfs-utils-2.3.3/utils/gssd/err_util.c.orig nfs-utils-2.3.3/utils/gssd/err_util.c
--- nfs-utils-2.3.3/utils/gssd/err_util.c.orig 2018-09-06 14:09:08.000000000 -0400
+++ nfs-utils-2.3.3/utils/gssd/err_util.c 2021-07-19 12:29:21.366829573 -0400
@@ -70,3 +70,17 @@ int get_verbosity(void)
{
return verbosity;
}
+
+char *
+sec2time(int value)
+{
+ static char buf[BUFSIZ];
+ int hr, min, sec;
+
+ hr = (value / 3600);
+ min = (value - (3600*hr))/60;
+ sec = (value - (3600*hr) - (min*60));
+ sprintf(buf, "%dh:%dm:%ds", hr, min, sec);
+ return(buf);
+}
+
diff -up nfs-utils-2.3.3/utils/gssd/err_util.h.orig nfs-utils-2.3.3/utils/gssd/err_util.h
--- nfs-utils-2.3.3/utils/gssd/err_util.h.orig 2018-09-06 14:09:08.000000000 -0400
+++ nfs-utils-2.3.3/utils/gssd/err_util.h 2021-07-19 12:29:21.367829599 -0400
@@ -34,5 +34,6 @@
void initerr(char *progname, int verbosity, int fg);
void printerr(int priority, char *format, ...);
int get_verbosity(void);
+char * sec2time(int);
#endif /* _ERR_UTIL_H_ */
diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.c
--- nfs-utils-2.3.3/utils/gssd/gssd.c.orig 2021-07-19 12:24:13.963644016 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.c 2021-07-19 12:29:21.368829626 -0400
@@ -396,7 +396,7 @@ gssd_free_client(struct clnt_info *clp)
if (refcnt > 0)
return;
- printerr(3, "freeing client %s\n", clp->relpath);
+ printerr(4, "freeing client %s\n", clp->relpath);
if (clp->krb5_fd >= 0)
close(clp->krb5_fd);
@@ -417,7 +417,7 @@ gssd_free_client(struct clnt_info *clp)
static void
gssd_destroy_client(struct clnt_info *clp)
{
- printerr(3, "destroying client %s\n", clp->relpath);
+ printerr(4, "destroying client %s\n", clp->relpath);
if (clp->krb5_ev) {
event_del(clp->krb5_ev);
@@ -494,7 +494,7 @@ scan_active_thread_list(void)
* upcall_thread_info from the list and free it.
*/
if (tret == PTHREAD_CANCELED)
- printerr(3, "watchdog: thread id 0x%lx cancelled successfully\n",
+ printerr(2, "watchdog: thread id 0x%lx cancelled successfully\n",
info->tid);
saveprev = info->list.tqe_prev;
TAILQ_REMOVE(&active_thread_list, info, list);
@@ -783,7 +783,7 @@ gssd_scan(void)
{
struct dirent *d;
- printerr(3, "doing a full rescan\n");
+ printerr(4, "doing a full rescan\n");
rewinddir(pipefs_dir);
while ((d = readdir(pipefs_dir))) {
diff -up nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig nfs-utils-2.3.3/utils/gssd/gssd_proc.c
--- nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig 2021-07-19 12:24:13.964644043 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd_proc.c 2021-07-19 12:29:21.368829626 -0400
@@ -166,8 +166,9 @@ do_downcall(int k5_fd, uid_t uid, struct
unsigned int buf_size = 0;
pthread_t tid = pthread_self();
- printerr(2, "do_downcall(0x%x): lifetime_rec=%u acceptor=%.*s\n",
- tid, lifetime_rec, acceptor->length, acceptor->value);
+ if (get_verbosity() > 1)
+ printerr(2, "do_downcall(0x%lx): lifetime_rec=%s acceptor=%.*s\n",
+ tid, sec2time(lifetime_rec), acceptor->length, acceptor->value);
buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
sizeof(context_token->length) + context_token->length +
@@ -193,7 +194,7 @@ do_downcall(int k5_fd, uid_t uid, struct
return;
out_err:
free(buf);
- printerr(1, "do_downcall(0x%x): Failed to write downcall!\n", tid);
+ printerr(1, "do_downcall(0x%lx): Failed to write downcall!\n", tid);
return;
}
@@ -204,8 +205,9 @@ do_error_downcall(int k5_fd, uid_t uid,
char *p = buf, *end = buf + 1024;
unsigned int timeout = 0;
int zero = 0;
+ pthread_t tid = pthread_self();
- printerr(2, "doing error downcall\n");
+ printerr(2, "do_error_downcall(0x%lx): uid %d err %d\n", tid, uid, err);
if (WRITE_BYTES(&p, end, uid)) goto out_err;
if (WRITE_BYTES(&p, end, timeout)) goto out_err;
@@ -328,6 +330,7 @@ create_auth_rpc_client(struct clnt_info
struct timeval timeout;
struct sockaddr *addr = (struct sockaddr *) &clp->addr;
socklen_t salen;
+ pthread_t tid = pthread_self();
sec.qop = GSS_C_QOP_DEFAULT;
sec.svc = RPCSEC_GSS_SVC_NONE;
@@ -361,8 +364,8 @@ create_auth_rpc_client(struct clnt_info
/* create an rpc connection to the nfs server */
- printerr(2, "creating %s client for server %s\n", clp->protocol,
- clp->servername);
+ printerr(3, "create_auth_rpc_client(0x%lx): creating %s client for server %s\n",
+ tid, clp->protocol, clp->servername);
protocol = IPPROTO_TCP;
if ((strcmp(clp->protocol, "udp")) == 0)
@@ -405,7 +408,8 @@ create_auth_rpc_client(struct clnt_info
if (!tgtname)
tgtname = clp->servicename;
- printerr(2, "creating context with server %s\n", tgtname);
+ printerr(3, "create_auth_rpc_client(0x%lx): creating context with server %s\n",
+ tid, tgtname);
auth = authgss_create_default(rpc_clnt, tgtname, &sec);
if (!auth) {
/* Our caller should print appropriate message */
@@ -507,9 +511,10 @@ krb5_not_machine_creds(struct clnt_info
gss_cred_id_t gss_cred;
char **dname;
int err, resp = -1;
+ pthread_t tid = pthread_self();
- printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n",
- uid, tgtname);
+ printerr(2, "krb5_not_machine_creds(0x%lx): uid %d tgtname %s\n",
+ tid, uid, tgtname);
*chg_err = change_identity(uid);
if (*chg_err) {
@@ -555,9 +560,10 @@ krb5_use_machine_creds(struct clnt_info
char **ccname;
int nocache = 0;
int success = 0;
+ pthread_t tid = pthread_self();
- printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n",
- uid, tgtname);
+ printerr(2, "krb5_use_machine_creds(0x%lx): uid %d tgtname %s\n",
+ tid, uid, tgtname);
do {
gssd_refresh_krb5_machine_credential(clp->servername,
@@ -874,6 +880,7 @@ start_upcall_thread(void (*func)(struct
pthread_t th;
struct upcall_thread_info *tinfo;
int ret;
+ pthread_t tid = pthread_self();
tinfo = alloc_upcall_thread_info();
if (!tinfo)
@@ -896,6 +903,9 @@ start_upcall_thread(void (*func)(struct
free(tinfo);
return ret;
}
+ printerr(2, "start_upcall_thread(0x%lx): created thread id 0x%lx\n",
+ tid, th);
+
tinfo->tid = th;
pthread_mutex_lock(&active_thread_list_lock);
clock_gettime(CLOCK_MONOTONIC, &tinfo->timeout);
@@ -958,7 +968,7 @@ handle_gssd_upcall(struct clnt_info *clp
}
lbuf[lbuflen-1] = 0;
- printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid,
+ printerr(2, "\n%s(0x%lx): '%s' (%s)\n", __func__, tid,
lbuf, clp->relpath);
for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) {
diff -up nfs-utils-2.3.3/utils/gssd/krb5_util.c.orig nfs-utils-2.3.3/utils/gssd/krb5_util.c
--- nfs-utils-2.3.3/utils/gssd/krb5_util.c.orig 2021-07-19 12:24:13.951643697 -0400
+++ nfs-utils-2.3.3/utils/gssd/krb5_util.c 2021-07-19 12:36:27.746223992 -0400
@@ -375,6 +375,7 @@ gssd_get_single_krb5_cred(krb5_context c
char *cache_type;
char *pname = NULL;
char *k5err = NULL;
+ pthread_t tid = pthread_self();
memset(&my_creds, 0, sizeof(my_creds));
@@ -385,8 +386,8 @@ gssd_get_single_krb5_cred(krb5_context c
now += 300;
pthread_mutex_lock(&ple_lock);
if (ple->ccname && ple->endtime > now && !nocache) {
- printerr(3, "INFO: Credentials in CC '%s' are good until %d\n",
- ple->ccname, ple->endtime);
+ printerr(3, "%s(0x%lx): Credentials in CC '%s' are good until %s",
+ __func__, tid, ple->ccname, ctime((time_t *)&ple->endtime));
code = 0;
pthread_mutex_unlock(&ple_lock);
goto out;
@@ -486,7 +487,8 @@ gssd_get_single_krb5_cred(krb5_context c
}
code = 0;
- printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name);
+ printerr(2, "%s(0x%lx): principal '%s' ccache:'%s'\n",
+ __func__, tid, pname, cc_name);
out:
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
if (init_opts)
@@ -615,6 +617,7 @@ get_full_hostname(const char *inhost, ch
struct addrinfo hints;
int retval;
char *c;
+ pthread_t tid = pthread_self();
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
@@ -624,8 +627,8 @@ get_full_hostname(const char *inhost, ch
/* Get full target hostname */
retval = getaddrinfo(inhost, NULL, &hints, &addrs);
if (retval) {
- printerr(1, "%s while getting full hostname for '%s'\n",
- gai_strerror(retval), inhost);
+ printerr(1, "%s(0x%lx): getaddrinfo(%s) failed: %s\n",
+ __func__, tid, inhost, gai_strerror(retval));
goto out;
}
strncpy(outhost, addrs->ai_canonname, outhostlen);
@@ -633,7 +636,10 @@ get_full_hostname(const char *inhost, ch
for (c = outhost; *c != '\0'; c++)
*c = tolower(*c);
- printerr(3, "Full hostname for '%s' is '%s'\n", inhost, outhost);
+ if (get_verbosity() && strcmp(inhost, outhost))
+ printerr(1, "%s(0x%0lx): inhost '%s' different than outhost'%s'\n",
+ inhost, outhost);
+
retval = 0;
out:
return retval;
@@ -819,6 +825,7 @@ find_keytab_entry(krb5_context context,
krb5_principal princ;
const char *notsetstr = "not set";
char *adhostoverride = NULL;
+ pthread_t tid = pthread_self();
/* Get full target hostname */
@@ -972,7 +979,7 @@ find_keytab_entry(krb5_context context,
tried_upper = 1;
}
} else {
- printerr(2, "Success getting keytab entry for '%s'\n",spn);
+ printerr(2, "find_keytab_entry(0x%lx): Success getting keytab entry for '%s'\n",tid, spn);
retval = 0;
goto out;
}
@@ -1113,9 +1120,6 @@ gssd_refresh_krb5_machine_credential_int
char *k5err = NULL;
const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
- printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
- __func__, hostname, ple, service, srchost);
-
/*
* If a specific service name was specified, use it.
* Otherwise, use the default list.
@@ -1124,9 +1128,10 @@ gssd_refresh_krb5_machine_credential_int
svcnames[0] = service;
svcnames[1] = NULL;
}
- if (hostname == NULL && ple == NULL)
+ if (hostname == NULL && ple == NULL) {
+ printerr(0, "ERROR: %s: Invalid args\n", __func__);
return EINVAL;
-
+ }
code = krb5_init_context(&context);
if (code) {
k5err = gssd_k5_err_msg(NULL, code);

View File

@ -0,0 +1,402 @@
diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.c
--- nfs-utils-2.3.3/utils/gssd/gssd.c.orig 2021-07-19 09:39:04.273895536 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.c 2021-07-19 09:40:13.942751214 -0400
@@ -364,7 +364,7 @@ out:
/* Actually frees clp and fields that might be used from other
* threads if was last reference.
*/
-static void
+void
gssd_free_client(struct clnt_info *clp)
{
int refcnt;
@@ -416,55 +416,6 @@ gssd_destroy_client(struct clnt_info *cl
static void gssd_scan(void);
-static int
-start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info)
-{
- pthread_attr_t attr;
- pthread_t th;
- int ret;
-
- ret = pthread_attr_init(&attr);
- if (ret != 0) {
- printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n",
- ret, strerror(errno));
- return ret;
- }
- ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ret != 0) {
- printerr(0, "ERROR: failed to create pthread attr: ret %d: "
- "%s\n", ret, strerror(errno));
- return ret;
- }
-
- ret = pthread_create(&th, &attr, (void *)func, (void *)info);
- if (ret != 0)
- printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
- ret, strerror(errno));
- return ret;
-}
-
-static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp)
-{
- struct clnt_upcall_info *info;
-
- info = malloc(sizeof(struct clnt_upcall_info));
- if (info == NULL)
- return NULL;
-
- pthread_mutex_lock(&clp_lock);
- clp->refcount++;
- pthread_mutex_unlock(&clp_lock);
- info->clp = clp;
-
- return info;
-}
-
-void free_upcall_info(struct clnt_upcall_info *info)
-{
- gssd_free_client(info->clp);
- free(info);
-}
-
/* For each upcall read the upcall info into the buffer, then create a
* thread in a detached state so that resources are released back into
* the system without the need for a join.
@@ -473,44 +424,16 @@ static void
gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- struct clnt_upcall_info *info;
-
- info = alloc_upcall_info(clp);
- if (info == NULL)
- return;
-
- info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf));
- if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') {
- printerr(0, "WARNING: %s: failed reading request\n", __func__);
- free_upcall_info(info);
- return;
- }
- info->lbuf[info->lbuflen-1] = 0;
- if (start_upcall_thread(handle_gssd_upcall, info))
- free_upcall_info(info);
+ handle_gssd_upcall(clp);
}
static void
gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- struct clnt_upcall_info *info;
-
- info = alloc_upcall_info(clp);
- if (info == NULL)
- return;
-
- if (read(clp->krb5_fd, &info->uid,
- sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) {
- printerr(0, "WARNING: %s: failed reading uid from krb5 "
- "upcall pipe: %s\n", __func__, strerror(errno));
- free_upcall_info(info);
- return;
- }
- if (start_upcall_thread(handle_krb5_upcall, info))
- free_upcall_info(info);
+ handle_krb5_upcall(clp);
}
static struct clnt_info *
diff -up nfs-utils-2.3.3/utils/gssd/gssd.h.orig nfs-utils-2.3.3/utils/gssd/gssd.h
--- nfs-utils-2.3.3/utils/gssd/gssd.h.orig 2021-07-19 09:39:04.269895430 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.h 2021-07-19 09:40:13.943751240 -0400
@@ -84,14 +84,17 @@ struct clnt_info {
struct clnt_upcall_info {
struct clnt_info *clp;
- char lbuf[RPC_CHAN_BUF_SIZE];
- int lbuflen;
uid_t uid;
+ int fd;
+ char *srchost;
+ char *target;
+ char *service;
};
-void handle_krb5_upcall(struct clnt_upcall_info *clp);
-void handle_gssd_upcall(struct clnt_upcall_info *clp);
+void handle_krb5_upcall(struct clnt_info *clp);
+void handle_gssd_upcall(struct clnt_info *clp);
void free_upcall_info(struct clnt_upcall_info *info);
+void gssd_free_client(struct clnt_info *clp);
#endif /* _RPC_GSSD_H_ */
diff -up nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig nfs-utils-2.3.3/utils/gssd/gssd_proc.c
--- nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig 2021-07-19 09:39:04.269895430 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd_proc.c 2021-07-19 09:40:13.944751267 -0400
@@ -80,6 +80,8 @@
#include "nfslib.h"
#include "gss_names.h"
+extern pthread_mutex_t clp_lock;
+
/* Encryption types supported by the kernel rpcsec_gss code */
int num_krb5_enctypes = 0;
krb5_enctype *krb5_enctypes = NULL;
@@ -719,22 +721,133 @@ out_return_error:
goto out;
}
-void
-handle_krb5_upcall(struct clnt_upcall_info *info)
-{
- struct clnt_info *clp = info->clp;
+static struct clnt_upcall_info *
+alloc_upcall_info(struct clnt_info *clp, uid_t uid, int fd, char *srchost,
+ char *target, char *service)
+{
+ struct clnt_upcall_info *info;
+
+ info = malloc(sizeof(struct clnt_upcall_info));
+ if (info == NULL)
+ return NULL;
+
+ memset(info, 0, sizeof(*info));
+ pthread_mutex_lock(&clp_lock);
+ clp->refcount++;
+ pthread_mutex_unlock(&clp_lock);
+ info->clp = clp;
+ info->uid = uid;
+ info->fd = fd;
+ if (srchost) {
+ info->srchost = strdup(srchost);
+ if (info->srchost == NULL)
+ goto out_info;
+ }
+ if (target) {
+ info->target = strdup(target);
+ if (info->target == NULL)
+ goto out_srchost;
+ }
+ if (service) {
+ info->service = strdup(service);
+ if (info->service == NULL)
+ goto out_target;
+ }
+
+out:
+ return info;
- printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath);
+out_target:
+ if (info->target)
+ free(info->target);
+out_srchost:
+ if (info->srchost)
+ free(info->srchost);
+out_info:
+ free(info);
+ info = NULL;
+ goto out;
+}
+
+void free_upcall_info(struct clnt_upcall_info *info)
+{
+ gssd_free_client(info->clp);
+ if (info->service)
+ free(info->service);
+ if (info->target)
+ free(info->target);
+ if (info->srchost)
+ free(info->srchost);
+ free(info);
+}
- process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL);
+static void
+gssd_work_thread_fn(struct clnt_upcall_info *info)
+{
+ process_krb5_upcall(info->clp, info->uid, info->fd, info->srchost, info->target, info->service);
free_upcall_info(info);
}
+static int
+start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info)
+{
+ pthread_attr_t attr;
+ pthread_t th;
+ int ret;
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to create pthread attr: ret %d: "
+ "%s\n", ret, strerror(errno));
+ return ret;
+ }
+
+ ret = pthread_create(&th, &attr, (void *)func, (void *)info);
+ if (ret != 0)
+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+}
+
void
-handle_gssd_upcall(struct clnt_upcall_info *info)
+handle_krb5_upcall(struct clnt_info *clp)
{
- struct clnt_info *clp = info->clp;
uid_t uid;
+ struct clnt_upcall_info *info;
+ int err;
+
+ if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
+ printerr(0, "WARNING: failed reading uid from krb5 "
+ "upcall pipe: %s\n", strerror(errno));
+ return;
+ }
+ printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath);
+
+ info = alloc_upcall_info(clp, uid, clp->krb5_fd, NULL, NULL, NULL);
+ if (info == NULL) {
+ printerr(0, "%s: failed to allocate clnt_upcall_info\n", __func__);
+ do_error_downcall(clp->krb5_fd, uid, -EACCES);
+ return;
+ }
+ err = start_upcall_thread(gssd_work_thread_fn, info);
+ if (err != 0) {
+ do_error_downcall(clp->krb5_fd, uid, -EACCES);
+ free_upcall_info(info);
+ }
+}
+
+void
+handle_gssd_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+ char lbuf[RPC_CHAN_BUF_SIZE];
+ int lbuflen = 0;
char *p;
char *mech = NULL;
char *uidstr = NULL;
@@ -742,20 +855,22 @@ handle_gssd_upcall(struct clnt_upcall_in
char *service = NULL;
char *srchost = NULL;
char *enctypes = NULL;
- char *upcall_str;
- char *pbuf = info->lbuf;
pthread_t tid = pthread_self();
+ struct clnt_upcall_info *info;
+ int err;
- printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid,
- info->lbuf, clp->relpath);
-
- upcall_str = strdup(info->lbuf);
- if (upcall_str == NULL) {
- printerr(0, "ERROR: malloc failure\n");
- goto out_nomem;
+ lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf));
+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed reading request\n");
+ return;
}
+ lbuf[lbuflen-1] = 0;
+
+ printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid,
+ lbuf, clp->relpath);
- while ((p = strsep(&pbuf, " "))) {
+ for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) {
if (!strncmp(p, "mech=", strlen("mech=")))
mech = p + strlen("mech=");
else if (!strncmp(p, "uid=", strlen("uid=")))
@@ -773,8 +888,8 @@ handle_gssd_upcall(struct clnt_upcall_in
if (!mech || strlen(mech) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find gss mechanism name "
- "in upcall string '%s'\n", upcall_str);
- goto out;
+ "in upcall string '%s'\n", lbuf);
+ return;
}
if (uidstr) {
@@ -786,21 +901,21 @@ handle_gssd_upcall(struct clnt_upcall_in
if (!uidstr) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find uid "
- "in upcall string '%s'\n", upcall_str);
- goto out;
+ "in upcall string '%s'\n", lbuf);
+ return;
}
if (enctypes && parse_enctypes(enctypes) != 0) {
printerr(0, "WARNING: handle_gssd_upcall: "
"parsing encryption types failed: errno %d\n", errno);
- goto out;
+ return;
}
if (target && strlen(target) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse target name "
- "in upcall string '%s'\n", upcall_str);
- goto out;
+ "in upcall string '%s'\n", lbuf);
+ return;
}
/*
@@ -814,21 +929,26 @@ handle_gssd_upcall(struct clnt_upcall_in
if (service && strlen(service) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse service type "
- "in upcall string '%s'\n", upcall_str);
- goto out;
+ "in upcall string '%s'\n", lbuf);
+ return;
}
- if (strcmp(mech, "krb5") == 0 && clp->servername)
- process_krb5_upcall(clp, uid, clp->gssd_fd, srchost, target, service);
- else {
+ if (strcmp(mech, "krb5") == 0 && clp->servername) {
+ info = alloc_upcall_info(clp, uid, clp->gssd_fd, srchost, target, service);
+ if (info == NULL) {
+ printerr(0, "%s: failed to allocate clnt_upcall_info\n", __func__);
+ do_error_downcall(clp->gssd_fd, uid, -EACCES);
+ return;
+ }
+ err = start_upcall_thread(gssd_work_thread_fn, info);
+ if (err != 0) {
+ do_error_downcall(clp->gssd_fd, uid, -EACCES);
+ free_upcall_info(info);
+ }
+ } else {
if (clp->servername)
printerr(0, "WARNING: handle_gssd_upcall: "
"received unknown gss mech '%s'\n", mech);
do_error_downcall(clp->gssd_fd, uid, -EACCES);
}
-out:
- free(upcall_str);
-out_nomem:
- free_upcall_info(info);
- return;
}

View File

@ -1,6 +1,6 @@
diff -up nfs-utils-2.3.3/nfs.conf.orig nfs-utils-2.3.3/nfs.conf diff -up nfs-utils-2.3.3/nfs.conf.orig nfs-utils-2.3.3/nfs.conf
--- nfs-utils-2.3.3/nfs.conf.orig 2021-09-07 13:08:02.683442977 -0400 --- nfs-utils-2.3.3/nfs.conf.orig 2021-04-17 10:49:23.660184527 -0400
+++ nfs-utils-2.3.3/nfs.conf 2021-09-07 13:09:33.500797181 -0400 +++ nfs-utils-2.3.3/nfs.conf 2021-04-17 11:14:41.482108562 -0400
@@ -21,6 +21,7 @@ use-gss-proxy=1 @@ -21,6 +21,7 @@ use-gss-proxy=1
# keytab-file=/etc/krb5.keytab # keytab-file=/etc/krb5.keytab
# cred-cache-directory= # cred-cache-directory=
@ -10,8 +10,8 @@ diff -up nfs-utils-2.3.3/nfs.conf.orig nfs-utils-2.3.3/nfs.conf
[lockd] [lockd]
# port=0 # port=0
diff -up nfs-utils-2.3.3/systemd/nfs.conf.man.orig nfs-utils-2.3.3/systemd/nfs.conf.man diff -up nfs-utils-2.3.3/systemd/nfs.conf.man.orig nfs-utils-2.3.3/systemd/nfs.conf.man
--- nfs-utils-2.3.3/systemd/nfs.conf.man.orig 2021-09-07 13:08:02.723444014 -0400 --- nfs-utils-2.3.3/systemd/nfs.conf.man.orig 2021-04-17 10:49:23.696185472 -0400
+++ nfs-utils-2.3.3/systemd/nfs.conf.man 2021-09-07 13:09:33.500797181 -0400 +++ nfs-utils-2.3.3/systemd/nfs.conf.man 2021-04-17 11:14:41.483108588 -0400
@@ -222,7 +222,8 @@ Recognized values: @@ -222,7 +222,8 @@ Recognized values:
.BR rpc-timeout , .BR rpc-timeout ,
.BR keytab-file , .BR keytab-file ,
@ -23,8 +23,8 @@ diff -up nfs-utils-2.3.3/systemd/nfs.conf.man.orig nfs-utils-2.3.3/systemd/nfs.c
See See
.BR rpc.gssd (8) .BR rpc.gssd (8)
diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.c diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.c
--- nfs-utils-2.3.3/utils/gssd/gssd.c.orig 2021-09-07 13:08:02.709443651 -0400 --- nfs-utils-2.3.3/utils/gssd/gssd.c.orig 2021-04-17 10:49:23.684185157 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.c 2021-09-07 13:09:33.500797181 -0400 +++ nfs-utils-2.3.3/utils/gssd/gssd.c 2021-04-17 11:14:41.483108588 -0400
@@ -87,6 +87,8 @@ unsigned int context_timeout = 0; @@ -87,6 +87,8 @@ unsigned int context_timeout = 0;
unsigned int rpc_timeout = 5; unsigned int rpc_timeout = 5;
char *preferred_realm = NULL; char *preferred_realm = NULL;
@ -97,8 +97,8 @@ diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.
if (use_gssproxy) { if (use_gssproxy) {
diff -up nfs-utils-2.3.3/utils/gssd/gssd.man.orig nfs-utils-2.3.3/utils/gssd/gssd.man diff -up nfs-utils-2.3.3/utils/gssd/gssd.man.orig nfs-utils-2.3.3/utils/gssd/gssd.man
--- nfs-utils-2.3.3/utils/gssd/gssd.man.orig 2021-09-07 13:08:02.670442640 -0400 --- nfs-utils-2.3.3/utils/gssd/gssd.man.orig 2021-04-17 10:49:23.650184264 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.man 2021-09-07 13:09:33.500797181 -0400 +++ nfs-utils-2.3.3/utils/gssd/gssd.man 2021-04-17 11:14:41.484108615 -0400
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
rpc.gssd \- RPCSEC_GSS daemon rpc.gssd \- RPCSEC_GSS daemon
.SH SYNOPSIS .SH SYNOPSIS

View File

@ -0,0 +1,17 @@
diff -up nfs-utils-2.3.3/utils/gssd/gssd.man.orig nfs-utils-2.3.3/utils/gssd/gssd.man
--- nfs-utils-2.3.3/utils/gssd/gssd.man.orig 2021-04-17 11:21:18.326543446 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.man 2021-04-17 12:35:59.867574517 -0400
@@ -347,11 +347,11 @@ Equivalent to
.TP
.B context-timeout
Equivalent to
-.BR -T .
+.BR -t .
.TP
.B rpc-timeout
Equivalent to
-.BR -t .
+.BR -T .
.TP
.B keytab-file
Equivalent to

View File

@ -0,0 +1,43 @@
diff -up nfs-utils-2.3.3/utils/gssd/krb5_util.c.orig nfs-utils-2.3.3/utils/gssd/krb5_util.c
--- nfs-utils-2.3.3/utils/gssd/krb5_util.c.orig 2021-07-22 15:27:27.728680553 -0400
+++ nfs-utils-2.3.3/utils/gssd/krb5_util.c 2021-07-22 15:30:08.916979585 -0400
@@ -165,18 +165,28 @@ static int gssd_get_single_krb5_cred(krb
static int query_krb5_ccache(const char* cred_cache, char **ret_princname,
char **ret_realm);
-static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple)
+static void release_ple_locked(krb5_context context,
+ struct gssd_k5_kt_princ *ple)
{
if (--ple->refcount)
return;
- printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", ple->ccname, ple->realm);
+ printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n",
+ ple->ccname, ple->realm);
krb5_free_principal(context, ple->princ);
free(ple->ccname);
free(ple->realm);
free(ple);
}
+static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple)
+{
+ pthread_mutex_lock(&ple_lock);
+ release_ple_locked(context, ple);
+ pthread_mutex_unlock(&ple_lock);
+}
+
+
/*
* Called from the scandir function to weed out potential krb5
* credentials cache files
@@ -1396,7 +1406,7 @@ gssd_destroy_krb5_principals(int destroy
}
}
- release_ple(context, ple);
+ release_ple_locked(context, ple);
}
pthread_mutex_unlock(&ple_lock);
krb5_free_context(context);

View File

@ -0,0 +1,625 @@
diff -up nfs-utils-2.3.3/nfs.conf.orig nfs-utils-2.3.3/nfs.conf
--- nfs-utils-2.3.3/nfs.conf.orig 2021-07-19 09:45:40.441448059 -0400
+++ nfs-utils-2.3.3/nfs.conf 2021-07-19 12:08:55.314182838 -0400
@@ -22,6 +22,8 @@ use-gss-proxy=1
# cred-cache-directory=
# preferred-realm=
# set-home=1
+# upcall-timeout=30
+# cancel-timed-out-upcalls=0
#
[lockd]
# port=0
diff -up nfs-utils-2.3.3/utils/gssd/gssd.c.orig nfs-utils-2.3.3/utils/gssd/gssd.c
--- nfs-utils-2.3.3/utils/gssd/gssd.c.orig 2021-07-19 09:45:40.448448246 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.c 2021-07-19 12:08:55.315182865 -0400
@@ -96,8 +96,29 @@ pthread_mutex_t clp_lock = PTHREAD_MUTEX
static bool signal_received = false;
static struct event_base *evbase = NULL;
+int upcall_timeout = DEF_UPCALL_TIMEOUT;
+static bool cancel_timed_out_upcalls = false;
+
TAILQ_HEAD(topdir_list_head, topdir) topdir_list;
+/*
+ * active_thread_list:
+ *
+ * used to track upcalls for timeout purposes.
+ *
+ * protected by the active_thread_list_lock mutex.
+ *
+ * upcall_thread_info structures are added to the tail of the list
+ * by start_upcall_thread(), so entries closer to the head of the list
+ * will be closer to hitting the upcall timeout.
+ *
+ * upcall_thread_info structures are removed from the list upon a
+ * sucessful join of the upcall thread by the watchdog thread (via
+ * scan_active_thread_list().
+ */
+TAILQ_HEAD(active_thread_list_head, upcall_thread_info) active_thread_list;
+pthread_mutex_t active_thread_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
struct topdir {
TAILQ_ENTRY(topdir) list;
TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
@@ -436,6 +457,138 @@ gssd_clnt_krb5_cb(int UNUSED(fd), short
handle_krb5_upcall(clp);
}
+/*
+ * scan_active_thread_list:
+ *
+ * Walks the active_thread_list, trying to join as many upcall threads as
+ * possible. For threads that have terminated, the corresponding
+ * upcall_thread_info will be removed from the list and freed. Threads that
+ * are still busy and have exceeded the upcall_timeout will cause an error to
+ * be logged and may be canceled (depending on the value of
+ * cancel_timed_out_upcalls).
+ *
+ * Returns the number of seconds that the watchdog thread should wait before
+ * calling scan_active_thread_list() again.
+ */
+static int
+scan_active_thread_list(void)
+{
+ struct upcall_thread_info *info;
+ struct timespec now;
+ unsigned int sleeptime;
+ bool sleeptime_set = false;
+ int err;
+ void *tret, *saveprev;
+
+ sleeptime = upcall_timeout;
+ pthread_mutex_lock(&active_thread_list_lock);
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ TAILQ_FOREACH(info, &active_thread_list, list) {
+ err = pthread_tryjoin_np(info->tid, &tret);
+ switch (err) {
+ case 0:
+ /*
+ * The upcall thread has either completed successfully, or
+ * has been canceled _and_ has acted on the cancellation request
+ * (i.e. has hit a cancellation point). We can now remove the
+ * upcall_thread_info from the list and free it.
+ */
+ if (tret == PTHREAD_CANCELED)
+ printerr(3, "watchdog: thread id 0x%lx cancelled successfully\n",
+ info->tid);
+ saveprev = info->list.tqe_prev;
+ TAILQ_REMOVE(&active_thread_list, info, list);
+ free(info);
+ info = saveprev;
+ break;
+ case EBUSY:
+ /*
+ * The upcall thread is still running. If the timeout has expired
+ * then we either cancel the thread, log an error, and do an error
+ * downcall to the kernel (cancel_timed_out_upcalls=true) or simply
+ * log an error (cancel_timed_out_upcalls=false). In either case,
+ * the error is logged only once.
+ */
+ if (now.tv_sec >= info->timeout.tv_sec) {
+ if (cancel_timed_out_upcalls && !(info->flags & UPCALL_THREAD_CANCELED)) {
+ printerr(0, "watchdog: thread id 0x%lx timed out\n",
+ info->tid);
+ pthread_cancel(info->tid);
+ info->flags |= (UPCALL_THREAD_CANCELED|UPCALL_THREAD_WARNED);
+ do_error_downcall(info->fd, info->uid, -ETIMEDOUT);
+ } else {
+ if (!(info->flags & UPCALL_THREAD_WARNED)) {
+ printerr(0, "watchdog: thread id 0x%lx running for %ld seconds\n",
+ info->tid,
+ now.tv_sec - info->timeout.tv_sec + upcall_timeout);
+ info->flags |= UPCALL_THREAD_WARNED;
+ }
+ }
+ } else if (!sleeptime_set) {
+ /*
+ * The upcall thread is still running, but the timeout has not yet
+ * expired. Calculate the time remaining until the timeout will
+ * expire. This is the amount of time the watchdog thread will
+ * wait before running again. We only need to do this for the busy
+ * thread closest to the head of the list - entries appearing later
+ * in the list will time out later.
+ */
+ sleeptime = info->timeout.tv_sec - now.tv_sec;
+ sleeptime_set = true;
+ }
+ break;
+ default:
+ /* EDEADLK, EINVAL, and ESRCH... none of which should happen! */
+ printerr(0, "watchdog: attempt to join thread id 0x%lx returned %d (%s)!\n",
+ info->tid, err, strerror(err));
+ break;
+ }
+ }
+ pthread_mutex_unlock(&active_thread_list_lock);
+
+ return sleeptime;
+}
+
+static void *
+watchdog_thread_fn(void *UNUSED(arg))
+{
+ unsigned int sleeptime;
+
+ for (;;) {
+ sleeptime = scan_active_thread_list();
+ printerr(4, "watchdog: sleeping %u secs\n", sleeptime);
+ sleep(sleeptime);
+ }
+ return (void *)0;
+}
+
+static int
+start_watchdog_thread(void)
+{
+ pthread_attr_t attr;
+ pthread_t th;
+ int ret;
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to create pthread attr: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ ret = pthread_create(&th, &attr, watchdog_thread_fn, NULL);
+ if (ret != 0) {
+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
+ ret, strerror(errno));
+ }
+ return ret;
+}
+
static struct clnt_info *
gssd_get_clnt(struct topdir *tdi, const char *name)
{
@@ -810,7 +963,7 @@ sig_die(int signal)
static void
usage(char *progname)
{
- fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D] [-H]\n",
+ fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm] [-D] [-H] [-U upcall timeout] [-C]\n",
progname);
exit(1);
}
@@ -831,6 +984,9 @@ read_gss_conf(void)
#endif
context_timeout = conf_get_num("gssd", "context-timeout", context_timeout);
rpc_timeout = conf_get_num("gssd", "rpc-timeout", rpc_timeout);
+ upcall_timeout = conf_get_num("gssd", "upcall-timeout", upcall_timeout);
+ cancel_timed_out_upcalls = conf_get_bool("gssd", "cancel-timed-out-upcalls",
+ cancel_timed_out_upcalls);
s = conf_get_str("gssd", "pipefs-directory");
if (!s)
s = conf_get_str("general", "pipefs-directory");
@@ -872,7 +1028,7 @@ main(int argc, char *argv[])
verbosity = conf_get_num("gssd", "verbosity", verbosity);
rpc_verbosity = conf_get_num("gssd", "rpc-verbosity", rpc_verbosity);
- while ((opt = getopt(argc, argv, "HDfvrlmnMp:k:d:t:T:R:")) != -1) {
+ while ((opt = getopt(argc, argv, "HDfvrlmnMp:k:d:t:T:R:U:C")) != -1) {
switch (opt) {
case 'f':
fg = 1;
@@ -923,6 +1079,12 @@ main(int argc, char *argv[])
case 'H':
set_home = false;
break;
+ case 'U':
+ upcall_timeout = atoi(optarg);
+ break;
+ case 'C':
+ cancel_timed_out_upcalls = true;
+ break;
default:
usage(argv[0]);
break;
@@ -995,6 +1157,11 @@ main(int argc, char *argv[])
else
progname = argv[0];
+ if (upcall_timeout > MAX_UPCALL_TIMEOUT)
+ upcall_timeout = MAX_UPCALL_TIMEOUT;
+ else if (upcall_timeout < MIN_UPCALL_TIMEOUT)
+ upcall_timeout = MIN_UPCALL_TIMEOUT;
+
initerr(progname, verbosity, fg);
#ifdef HAVE_LIBTIRPC_SET_DEBUG
/*
@@ -1045,6 +1212,14 @@ main(int argc, char *argv[])
gssd_inotify_cb, NULL);
event_add(inotify_ev, NULL);
+ TAILQ_INIT(&active_thread_list);
+
+ rc = start_watchdog_thread();
+ if (rc != 0) {
+ printerr(0, "ERROR: failed to start watchdog thread: %d\n", rc);
+ exit(EXIT_FAILURE);
+ }
+
TAILQ_INIT(&topdir_list);
gssd_scan();
daemon_ready();
diff -up nfs-utils-2.3.3/utils/gssd/gssd.h.orig nfs-utils-2.3.3/utils/gssd/gssd.h
--- nfs-utils-2.3.3/utils/gssd/gssd.h.orig 2021-07-19 09:45:40.449448272 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.h 2021-07-19 12:08:55.315182865 -0400
@@ -50,6 +50,12 @@
#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab"
#define GSSD_SERVICE_NAME "nfs"
#define RPC_CHAN_BUF_SIZE 32768
+
+/* timeouts are in seconds */
+#define MIN_UPCALL_TIMEOUT 5
+#define DEF_UPCALL_TIMEOUT 30
+#define MAX_UPCALL_TIMEOUT 600
+
/*
* The gss mechanisms that we can handle
*/
@@ -91,10 +97,22 @@ struct clnt_upcall_info {
char *service;
};
+struct upcall_thread_info {
+ TAILQ_ENTRY(upcall_thread_info) list;
+ pthread_t tid;
+ struct timespec timeout;
+ uid_t uid;
+ int fd;
+ unsigned short flags;
+#define UPCALL_THREAD_CANCELED 0x0001
+#define UPCALL_THREAD_WARNED 0x0002
+};
+
void handle_krb5_upcall(struct clnt_info *clp);
void handle_gssd_upcall(struct clnt_info *clp);
void free_upcall_info(struct clnt_upcall_info *info);
void gssd_free_client(struct clnt_info *clp);
+int do_error_downcall(int k5_fd, uid_t uid, int err);
#endif /* _RPC_GSSD_H_ */
diff -up nfs-utils-2.3.3/utils/gssd/gssd.man.orig nfs-utils-2.3.3/utils/gssd/gssd.man
--- nfs-utils-2.3.3/utils/gssd/gssd.man.orig 2021-07-19 09:45:40.443448112 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd.man 2021-07-19 12:08:55.315182865 -0400
@@ -8,7 +8,7 @@
rpc.gssd \- RPCSEC_GSS daemon
.SH SYNOPSIS
.B rpc.gssd
-.RB [ \-DfMnlvrH ]
+.RB [ \-DfMnlvrHC ]
.RB [ \-k
.IR keytab ]
.RB [ \-p
@@ -17,6 +17,10 @@ rpc.gssd \- RPCSEC_GSS daemon
.IR ccachedir ]
.RB [ \-t
.IR timeout ]
+.RB [ \-T
+.IR timeout ]
+.RB [ \-U
+.IR timeout ]
.RB [ \-R
.IR realm ]
.SH INTRODUCTION
@@ -290,7 +294,7 @@ seconds, which allows changing Kerberos
The default is no explicit timeout, which means the kernel context will live
the lifetime of the Kerberos service ticket used in its creation.
.TP
-.B -T timeout
+.BI "-T " timeout
Timeout, in seconds, to create an RPC connection with a server while
establishing an authenticated gss context for a user.
The default timeout is set to 5 seconds.
@@ -298,6 +302,18 @@ If you get messages like "WARNING: can't
%servername% for user with uid %uid%: RPC: Remote system error -
Connection timed out", you should consider an increase of this timeout.
.TP
+.BI "-U " timeout
+Timeout, in seconds, for upcall threads. Threads executing longer than
+.I timeout
+seconds will cause an error message to be logged. The default
+.I timeout
+is 30 seconds. The minimum is 5 seconds. The maximum is 600 seconds.
+.TP
+.B -C
+In addition to logging an error message for threads that have timed out,
+the thread will be canceled and an error of -ETIMEDOUT will be reported
+to the kernel.
+.TP
.B -H
Avoids setting $HOME to "/". This allows rpc.gssd to read per user k5identity
files versus trying to read /.k5identity for each user.
@@ -365,6 +381,17 @@ Equivalent to
Equivalent to
.BR -R .
.TP
+.B upcall-timeout
+Equivalent to
+.BR -U .
+.TP
+.B cancel-timed-out-upcalls
+Setting to
+.B true
+is equivalent to providing the
+.B -C
+flag.
+.TP
.B set-home
Setting to
.B false
diff -up nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig nfs-utils-2.3.3/utils/gssd/gssd_proc.c
--- nfs-utils-2.3.3/utils/gssd/gssd_proc.c.orig 2021-07-19 09:45:40.449448272 -0400
+++ nfs-utils-2.3.3/utils/gssd/gssd_proc.c 2021-07-19 12:08:55.316182891 -0400
@@ -81,11 +81,24 @@
#include "gss_names.h"
extern pthread_mutex_t clp_lock;
+extern pthread_mutex_t active_thread_list_lock;
+extern int upcall_timeout;
+extern TAILQ_HEAD(active_thread_list_head, upcall_thread_info) active_thread_list;
/* Encryption types supported by the kernel rpcsec_gss code */
int num_krb5_enctypes = 0;
krb5_enctype *krb5_enctypes = NULL;
+/* Args for the cleanup_handler() */
+struct cleanup_args {
+ OM_uint32 *min_stat;
+ gss_buffer_t acceptor;
+ gss_buffer_t token;
+ struct authgss_private_data *pd;
+ AUTH **auth;
+ CLIENT **rpc_clnt;
+};
+
/*
* Parse the supported encryption type information
*/
@@ -184,7 +197,7 @@ out_err:
return;
}
-static int
+int
do_error_downcall(int k5_fd, uid_t uid, int err)
{
char buf[1024];
@@ -604,27 +617,66 @@ out:
}
/*
+ * cleanup_handler:
+ *
+ * Free any resources allocated by process_krb5_upcall().
+ *
+ * Runs upon normal termination of process_krb5_upcall as well as if the
+ * thread is canceled.
+ */
+static void
+cleanup_handler(void *arg)
+{
+ struct cleanup_args *args = (struct cleanup_args *)arg;
+
+ gss_release_buffer(args->min_stat, args->acceptor);
+ if (args->token->value)
+ free(args->token->value);
+#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
+ if (args->pd->pd_ctx_hndl.length != 0 || args->pd->pd_ctx != 0)
+ authgss_free_private_data(args->pd);
+#endif
+ if (*args->auth)
+ AUTH_DESTROY(*args->auth);
+ if (*args->rpc_clnt)
+ clnt_destroy(*args->rpc_clnt);
+}
+
+/*
+ * process_krb5_upcall:
+ *
* this code uses the userland rpcsec gss library to create a krb5
* context on behalf of the kernel
+ *
+ * This is the meat of the upcall thread. Note that cancelability is disabled
+ * and enabled at various points to ensure that any resources reserved by the
+ * lower level libraries are released safely.
*/
static void
-process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *srchost,
- char *tgtname, char *service)
+process_krb5_upcall(struct clnt_upcall_info *info)
{
+ struct clnt_info *clp = info->clp;
+ uid_t uid = info->uid;
+ int fd = info->fd;
+ char *srchost = info->srchost;
+ char *tgtname = info->target;
+ char *service = info->service;
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
struct authgss_private_data pd;
gss_buffer_desc token;
- int err, downcall_err = -EACCES;
+ int err, downcall_err;
OM_uint32 maj_stat, min_stat, lifetime_rec;
gss_name_t gacceptor = GSS_C_NO_NAME;
gss_OID mech;
gss_buffer_desc acceptor = {0};
+ struct cleanup_args cleanup_args = {&min_stat, &acceptor, &token, &pd, &auth, &rpc_clnt};
token.length = 0;
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
+ pthread_cleanup_push(cleanup_handler, &cleanup_args);
/*
* If "service" is specified, then the kernel is indicating that
* we must use machine credentials for this request. (Regardless
@@ -646,6 +698,8 @@ process_krb5_upcall(struct clnt_info *cl
* used for this case is not important.
*
*/
+ downcall_err = -EACCES;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
service == NULL)) {
@@ -666,15 +720,21 @@ process_krb5_upcall(struct clnt_info *cl
goto out_return_error;
}
}
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (!authgss_get_private_data(auth, &pd)) {
printerr(1, "WARNING: Failed to obtain authentication "
"data for user with uid %d for server %s\n",
uid, clp->servername);
goto out_return_error;
}
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
/* Grab the context lifetime and acceptor name out of the ctx. */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor,
&lifetime_rec, &mech, NULL, NULL, NULL);
@@ -686,37 +746,35 @@ process_krb5_upcall(struct clnt_info *cl
get_hostbased_client_buffer(gacceptor, mech, &acceptor);
gss_release_name(&min_stat, &gacceptor);
}
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
/*
* The serialization can mean turning pd.pd_ctx into a lucid context. If
* that happens then the pd.pd_ctx will be unusable, so we must never
* try to use it after this point.
*/
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
printerr(1, "WARNING: Failed to serialize krb5 context for "
"user with uid %d for server %s\n",
uid, clp->servername);
goto out_return_error;
}
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor);
out:
- gss_release_buffer(&min_stat, &acceptor);
- if (token.value)
- free(token.value);
-#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
- if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
- authgss_free_private_data(&pd);
-#endif
- if (auth)
- AUTH_DESTROY(auth);
- if (rpc_clnt)
- clnt_destroy(rpc_clnt);
+ pthread_cleanup_pop(1);
return;
out_return_error:
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+
do_error_downcall(fd, uid, downcall_err);
goto out;
}
@@ -782,36 +840,69 @@ void free_upcall_info(struct clnt_upcall
}
static void
-gssd_work_thread_fn(struct clnt_upcall_info *info)
+cleanup_clnt_upcall_info(void *arg)
{
- process_krb5_upcall(info->clp, info->uid, info->fd, info->srchost, info->target, info->service);
+ struct clnt_upcall_info *info = (struct clnt_upcall_info *)arg;
+
free_upcall_info(info);
}
+static void
+gssd_work_thread_fn(struct clnt_upcall_info *info)
+{
+ pthread_cleanup_push(cleanup_clnt_upcall_info, info);
+ process_krb5_upcall(info);
+ pthread_cleanup_pop(1);
+}
+
+static struct upcall_thread_info *
+alloc_upcall_thread_info(void)
+{
+ struct upcall_thread_info *info;
+
+ info = malloc(sizeof(struct upcall_thread_info));
+ if (info == NULL)
+ return NULL;
+ memset(info, 0, sizeof(*info));
+ return info;
+}
+
static int
-start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info)
+start_upcall_thread(void (*func)(struct clnt_upcall_info *), struct clnt_upcall_info *info)
{
pthread_attr_t attr;
pthread_t th;
+ struct upcall_thread_info *tinfo;
int ret;
+ tinfo = alloc_upcall_thread_info();
+ if (!tinfo)
+ return -ENOMEM;
+ tinfo->fd = info->fd;
+ tinfo->uid = info->uid;
+
ret = pthread_attr_init(&attr);
if (ret != 0) {
printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n",
ret, strerror(errno));
- return ret;
- }
- ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ret != 0) {
- printerr(0, "ERROR: failed to create pthread attr: ret %d: "
- "%s\n", ret, strerror(errno));
+ free(tinfo);
return ret;
}
ret = pthread_create(&th, &attr, (void *)func, (void *)info);
- if (ret != 0)
+ if (ret != 0) {
printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
ret, strerror(errno));
+ free(tinfo);
+ return ret;
+ }
+ tinfo->tid = th;
+ pthread_mutex_lock(&active_thread_list_lock);
+ clock_gettime(CLOCK_MONOTONIC, &tinfo->timeout);
+ tinfo->timeout.tv_sec += upcall_timeout;
+ TAILQ_INSERT_TAIL(&active_thread_list, tinfo, list);
+ pthread_mutex_unlock(&active_thread_list_lock);
+
return ret;
}

View File

@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser
Name: nfs-utils Name: nfs-utils
URL: http://linux-nfs.org/ URL: http://linux-nfs.org/
Version: 2.3.3 Version: 2.3.3
Release: 41%{?dist}.3 Release: 46%{?dist}
Epoch: 1 Epoch: 1
# group all 32bit related archs # group all 32bit related archs
@ -74,10 +74,17 @@ Patch036: nfs-utils-2.3.3-gssd-multithread-updates.patch
Patch037: nfs-utils-2.3.3-mountd-pseudofs.patch Patch037: nfs-utils-2.3.3-mountd-pseudofs.patch
# #
# RHEL 8.4-Z # RHEL 8.5
# #
Patch038: nfs-utils-2.3.3-mount-sloppy.patch Patch038: nfs-utils-2.3.3-gssd-k5identity.patch
Patch039: nfs-utils-2.3.3-gssd-home-opt.patch Patch039: nfs-utils-2.3.3-gssd-man-tflag.patch
Patch040: nfs-utils-2.3.3-exportfs-root.patch
Patch041: nfs-utils-2.3.3-mount-sloppy.patch
Patch042: nfs-utils-2.3.3-gssd-failed-thread.patch
Patch043: nfs-utils-2.3.3-gssd-timeout-thread.patch
Patch044: nfs-utils-2.3.3-gssd-debug-cleanup.patch
Patch045: nfs-utils-2.3.3-gssd-mutex-refcnt.patch
Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch
Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch
@ -146,16 +153,8 @@ developing programs which use the libnfsidmap library.
%description %description
The nfs-utils package provides a daemon for the kernel NFS server and The nfs-utils package provides various utilities for use with NFS
related tools, which provides a much higher level of performance than the clients and servers.
traditional Linux NFS server used by most users.
This package also contains the showmount program. Showmount queries the
mount daemon on a remote host for information about the NFS (Network File
System) server on the remote host. For example, showmount can display the
clients which are mounted on that host.
This package also contains the mount.nfs and umount.nfs program.
%prep %prep
%autosetup -p1 %autosetup -p1
@ -361,14 +360,25 @@ fi
%{_libdir}/libnfsidmap.so %{_libdir}/libnfsidmap.so
%changelog %changelog
* Tue Sep 7 2021 Steve Dickson <steved@redhat.com> 2.3.3-41_4.3 * Wed Jul 28 2021 Steve Dickson <steved@redhat.com> 2.3.3-46
- gssd: Add options allow for the use of $HOME/.k5identity file (bz 1995593) - mount.nfs: Fix the sloppy option processing (bz 1967883)
* Wed Jul 28 2021 Steve Dickson <steved@redhat.com> 2.3.3-41_4.2 * Thu Jul 22 2021 Steve Dickson <steved@redhat.com> 2.3.3-45
- mount.nfs: Fix the sloppy option processing (bz 1982340) - gssd: use mutex to protect decrement of refcount (bz 1511706)
* Wed Jul 14 2021 Steve Dickson <steved@redhat.com> 2.3.3-41_4.1 * Mon Jul 19 2021 Steve Dickson <steved@redhat.com> 2.3.3-44
- mount.nfs: insert 'sloppy' at beginning of the options (bz 1982340) - gssd: Deal with failed thread creation (bz 1981400)
- gssd: Add timeout for upcall threads (bz 1981403)
- gssd: Cleaned up debug messages (bz 1961056)
- spec: Updated description of the nfs-utils rpm (bz 1981419)
* Sat Jul 10 2021 Steve Dickson <steved@redhat.com> 2.3.3-43
- mount.nfs: insert 'sloppy' at beginning of the options (bz 1967883)
* Mon May 10 2021 Steve Dickson <steved@redhat.com> 2.3.3-42
- gssd: Add options to allow for the use of ~/.k5identity file (bz 1868087)
- man: Correct gssd(8) description of rpc-timeout and context-timeout (bz 1908232)
- exportfs: fix unexporting of '/' (bz 1944119)
* Wed Jan 20 2021 Steve Dickson <steved@redhat.com> 2.3.3-41 * Wed Jan 20 2021 Steve Dickson <steved@redhat.com> 2.3.3-41
- mountd: never root squash on the pseudofs (bz 1804912) - mountd: never root squash on the pseudofs (bz 1804912)