string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / security / keys / process_keys.c
index b0904cd..5c23afb 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/fs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/security.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -34,6 +36,7 @@ struct key_user root_key_user = {
        .nkeys          = ATOMIC_INIT(2),
        .nikeys         = ATOMIC_INIT(2),
        .uid            = 0,
+       .user_ns        = &init_user_ns,
 };
 
 /*****************************************************************************/
@@ -42,11 +45,15 @@ struct key_user root_key_user = {
  */
 int install_user_keyrings(void)
 {
-       struct user_struct *user = current->cred->user;
+       struct user_struct *user;
+       const struct cred *cred;
        struct key *uid_keyring, *session_keyring;
        char buf[20];
        int ret;
 
+       cred = current_cred();
+       user = cred->user;
+
        kenter("%p{%u}", user, user->uid);
 
        if (user->uid_keyring) {
@@ -67,7 +74,7 @@ int install_user_keyrings(void)
                uid_keyring = find_keyring_by_name(buf, true);
                if (IS_ERR(uid_keyring)) {
                        uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
-                                                   current, KEY_ALLOC_IN_QUOTA,
+                                                   cred, KEY_ALLOC_IN_QUOTA,
                                                    NULL);
                        if (IS_ERR(uid_keyring)) {
                                ret = PTR_ERR(uid_keyring);
@@ -83,8 +90,7 @@ int install_user_keyrings(void)
                if (IS_ERR(session_keyring)) {
                        session_keyring =
                                keyring_alloc(buf, user->uid, (gid_t) -1,
-                                             current, KEY_ALLOC_IN_QUOTA,
-                                             NULL);
+                                             cred, KEY_ALLOC_IN_QUOTA, NULL);
                        if (IS_ERR(session_keyring)) {
                                ret = PTR_ERR(session_keyring);
                                goto error_release;
@@ -116,142 +122,128 @@ error:
        return ret;
 }
 
-/*****************************************************************************/
 /*
- * deal with the UID changing
+ * install a fresh thread keyring directly to new credentials
  */
-void switch_uid_keyring(struct user_struct *new_user)
+int install_thread_keyring_to_cred(struct cred *new)
 {
-#if 0 /* do nothing for now */
-       struct key *old;
-
-       /* switch to the new user's session keyring if we were running under
-        * root's default session keyring */
-       if (new_user->uid != 0 &&
-           current->session_keyring == &root_session_keyring
-           ) {
-               atomic_inc(&new_user->session_keyring->usage);
-
-               task_lock(current);
-               old = current->session_keyring;
-               current->session_keyring = new_user->session_keyring;
-               task_unlock(current);
+       struct key *keyring;
 
-               key_put(old);
-       }
-#endif
+       keyring = keyring_alloc("_tid", new->uid, new->gid, new,
+                               KEY_ALLOC_QUOTA_OVERRUN, NULL);
+       if (IS_ERR(keyring))
+               return PTR_ERR(keyring);
 
-} /* end switch_uid_keyring() */
+       new->thread_keyring = keyring;
+       return 0;
+}
 
-/*****************************************************************************/
 /*
  * install a fresh thread keyring, discarding the old one
  */
-int install_thread_keyring(void)
+static int install_thread_keyring(void)
 {
-       struct task_struct *tsk = current;
-       struct key *keyring, *old;
-       char buf[20];
+       struct cred *new;
        int ret;
 
-       sprintf(buf, "_tid.%u", tsk->pid);
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-       keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
-                               KEY_ALLOC_QUOTA_OVERRUN, NULL);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
-               goto error;
+       BUG_ON(new->thread_keyring);
+
+       ret = install_thread_keyring_to_cred(new);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret;
        }
 
-       task_lock(tsk);
-       old = tsk->cred->thread_keyring;
-       tsk->cred->thread_keyring = keyring;
-       task_unlock(tsk);
+       return commit_creds(new);
+}
 
-       ret = 0;
+/*
+ * install a process keyring directly to a credentials struct
+ * - returns -EEXIST if there was already a process keyring, 0 if one installed,
+ *   and other -ve on any other error
+ */
+int install_process_keyring_to_cred(struct cred *new)
+{
+       struct key *keyring;
+       int ret;
 
-       key_put(old);
-error:
+       if (new->tgcred->process_keyring)
+               return -EEXIST;
+
+       keyring = keyring_alloc("_pid", new->uid, new->gid,
+                               new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
+       if (IS_ERR(keyring))
+               return PTR_ERR(keyring);
+
+       spin_lock_irq(&new->tgcred->lock);
+       if (!new->tgcred->process_keyring) {
+               new->tgcred->process_keyring = keyring;
+               keyring = NULL;
+               ret = 0;
+       } else {
+               ret = -EEXIST;
+       }
+       spin_unlock_irq(&new->tgcred->lock);
+       key_put(keyring);
        return ret;
+}
 
-} /* end install_thread_keyring() */
-
-/*****************************************************************************/
 /*
  * make sure a process keyring is installed
+ * - we
  */
-int install_process_keyring(void)
+static int install_process_keyring(void)
 {
-       struct task_struct *tsk = current;
-       struct key *keyring;
-       char buf[20];
+       struct cred *new;
        int ret;
 
-       might_sleep();
-
-       if (!tsk->signal->process_keyring) {
-               sprintf(buf, "_pid.%u", tsk->tgid);
-
-               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
-                                       KEY_ALLOC_QUOTA_OVERRUN, NULL);
-               if (IS_ERR(keyring)) {
-                       ret = PTR_ERR(keyring);
-                       goto error;
-               }
-
-               /* attach keyring */
-               spin_lock_irq(&tsk->sighand->siglock);
-               if (!tsk->signal->process_keyring) {
-                       tsk->signal->process_keyring = keyring;
-                       keyring = NULL;
-               }
-               spin_unlock_irq(&tsk->sighand->siglock);
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-               key_put(keyring);
+       ret = install_process_keyring_to_cred(new);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret != -EEXIST ?: 0;
        }
 
-       ret = 0;
-error:
-       return ret;
-
-} /* end install_process_keyring() */
+       return commit_creds(new);
+}
 
-/*****************************************************************************/
 /*
- * install a session keyring, discarding the old one
- * - if a keyring is not supplied, an empty one is invented
+ * install a session keyring directly to a credentials struct
  */
-static int install_session_keyring(struct key *keyring)
+static int install_session_keyring_to_cred(struct cred *cred,
+                                          struct key *keyring)
 {
-       struct task_struct *tsk = current;
        unsigned long flags;
        struct key *old;
-       char buf[20];
 
        might_sleep();
 
        /* create an empty session keyring */
        if (!keyring) {
-               sprintf(buf, "_ses.%u", tsk->tgid);
-
                flags = KEY_ALLOC_QUOTA_OVERRUN;
-               if (tsk->signal->session_keyring)
+               if (cred->tgcred->session_keyring)
                        flags = KEY_ALLOC_IN_QUOTA;
 
-               keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
-                                       flags, NULL);
+               keyring = keyring_alloc("_ses", cred->uid, cred->gid,
+                                       cred, flags, NULL);
                if (IS_ERR(keyring))
                        return PTR_ERR(keyring);
-       }
-       else {
+       } else {
                atomic_inc(&keyring->usage);
        }
 
        /* install the keyring */
-       spin_lock_irq(&tsk->sighand->siglock);
-       old = tsk->signal->session_keyring;
-       rcu_assign_pointer(tsk->signal->session_keyring, keyring);
-       spin_unlock_irq(&tsk->sighand->siglock);
+       spin_lock_irq(&cred->tgcred->lock);
+       old = cred->tgcred->session_keyring;
+       rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
+       spin_unlock_irq(&cred->tgcred->lock);
 
        /* we're using RCU on the pointer, but there's no point synchronising
         * on it if it didn't previously point to anything */
@@ -261,110 +253,29 @@ static int install_session_keyring(struct key *keyring)
        }
 
        return 0;
+}
 
-} /* end install_session_keyring() */
-
-/*****************************************************************************/
-/*
- * copy the keys in a thread group for fork without CLONE_THREAD
- */
-int copy_thread_group_keys(struct task_struct *tsk)
-{
-       key_check(current->thread_group->session_keyring);
-       key_check(current->thread_group->process_keyring);
-
-       /* no process keyring yet */
-       tsk->signal->process_keyring = NULL;
-
-       /* same session keyring */
-       rcu_read_lock();
-       tsk->signal->session_keyring =
-               key_get(rcu_dereference(current->signal->session_keyring));
-       rcu_read_unlock();
-
-       return 0;
-
-} /* end copy_thread_group_keys() */
-
-/*****************************************************************************/
-/*
- * copy the keys for fork
- */
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
-{
-       key_check(tsk->cred->thread_keyring);
-       key_check(tsk->cred->request_key_auth);
-
-       /* no thread keyring yet */
-       tsk->cred->thread_keyring = NULL;
-
-       /* copy the request_key() authorisation for this thread */
-       key_get(tsk->cred->request_key_auth);
-
-       return 0;
-
-} /* end copy_keys() */
-
-/*****************************************************************************/
-/*
- * dispose of thread group keys upon thread group destruction
- */
-void exit_thread_group_keys(struct signal_struct *tg)
-{
-       key_put(tg->session_keyring);
-       key_put(tg->process_keyring);
-
-} /* end exit_thread_group_keys() */
-
-/*****************************************************************************/
-/*
- * dispose of per-thread keys upon thread exit
- */
-void exit_keys(struct task_struct *tsk)
-{
-       key_put(tsk->cred->thread_keyring);
-       key_put(tsk->cred->request_key_auth);
-
-} /* end exit_keys() */
-
-/*****************************************************************************/
 /*
- * deal with execve()
+ * install a session keyring, discarding the old one
+ * - if a keyring is not supplied, an empty one is invented
  */
-int exec_keys(struct task_struct *tsk)
+static int install_session_keyring(struct key *keyring)
 {
-       struct key *old;
-
-       /* newly exec'd tasks don't get a thread keyring */
-       task_lock(tsk);
-       old = tsk->cred->thread_keyring;
-       tsk->cred->thread_keyring = NULL;
-       task_unlock(tsk);
-
-       key_put(old);
-
-       /* discard the process keyring from a newly exec'd task */
-       spin_lock_irq(&tsk->sighand->siglock);
-       old = tsk->signal->process_keyring;
-       tsk->signal->process_keyring = NULL;
-       spin_unlock_irq(&tsk->sighand->siglock);
-
-       key_put(old);
-
-       return 0;
+       struct cred *new;
+       int ret;
 
-} /* end exec_keys() */
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-/*****************************************************************************/
-/*
- * deal with SUID programs
- * - we might want to make this invent a new session keyring
- */
-int suid_keys(struct task_struct *tsk)
-{
-       return 0;
+       ret = install_session_keyring_to_cred(new, NULL);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret;
+       }
 
-} /* end suid_keys() */
+       return commit_creds(new);
+}
 
 /*****************************************************************************/
 /*
@@ -409,7 +320,7 @@ void key_fsgid_changed(struct task_struct *tsk)
 key_ref_t search_process_keyrings(struct key_type *type,
                                  const void *description,
                                  key_match_func_t match,
-                                 struct task_struct *context)
+                                 const struct cred *cred)
 {
        struct request_key_auth *rka;
        key_ref_t key_ref, ret, err;
@@ -428,10 +339,10 @@ key_ref_t search_process_keyrings(struct key_type *type,
        err = ERR_PTR(-EAGAIN);
 
        /* search the thread keyring first */
-       if (context->cred->thread_keyring) {
+       if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->cred->thread_keyring, 1),
-                       context, type, description, match);
+                       make_key_ref(cred->thread_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -449,10 +360,10 @@ key_ref_t search_process_keyrings(struct key_type *type,
        }
 
        /* search the process keyring second */
-       if (context->signal->process_keyring) {
+       if (cred->tgcred->process_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->signal->process_keyring, 1),
-                       context, type, description, match);
+                       make_key_ref(cred->tgcred->process_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -470,13 +381,13 @@ key_ref_t search_process_keyrings(struct key_type *type,
        }
 
        /* search the session keyring */
-       if (context->signal->session_keyring) {
+       if (cred->tgcred->session_keyring) {
                rcu_read_lock();
                key_ref = keyring_search_aux(
                        make_key_ref(rcu_dereference(
-                                            context->signal->session_keyring),
+                                            cred->tgcred->session_keyring),
                                     1),
-                       context, type, description, match);
+                       cred, type, description, match);
                rcu_read_unlock();
 
                if (!IS_ERR(key_ref))
@@ -495,10 +406,10 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
        /* or search the user-session keyring */
-       else if (context->cred->user->session_keyring) {
+       else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->cred->user->session_keyring, 1),
-                       context, type, description, match);
+                       make_key_ref(cred->user->session_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -519,20 +430,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
         * search the keyrings of the process mentioned there
         * - we don't permit access to request_key auth keys via this method
         */
-       if (context->cred->request_key_auth &&
-           context == current &&
+       if (cred->request_key_auth &&
+           cred == current_cred() &&
            type != &key_type_request_key_auth
            ) {
                /* defend against the auth key being revoked */
-               down_read(&context->cred->request_key_auth->sem);
+               down_read(&cred->request_key_auth->sem);
 
-               if (key_validate(context->cred->request_key_auth) == 0) {
-                       rka = context->cred->request_key_auth->payload.data;
+               if (key_validate(cred->request_key_auth) == 0) {
+                       rka = cred->request_key_auth->payload.data;
 
                        key_ref = search_process_keyrings(type, description,
-                                                         match, rka->context);
+                                                         match, rka->cred);
 
-                       up_read(&context->cred->request_key_auth->sem);
+                       up_read(&cred->request_key_auth->sem);
 
                        if (!IS_ERR(key_ref))
                                goto found;
@@ -549,7 +460,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
                                break;
                        }
                } else {
-                       up_read(&context->cred->request_key_auth->sem);
+                       up_read(&cred->request_key_auth->sem);
                }
        }
 
@@ -577,22 +488,23 @@ static int lookup_user_key_possessed(const struct key *key, const void *target)
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
 {
        struct request_key_auth *rka;
-       struct task_struct *t = current;
-       struct cred *cred = t->cred;
+       const struct cred *cred;
        struct key *key;
        key_ref_t key_ref, skey_ref;
        int ret;
 
+try_again:
+       cred = get_current_cred();
        key_ref = ERR_PTR(-ENOKEY);
 
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
                if (!cred->thread_keyring) {
-                       if (!create)
+                       if (!(lflags & KEY_LOOKUP_CREATE))
                                goto error;
 
                        ret = install_thread_keyring();
@@ -600,6 +512,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                                key = ERR_PTR(ret);
                                goto error;
                        }
+                       goto reget_creds;
                }
 
                key = cred->thread_keyring;
@@ -608,8 +521,8 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                break;
 
        case KEY_SPEC_PROCESS_KEYRING:
-               if (!t->signal->process_keyring) {
-                       if (!create)
+               if (!cred->tgcred->process_keyring) {
+                       if (!(lflags & KEY_LOOKUP_CREATE))
                                goto error;
 
                        ret = install_process_keyring();
@@ -617,15 +530,16 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                                key = ERR_PTR(ret);
                                goto error;
                        }
+                       goto reget_creds;
                }
 
-               key = t->signal->process_keyring;
+               key = cred->tgcred->process_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
 
        case KEY_SPEC_SESSION_KEYRING:
-               if (!t->signal->session_keyring) {
+               if (!cred->tgcred->session_keyring) {
                        /* always install a session keyring upon access if one
                         * doesn't exist yet */
                        ret = install_user_keyrings();
@@ -633,12 +547,14 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                                goto error;
                        ret = install_session_keyring(
                                cred->user->session_keyring);
+
                        if (ret < 0)
                                goto error;
+                       goto reget_creds;
                }
 
                rcu_read_lock();
-               key = rcu_dereference(t->signal->session_keyring);
+               key = rcu_dereference(cred->tgcred->session_keyring);
                atomic_inc(&key->usage);
                rcu_read_unlock();
                key_ref = make_key_ref(key, 1);
@@ -717,7 +633,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                /* check to see if we possess the key */
                skey_ref = search_process_keyrings(key->type, key,
                                                   lookup_user_key_possessed,
-                                                  current);
+                                                  cred);
 
                if (!IS_ERR(skey_ref)) {
                        key_put(key);
@@ -727,7 +643,14 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
                break;
        }
 
-       if (!partial) {
+       /* unlink does not use the nominated key in any way, so can skip all
+        * the permission checks as it is only concerned with the keyring */
+       if (lflags & KEY_LOOKUP_FOR_UNLINK) {
+               ret = 0;
+               goto error;
+       }
+
+       if (!(lflags & KEY_LOOKUP_PARTIAL)) {
                ret = wait_for_key_construction(key, true);
                switch (ret) {
                case -ERESTARTSYS:
@@ -745,15 +668,17 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
        }
 
        ret = -EIO;
-       if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+       if (!(lflags & KEY_LOOKUP_PARTIAL) &&
+           !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto invalid_key;
 
        /* check the permissions */
-       ret = key_task_permission(key_ref, t, perm);
+       ret = key_task_permission(key_ref, cred, perm);
        if (ret < 0)
                goto invalid_key;
 
 error:
+       put_cred(cred);
        return key_ref;
 
 invalid_key:
@@ -761,6 +686,12 @@ invalid_key:
        key_ref = ERR_PTR(ret);
        goto error;
 
+       /* if we attempted to install a keyring, then it may have caused new
+        * creds to be installed */
+reget_creds:
+       put_cred(cred);
+       goto try_again;
+
 } /* end lookup_user_key() */
 
 /*****************************************************************************/
@@ -772,20 +703,33 @@ invalid_key:
  */
 long join_session_keyring(const char *name)
 {
-       struct task_struct *tsk = current;
+       const struct cred *old;
+       struct cred *new;
        struct key *keyring;
-       long ret;
+       long ret, serial;
+
+       /* only permit this if there's a single thread in the thread group -
+        * this avoids us having to adjust the creds on all threads and risking
+        * ENOMEM */
+       if (!current_is_single_threaded())
+               return -EMLINK;
+
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
 
        /* if no name is provided, install an anonymous keyring */
        if (!name) {
-               ret = install_session_keyring(NULL);
+               ret = install_session_keyring_to_cred(new, NULL);
                if (ret < 0)
                        goto error;
 
-               rcu_read_lock();
-               ret = rcu_dereference(tsk->signal->session_keyring)->serial;
-               rcu_read_unlock();
-               goto error;
+               serial = new->tgcred->session_keyring->serial;
+               ret = commit_creds(new);
+               if (ret == 0)
+                       ret = serial;
+               goto okay;
        }
 
        /* allow the user to join or create a named keyring */
@@ -795,29 +739,81 @@ long join_session_keyring(const char *name)
        keyring = find_keyring_by_name(name, false);
        if (PTR_ERR(keyring) == -ENOKEY) {
                /* not found - try and create a new one */
-               keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
+               keyring = keyring_alloc(name, old->uid, old->gid, old,
                                        KEY_ALLOC_IN_QUOTA, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
                }
-       }
-       else if (IS_ERR(keyring)) {
+       } else if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error2;
        }
 
        /* we've got a keyring - now to install it */
-       ret = install_session_keyring(keyring);
+       ret = install_session_keyring_to_cred(new, keyring);
        if (ret < 0)
                goto error2;
 
+       commit_creds(new);
+       mutex_unlock(&key_session_mutex);
+
        ret = keyring->serial;
        key_put(keyring);
+okay:
+       return ret;
 
 error2:
        mutex_unlock(&key_session_mutex);
 error:
+       abort_creds(new);
        return ret;
+}
 
-} /* end join_session_keyring() */
+/*
+ * Replace a process's session keyring when that process resumes userspace on
+ * behalf of one of its children
+ */
+void key_replace_session_keyring(void)
+{
+       const struct cred *old;
+       struct cred *new;
+
+       if (!current->replacement_session_keyring)
+               return;
+
+       write_lock_irq(&tasklist_lock);
+       new = current->replacement_session_keyring;
+       current->replacement_session_keyring = NULL;
+       write_unlock_irq(&tasklist_lock);
+
+       if (!new)
+               return;
+
+       old = current_cred();
+       new->  uid      = old->  uid;
+       new-> euid      = old-> euid;
+       new-> suid      = old-> suid;
+       new->fsuid      = old->fsuid;
+       new->  gid      = old->  gid;
+       new-> egid      = old-> egid;
+       new-> sgid      = old-> sgid;
+       new->fsgid      = old->fsgid;
+       new->user       = get_uid(old->user);
+       new->group_info = get_group_info(old->group_info);
+
+       new->securebits = old->securebits;
+       new->cap_inheritable    = old->cap_inheritable;
+       new->cap_permitted      = old->cap_permitted;
+       new->cap_effective      = old->cap_effective;
+       new->cap_bset           = old->cap_bset;
+
+       new->jit_keyring        = old->jit_keyring;
+       new->thread_keyring     = key_get(old->thread_keyring);
+       new->tgcred->tgid       = old->tgcred->tgid;
+       new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
+
+       security_transfer_creds(new, old);
+
+       commit_creds(new);
+}