تم إعداد ترجمة لهذه المقالة خصيصًا لطلاب دورة Linux Administrator .
يتم استخدام القدرات أكثر وأكثر بفضل جزء كبير إلى SystemD ، Docker ، وأوركسترا مثل Kubernetes. ولكن ، كما يبدو لي ، من الصعب قليلاً فهم الوثائق وبعض أجزاء تنفيذ الامتيازات كانت مربكة إلى حد ما بالنسبة لي ، لذلك قررت أن أشارك معرفتي الحالية في هذا المقال القصير.

رابط الامتياز الأكثر أهمية هو صفحة
القدرات (7) . لكنها ليست مناسبة جدا للتعارف الأولي.
قدرات العملية
حقوق المستخدمين العاديين محدودة للغاية ، في حين أن حقوق المستخدم "الجذر" واسعة للغاية. على الرغم من أن العمليات التي تعمل كـ "الجذر" لا تتطلب غالبًا امتيازات الجذر.
لتقليل امتيازات المستخدم الجذر ، توفر أذونات POSIX (إمكانات POSIX) طريقة للحد من مجموعات عمليات النظام المتميزة التي يُسمح بتنفيذها العملية وأحفادها. في جوهرها ، فإنها تقسم جميع الحقوق "الجذر" إلى مجموعة من الامتيازات المنفصلة. تم وصف فكرة القدرات في عام 1997 في مسودة POSIX 1003.1e.
على نظام Linux ، تحتوي كل عملية (مهمة) على
خمسة أرقام (مجموعات)
64 بت تحتوي على وحدات بت إذن (قبل نظام Linux 2.6.25 كانت 32 بت) ، والتي يمكن عرضها في
/ proc / <pid> / status
.
CapInh: 00000000000004c0 CapPrm: 00000000000004c0 CapEff: 00000000000004c0 CapBnd: 00000000000004c0 CapAmb: 0000000000000000
هذه الأرقام (الموضحة هنا بترميز سداسي عشري) هي صور نقطية يتم تمثيل مجموعات الأذونات فيها. فيما يلي أسماءهم الكاملة:
- قابلية الوراثة - الأذونات التي يمكن أن يرثها أحفاد
- مسموح - أذونات يمكن استخدامها بواسطة المهمة.
- فعالة - أذونات فعالة الحالية
- Bounding - قبل Linux 2.6.25 ، كانت مجموعة الربط هي سمة على مستوى النظام مشتركة لجميع سلاسل العمليات ، مصممة لوصف مجموعة لا يمكن بعدها توسيع الأذونات. هذه مجموعة حاليًا لكل مهمة وهي جزء فقط من منطق execve ، التفاصيل أدناه.
- تمت إضافة Ambient (خارجي منذ Linux 4.3) لتسهيل توفير أذونات غير جذرية للمستخدم ، دون استخدام أذونات setuid أو ملف (المزيد حول ذلك لاحقًا).
إذا طلبت المهمة إجراء عملية مميزة (على سبيل المثال ، الربط بالمنافذ <1024) ، فإن النواة تتحقق من مجموعة الإحاطة الحالية لـ
CAP_NET_BIND_SERVICE . إذا تم تثبيته ، فستستمر العملية. خلاف ذلك ، يتم رفض العملية مع EPERM (العملية غير مسموح بها).
CAP_
في التعليمات البرمجية المصدر لـ kernel ويتم ترقيمها بالتسلسل ، لذا
CAP_NET_BIND_SERVICE
، تساوي 10 ، تعني البتة 1 << 10 = 0x400 (هذا هو الرقم السداسي عشر "4" في المثال السابق).
يمكن العثور على قائمة كاملة للقراءة من الامتيازات المعرفة حاليًا في صفحة
القدرات الحالية
(7) (القائمة هنا هي للإشارة فقط).
بالإضافة إلى ذلك ، هناك مكتبة libcap لتبسيط عمليات تدقيق الإدارة والتفويض. بالإضافة إلى
واجهة برمجة تطبيقات المكتبة ، تتضمن الحزمة الأداة المساعدة
capsh ، والتي تتيح لك ، من بين أشياء أخرى ، إظهار بيانات الاعتماد الخاصة بك.
هناك بعض النقاط المحيرة هنا:
- Current - يعرض الامتيازات الفعالة والموروثة والمتاحة لعملية capsh بالصيغة cap_to_text (3) . في هذا التنسيق ، يتم سرد الحقوق كمجموعات إذن
“capability[,capability…]+(e|i|p)”
، حيث تعني “e”
فعالة ، و “i”
موروثة ، و “p”
متوفرة. القائمة غير مفصولة برمز “,”
، كما قد تكون خمنت (cap_setgid+eip, cap_setuid+eip)
. تقسم الفاصلة الأذونات في مجموعة عمل واحدة. ثم يتم فصل قائمة مجموعات العمل الفعلية بمسافات. مثال آخر مع مجموعتي عمل سيكون “= cap_sys_chroot+ep cap_net_bind_service+eip”
. وكذلك مجموعتي الإجراءات “= cap_net_bind_service+e cap_net_bind_service+ip”
ستعمل على ترميز نفس القيمة مثل “cap_net_bind_service+eip”
. - يحد مجموعة / المحيطة مجموعة . لمزيد من الخلط ، يحتوي هذان السطحان فقط على قائمة الأذونات المحددة في هذه المجموعات ، مفصولة بمسافات. لا يتم استخدام تنسيق cap_to_text هنا ، لأنه لا يحتوي على مجموعات من الأذونات المتاحة والفعالة والموروثة ، ولكن مجموعة واحدة فقط (محيط / محيط).
- Securebits : يعرض إشارات securebits المهمة بالتنسيق العشري / الست عشري / بتنسيق Verilog (نعم ، الكل يتوقعها هنا ، وهذا واضح تمامًا من النقطة التي يقوم فيها كل مسؤول نظام ببرامج
FPGA
و ASIC
الخاصة بهم). ما يلي هو حالة securebits. يتم تعريف العلامات الفعلية على أنها SECBIT_*
في securebits.h ، ويتم أيضًا وصفها في الإمكانيات (7) . - تفتقر هذه الأداة المساعدة إلى عرض معلومات "NoNewPrivs" ، والتي يمكن عرضها في
/ proc / <pid> / status
. يتم ذكره فقط في prctl (2) ، على الرغم من أنه يؤثر بشكل مباشر على الحقوق عند استخدامها مع أذونات الملفات (بمزيد من التفاصيل أدناه). يتم وصف NoNewPrivs على النحو التالي: "مع no_new_privs
على 1 ، يعد execve (2) بعدم منح امتيازات لما لم يكن من الممكن القيام به دون استدعاء execve (2) (على سبيل المثال ، معالجة set-user-ID
، بت set-group-ID
وتعطيل معالجة أذونات الملفات) . بعد التثبيت ، لا يمكن إعادة تعيين سمة no_new_privs
. يتم توريث قيمة هذه السمة بواسطة أحفاد تم إنشاؤها من خلال شوكة (2) واستنساخ (2) وتخزينها من خلال execve (2). " تقوم Kubernetes بتعيين هذه العلامة على 1 عندما يكون allowPrivilegeEscalation خاطئًا في pod securityContext.
عند بدء عملية جديدة من خلال execve (2) ، يتم تحويل أذونات العملية التابعة باستخدام الصيغة المحددة في
القدرات (7) :
P'(ambient) = (file is privileged) ? 0 : P(ambient) P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & P(bounding)) | P'(ambient) P'(effective) = F(effective) ? P'(permitted) : P'(ambient) P'(inheritable) = P(inheritable) [ie, unchanged] P'(bounding) = P(bounding) [ie, unchanged] where: P() denotes the value of a thread capability set before the execve(2) - execve(2) P'() denotes the value of a thread capability set after the execve(2) - execve(2) F() denotes a file capability set -
تصف هذه القواعد الإجراءات التي يتم تنفيذها لكل بت في كل مجموعات الأذونات (المحيطة / المسموح بها / الفعالة / القابلة للتوريث / المحيط). يتم استخدام بناء جملة C القياسي (& - لـ AND ، | - لـ OR المنطقي). P 'هي عملية تابعة. P هي العملية الحالية التي تستدعي execve (2). F هو ما يسمى "أذونات الملفات" لملف تم إطلاقه من خلال execve.
بالإضافة إلى ذلك ، يمكن للعملية تغيير مجموعاتها الموروثة والوصول إليها والفعالة برمجيًا باستخدام libcap في أي وقت وفقًا للقواعد التالية:
- إذا لم يكن المتصل
CAP_SETPCAP
، يجب أن تكون المجموعة الموروثة الجديدة مجموعة فرعية من P (موروثة) و P (متوفرة) - (في نظام Linux 2.6.25) يجب أن تكون المجموعة الموروثة الجديدة مجموعة فرعية من P (ورثت) و P (الحد)
- يجب أن تكون المجموعة الجديدة المتاحة مجموعة فرعية من P (متوفرة)
- يجب أن تكون المجموعة الفعالة الجديدة مجموعة فرعية من P (فعالة)
أذونات الملف
في بعض الأحيان ، يحتاج المستخدم الذي لديه مجموعة محدودة من الحقوق إلى تشغيل ملف يتطلب المزيد من الامتيازات. تم تحقيق ذلك مسبقًا عن طريق تعيين بت setuid (
chmod + s ./executable
) في ملف ثنائي. مثل هذا الملف ، إذا كان ينتمي إلى الجذر ، فسيتمتع بحقوق الجذر الكاملة عند تنفيذه من قبل أي مستخدم.
ولكن هذه الآلية تمنح امتيازات كثيرة للملف ، لذا فقد طبقت أذونات POSIX مفهومًا يسمى "أذونات الملفات". يتم تخزينها
كسمات ملف ممتدة تسمى "security.capability" ، لذلك تحتاج إلى نظام ملفات مع دعم للسمات الموسعة (ext * ، XFS ، Raiserfs ، Brtfs ، overlay2 ، ...). لتغيير هذه السمة ،
CAP_SETFCAP
إذن
CAP_SETFCAP
(في المجموعة المتاحة من أذونات العملية).
$ getfattr -m - -d `which ping`
حالات خاصة وتعليقات
بالطبع ، في الواقع ، كل شيء ليس بهذه البساطة ، وهناك العديد من الحالات الخاصة الموضحة في صفحة
القدرات (7) . ربما أهمها:
- يتم تجاهل بت setuid وأذونات الملف إذا تم تثبيت NoNewPrivs أو تم تثبيت نظام الملفات مع nosuid أو تتبع عملية استدعاء execve بواسطة ptrace. يتم تجاهل أذونات الملفات أيضًا عند بدء تشغيل kernel باستخدام خيار
no_file_caps
. - الملف "الغبي" (capacity-dumb) هو ملف ثنائي يتم تحويله من ملف setuid إلى ملف له أذونات الملف ، ولكن دون تغيير الكود المصدر الخاص به. غالبًا ما يتم الحصول على هذه الملفات عن طريق تعيين أذونات + ep عليها ، على سبيل المثال ،
“setcap cap_net_bind_service+ep ./binary”
. الجزء المهم هو "ه" - فعالة. بعد التنفيذ ، ستتم إضافة هذه الأذونات إلى كل منها المتاحة والحالية ، لذلك سيكون الملف القابل للتنفيذ جاهزًا لاستخدام العملية المميزة. في المقابل ، يمكن لملف "القدرة الذكية" الذي يستخدم libcap أو وظيفة مشابهة استخدام cap_set_proc (3) (أو capset ) لتعيين البتات "الفعالة" أو "الموروثة" في أي وقت إذا كان هذا الإذن موجودًا بالفعل " مجموعة بأسعار معقولة. لذلك ، setcap cap_net_bind_service+p ./binary”
" setcap cap_net_bind_service+p ./binary”
كافيًا لملف "ذكي" ، لأنه سيكون قادرًا على تعيين الأذونات اللازمة في مجموعة فعالة نفسه قبل استدعاء عملية مميزة. انظر رمز عينة . - تستمر الملفات ذات الجذر setuid في العمل ، حيث تمنح كل امتيازات الجذر عندما يبدأ المستخدم كجذر. ولكن إذا كان لديهم مجموعة أذونات الملفات ، فسيتم منحها فقط. يمكنك أيضًا إنشاء ملف setuid مع مجموعة فارغة من الأذونات ، مما سيجعله يعمل كمستخدم له UID 0 دون أي أذونات. هناك حالات خاصة للمستخدم الجذر عند تشغيل ملف باستخدام setuid-root وتعيين أعلام bitbits المختلفة (انظر الرجل).
- تقوم مجموعة محيطية بإقناع الأذونات المتاحة ، ولكن ليست تلك الموروثة. تذكر P '(متوفر) = F (متوفر) و P (الحد). إذا كان للتيار دفق في مجموعته الموروثة وليس ضمن مجموعة الإحاطة ، فلا يزال بإمكانه الحصول على هذا الإذن في مجموعته المتاحة عن طريق تشغيل ملف له إذن في مجموعته الموروثة - P '(متوفر) = P ( ورثت) و F (ورثت).
- سيؤدي تنفيذ برنامج يغيّر UID أو GID من خلال معرّف مجموعة المستخدم أو بتات معرف مجموعة المعرفات أو تنفيذ برنامج لتعيين أي أذونات ملفات إليه إلى مسح المجموعة المحيطة . تتم إضافة أذونات إلى المجموعة المحيطة باستخدام
PR_CAP_AMBIENT
prctl . يجب أن تكون هذه الأذونات موجودة بالفعل في مجموعات العملية التي يمكن الوصول إليها والموروثة . - إذا تم تنفيذ عملية بمعرف UID بخلاف 0 (2) ، فسيتم حذف جميع الحقوق في مجموعاتها المتاحة والنشطة.
- إذا لم يتم تعيين
SECBIT_KEEP_CAPS
(أو SECBIT_NO_SETUID_FIXUP
الأوسع) ، وتغيير UID من 0 إلى صفر يزيل جميع الأذونات من المجموعات الموروثة ، التي يمكن الوصول إليها ، والفعالة .
لذلك ...
إذا كانت الحاوية nginx الرسمية ، أو ingress-nginx ، أو توقف أو أعيد تشغيلها مع وجود خطأ:
bind() to 0.0.0.0:80 failed (13: Permission denied)
... هذا يعني أنه كانت هناك محاولة للاستماع على المنفذ 80 كمستخدم غير مفضّل (وليس 0) ، ولم يكن هناك
CAP_NET_BIND_SERVICE
في
CAP_NET_BIND_SERVICE
الأذونات الحالية. للحصول على هذه الحقوق ، يجب استخدام xattr وتعيين (باستخدام
setcap
) للحصول على إذن ملف nginx على الأقل
cap_net_bind_service+ie
. سيتم دمج إذن الملف هذا مع المجموعة القديمة (المحددة مع مجموعة الربط من pod SecurityContext / capacity / add / NET_BIND_SERVICE) ، وسيتم وضعها أيضًا في مجموعة الأذونات المتاحة. والنتيجة هي
cap_net_bind_service+pie
.
يعمل كل هذا طالما أن securityContext / allowPrivilegeEscalation مضبوط على "صحيح" ويدعم برنامج تشغيل وحدة التخزين / عامل التخزين (انظر وثائق عامل ميناء) xattrs.
إذا كانت nginx ذكية فيما يتعلق بالأذونات ، فستكون
cap_net_bind_service+i
كافية. ثم يمكنه استخدام libcap لتوسيع الحقوق من المجموعة المتاحة إلى فعالة. تلقيت نتيجة لذلك
cap_net_bind_service+pie
.
إلى جانب استخدام xattr ، فإن الطريقة الوحيدة للحصول على
cap_net_bind_service
في حاوية غير الجذر هي السماح لـ Docker بتعيين إمكاناته الخارجية (القدرات المحيطة). ولكن اعتبارًا من أبريل 2019 ،
لم يتم
تنفيذ ذلك بعد.
أمثلة التعليمات البرمجية
إليك نموذج التعليمات البرمجية باستخدام libcap لإضافة
CAP_NET_BIND_SERVICE
إلى مجموعة أذونات فعالة. يتطلب إذن
CAP_BIND_SERVICE+p
للملف الثنائي.
المراجع (المهندس):