*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/nsproxy.h>
+#include <linux/slab.h>
#include <linux/user_namespace.h>
+#include <linux/cred.h>
-struct user_namespace init_user_ns = {
- .kref = {
- .refcount = ATOMIC_INIT(2),
- },
- .root_user = &root_user,
-};
+/*
+ * Create a new user namespace, deriving the creator from the user in the
+ * passed credentials, and replacing that user with the new root user for the
+ * new namespace.
+ *
+ * This is called by copy_creds(), which will finish setting the target task's
+ * credentials.
+ */
+int create_user_ns(struct cred *new)
+{
+ struct user_namespace *ns;
+ struct user_struct *root_user;
+ int n;
-EXPORT_SYMBOL_GPL(init_user_ns);
+ ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
+ if (!ns)
+ return -ENOMEM;
-#ifdef CONFIG_USER_NS
+ kref_init(&ns->kref);
-struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
-{
- struct user_namespace *new_ns;
+ for (n = 0; n < UIDHASH_SZ; ++n)
+ INIT_HLIST_HEAD(ns->uidhash_table + n);
+
+ /* Alloc new root user. */
+ root_user = alloc_uid(ns, 0);
+ if (!root_user) {
+ kfree(ns);
+ return -ENOMEM;
+ }
- BUG_ON(!old_ns);
- get_user_ns(old_ns);
+ /* set the new root user in the credentials under preparation */
+ ns->creator = new->user;
+ new->user = root_user;
+ new->uid = new->euid = new->suid = new->fsuid = 0;
+ new->gid = new->egid = new->sgid = new->fsgid = 0;
+ put_group_info(new->group_info);
+ new->group_info = get_group_info(&init_groups);
+#ifdef CONFIG_KEYS
+ key_put(new->request_key_auth);
+ new->request_key_auth = NULL;
+#endif
+ /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
- new_ns = old_ns;
- return new_ns;
+ /* alloc_uid() incremented the userns refcount. Just set it to 1 */
+ kref_set(&ns->kref, 1);
+
+ return 0;
}
void free_user_ns(struct kref *kref)
struct user_namespace *ns;
ns = container_of(kref, struct user_namespace, kref);
+ free_uid(ns->creator);
kfree(ns);
}
-
-#endif /* CONFIG_USER_NS */
+EXPORT_SYMBOL(free_user_ns);