diff --git a/ns.c b/ns.c index 9b68f36..4d58499 100644 --- a/ns.c +++ b/ns.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -104,13 +105,21 @@ static int is_setns(const struct nsid *ns) are entered via unshare (or not changed at all). */ static int cmp_nsids(const void *lhs, const void *rhs) { + const struct nsid *lns = lhs; + const struct nsid *rns = rhs; + printf("\tcomparing lhs=%d (is_setns=%d) with rhs=%d (is_setns=%d): ", + lns->ns, is_setns(lhs), + rns->ns, is_setns(rhs)); int diff = is_setns(rhs) - is_setns(lhs); if (diff != 0) { + printf("%d via setns diff\n", diff); return diff; } /* Both namespaces are the same kind -- keep ordering intact by comparing pointer values. */ - return (int) ((intptr_t) lhs - (intptr_t) rhs); + diff = (int) ((intptr_t) lhs - (intptr_t) rhs); + printf("%d via pointer comparison\n", diff); + return diff; } static void ns_enter_one(struct nsid *ns) @@ -140,6 +149,8 @@ static void ns_enter_one(struct nsid *ns) } } +// Note that for namespaces that want to enter into a specific namespace, +// we actually setns those before forking. static bool is_postfork_ns(struct nsid *ns) { /* For now, only the cgroup namespace needs to be unshared postfork */ @@ -151,40 +162,39 @@ void ns_enter_prefork(struct nsid *namespaces, size_t *len) /* Enter all relevant namespaces. It's hard to check in advance which namespaces are supported, so we unshare them one by one in order. */ - /* If we have CAP_SYS_ADMIN from the get-go, starting by entering - the userns may restrict us from joining additional namespaces, so - we rearrange the order so that we setns into target nsfs files first. */ - if (capable(BST_CAP_SYS_ADMIN)) { - qsort(namespaces, *len, sizeof (namespaces[0]), - cmp_nsids); - } - - struct nsid *first_postfork = NULL; + // First we setns the things that have a specific fd to share into. struct nsid *ns = &namespaces[0]; for (; ns < namespaces + *len; ++ns) { - if (ns->action != NSACTION_SHARE_WITH_PARENT && is_postfork_ns(ns)) { - first_postfork = ns; - break; - } + if (ns->action < 0) { + continue; + } ns_enter_one(ns); } - size_t i = 0; - for (; ns < namespaces + *len; ++ns, ++i) { - if (first_postfork != NULL && !is_postfork_ns(ns)) { - errx(1, "incompatible options: %s namespace must be entered before " - "forking, but must be done after %s namespace is entered post-fork.", - ns_name(ns->ns), - ns_name(first_postfork->ns)); - } - namespaces[i] = *ns; + // Then setns the things that just need a blanket unshare (postfork + // namespaces with NSACTION_UNSHARE need to be shard post-fork). + ns = &namespaces[0]; + for (; ns < namespaces + *len; ++ns) { + if (is_postfork_ns(ns)) { + continue; + } + if (ns->action >= 0) { + continue; + } + ns_enter_one(ns); } - *len = i; } void ns_enter_postfork(struct nsid *namespaces, size_t len) { for (struct nsid *ns = &namespaces[0]; ns < namespaces + len; ++ns) { + if (!is_postfork_ns(ns)) { + continue; + } + if (ns->action > 0) { + // If there is an fd action then we already did this prefork. + continue; + } ns_enter_one(ns); } } diff --git a/ns.h b/ns.h index 35fcf9f..4550cc6 100644 --- a/ns.h +++ b/ns.h @@ -37,13 +37,13 @@ enum { enum nstype { NS_CGROUP = 0, - NS_IPC, - NS_MNT, - NS_NET, - NS_PID, - NS_TIME, - NS_USER, - NS_UTS, + NS_IPC, // 1 + NS_MNT, // 2 + NS_NET, // 3 + NS_PID, // 4 + NS_TIME,// 5 + NS_USER,// 6 + NS_UTS, // 7 MAX_NS };