【发布时间】:2019-06-17 15:55:33
【问题描述】:
我对 TCL 8.6.8 源码 tclInt.h 中的以下代码有疑问:
4277 #define TclInvalidateStringRep(objPtr) \
4278 if (objPtr->bytes != NULL) { \
4279 if (objPtr->bytes != tclEmptyStringRep) { \
4280 ckfree((char *) objPtr->bytes); \
4281 } \
4282 objPtr->bytes = NULL; \
4283 }
此宏由 tclObj.c 中的 Tcl_InvalidateStringRep() 调用。
我的疑问是,为什么 tclObj 的长度不重置为零?
这里是Tcl_Obj的定义:
808 typedef struct Tcl_Obj {
809 int refCount; /* When 0 the object will be freed. */
810 char *bytes; /* This points to the first byte of the
811 * object's string representation. The array
812 * must be followed by a null byte (i.e., at
813 * offset length) but may also contain
814 * embedded null characters. The array's
815 * storage is allocated by ckalloc. NULL means
816 * the string rep is invalid and must be
817 * regenerated from the internal rep. Clients
818 * should use Tcl_GetStringFromObj or
819 * Tcl_GetString to get a pointer to the byte
820 * array as a readonly value. */
821 int length; /* The number of bytes at *bytes, not
822 * including the terminating null. */
所以你可以看到长度与字节紧密耦合,当字节被清除时,我们不应该重置长度吗?
我的疑问来自以下代码,tclLiteral.c 中的 TclCreateLiteral():
200 for (globalPtr=globalTablePtr->buckets[globalHash] ; globalPtr!=NULL;
201 globalPtr = globalPtr->nextPtr) {
202 objPtr = globalPtr->objPtr;
203 if ((globalPtr->nsPtr == nsPtr)
204 && (objPtr->length == length) && ((length == 0)
205 || ((objPtr->bytes[0] == bytes[0])
206 && (memcmp(objPtr->bytes, bytes, (unsigned) length) == 0)))) {
所以在第 204 行,当 length 不为零而 bytes 为 NULL 时,程序会崩溃。
我的产品包含 TCL 源码,我在跟踪程序崩溃时发现了上述问题。我将解决方法放在我们的代码中,但想与社区确认它是否确实是一个漏洞。
【问题讨论】:
-
对我来说这看起来像是
TclCreateLiteral中的一个错误;如果bytes字段为NULL,则不应直接触及length字段。使用TclGetStringFromObj宏来提取这些字段(而不是直接在结构内部四处寻找)确保语义正确。 -
另外,你是如何触发这个代码路径的?如果我们要测试它(我们应该!),那么我们需要重现它……
标签: tcl