[CSA Bug Report]Clang Static Analyzer(CSA) Memory Bug Detected
まだ誰も着手していません。
評価
調査の方向性
rosidl_generator_py/resource/_msg_support.c.em から始め、特に179-193行目と538行目以降のエラー戻りパスを確認してください。各失敗パスを通じて、name_attr、module_attr、class_attr、_pymessage の所有権を追跡してください。借用した文字列データが所有者の解放後に使用されず、割り当てられた _pymessage オブジェクトがすべての NULL または false の戻りの前に解放されていれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Bug report
Clang Static Analyzer(CSA), pyrefcon @Snape3058 (http://lcs.ios.ac.cn/~maxt/PyRefcon/ASE-2023.pdf)
- Operating System:
- Linux d18de72e1bb7 5.4.0-196-generic x86
Bug Type: Access released Memory/Use After Free
File: _msg_support.c.em
Commit: https://github.com/ros2/rosidl_python/blob/1fbd99b5fe1fa04674c73e7e5992ccc88e28157c/rosidl_generator_py/resource/_msg_support.c.em#L179-L193
Detail: after Py_DECREF module_attr and class_attr may be released, module_name and class_name are possible freed, Causing Access released Memory/Use After Free.
Prove of Content(POC):
static *
poc(PyObject * object) {
PyObject * module_attr = PyObject_GetAttrString(object, "__class__");
char * module_name = NULL;
if (module_attr) {
PyObject *name_attr = PyObject_GetAttrString(module_attr, "__name__");
if (name_attr) {
module_name = (char *)PyUnicode_1BYTE_DATA(name_attr);
Py_DECREF(name_attr);
Py_DECREF(module_attr);
printf("%s", module_name);
}
}
return PyLong_FromLong(0);
}
And this is the correct result.
However, If the garbege collect was triggered between Py_DECREF(object) and usage of string module_name, things will become troublesome.
static *
poc(PyObject * object) {
PyObject * module_attr = PyObject_GetAttrString(object, "__class__");
char * module_name = NULL;
if (module_attr) {
PyObject *name_attr = PyObject_GetAttrString(module_attr, "__name__");
if (name_attr) {
module_name = (char *)PyUnicode_1BYTE_DATA(name_attr);
Py_DECREF(name_attr);
Py_DECREF(module_attr);
call_gc_collect();
printf("%s\n", module_name);
}
}
return PyLong_FromLong(0);
}
void call_gc_collect() {
PyObject *gc_module = PyImport_ImportModule("gc");
if (gc_module) {
PyObject *gc_collect = PyObject_GetAttrString(gc_module, "collect");
if (gc_collect && PyCallable_Check(gc_collect)) {
PyObject *result = PyObject_CallObject(gc_collect, NULL);
Py_XDECREF(result);
}
Py_XDECREF(gc_collect);
Py_DECREF(gc_module);
}
}
This is the result:
Finding that module_name has been freed. In this case, I manually call gc.collect() to explain it. In real python environment, GC could free module_name at any time, Causing Use After Free Bug.
How to Fix: I think it's better to use these string before Py_DECREF:
{
PyObject * class_attr = PyObject_GetAttrString(_pymsg, "__class__");
if (class_attr) {
PyObject * name_attr = PyObject_GetAttrString(class_attr, "__name__");
if (name_attr) {
class_name = (char *)PyUnicode_1BYTE_DATA(name_attr);
}
PyObject * module_attr = PyObject_GetAttrString(class_attr, "__module__");
if (module_attr) {
module_name = (char *)PyUnicode_1BYTE_DATA(module_attr);
}
if (!class_name || !module_name) {
return false;
}
snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", module_name, class_name);
Py_XDECREF(module_attr);
Py_XDECREF(name_attr);
Py_DECREF(class_attr);
}
}
Bug Type: Non-Zero Dead Object/Memory Leak
File: _msg_support.c.em
Commit: https://github.com/ros2/rosidl_python/blob/1fbd99b5fe1fa04674c73e7e5992ccc88e28157c/rosidl_generator_py/resource/_msg_support.c.em#L538
Detail: If _pymessage has been correctly allocated, function may return NULL without freeing _pymessage, Causing Non-Zero Dead Object/Memory Leak.
field = PyObject_GetAttrString(_pymessage, "@(member.name)");
if (!field) {
return NULL;
}
Detail: if PyObject_GetAttrString fail and return NULL, function will return NULL causing _pymessage leak.
Same in any code block fail and return NULL or false: https://github.com/ros2/rosidl_python/blob/1fbd99b5fe1fa04674c73e7e5992ccc88e28157c/rosidl_generator_py/resource/_msg_support.c.em#L576-L579
Fix: I think it's better to add Py_DECREF(_pymessage) before return NULL;
- 主要言語
- EmberScript
- スター
- 26
- フォーク
- 68
- 平均マージ
- 1日 9時間
- マージ済み PR(30日)
- 3
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
ros2/rosidl_python のほかの issue
-
Eliminate array resetting loop in _msg_support.c.em対応中かも @Lidang-Jiang が 169 日前に担当しました。 オープンenhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
ros2/rosidl_python#255 · リアクション 1 件 ·
-
bug
難易度 3/5 1〜2日 初心者へのやさしさ 56/100
ros2/rosidl_python#264 · コメント 2 件 ·
-
Message named pkg/Duration with field builtin_interfaces/Duration is invalid対応中かも @Lidang-Jiang が 168 日前に担当しました。 オープンbug
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
ros2/rosidl_python#257 · コメント 8 件 ·
-
enhancement
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
ros2/rosidl_python#242 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 32/100
ros2/rosidl_python#219 · コメント 2 件 ·
ros2/rosidl_python の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
NationalSecurityAgency/ghidra#9883 ·
メンテナーはふだん 2 日以内に返信
-
good first issue No-AI
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
Frontmatter next to `src:` is applied to every imported slide, not only the first (undocumented)オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
bug needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
Fission-AI/OpenSpec#2084 ·
メンテナーはふだん 2 日以内に返信
-
[scanner] check:spelling skips blog/ — posts and author metadata are never spell-checked対応中かも @hivecommons-hive が今日担当しました。 オープンagent/scanner bug hive/covered-by-pr hive/hosted-available-lke648397-260827-5n31
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
cncf/endusers#1452 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信