提交 675f605d 编写于 作者: B Bodo Möller

Thread-safety fixes

上级 6a983d42
...@@ -289,6 +289,10 @@ ...@@ -289,6 +289,10 @@
Changes between 0.9.8b and 0.9.8c [xx XXX xxxx] Changes between 0.9.8b and 0.9.8c [xx XXX xxxx]
*) Fix RSA blinding Heisenbug (problems sometimes occured on
dual-core machines) and other potential thread-safety issues.
[Bodo Moeller]
*) Add the symmetric cipher Camellia (128-bit, 192-bit, 256-bit key *) Add the symmetric cipher Camellia (128-bit, 192-bit, 256-bit key
versions), which is now available for royalty-free use versions), which is now available for royalty-free use
(see http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html). (see http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html).
...@@ -389,6 +393,9 @@ ...@@ -389,6 +393,9 @@
Changes between 0.9.7h and 0.9.8 [05 Jul 2005] Changes between 0.9.7h and 0.9.8 [05 Jul 2005]
[NB: OpenSSL 0.9.7i and later 0.9.7 patch levels were released after
OpenSSL 0.9.8.]
*) Add libcrypto.pc and libssl.pc for those who feel they need them. *) Add libcrypto.pc and libssl.pc for those who feel they need them.
[Richard Levitte] [Richard Levitte]
...@@ -1206,6 +1213,27 @@ ...@@ -1206,6 +1213,27 @@
differing sizes. differing sizes.
[Richard Levitte] [Richard Levitte]
Changes between 0.9.7j and 0.9.7k [xx XXX xxxx]
*) Fix RSA blinding Heisenbug (problems sometimes occured on
dual-core machines) and other potential thread-safety issues.
[Bodo Moeller]
Changes between 0.9.7i and 0.9.7j [04 May 2006]
*) Adapt fipsld and the build system to link against the validated FIPS
module in FIPS mode.
[Steve Henson]
*) Fixes for VC++ 2005 build under Windows.
[Steve Henson]
*) Add new Windows build target VC-32-GMAKE for VC++. This uses GNU make
from a Windows bash shell such as MSYS. It is autodetected from the
"config" script when run from a VC++ environment. Modify standard VC++
build to use fipscanister.o from the GNU make build.
[Steve Henson]
Changes between 0.9.7h and 0.9.7i [14 Oct 2005] Changes between 0.9.7h and 0.9.7i [14 Oct 2005]
*) Wrapped the definition of EVP_MAX_MD_SIZE in a #ifdef OPENSSL_FIPS. *) Wrapped the definition of EVP_MAX_MD_SIZE in a #ifdef OPENSSL_FIPS.
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
--------------- ---------------
/* ==================================================================== /* ====================================================================
* Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
......
...@@ -55,6 +55,59 @@ ...@@ -55,6 +55,59 @@
* copied and put under another distribution licence * copied and put under another distribution licence
* [including the GNU Public Licence.] * [including the GNU Public Licence.]
*/ */
/* ====================================================================
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/* /*
* Details about Montgomery multiplication algorithms can be found at * Details about Montgomery multiplication algorithms can be found at
...@@ -427,18 +480,30 @@ BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from) ...@@ -427,18 +480,30 @@ BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from)
BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock, BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
const BIGNUM *mod, BN_CTX *ctx) const BIGNUM *mod, BN_CTX *ctx)
{ {
if (*pmont) int got_write_lock = 0;
return *pmont;
CRYPTO_w_lock(lock); CRYPTO_r_lock(lock);
if (!*pmont) if (!*pmont)
{ {
BN_MONT_CTX *mtmp; CRYPTO_r_unlock(lock);
mtmp = BN_MONT_CTX_new(); CRYPTO_w_lock(lock);
if (mtmp && !BN_MONT_CTX_set(mtmp, mod, ctx)) got_write_lock = 1;
BN_MONT_CTX_free(mtmp);
else if (!*pmont)
*pmont = mtmp; {
BN_MONT_CTX *mtmp;
mtmp = BN_MONT_CTX_new();
if (mtmp && !BN_MONT_CTX_set(mtmp, mod, ctx))
BN_MONT_CTX_free(mtmp);
else
*pmont = mtmp;
}
} }
CRYPTO_w_unlock(lock);
if (got_write_lock)
CRYPTO_w_unlock(lock);
else
CRYPTO_r_unlock(lock);
return *pmont; return *pmont;
} }
...@@ -550,9 +550,20 @@ static void build_SYS_str_reasons(void) ...@@ -550,9 +550,20 @@ static void build_SYS_str_reasons(void)
int i; int i;
static int init = 1; static int init = 1;
if (!init) return; CRYPTO_r_lock(CRYPTO_LOCK_ERR);
if (!init)
{
CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
return;
}
CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
CRYPTO_w_lock(CRYPTO_LOCK_ERR); CRYPTO_w_lock(CRYPTO_LOCK_ERR);
if (!init)
{
CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
return;
}
for (i = 1; i <= NUM_SYS_STR_REASONS; i++) for (i = 1; i <= NUM_SYS_STR_REASONS; i++)
{ {
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
* [including the GNU Public Licence.] * [including the GNU Public Licence.]
*/ */
/* ==================================================================== /* ====================================================================
* Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -238,40 +238,63 @@ err: ...@@ -238,40 +238,63 @@ err:
return(r); return(r);
} }
static BN_BLINDING *rsa_get_blinding(RSA *rsa, BIGNUM **r, int *local, BN_CTX *ctx) static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
{ {
BN_BLINDING *ret; BN_BLINDING *ret;
int got_write_lock = 0;
CRYPTO_r_lock(CRYPTO_LOCK_RSA);
if (rsa->blinding == NULL) if (rsa->blinding == NULL)
{ {
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
CRYPTO_w_lock(CRYPTO_LOCK_RSA);
got_write_lock = 1;
if (rsa->blinding == NULL) if (rsa->blinding == NULL)
{ rsa->blinding = RSA_setup_blinding(rsa, ctx);
CRYPTO_w_lock(CRYPTO_LOCK_RSA);
if (rsa->blinding == NULL)
rsa->blinding = RSA_setup_blinding(rsa, ctx);
CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
}
} }
ret = rsa->blinding; ret = rsa->blinding;
if (ret == NULL) if (ret == NULL)
return NULL; goto err;
if (BN_BLINDING_get_thread_id(ret) != CRYPTO_thread_id()) if (BN_BLINDING_get_thread_id(ret) == CRYPTO_thread_id())
{ {
*local = 0; /* rsa->blinding is ours! */
*local = 1;
}
else
{
/* resort to rsa->mt_blinding instead */
*local = 0; /* instructs rsa_blinding_convert(), rsa_blinding_invert()
* that the BN_BLINDING is shared, meaning that accesses
* require locks, and that the blinding factor must be
* stored outside the BN_BLINDING
*/
if (rsa->mt_blinding == NULL) if (rsa->mt_blinding == NULL)
{ {
CRYPTO_w_lock(CRYPTO_LOCK_RSA); if (!got_write_lock)
{
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
CRYPTO_w_lock(CRYPTO_LOCK_RSA);
got_write_lock = 1;
}
if (rsa->mt_blinding == NULL) if (rsa->mt_blinding == NULL)
rsa->mt_blinding = RSA_setup_blinding(rsa, ctx); rsa->mt_blinding = RSA_setup_blinding(rsa, ctx);
CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
} }
ret = rsa->mt_blinding; ret = rsa->mt_blinding;
} }
else
*local = 1;
err:
if (got_write_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
else
CRYPTO_r_unlock(CRYPTO_LOCK_RSA);
return ret; return ret;
} }
...@@ -358,7 +381,7 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from, ...@@ -358,7 +381,7 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
{ {
blinding = rsa_get_blinding(rsa, &br, &local_blinding, ctx); blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
if (blinding == NULL) if (blinding == NULL)
{ {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR); RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
...@@ -479,7 +502,7 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from, ...@@ -479,7 +502,7 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
{ {
blinding = rsa_get_blinding(rsa, &br, &local_blinding, ctx); blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
if (blinding == NULL) if (blinding == NULL)
{ {
RSAerr(RSA_F_RSA_EAY_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR); RSAerr(RSA_F_RSA_EAY_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR);
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
* [including the GNU Public Licence.] * [including the GNU Public Licence.]
*/ */
/* ==================================================================== /* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved. * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -73,12 +73,12 @@ ...@@ -73,12 +73,12 @@
* 3. All advertising materials mentioning features or use of this * 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment: * software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project * "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
* *
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without * endorse or promote products derived from this software without
* prior written permission. For written permission, please contact * prior written permission. For written permission, please contact
* openssl-core@OpenSSL.org. * openssl-core@openssl.org.
* *
* 5. Products derived from this software may not be called "OpenSSL" * 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written * nor may "OpenSSL" appear in their names without prior written
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
* 6. Redistributions of any form whatsoever must retain the following * 6. Redistributions of any form whatsoever must retain the following
* acknowledgment: * acknowledgment:
* "This product includes software developed by the OpenSSL Project * "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
* *
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
...@@ -102,6 +102,11 @@ ...@@ -102,6 +102,11 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
* ==================================================================== * ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/ */
/* ==================================================================== /* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
...@@ -130,21 +135,28 @@ ...@@ -130,21 +135,28 @@
int SSL_get_ex_data_X509_STORE_CTX_idx(void) int SSL_get_ex_data_X509_STORE_CTX_idx(void)
{ {
static volatile int ssl_x509_store_ctx_idx= -1; static volatile int ssl_x509_store_ctx_idx= -1;
int got_write_lock = 0;
CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
if (ssl_x509_store_ctx_idx < 0) if (ssl_x509_store_ctx_idx < 0)
{ {
/* any write lock will do; usually this branch CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
* will only be taken once anyway */
CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
got_write_lock = 1;
if (ssl_x509_store_ctx_idx < 0) if (ssl_x509_store_ctx_idx < 0)
{ {
ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index( ssl_x509_store_ctx_idx=X509_STORE_CTX_get_ex_new_index(
0,"SSL for verify callback",NULL,NULL,NULL); 0,"SSL for verify callback",NULL,NULL,NULL);
} }
CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
} }
if (got_write_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
else
CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
return ssl_x509_store_ctx_idx; return ssl_x509_store_ctx_idx;
} }
......
...@@ -55,6 +55,59 @@ ...@@ -55,6 +55,59 @@
* copied and put under another distribution licence * copied and put under another distribution licence
* [including the GNU Public Licence.] * [including the GNU Public Licence.]
*/ */
/* ====================================================================
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/* ==================================================================== /* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
* ECC cipher suite support in OpenSSL originally developed by * ECC cipher suite support in OpenSSL originally developed by
...@@ -243,36 +296,46 @@ static int sk_comp_cmp(const SSL_COMP * const *a, ...@@ -243,36 +296,46 @@ static int sk_comp_cmp(const SSL_COMP * const *a,
static void load_builtin_compressions(void) static void load_builtin_compressions(void)
{ {
if (ssl_comp_methods != NULL) int got_write_lock = 0;
return;
CRYPTO_w_lock(CRYPTO_LOCK_SSL); CRYPTO_r_lock(CRYPTO_LOCK_SSL);
if (ssl_comp_methods == NULL) if (ssl_comp_methods == NULL)
{ {
SSL_COMP *comp = NULL; CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
CRYPTO_w_lock(CRYPTO_LOCK_SSL);
MemCheck_off(); got_write_lock = 1;
ssl_comp_methods=sk_SSL_COMP_new(sk_comp_cmp);
if (ssl_comp_methods != NULL) if (ssl_comp_methods == NULL)
{ {
comp=(SSL_COMP *)OPENSSL_malloc(sizeof(SSL_COMP)); SSL_COMP *comp = NULL;
if (comp != NULL)
MemCheck_off();
ssl_comp_methods=sk_SSL_COMP_new(sk_comp_cmp);
if (ssl_comp_methods != NULL)
{ {
comp->method=COMP_zlib(); comp=(SSL_COMP *)OPENSSL_malloc(sizeof(SSL_COMP));
if (comp->method if (comp != NULL)
&& comp->method->type == NID_undef)
OPENSSL_free(comp);
else
{ {
comp->id=SSL_COMP_ZLIB_IDX; comp->method=COMP_zlib();
comp->name=comp->method->name; if (comp->method
sk_SSL_COMP_push(ssl_comp_methods,comp); && comp->method->type == NID_undef)
OPENSSL_free(comp);
else
{
comp->id=SSL_COMP_ZLIB_IDX;
comp->name=comp->method->name;
sk_SSL_COMP_push(ssl_comp_methods,comp);
}
} }
} }
MemCheck_on();
} }
MemCheck_on();
} }
CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
if (got_write_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
else
CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
} }
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册