From 398e9e0ab167a545a8c74e711197c4ea97c162d9 Mon Sep 17 00:00:00 2001 From: chengyuli Date: Fri, 22 Aug 2025 15:24:14 +0800 Subject: [PATCH] Fix buffer pool use-after-free https://gitee.com/openharmony/commonlibrary_ets_utils/issues/ICU99W?from=project-issue Signed-off-by: chengyuli Change-Id: I7f57447c66600c7afbc7bdf319fd4d19f7319b74 --- js_api_module/buffer/js_buffer.cpp | 17 +++++++----- js_api_module/buffer/js_buffer.h | 6 ++++- js_api_module/buffer/native_module_buffer.cpp | 13 ++++++++++ js_api_module/buffer/src/js_buffer.ts | 26 ++++++++++++++++++- js_api_module/buffer/tsconfig.json | 1 - 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/js_api_module/buffer/js_buffer.cpp b/js_api_module/buffer/js_buffer.cpp index 800f17d3..59d378f6 100644 --- a/js_api_module/buffer/js_buffer.cpp +++ b/js_api_module/buffer/js_buffer.cpp @@ -27,6 +27,7 @@ void Buffer::Init(uint32_t size) HILOG_FATAL("Buffer:: constructor malloc failed"); length_ = 0; } + this->poolPtr_ = std::shared_ptr(raw_); } length_ = size; } @@ -38,6 +39,7 @@ void Buffer::Init(Buffer *buffer) if (raw_ == nullptr) { HILOG_FATAL("Buffer:: constructor malloc failed"); } else { + this->poolPtr_ = std::shared_ptr(this->raw_); this->length_ = buffer->length_; if (memcpy_s(raw_, length_, buffer->raw_ + buffer->byteOffset_, length_) != EOK) { HILOG_FATAL("Buffer:: constructor memcpy_s failed"); @@ -50,6 +52,9 @@ void Buffer::Init(Buffer *pool, unsigned int poolOffset, unsigned int length) { if (pool != nullptr) { this->raw_ = pool->GetRaw(); + if (this->raw_ != nullptr) { + this->poolPtr_ = std::shared_ptr(this->raw_); + } this->byteOffset_ = poolOffset; this->length_ = length; } @@ -66,13 +71,6 @@ void Buffer::Init(uint8_t *buffer, unsigned int byteOffset, unsigned int length) this->needRelease_ = false; } -Buffer::~Buffer() -{ - if (raw_ != nullptr && needRelease_) { - free(raw_); - raw_ = nullptr; - } -} EncodingType Buffer::GetEncodingType(std::string encode) { @@ -105,6 +103,11 @@ unsigned int Buffer::GetLength() return length_; } +unsigned int Buffer::GetSharedTimes() +{ + return poolPtr_.use_count(); +} + void Buffer::SetLength(unsigned int len) { length_ = len; diff --git a/js_api_module/buffer/js_buffer.h b/js_api_module/buffer/js_buffer.h index a43e0ee0..472b39df 100644 --- a/js_api_module/buffer/js_buffer.h +++ b/js_api_module/buffer/js_buffer.h @@ -29,13 +29,14 @@ namespace OHOS::buffer { class Buffer { public: Buffer() = default; - virtual ~Buffer(); + virtual ~Buffer() = default; void Init(uint32_t size); void Init(Buffer *buffer); void Init(Buffer *pool, unsigned int poolOffset, unsigned int length); void Init(uint8_t *buffer, unsigned int byteOffset, unsigned int length); unsigned int GetLength(); + unsigned int GetSharedTimes(); void SetLength(unsigned int len); unsigned int GetByteOffset(); int32_t Get(uint32_t index); @@ -93,6 +94,9 @@ private: unsigned int byteOffset_ {}; unsigned int length_ {}; bool needRelease_ {true}; + // delete data created by Buffer::Init automatically + std::shared_ptr poolPtr_; + }; } // namespace OHOS::Buffer #endif // BUFFER_JS_BUFFER_H diff --git a/js_api_module/buffer/native_module_buffer.cpp b/js_api_module/buffer/native_module_buffer.cpp index 559f5485..eadf77fc 100644 --- a/js_api_module/buffer/native_module_buffer.cpp +++ b/js_api_module/buffer/native_module_buffer.cpp @@ -517,6 +517,18 @@ static napi_value GetLength(napi_env env, napi_callback_info info) return result; } +static napi_value GetSharedTimes(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); + Buffer *buf = nullptr; + NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast(&buf))); + uint32_t res = buf->GetSharedTimes(); + napi_value result = nullptr; + napi_create_uint32(env, res, &result); + return result; +} + static napi_value GetByteOffset(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; @@ -1158,6 +1170,7 @@ static napi_value BufferInit(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("readUInt32LE", ReadUInt32LE), DECLARE_NAPI_FUNCTION("setArray", SetArray), DECLARE_NAPI_FUNCTION("getLength", GetLength), + DECLARE_NAPI_FUNCTION("getSharedTimes", GetSharedTimes), DECLARE_NAPI_FUNCTION("getByteOffset", GetByteOffset), DECLARE_NAPI_FUNCTION("writeString", WriteString), DECLARE_NAPI_FUNCTION("fromString", FromString), diff --git a/js_api_module/buffer/src/js_buffer.ts b/js_api_module/buffer/src/js_buffer.ts index 7e5b9624..bf06006b 100644 --- a/js_api_module/buffer/src/js_buffer.ts +++ b/js_api_module/buffer/src/js_buffer.ts @@ -286,10 +286,21 @@ const float64Array: Float64Array = new Float64Array(1); const uInt8Float64Array: Uint8Array = new Uint8Array(float64Array.buffer); const float32Array: Float32Array = new Float32Array(1); const uInt8Float32Array: Uint8Array = new Uint8Array(float32Array.buffer); +const maxPoolListSize = 128; + +interface ArkPrivate { + LinkedList: number; + Load(key: number): Object; +} +let arkPritvate: ArkPrivate = globalThis.ArkPrivate; +let LinkedList = undefined; +LinkedList = arkPritvate.Load(arkPritvate.LinkedList); +let poolList = new LinkedList(); function createPool(): void { poolSize = initialPoolSize; pool = new Buffer(poolSize); + poolList.add(pool); poolOffset = 0; } @@ -1995,15 +2006,28 @@ function alloc(size: number, fill?: string | Buffer | number, encoding?: string) return buf; } +function UpdatePoolList() { + let length = poolList.length - 1; + for (let i = 0; i < length;) { + if (poolList.get(i)[bufferSymbol].getSharedTimes() != 1) { + i++; + continue; + } + poolList.removeByIndex(i); + length--; + } +} + function allocUninitializedFromPool(size: number): Buffer { sizeErrorCheck(size, 'size', ['number'], 0, MAX_LENGTH); if (!pool) { createPool(); } - if (size < (poolSize >>> 1)) { + if (poolList.length < maxPoolListSize && size < (poolSize >>> 1)) { if (size > (poolSize - poolOffset)) { createPool(); } + UpdatePoolList(); const b = new Buffer(pool, poolOffset, size); poolOffset += size; alignPool(); diff --git a/js_api_module/buffer/tsconfig.json b/js_api_module/buffer/tsconfig.json index 8dda14ec..04c66581 100644 --- a/js_api_module/buffer/tsconfig.json +++ b/js_api_module/buffer/tsconfig.json @@ -6,7 +6,6 @@ "outDir": "./out", /* Specify an output folder for all emitted files. */ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "strict": true, "skipLibCheck": true, "noImplicitThis": false, "suppressImplicitAnyIndexErrors": true -- Gitee