
Apache Spark 4.2.0 - عالي - عن بُعد - بقايا صلاحيات - خريطة مصدر بيانات Python على مستوى العملية
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-python-ds-static
الفئة: صلاحية متبقية الوصول: عن بُعد
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
DataSourceManager.dataSourceBuilders هي خريطة على مستوى JVM يفوز فيها الأول. يسجّل SPARK-45917 تلقائيًا مصادر بيانات Python من نوع pyspark_* من sys.path الخاص بعامل البحث. يحافظ عزل جلسة Connect على المخرجات تحت SparkFiles/<sessionUUID>/، ويبقى registerPython لكل جلسة على runtimeDataSourceBuilders. لا يزال البحث الأول يضع دليل SparkFiles الخاص بالجلسة المُطلِقة على sys.path، ويُسلسل (pickle) كل DefaultSource، ويخزّن تلك الأصناف في الكائن المرافق. لاحقًا، تشغيل Connect SQL (أو Hive Thrift SQL) لـ read.format(name) / USING name ينفّذ ذلك الصنف بصفته Spark UID دون إرسال Python proto.
الزارع هو مستأجر Connect Python مسموح له أصلًا باستخدام Python. الضحية هو مستأجر SQL فقط على نفس مشغّل Connect. تبقى الأسماء المستعارة في Java (parquet، csv، json، orc، jdbc) على مسار ServiceLoader الخاص بـ Java. الزرعات اللاحقة بعد امتلاء الخريطة لا تُحدَّث. AC:H هو البحث الأول بالإضافة إلى اسم ليس اسمًا مستعارًا في Java.
| ID | لا يوجد CVE بعد |
| الفئة | صلاحية متبقية (مصدر بيانات Python عبر الجلسات بصفته Spark UID؛ وليس إرسال مهمة دون مصادقة) |
| الوصول | عن بُعد (مشغّل Spark Connect مشترك) |
| CWE | CWE-269، CWE-502 |
| CVSS | مرتفع: 8.8 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H |
| المنتج | Apache Spark |
| المتأثر | 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) السجل الثابت لمصادر بيانات Python |
| المصادقة | مستأجر Connect Python (الزارع) بالإضافة إلى مستخدم Connect SQL فقط / Hive Thrift SQL لاحقًا (الضحية) |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1:18970 فقط. ملف الشاهد. أداة الخريطة المرافقة. |
احتفظ بجلسة Spark Connect Python على مشغّل مشترك. ازرع pyfiles/pyspark_<name>.py بحيث يكون DefaultSource.name() الخاص به اسمًا مختصرًا لموصل غير موجود (delta، iceberg، hudi، ...). أطلق أول بحث عن مصدر بيانات Python على تلك الجلسة. كل جلسة لاحقة في نفس JVM تقوم بـ read.format(name) أو SQL USING name تُنشئ الصنف المُسلسل بصفته Spark UID على عامل مخطط المشغّل وعلى المنفّذات.
هذه هي مجموعة الصلاحيات الكاملة. الزارع يشغّل Python بالفعل. المتبقي هو أن مستأجر SQL فقط، لم يرسل قط REGISTER_DATA_SOURCE / Python UDF proto، لا يزال ينفّذ ذلك الصنف.
| الطريقة | المصب | الصلاحية |
|---|---|---|
الزارع: AddArtifacts باسم pyfiles/pyspark_<name>.py ثم أول format(name) / بحث | المرافق DataSourceManager.dataSourceBuilders (كائن DataSourceManager.scala) بالإضافة إلى lookup_data_sources.py iter_modules لـ pyspark_* | تخزين DefaultSource المُسلسل للجلسة المُطلِقة على مستوى JVM. المختبر: layer='static' trigger='attacker' first-wins=yes. |
الضحية: SQL USING <name> / spark.read.format(name) على جلسة لم تزرع قط | PythonDataSourceV2 createDataSourceInPython | تنفيذ ذلك الصنف بصفته Spark UID. المختبر: planted_by='attacker' witness_written=True static-cross-session=yes. ملف Oracle يحتوي على SPARK-PYTHON-DS-STATIC-WITNESS. |
| الطريقة | المصب | النتيجة |
|---|---|---|
| زرع لاحق لاسم ثانٍ بعد امتلاء الخريطة | نفس الخريطة الثابتة | مُغلق. يفوز الأول. المختبر: later-lookup found=False، المرافق لا يزال delta فقط. |
registerPython("alpha") لكل جلسة | runtimeDataSourceBuilders | معزول. النسخة تنسخ وقت التشغيل فقط. المختبر: runtime-isolated=yes. قراءة الضحية لـ alpha هي found=False. |
الاسم المستعار في Java parquet | Java DataSourceRegister ServiceLoader | مُغلق. المختبر: java-alias-closed=yes layer='java'. نفس الشيء لـ csv/json/orc/jdbc. |
| الطريقة | المصب | الصلاحية |
|---|---|---|
الضحية USING بعد الزرع | عاملو Python على المشغّل + المنفّذ | كود على مستوى العنقود بصفته Spark UID. يكتب المختبر ملف شاهد بدلًا من حمولة. |
| نفس المسار | انهيار / دوران العامل | التوافر بصفته Spark UID. ليس المرتفع. المرتفع هو تنفيذ الكود. |
Hive Thrift SQL USING على SparkSession مشترك | نفس الخريطة الثابتة | نفس المتبقي إذا شارك Thrift و Connect نفس JVM للمشغّل. لم يُختبر. |
parquet / csv / json / orc / jdbc. يفوز ServiceLoader.concatenatePaths يرفض .. والأسماء المطلقة).pythonExec المُقدَّم من العميل. يستخدم مخطط Connect خادم PYSPARK_PYTHON / python3.registerPython عبر الجلسات. خريطة وقت التشغيل لكل نسخة DataSourceManager.pyspark محلي أحادي المستخدم بجلسة واحدة. لا يوجد مستأجر آخر.ثبّتُ apache/spark v4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8). ثمانية وعشرون بحثًا في المصدر. إرسال مهمة ينفّذ كود المستخدم بحسب التصميم. History Jackson، وUI shell، وانتحال PySpark المحلي، ومسار استقبال RPC المستقل مُغلقة في هذا التقشير. تعزل مخرجات Connect ملفات pyfiles تحت UUID جلسة. registerPython في وقت التشغيل لكل جلسة. الكائن المرافق ليس كذلك.
يسجّل SPARK-45917 تلقائيًا حزم pyspark_* من PYTHONPATH. هذا مقصود للموصلات المثبّتة من المشغّل. المتبقي هو أن عامل البحث أيضًا يقوم بـ sys.path.insert لدليل SparkFiles الخاص بالجلسة المُطلِقة (worker_util.setup_spark_files)، ثم يُسلسل أي DefaultSource من pyspark_* يجده إلى خريطة على مستوى العملية لا تُحدَّث أبدًا.
منعطف خاطئ: اعتبار عزل registerPython هو حد المستأجر بالكامل. وقت التشغيل معزول. الثابت ليس كذلك.
cd lab
./run.sh
Loopback 127.0.0.1:18970. مشروع Compose spark-python-ds-static. الشاهد SPARK-PYTHON-DS-STATIC-WITNESS. أداة Python لكائن DataSourceManager بالإضافة إلى خرائط وقت التشغيل لكل جلسة. ازرع pyspark_delta.py فقط في SparkFiles الخاص بالمهاجم. بحث المهاجم يملأ المرافق. الزرع اللاحق لـ iceberg لا يُحدَّث. قراءة الضحية لـ delta تكتب الـ oracle. registerPython("alpha") لا يتسرب. Java parquet يبقى Java.
السطر الأخير:
SUCCESS SPARK-PYTHON-DS-STATIC static-cross-session=yes runtime-isolated=yes first-wins=yes java-alias-closed=yes SPARK-PYTHON-DS-STATIC-WITNESS
لا تضع SparkFiles الخاص بالجلسة على sys.path لعامل البحث عند ملء الخريطة الثابتة. حمّل حزم PYTHONPATH الخاصة بالمشغّل فقط (SPARK-45917 كما هو مصمم). أو اجعل مفتاح الخريطة الثابتة حسب الجلسة / UUID الخاص بـ JobArtifactSet، بالطريقة التي تكون بها المخرجات بالفعل. يجب ألا يثبّت الملء الفارغ الذي يفوز فيه الأول أصناف مستأجر آخر طوال عمر المشغّل.
حتى ذلك الحين، لا تشارك مشغّل Connect بين مستأجر Python ومستأجر SQL فقط لن تثق به أصلًا في Python الخاص بالمشغّل.