]) # LC_DIRTY_INODE_WITH_FLAG
#
+# LC_SETNS
+#
+# 3.0 introduced setns
+#
+AC_DEFUN([LC_SETNS], [
+AC_CHECK_HEADERS([sched.h], [], [],
+ [#define _GNU_SOURCE
+ ])
+AC_CHECK_FUNCS([setns])
+]) # LC_SETNS
+
+#
# LC_GENERIC_PERMISSION
#
# 2.6.38 generic_permission taken 4 parameters.
]) # LC_HAVE_DCOUNT
#
+# LC_PID_NS_FOR_CHILDREN
+#
+# 3.11 replaces pid_ns by pid_ns_for_children in struct nsproxy
+#
+AC_DEFUN([LC_PID_NS_FOR_CHILDREN], [
+LB_CHECK_COMPILE([if 'struct nsproxy' has 'pid_ns_for_children'],
+pid_ns_for_children, [
+ #include <linux/nsproxy.h>
+],[
+ struct nsproxy ns;
+ ns.pid_ns_for_children = NULL;
+],[
+ AC_DEFINE(HAVE_PID_NS_FOR_CHILDREN, 1,
+ ['struct nsproxy' has 'pid_ns_for_children'])
+])
+]) # LC_PID_NS_FOR_CHILDREN
+
+#
# LC_OLDSIZE_TRUNCATE_PAGECACHE
#
# 3.12 truncate_pagecache without oldsize parameter
# 3.0
LC_DIRTY_INODE_WITH_FLAG
+ LC_SETNS
# 3.1
LC_LM_XXX_LOCK_MANAGER_OPS
LC_HAVE_DCOUNT
LC_HAVE_DENTRY_D_U_D_ALIAS
LC_HAVE_DENTRY_D_CHILD
+ LC_PID_NS_FOR_CHILDREN
# 3.12
LC_OLDSIZE_TRUNCATE_PAGECACHE
#endif
#endif
+#ifdef HAVE_PID_NS_FOR_CHILDREN
+# define ll_task_pid_ns(task) ((task)->nsproxy->pid_ns_for_children)
+#else
+# define ll_task_pid_ns(task) ((task)->nsproxy->pid_ns)
+#endif
+
#endif /* _LUSTRE_COMPAT_H */
* some seciruty-related fields
* @{
*/
- struct ptlrpc_sec *imp_sec;
+ struct ptlrpc_sec *imp_sec;
struct mutex imp_sec_mutex;
- cfs_time_t imp_sec_expire;
+ cfs_time_t imp_sec_expire;
+ pid_t imp_sec_refpid;
/** @} */
/** Wait queue for those who need to wait for recovery completion */
#define DEBUG_SUBSYSTEM S_CLASS
+#include <linux/pid_namespace.h>
#include <linux/kthread.h>
#include <obd_class.h>
#include <lprocfs_status.h>
struct obd_import *class_new_import(struct obd_device *obd)
{
struct obd_import *imp;
+ struct pid_namespace *curr_pid_ns = ll_task_pid_ns(current);
OBD_ALLOC(imp, sizeof(*imp));
if (imp == NULL)
mutex_init(&imp->imp_sec_mutex);
init_waitqueue_head(&imp->imp_recovery_waitq);
+ if (curr_pid_ns->child_reaper)
+ imp->imp_sec_refpid = curr_pid_ns->child_reaper->pid;
+ else
+ imp->imp_sec_refpid = 1;
+
atomic_set(&imp->imp_refcount, 2);
atomic_set(&imp->imp_unregistering, 0);
atomic_set(&imp->imp_inflight, 0);
#define DEBUG_SUBSYSTEM S_LOG
+#include <linux/pid_namespace.h>
#include <linux/kthread.h>
#include <llog_swab.h>
#include <lustre_log.h>
struct llog_process_info *lpi = arg;
struct lu_env env;
int rc;
+ struct nsproxy *new_ns, *curr_ns = current->nsproxy;
+
+ task_lock(lpi->lpi_reftask);
+ new_ns = lpi->lpi_reftask->nsproxy;
+ if (curr_ns != new_ns) {
+ get_nsproxy(new_ns);
+
+ current->nsproxy = new_ns;
+ /* XXX: we should call put_nsproxy() instead of
+ * atomic_dec(&ns->count) directly. But put_nsproxy() cannot be
+ * used outside of the kernel itself, because it calls
+ * free_nsproxy() which is not exported by the kernel
+ * (defined in kernel/nsproxy.c) */
+ atomic_dec(&curr_ns->count);
+ }
+ task_unlock(lpi->lpi_reftask);
unshare_fs_struct();
ENTRY;
- OBD_ALLOC_PTR(lpi);
- if (lpi == NULL) {
- CERROR("cannot alloc pointer\n");
- RETURN(-ENOMEM);
- }
- lpi->lpi_loghandle = loghandle;
- lpi->lpi_cb = cb;
- lpi->lpi_cbdata = data;
- lpi->lpi_catdata = catdata;
+ OBD_ALLOC_PTR(lpi);
+ if (lpi == NULL) {
+ CERROR("cannot alloc pointer\n");
+ RETURN(-ENOMEM);
+ }
+ lpi->lpi_loghandle = loghandle;
+ lpi->lpi_cb = cb;
+ lpi->lpi_cbdata = data;
+ lpi->lpi_catdata = catdata;
if (fork) {
struct task_struct *task;
* init the new one in llog_process_thread_daemonize. */
lpi->lpi_env = NULL;
init_completion(&lpi->lpi_completion);
+ /* take reference to current, so that
+ * llog_process_thread_daemonize() can use it to switch to
+ * namespace associated with current */
+ lpi->lpi_reftask = current;
task = kthread_run(llog_process_thread_daemonize, lpi,
"llog_process_thread");
if (IS_ERR(task)) {
#include <lustre_log.h>
struct llog_process_info {
- struct llog_handle *lpi_loghandle;
- llog_cb_t lpi_cb;
- void *lpi_cbdata;
- void *lpi_catdata;
- int lpi_rc;
- struct completion lpi_completion;
+ struct llog_handle *lpi_loghandle;
+ llog_cb_t lpi_cb;
+ void *lpi_cbdata;
+ void *lpi_catdata;
+ int lpi_rc;
+ struct completion lpi_completion;
const struct lu_env *lpi_env;
+ struct task_struct *lpi_reftask;
};
struct llog_thread_info {
construct_key_desc(desc, sizeof(desc), sec, vcred->vc_uid);
/* callout info format:
- * secid:mech:uid:gid:sec_flags:svc_flag:svc_type:peer_nid:target_uuid
+ * secid:mech:uid:gid:sec_flags:svc_flag:svc_type:peer_nid:target_uuid:
+ * self_nid:pid
*/
- coinfo_size = sizeof(struct obd_uuid) + MAX_OBD_NAME + 64;
- OBD_ALLOC(coinfo, coinfo_size);
- if (coinfo == NULL)
- goto out;
-
- snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%c:%d:%#llx:%s:%#llx",
+ coinfo_size = sizeof(struct obd_uuid) + MAX_OBD_NAME + 64;
+ OBD_ALLOC(coinfo, coinfo_size);
+ if (coinfo == NULL)
+ goto out;
+
+ /* Last callout parameter is pid of process whose namespace will be used
+ * for credentials' retrieval.
+ * For user's credentials (in which case sec_part_flags is empty), use
+ * current PID instead of import's reference PID to get reference
+ * namespace. */
+ snprintf(coinfo, coinfo_size, "%d:%s:%u:%u:%s:%c:%d:%#llx:%s:%#llx:%d",
sec->ps_id, sec2gsec(sec)->gs_mech->gm_name,
vcred->vc_uid, vcred->vc_gid,
sec_part_flags, svc_flag, import_to_gss_svc(imp),
imp->imp_connection->c_peer.nid, imp->imp_obd->obd_name,
- imp->imp_connection->c_self);
+ imp->imp_connection->c_self,
+ sec_part_flags[0] == '\0' ?
+ current_pid() : imp->imp_sec_refpid);
CDEBUG(D_SEC, "requesting key for %s\n", desc);
# GSS daemons & tools Makefile
AM_CFLAGS := -fPIC \
- -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DLUSTRE_UTILS=1
+ -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DLUSTRE_UTILS=1 \
+ -D_GNU_SOURCE
LIBCFS := $(top_builddir)/libcfs/libcfs/libcfs.a
* Author: Eric Mei <ericm@clusterfs.com>
*/
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
};
struct keyring_upcall_param {
- uint32_t kup_ver;
- uint32_t kup_secid;
- uint32_t kup_uid;
- uint32_t kup_fsuid;
- uint32_t kup_gid;
- uint32_t kup_fsgid;
- uint32_t kup_svc;
- uint64_t kup_nid;
- uint64_t kup_selfnid;
+ uint32_t kup_ver;
+ uint32_t kup_secid;
+ uint32_t kup_uid;
+ uint32_t kup_fsuid;
+ uint32_t kup_gid;
+ uint32_t kup_fsgid;
+ uint32_t kup_svc;
+ uint64_t kup_nid;
+ uint64_t kup_selfnid;
char kup_svc_type;
- char kup_tgt[64];
- char kup_mech[16];
- unsigned int kup_is_root:1,
+ char kup_tgt[64];
+ char kup_mech[16];
+ unsigned int kup_is_root:1,
kup_is_mdt:1,
kup_is_ost:1;
+ uint32_t kup_pid;
};
/****************************************
* [7]: target_nid (uint64)
* [8]: target_uuid (string)
* [9]: self_nid (uint64)
+ * [10]: pid (uint)
*/
static int parse_callout_info(const char *coinfo,
struct keyring_upcall_param *uparam)
{
- const int nargs = 10;
+ const int nargs = 11;
char buf[1024];
char *string = buf;
int length, i;
}
data[i] = string;
- logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s\n",
+ logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s,%s\n",
data[0], data[1], data[2], data[3], data[4], data[5][0],
- data[6], data[7], data[8], data[9]);
+ data[6], data[7], data[8], data[9], data[10]);
uparam->kup_secid = strtol(data[0], NULL, 0);
strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
uparam->kup_nid = strtoll(data[7], NULL, 0);
strlcpy(uparam->kup_tgt, data[8], sizeof(uparam->kup_tgt));
uparam->kup_selfnid = strtoll(data[9], NULL, 0);
+ uparam->kup_pid = strtol(data[10], NULL, 0);
logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
"is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
- "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64"\n",
+ "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64", pid %d\n",
uparam->kup_secid, uparam->kup_mech,
uparam->kup_uid, uparam->kup_gid,
uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
- uparam->kup_tgt, uparam->kup_selfnid);
+ uparam->kup_tgt, uparam->kup_selfnid, uparam->kup_pid);
return 0;
}
fclose(file);
}
+#ifdef HAVE_SETNS
+static int associate_with_ns(char *path)
+{
+ int fd, rc = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd != -1) {
+ rc = setns(fd, 0);
+ close(fd);
+ }
+
+ return rc;
+}
+#endif
+
/****************************************
* main process *
****************************************/
pid_t child;
struct lgss_mech_type *mech;
struct lgss_cred *cred;
+#ifdef HAVE_SETNS
+ char path[PATH_MAX];
+ struct stat parent_ns = { .st_ino = 0 }, caller_ns = { .st_ino = 0 };
+#endif
set_log_level();
cred->lc_svc_type = uparam.kup_svc_type;
cred->lc_self_nid = uparam.kup_selfnid;
- if (lgss_prepare_cred(cred)) {
- logmsg(LL_ERR, "key %08x: failed to prepare credentials "
- "for user %d\n", keyid, uparam.kup_uid);
- return 1;
- }
+#ifdef HAVE_SETNS
+ /* Is caller in different namespace? */
+ snprintf(path, sizeof(path), "/proc/%d/ns/mnt", getpid());
+ if (stat(path, &parent_ns))
+ logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno));
+ snprintf(path, sizeof(path), "/proc/%d/ns/mnt", uparam.kup_pid);
+ if (stat(path, &caller_ns))
+ logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno));
+ if (caller_ns.st_ino != parent_ns.st_ino) {
+ /*
+ * do credentials preparation in caller's namespace
+ */
+ if (associate_with_ns(path) != 0) {
+ logmsg(LL_ERR, "failed to attach to pid %d namespace: "
+ "%s\n", uparam.kup_pid, strerror(errno));
+ return 1;
+ }
+ logmsg(LL_TRACE, "working in namespace of pid %d\n",
+ uparam.kup_pid);
+ } else {
+ logmsg(LL_TRACE, "caller's namespace is the same\n");
+ }
+#endif /* HAVE_SETNS */
+
+ if (lgss_prepare_cred(cred)) {
+ logmsg(LL_ERR, "key %08x: failed to prepare credentials "
+ "for user %d\n", keyid, uparam.kup_uid);
+ return 1;
+ }
/* pre initialize the key. note the keyring linked to is actually of the
* original requesting process, not _this_ upcall process. if it's for