> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# صلاحيات الملفات Permissions في Linux وأخطاؤها الشائعة
- URL: https://arabroot.io/articles/صلاحيات-الملفات-في-linux-واخطاؤها/
- Published: 2026-10-06T06:45:00.000Z
- Updated: 2026-10-09T09:43:37.000Z
- Description: ماذا تعني الحروف rwx، ولماذا تظهر رسالة Permission denied، وكيف تصلحها دون أن تلجأ إلى chmod 777.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, الشبكات والبنية التحتية, لينكس والسيرفرات, Docker والحاويات, الاستضافة الذاتية

أكثر رسالة خطأ سوف تراها على سيرفر Linux هي `Permission denied`: سكربت كتبته للتو ولا يعمل، وContainer يتوقف لأنه لا يستطيع الكتابة في مجلد بياناته، وملف إعداد نسخته بنفسك ولا تستطيع تعديله، ومفتاح SSH يرفضه السيرفر دون سبب واضح. وأول ما يفعله كثير من الناس عندها هو `chmod 777`، فيختفي الخطأ ويظهر بدلاً منه ثغرة لا يراها أحد. وفي [مقال سطر الأوامر](https://arabroot.io/articles/%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A7%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-linux-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/) تجاوزنا الحروف `rwx` التي تظهر في أول كل سطر من `ls -l`، أما هذا المقال فيشرحها حرفاً حرفاً، لأنها القاعدة التي يبني عليها النظام كله قراره: من يقرأ هذا الملف، ومن يعدله، ومن يشغله.

وسوف نناقش في هذا المقال ما يلي:

- المستخدمون والمجموعات وأرقامهم UID وGID، لأن الصلاحيات تعتمد على الأرقام لا على الأسماء.
- قراءة سطر `ls -l`، ومعنى r وw وx على الملف وعلى المجلد، وهما مختلفان أكثر مما تتوقع.
- الترتيب الذي تفحص به النواة الصلاحيات، ولماذا قد يمنع المالك من ملف يقرؤه غيره.
- الصيغة الرقمية Octal مثل 755 و640، والأوامر `chmod` و`chown` و`chgrp`.
- القناع umask الذي يحدد صلاحيات كل ملف جديد.
- البتات الخاصة: setuid وsetgid والبت اللاصق Sticky Bit على `/tmp`.
- قوائم التحكم في الوصول ACL باختصار، والفرق بين sudo والعمل بحساب root.
- الأخطاء الشائعة: `chmod 777`، وPermission denied في Docker Volume، والمالك الخطأ بعد النسخ، وصلاحية التشغيل على السكربتات.

وهذا المقال من [مرحلة أساسيات Linux](https://arabroot.io/start/#stage-linux)، أما إدارة المستخدمين والمجموعات نفسها وإعداد sudo وما تفعله عندما يغادر مسؤول النظام فلها عنصر مستقل في المرحلة نفسها، لذلك سوف نذكر منها هنا ما تحتاجه لفهم الصلاحيات فقط.

## تجهيز المختبر Lab

كما في المقال السابق، سوف ننفذ كل شيء داخل Container من Docker Image موجودة عندنا هي `postgres:18`، ونستخدم منها نظام Debian 13 وأدواته فقط، وننشئ فيه مستخدمين اثنين حتى نرى ما يراه كل منهما:

```bash
docker run -d --name lab-linux-perm --hostname lab --entrypoint sleep postgres:18 infinity
docker exec -it lab-linux-perm bash
```

ثم ننشئ داخل ال Container مجموعة اسمها `devs`، والمستخدمة `sara` وهي عضو فيها، والمستخدم `omar` وهو ليس عضواً فيها:

```text
$ groupadd devs
$ useradd -m -s /bin/bash -G devs sara
$ useradd -m -s /bin/bash omar
$ id sara
uid=1000(sara) gid=1001(sara) groups=1001(sara),1000(devs)
$ id omar
uid=1001(omar) gid=1002(omar) groups=1002(omar)
$ grep -E '^(sara|omar)' /etc/passwd
sara:x:1000:1001::/home/sara:/bin/bash
omar:x:1001:1002::/home/omar:/bin/bash
$ grep -E '^(devs|sara|omar)' /etc/group
devs:x:1000:sara
sara:x:1001:
omar:x:1002:
$ ls -ld /home/sara /home/omar
drwx------ 2 omar omar 4096 Oct  7 05:31 /home/omar
drwx------ 2 sara sara 4096 Oct  7 05:31 /home/sara
$ grep -E '^(HOME_MODE|UMASK)' /etc/login.defs
HOME_MODE       0700
```

في الإعداد أعلاه لاحظ التالي:

- لكل مستخدم رقم UID، ولكل مجموعة رقم GID، ولكل مستخدم مجموعة رئيسية Primary Group تحمل اسمه في العادة، ثم مجموعات إضافية Supplementary Groups مثل `devs` لسارة. والنواة Kernel لا تعرف الأسماء أصلاً، وإنما تخزن مع كل ملف رقم مالكه ورقم مجموعته، والأسماء تأتي من `/etc/passwd` و`/etc/group` عند العرض فقط.
- أنشأ `useradd` مجلد كل مستخدم بالصلاحيات `drwx------`، أي لصاحبه وحده، والسبب الإعداد `HOME_MODE 0700` في `/etc/login.defs` على Debian 13، فعمر لا يستطيع أن يرى ما في مجلد سارة. وهذا يختلف بين التوزيعات والإصدارات، فافحص مجلدات المستخدمين على سيرفرك.
- سوف ترى في المخرجات أوامر نفذناها بحساب root وأخرى بحساب سارة أو عمر، وسوف نذكر في كل مرة من الذي ينفذ الأمر. ورسائل Bash التي تبدأ ب `/usr/local/bin/run.sh: line 7:` سببها السكربت الذي شغلنا به الأوامر بالترتيب، وفي طرفيتك تبدأ ب `bash:`.

## قراءة سطر ls -l

أنشأت سارة في مجلدها سكربتاً صغيراً اسمه `deploy.sh` ومجلداً اسمه `site`، ثم عرضتهما ب `ls -l`، وب `stat` الذي يعرض الصلاحيات بالحروف وبالأرقام معاً:

```text
$ printf '#!/bin/bash\necho "deploying..."\n' > deploy.sh
$ mkdir site
$ ls -l
total 8
-rw-r--r-- 1 sara sara   32 Oct  7 05:32 deploy.sh
drwxr-xr-x 2 sara sara 4096 Oct  7 05:32 site
$ stat -c '%A %a %U %G %n' deploy.sh site
-rw-r--r-- 644 sara sara deploy.sh
drwxr-xr-x 755 sara sara site
```

والصورة التالية تفكك السطر الأول بعد أن نعطيه الصلاحية 750 كما سيأتي:

![السطر -rwxr-x--- 1 sara devs deploy.sh مقسماً إلى خانات: حرف النوع، ثم ثلاث خانات للمالك rwx وثلاث للمجموعة r-x وثلاث للآخرين ---، وتحت كل خانة قيمتها 4 و2 و1، ومجموع كل ثلاثية 7 و5 و0 أي chmod 750، وتحتها جدول معنى r وw وx على الملف وعلى المجلد، وجدول البتات الخاصة setuid وsetgid وsticky التي تظهر مكان x](https://arabroot.io/content/images/2026/10/linux-permissions-01-mode-bits.webp)

عشرة حروف: النوع، ثم ثلاث خانات لكل من المالك والمجموعة والآخرين

- **الحرف الأول هو النوع:** `-` ملف عادي، و`d` مجلد Directory، و`l` رابط رمزي Symbolic Link.
- **الخانات الثلاث التالية للمالك User** ورمزه `u`، وهو المستخدم المذكور في العمود الثالث.
- **الثلاث التي بعدها للمجموعة Group** ورمزها `g`، وهي المجموعة المذكورة في العمود الرابع.
- **الثلاث الأخيرة للآخرين Others** ورمزهم `o`، أي كل مستخدم ليس المالك وليس عضواً في المجموعة.
- وفي كل ثلاثية: `r` للقراءة Read، و`w` للكتابة Write، و`x` للتشغيل Execute، والشرطة تعني أن الصلاحية غير موجودة.

### r وw وx على المجلد Directory

على الملف المعنى واضح: r تقرأ محتواه، وw تعدله، وx تشغله كبرنامج. أما المجلد فهو في الحقيقة قائمة أسماء، وكل اسم يشير إلى ملف، لذلك فإن r على المجلد تعني أن تقرأ قائمة الأسماء فقط، وx تعني أن تدخله وتصل إلى الملفات التي فيه إذا عرفت أسماءها، وw تعني أن تضيف أسماء إلى القائمة أو تحذفها أو تغيرها، أي أن تنشئ ملفات وتحذفها وتعيد تسميتها، كما تشرح صفحة الدليل [path\_resolution(7)](https://man7.org/linux/man-pages/man7/path%5Fresolution.7.html?ref=arabroot.io). ولنرى ذلك في التجربة، أنشأت سارة مجلداً فيه ملف، ثم غيرت صلاحيات المجلد ثلاث مرات:

```text
$ mkdir box && echo "secret plan" > box/plan.txt
$ chmod 600 box
$ ls -ld box
drw------- 2 sara sara 4096 Oct  7 05:34 box
$ ls box
plan.txt
$ cat box/plan.txt
cat: box/plan.txt: Permission denied
$ chmod 100 box
$ ls box
ls: cannot open directory 'box': Permission denied
$ cat box/plan.txt
secret plan
$ chmod 500 box
$ touch box/new.txt
touch: cannot touch 'box/new.txt': Permission denied
$ rm box/plan.txt
rm: cannot remove 'box/plan.txt': Permission denied
$ chmod 700 box
```

في الإعداد أعلاه لاحظ التالي:

- مع `rw-` فقط استطاعت أن ترى اسم الملف `plan.txt`، لكنها لم تستطع قراءته مع أن الملف نفسه يسمح لها بالقراءة، والسبب أن الوصول إلى أي ملف يحتاج x على كل مجلد في الطريق إليه.
- مع `--x` فقط انعكس الوضع: لا تستطيع أن ترى ما في المجلد، لكنها قرأت الملف لأنها تعرف اسمه.
- مع `r-x` قرأت ودخلت، لكنها لم تستطع إنشاء ملف ولا حذف ملف، فالحذف يحتاج w على المجلد لا على الملف، وهذه نقطة سوف نعود إليها في الأخطاء الشائعة.

ولهذا السبب فإن المجلدات تأخذ عادة 755 أو 750 أو 700، أي أن x موجودة دائماً مع r، والمجلد الذي فيه r دون x لا فائدة منه تقريباً.

## من يطبق عليه أي جزء؟ ترتيب الفحص في النواة Kernel

عندما تحاول عملية أن تفتح ملفاً، لا تجمع النواة صلاحيات المالك والمجموعة والآخرين، وإنما تختار ثلاثية واحدة فقط بهذا الترتيب كما تشرح صفحة [path\_resolution(7)](https://man7.org/linux/man-pages/man7/path%5Fresolution.7.html?ref=arabroot.io): إذا كانت العملية تعمل بحساب مالك الملف تطبق ثلاثية المالك، وإلا فإذا كانت مجموعة الملف من مجموعات العملية تطبق ثلاثية المجموعة، وإلا تطبق ثلاثية الآخرين. وحساب root يتجاوز هذا الفحص كله، مع استثناء واحد هو أن التشغيل يحتاج x واحدة على الأقل في أي من الثلاثيات. والصورة التالية تبين الترتيب:

![مخطط تدفق لعملية cat تعمل بحساب sara: هل العملية root؟ إذا نعم فمسموح، وإلا هل هي مالكة الملف؟ إذا نعم تستخدم صلاحيات المالك وتتوقف هنا حتى لو كانت المجموعة أو الآخرون يسمحون بأكثر، وإلا هل هي في مجموعة الملف؟ إذا نعم تستخدم صلاحيات المجموعة، وإلا صلاحيات الآخرين. وعلى اليمين مثال الملف ----rwxrwx الذي تملكه sara فترفض قراءته بينما يقرؤه omar](https://arabroot.io/content/images/2026/10/linux-permissions-02-check-order.webp)

ثلاثية واحدة فقط تطبق، وأولها الذي ينطبق

والمثال على اليمين في الصورة من مختبرنا: أنشأت سارة ملفاً في `/tmp` وأعطته الصلاحيات 077، أي لا شيء للمالك وكل شيء للمجموعة والآخرين:

```text
$ echo "for everyone except me" > /tmp/odd.txt
$ chmod 077 /tmp/odd.txt
$ ls -l /tmp/odd.txt
----rwxrwx 1 sara sara 23 Oct  7 05:34 /tmp/odd.txt
$ cat /tmp/odd.txt
cat: /tmp/odd.txt: Permission denied
```

ثم قرأه عمر دون مشكلة:

```text
$ whoami
omar
$ cat /tmp/odd.txt
for everyone except me
$ ls /home/sara
ls: cannot open directory '/home/sara': Permission denied
```

سارة هي المالكة، فطبقت عليها ثلاثية المالك وهي فارغة، ولم تنظر النواة إلى ما بعدها، أما عمر فليس المالك ولا عضواً في مجموعة `sara` فطبقت عليه ثلاثية الآخرين. وهذا المثال غريب عمداً، لكن الحالة نفسها تحدث في الواقع بشكل أهدأ، مثل ملف صلاحياته 604 يقرؤه الجميع إلا أعضاء مجموعته. ولاحظ أن سارة تستطيع دائماً إعادة الصلاحيات بالأمر `chmod` لأنها المالكة.

## تغيير الصلاحيات بالأمر chmod

للأمر [chmod](https://man7.org/linux/man-pages/man1/chmod.1.html?ref=arabroot.io) صيغتان: الصيغة الرقمية Octal، والصيغة الرمزية Symbolic.

في الصيغة الرقمية لكل صلاحية قيمة: r تساوي 4، وw تساوي 2، وx تساوي 1، وتجمع قيم كل ثلاثية في رقم واحد من 0 إلى 7، فتكتب ثلاثة أرقام للمالك ثم المجموعة ثم الآخرين. ف `rwx` تساوي 7، و`r-x` تساوي 5، و`r--` تساوي 4، و`---` تساوي 0، وبالتالي فإن `rwxr-x---` هي 750\. وهذه القيم التي سوف تكتبها أغلب الوقت:

| القيمة | الحروف    | الاستخدام                                                     |
| ------ | --------- | ------------------------------------------------------------- |
| 644    | rw-r--r-- | ملف عادي يقرؤه الجميع ويعدله المالك، مثل ملفات الموقع الثابتة |
| 640    | rw-r----- | ملف إعداد يقرؤه أعضاء مجموعة الخدمة فقط                       |
| 600    | rw------- | الأسرار: ملف .env والمفتاح الخاص لSSH                         |
| 755    | rwxr-xr-x | مجلد عام، أو سكربت يشغله الجميع                               |
| 750    | rwxr-x--- | مجلد أو سكربت للمالك ومجموعته فقط                             |
| 700    | rwx------ | مجلد خاص، مثل \~/.ssh                                         |

أما الصيغة الرمزية فتغير جزءاً محدداً وتترك الباقي كما هو: تختار الفئة `u` أو `g` أو `o` أو `a` للجميع، ثم `+` للإضافة أو `-` للحذف أو `=` للتحديد الكامل، ثم الصلاحيات. والمثال التالي يبين الصيغتين على السكربت نفسه:

```text
$ ./deploy.sh
/usr/local/bin/run.sh: line 7: ./deploy.sh: Permission denied
$ chmod u+x deploy.sh
$ ./deploy.sh
deploying...
$ ls -l deploy.sh
-rwxr--r-- 1 sara sara 32 Oct  7 05:32 deploy.sh
$ chmod 750 deploy.sh
$ ls -l deploy.sh
-rwxr-x--- 1 sara sara 32 Oct  7 05:32 deploy.sh
$ chmod u=rw,g=r,o= deploy.sh
$ ls -l deploy.sh
-rw-r----- 1 sara sara 32 Oct  7 05:32 deploy.sh
```

والقاعدة العملية أن الصيغة الرقمية مناسبة عندما تعرف النتيجة النهائية التي تريدها، والرمزية مناسبة عندما تريد تغيير صلاحية واحدة دون أن تلمس الباقي، مثل `chmod +x` على سكربت.

### chmod -R والحرف X الكبير

الخيار `-R` يطبق الصلاحيات على المجلد وكل ما فيه، وهنا خطأ يقع فيه كثيرون: الملفات تحتاج 640 مثلاً والمجلدات تحتاج 750، فإذا طبقت 640 على الشجرة كلها نزعت x من المجلدات فلم يعد أحد يستطيع دخولها، حتى أنت. والمثال التالي من المختبر يبين ذلك، ثم يبين الحل بالحرف `X` الكبير الذي يعني «أعط x للمجلدات، وللملفات التي فيها x أصلاً»:

```text
$ mkdir -p www/css && touch www/index.html www/css/site.css
$ chmod -R 640 www
chmod: cannot access 'www/index.html': Permission denied
chmod: cannot access 'www/css': Permission denied
$ ls -l www
ls: cannot access 'www/index.html': Permission denied
ls: cannot access 'www/css': Permission denied
total 0
d????????? ? ? ? ?            ? css
-????????? ? ? ? ?            ? index.html
$ chmod -R u=rwX,g=rX,o= www
$ ls -lR www
www:
total 4
drwxr-x--- 2 sara sara 4096 Oct  7 05:44 css
-rw-r----- 1 sara sara    0 Oct  7 05:44 index.html

www/css:
total 0
-rw-r----- 1 sara sara 0 Oct  7 05:44 site.css
```

غير `chmod` صلاحيات المجلد `www` نفسه أولاً إلى `rw-r-----`، فلم يعد يستطيع الدخول إليه ليكمل على ما فيه، ثم أظهر `ls -l` علامات الاستفهام لأنه يرى الأسماء (بفضل r) ولا يستطيع الوصول إلى الملفات لمعرفة تفاصيلها (لغياب x). والصيغة `u=rwX,g=rX,o=` أصلحت الشجرة في أمر واحد، فأخذت المجلدات 750 والملفات 640.

## تغيير المالك Owner والمجموعة Group بالأمرين chown وchgrp

الأمر [chown](https://man7.org/linux/man-pages/man1/chown.1.html?ref=arabroot.io) يغير مالك الملف ومجموعته بالصيغة `chown user:group file`، والأمر `chgrp` يغير المجموعة فقط. وهنا قاعدة تحددها النواة كما تشرح صفحة [chown(2)](https://man7.org/linux/man-pages/man2/chown.2.html?ref=arabroot.io): لا يستطيع تغيير مالك الملف إلا root، أما المالك فيستطيع أن يغير مجموعة ملفه إلى أي مجموعة هو عضو فيها فقط. والمثال التالي نفذته سارة:

```text
$ touch report.txt
$ chown omar report.txt
chown: changing ownership of 'report.txt': Operation not permitted
$ chgrp devs report.txt
$ chgrp omar report.txt
chgrp: changing group of 'report.txt': Operation not permitted
$ ls -l report.txt
-rw-r--r-- 1 sara devs 0 Oct  7 05:36 report.txt
```

ثم نفذ root الأمر نفسه فنجح:

```text
# chown omar:devs report.txt
# ls -l report.txt
-rw-r--r-- 1 omar devs 0 Oct  7 05:36 report.txt
```

لاحظ أن سارة استطاعت تغيير المجموعة إلى `devs` لأنها عضو فيها، ورفض النظام المجموعة `omar` لأنها ليست عضواً فيها. والخيار `-R` يعمل مع `chown` أيضاً، وسوف تستخدمه كثيراً مع مجلدات Docker كما سيأتي.

## صلاحيات كل ملف جديد والقناع umask

لم نحدد صلاحيات أي ملف أنشأناه حتى الآن، ومع ذلك أخذ كل ملف 644 وكل مجلد 755\. والسبب أن البرنامج الذي ينشئ الملف يطلب صلاحيات معينة، فالأمر `touch` يطلب 666 للملف والأمر `mkdir` يطلب 777 للمجلد، ثم تحذف النواة منها كل صلاحية مذكورة في القناع umask الخاص بالعملية، كما تشرح صفحة [umask(2)](https://man7.org/linux/man-pages/man2/umask.2.html?ref=arabroot.io). والصورة التالية تبين الحساب بتاً بتاً:

![ثلاث حالات: ملف جديد يطلب 666 والقناع 022 يحذف w من المجموعة والآخرين فتكون النتيجة 644 أي rw-r--r--، ومجلد جديد يطلب 777 والقناع 022 فتكون النتيجة 755 أي rwxr-xr-x، وملف جديد يطلب 666 والقناع 033 يحذف w وx من المجموعة والآخرين، ولأن x لم تكن مطلوبة أصلاً فالنتيجة 644 وليست 633](https://arabroot.io/content/images/2026/10/linux-permissions-03-umask.webp)

القناع يحذف ولا يطرح، لذلك 666 مع القناع 033 تعطي 644 وليس 633

والمثال التالي نفذته سارة بثلاث قيم للقناع:

```text
$ umask
0022
$ umask -S
u=rwx,g=rx,o=rx
$ touch a.txt; mkdir a-dir
$ ls -ld a.txt a-dir
drwxr-xr-x 2 sara sara 4096 Oct  7 05:36 a-dir
-rw-r--r-- 1 sara sara    0 Oct  7 05:36 a.txt
$ umask 077
$ touch b.txt; mkdir b-dir
$ ls -ld b.txt b-dir
drwx------ 2 sara sara 4096 Oct  7 05:36 b-dir
-rw------- 1 sara sara    0 Oct  7 05:36 b.txt
$ umask 033
$ touch c.txt; mkdir c-dir
$ ls -ld c.txt c-dir
drwxr--r-- 2 sara sara 4096 Oct  7 05:36 c-dir
-rw-r--r-- 1 sara sara    0 Oct  7 05:36 c.txt
$ umask 022
```

في الإعداد أعلاه لاحظ التالي:

- القناع 022 يحذف w من المجموعة والآخرين، وهو ما رأيناه في كل الملفات السابقة.
- القناع 077 يجعل كل ملف ومجلد جديد لصاحبه وحده، وهو مناسب للسكربت الذي ينشئ ملفات فيها أسرار أو نسخاً احتياطية، فتضعه في أول السكربت بدل أن تتذكر `chmod` بعد كل ملف.
- مع القناع 033 أخذ الملف 644 وليس 633 كما يتوقع من يطرح الأرقام، لأن x لم تكن مطلوبة أصلاً فلا يوجد ما يحذف. وأخذ المجلد 744، أي أن المجموعة والآخرين يرون الأسماء ولا يدخلون، وهي الحالة التي قلنا إنه لا فائدة منها.
- القناع خاص بكل عملية، يرثه البرنامج من الصدفة التي شغلته، والأمر `umask` يغيره للصدفة الحالية فقط، لذلك عدنا إلى 022 في آخر المثال.

والقناع لا يضيف صلاحية أبداً، فإذا أردت ملفاً تنفيذياً فعليك أن تضيف x بنفسك بالأمر `chmod +x`، أو تنشئه بالأمر [install -m 755](https://man7.org/linux/man-pages/man1/install.1.html?ref=arabroot.io) الذي يحدد الصلاحيات النهائية مباشرة.

## البتات الخاصة: setuid وsetgid والبت اللاصق Sticky Bit

بجانب التسع صلاحيات هناك ثلاثة بتات أخرى قيمها 4000 و2000 و1000، كما تشرح صفحة [inode(7)](https://man7.org/linux/man-pages/man7/inode.7.html?ref=arabroot.io)، وتكتب كرقم رابع قبل الثلاثة، مثل `chmod 2770`، وتظهر في `ls -l` مكان حرف x في إحدى الثلاثيات كما في جدول الصورة الأولى.

### البرنامج يعمل بصلاحيات مالكه مع setuid

عندما تغير كلمة مرورك بالأمر `passwd`، فإن البرنامج يكتب في الملف `/etc/shadow` الذي لا يستطيع قراءته إلا root، فكيف يفعل ذلك وأنت مستخدم عادي؟ والإجابة هي البت setuid: إذا كان موجوداً على ملف تنفيذي فإن البرنامج يعمل بصلاحيات مالك الملف لا بصلاحيات من شغله، كما تشرح صفحة [execve(2)](https://man7.org/linux/man-pages/man2/execve.2.html?ref=arabroot.io)، ومالك `passwd` هو root. والمثال التالي من المختبر بحساب root:

```text
$ ls -l /usr/bin/passwd /usr/bin/su /usr/bin/chage
-rwxr-sr-x 1 root shadow 113848 Apr 19  2025 /usr/bin/chage
-rwsr-xr-x 1 root root   118168 Apr 19  2025 /usr/bin/passwd
-rwsr-xr-x 1 root root    84360 Jul 31 15:34 /usr/bin/su
$ find / -xdev -perm -4000 -type f 2>/dev/null
/usr/bin/su
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/umount
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/passwd
/usr/bin/gpasswd
$ find / -xdev -perm -2000 -type f 2>/dev/null
/usr/sbin/unix_chkpwd
/usr/bin/chage
/usr/bin/expiry
```

في الإعداد أعلاه لاحظ التالي:

- الحرف `s` مكان x المالك في `passwd` و`su` هو setuid، والحرف `s` مكان x المجموعة في `chage` هو setgid على ملف، فيعمل البرنامج بصلاحيات المجموعة `shadow`.
- الأمر `find / -perm -4000` يعرض كل برامج setuid على النظام، وهي قائمة يجب أن تعرفها على سيرفرك، لأن كل برنامج فيها يعمل بصلاحيات root مهما كان من شغله، وأي ثغرة فيه تعطي المستخدم العادي صلاحيات root مباشرة.

📌

في 25 يناير 2022 نشر فريق Qualys تحليلاً لثغرة أسماها [PwnKit](https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034?ref=arabroot.io) برقم [CVE-2021-4034](https://nvd.nist.gov/vuln/detail/CVE-2021-4034?ref=arabroot.io)، في البرنامج `pkexec` من حزمة polkit، وهو برنامج setuid يملكه root ومثبت افتراضياً في كل التوزيعات الكبيرة. وكانت الثغرة موجودة منذ أول نسخة من `pkexec` في مايو 2009، أي أكثر من اثنتي عشرة سنة، وسمحت لأي مستخدم عادي بالحصول على صلاحيات root كاملة على التثبيت الافتراضي ل Ubuntu وDebian وFedora وCentOS. وكان الحل المؤقت الذي اقترحه الفريق لمن لم يصله التحديث هو نزع البت setuid من `pkexec`. والدرس أن كل برنامج setuid على سيرفرك باب محتمل إلى root، فاعرف قائمتها، ولا تضف إليها شيئاً، واحرص على التحديثات الأمنية.

ولا تحاول أن تجعل سكربت Bash يعمل بصلاحيات root عبر setuid، فقد جربنا ذلك في المختبر: أنشأ root سكربتاً يطبع رقم المستخدم الحقيقي والفعال وأعطاه 4755، ثم شغلته سارة (السطر الأخير):

```text
$ printf '#!/bin/bash\necho "real uid: $(id -ru)  effective uid: $(id -u)"\n' > /usr/local/bin/whoami-script.sh
$ chmod 4755 /usr/local/bin/whoami-script.sh
$ ls -l /usr/local/bin/whoami-script.sh
-rwsr-xr-x 1 root root 64 Oct  7 05:39 /usr/local/bin/whoami-script.sh

$ whoami-script.sh
real uid: 1000  effective uid: 1000
```

البت موجود، لكن السكربت عمل بحساب سارة، والسبب أن Linux «يتجاهل setuid وsetgid على السكربتات» كما تقول صفحة [execve(2)](https://man7.org/linux/man-pages/man2/execve.2.html?ref=arabroot.io). وإذا احتاج مستخدم أن يشغل سكربتاً معيناً بصلاحيات root، فالطريقة الصحيحة هي قاعدة في sudo تسمح له بهذا السكربت وحده.

وإذا رأيت `S` كبيرة بدل `s`، فهذا يعني أن البت الخاص موجود لكن x غير موجودة تحته، وهي غالباً خطأ لا معنى له، كما في هذا المثال بحساب root:

```text
$ touch /tmp/plain.txt && chmod u+s /tmp/plain.txt && ls -l /tmp/plain.txt
-rwSr--r-- 1 root root 0 Oct  7 05:39 /tmp/plain.txt
```

### مجلد مشترك لفريق مع setgid

على المجلد يعني setgid شيئاً آخر مفيداً جداً: كل ملف جديد في المجلد يأخذ مجموعة المجلد بدل المجموعة الرئيسية لمن أنشأه، وكل مجلد فرعي جديد يرث البت نفسه، كما يشرح [دليل GNU coreutils](https://www.gnu.org/software/coreutils/manual/html%5Fnode/Directory-Setuid-and-Setgid.html?ref=arabroot.io). وهذا ما تحتاجه لمجلد يعمل فيه فريق، والمثال التالي بحساب root في الأسطر الأربعة الأولى ثم سارة:

```text
$ mkdir /srv/team
$ chgrp devs /srv/team
$ chmod 2770 /srv/team
$ ls -ld /srv/team
drwxrws--- 2 root devs 4096 Oct  7 05:39 /srv/team

$ touch /srv/team/notes.md
$ mkdir /srv/team/drafts
$ ls -l /srv/team
total 4
drwxr-sr-x 2 sara devs 4096 Oct  7 05:39 drafts
-rw-r--r-- 1 sara devs    0 Oct  7 05:39 notes.md
```

الملف والمجلد الجديدان ملك سارة لكن مجموعتهما `devs` وليست `sara`، والمجلد الفرعي ورث البت `s`، أما عمر فليس عضواً في `devs` لذلك لا يستطيع حتى أن يرى ما في المجلد:

```text
$ ls /srv/team
ls: cannot open directory '/srv/team': Permission denied
```

ولاحظ أن الملف أخذ 644 بسبب القناع 022، أي أن بقية أعضاء الفريق يقرؤونه ولا يعدلونه، فإذا أردت أن يعدل الجميع ملفات بعضهم فاجعل القناع 002 لمن يعمل في هذا المجلد، أو استخدم ACL كما سيأتي.

### البت اللاصق Sticky Bit على /tmp

المجلد `/tmp` يكتب فيه كل المستخدمين، فصلاحياته `rwx` للجميع، ومعنى w على المجلد كما رأينا أن تحذف أي اسم فيه، فما الذي يمنع عمر من حذف ملفات سارة المؤقتة؟ والإجابة هي الحرف `t` في آخر صلاحياته:

```text
$ ls -ld /tmp
drwxrwxrwt 1 root root 4096 Oct  7 05:38 /tmp
```

البت اللاصق على المجلد يعني أن الملف فيه لا يحذف ولا يعاد تسميته إلا بيد مالك الملف أو مالك المجلد أو root، كما تشرح صفحة [inode(7)](https://man7.org/linux/man-pages/man7/inode.7.html?ref=arabroot.io). ولنرى حدوده، أنشأت سارة ملفاً في `/tmp` وأعطته 666:

```text
$ echo "sara's list" > /tmp/sara-list.txt
$ chmod 666 /tmp/sara-list.txt
$ ls -l /tmp/sara-list.txt
-rw-rw-rw- 1 sara sara 12 Oct  7 05:39 /tmp/sara-list.txt
```

ثم حاول عمر:

```text
$ echo "omar was here" >> /tmp/sara-list.txt
$ cat /tmp/sara-list.txt
sara's list
omar was here
$ rm /tmp/sara-list.txt
rm: cannot remove '/tmp/sara-list.txt': Operation not permitted
$ mv /tmp/sara-list.txt /tmp/mine.txt
mv: cannot move '/tmp/sara-list.txt' to '/tmp/mine.txt': Operation not permitted
```

البت اللاصق منع الحذف وإعادة التسمية، لكنه لم يمنع عمر من الكتابة داخل الملف، لأن هذا تحكمه صلاحيات الملف نفسه وهي 666\. والقاعدة أن البت اللاصق يحمي الاسم في المجلد، والصلاحيات تحمي المحتوى، فلا تعط ملفاً 666 في أي مكان.

⚠️

على سيرفر Ubuntu أو Debian يعمل ب systemd قد ترفض الإضافة `>>` التي نجحت في مختبرنا، والسبب الإعداد [fs.protected\_regular](https://docs.kernel.org/admin-guide/sysctl/fs.html?ref=arabroot.io) في النواة، الذي يمنع فتح ملف بالخيار O\_CREAT في مجلد لاصق يكتب فيه الجميع إذا لم يكن الملف ملك من يفتحه، ويضبطه systemd على 1 في [إعداداته الافتراضية](https://github.com/systemd/systemd/blob/main/sysctl.d/50-default.conf?ref=arabroot.io). أما نواة Docker Desktop التي جربنا عليها فقيمته فيها 0، ولذلك نجحت الكتابة. وهذه حماية إضافية لا تغني عن الصلاحيات الصحيحة.

## قوائم التحكم في الوصول ACL باختصار

الصلاحيات الأساسية تعطيك مالكاً واحداً ومجموعة واحدة، فماذا تفعل إذا أردت أن يقرأ عمر ملفاً واحداً من ملفات سارة دون أن تضيفه إلى مجموعتها ودون أن تفتح الملف للجميع؟ والحل هو قوائم التحكم في الوصول Access Control Lists، واختصاراً ACL، وهي صلاحيات إضافية لمستخدمين أو مجموعات بالاسم فوق الثلاثيات الأساسية، كما تشرح صفحة [acl(5)](https://man7.org/linux/man-pages/man5/acl.5.html?ref=arabroot.io).

ولم نستطع تجربتها في مختبرنا، لأن الأداتين `getfacl` و`setfacl` غير موجودتين في ال Docker Image التي استخدمناها، ولم نثبتهما حتى لا نحمل حزماً على جهاز مساحته محدودة، لذلك فالأوامر التالية من صفحتي الدليل [setfacl(1)](https://man7.org/linux/man-pages/man1/setfacl.1.html?ref=arabroot.io) و[getfacl(1)](https://man7.org/linux/man-pages/man1/getfacl.1.html?ref=arabroot.io) وليست مخرجاً من تجربتنا. وعلى Ubuntu وDebian تثبتهما من الحزمة `acl`:

```bash
sudo apt install acl
setfacl -m u:omar:r report.txt      # give omar read access to this one file
getfacl report.txt                  # show the full list
setfacl -d -m g:devs:rw /srv/team   # default ACL: new files in the folder get it too
setfacl -x u:omar report.txt        # remove omar's entry
setfacl -b report.txt               # remove all extra entries
```

والملف الذي عليه ACL يظهر في `ls -l` بعلامة `+` بعد الصلاحيات، كما يشرح [دليل GNU coreutils](https://www.gnu.org/software/coreutils/manual/html%5Fnode/What-information-is-listed.html?ref=arabroot.io)، لذلك إذا رأيت `-rw-r-----+` فاعلم أن الصلاحيات التي تراها ليست كل القصة واقرأ `getfacl`. واستخدم ACL للاستثناءات فقط، فالسيرفر الذي كل ملف فيه له قائمة مختلفة يصعب أن تراجع صلاحياته أو تعرف من يصل إلى ماذا.

## sudo أم الدخول بحساب root؟

الحساب root هو المستخدم رقم 0، والنواة تتجاوز فحص الصلاحيات كله لأي عملية تعمل به، كما رأينا في ترتيب الفحص. وهناك طريقتان لتعمل بهذا الحساب:

- **الأمر** [**su**](https://man7.org/linux/man-pages/man1/su.1.html?ref=arabroot.io)**:** يفتح لك صدفة كاملة بحساب root بعد أن تكتب كلمة مرور root نفسها، فكل من يدير السيرفر يعرف كلمة مرور واحدة مشتركة، وكل ما يكتبه بعد ذلك يعمل بحساب root حتى يخرج، ولا يعرف السجل من كتب ماذا.
- **الأمر** [**sudo**](https://www.sudo.ws/docs/man/sudo.man/?ref=arabroot.io)**:** يشغل أمراً واحداً بحساب root بعد أن تكتب كلمة مرورك أنت، ووفق قواعد في الملف sudoers تحدد من يحق له ماذا، ويستطيع أن يسجل كل محاولة ناجحة أو فاشلة باسم صاحبها. وهو ما أعددناه في [دليل تأمين السيرفر](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/#sudo-user) عندما أنشأنا مستخدماً عادياً ومنعنا الدخول المباشر بحساب root.

والسبب في تفضيل sudo ليس الراحة، وإنما أنك تعمل بصلاحيات root لحظة الأمر الذي يحتاجها فقط، وأن لكل شخص حسابه وسجله، وهذا أساس إدارة الوصول المميز الذي شرحناه في [مقال IAM وPAM](https://arabroot.io/articles/%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%87%D9%88%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-iam-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%85%D9%8A%D8%B2-pam/#privileged-accounts)، ومنه [تسجيل جلسات sudo وإعادة تشغيلها](https://arabroot.io/articles/%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%87%D9%88%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-iam-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%85%D9%8A%D8%B2-pam/#demo-sudo). أما إعداد sudoers نفسه والمستخدمين والمجموعات فلها عنصر «المستخدمون والمجموعات وصلاحية sudo» في [المرحلة](https://arabroot.io/start/#stage-linux).

وهناك خطأ مع sudo يتكرر كثيراً: تريد أن تكتب في ملف يملكه root فتكتب `sudo echo "Welcome" > /etc/motd` فيظهر Permission denied مع أنك استخدمت sudo. والسبب أن التوجيه `>` من عمل صدفتك أنت كما شرحنا في [مقال سطر الأوامر](https://arabroot.io/articles/%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A7%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-linux-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#redirection)، فصدفتك هي التي تفتح الملف بحسابك العادي قبل أن يبدأ sudo، ولم يعمل بحساب root إلا `echo`. وهذا ما رأيناه عندما حاولت سارة الكتابة في الملف دون sudo، فالخطأ صادر من الصدفة لا من الأمر:

```text
$ echo "Welcome" > /etc/motd
bash: line 1: /etc/motd: Permission denied
```

والحل أن تجعل الكتابة نفسها تعمل بحساب root، إما بالأمر [tee](https://man7.org/linux/man-pages/man1/tee.1.html?ref=arabroot.io) الذي يقرأ stdin ويكتبه في الملف، أو بتشغيل صدفة كاملة بحساب root للأمر كما في أمثلة دليل sudo:

```bash
echo "Welcome" | sudo tee /etc/motd > /dev/null
echo "one more line" | sudo tee -a /etc/motd > /dev/null
sudo sh -c 'echo "Welcome" > /etc/motd'
```

ولا تحل المشكلة ب `sudo su` ثم تكمل عملك كله بحساب root، فهذا يلغي الفائدة التي من أجلها استخدمت sudo.

## الأخطاء الشائعة Common Mistakes وكيف تصلحها

### chmod 777 لحل أي Permission denied

الحل البسيط الذي تجده في كثير من المنتديات هو `chmod -R 777`، وهو يحل الخطأ فعلاً لأنه يعطي كل مستخدم على السيرفر كل الصلاحيات، وهذه هي المشكلة. ولنرى ما يعنيه ذلك، نسخت سارة سكربتها إلى `/tmp/backup.sh` وأعطته 777:

```text
$ cp deploy.sh /tmp/backup.sh && chmod 777 /tmp/backup.sh
$ ls -l /tmp/backup.sh
-rwxrwxrwx 1 sara sara 32 Oct  7 05:43 /tmp/backup.sh
```

ثم أضاف عمر سطراً إلى السكربت:

```text
$ echo 'echo "omar runs as $(whoami)"' >> /tmp/backup.sh
```

وعندما شغلت سارة سكربتها:

```text
$ /tmp/backup.sh
deploying...
omar runs as sara
```

نفذ سطر عمر بحساب سارة، ولو كان السكربت يعمل من cron بحساب root لنفذ بحساب root. وهذا بالضبط ما يحدث عندما يعطى مجلد موقع 777 فيرفع المخترق ملفاً إلى أي مكان فيه، أو يعطى سكربت نسخ احتياطي 777 فيعدله أي حساب على السيرفر ولو كان حساب خدمة مخترقة. بل إن بعض الأدوات ترفض العمل أصلاً مع صلاحيات واسعة، فبرنامج [ssh](https://man.openbsd.org/ssh?ref=arabroot.io) «يتجاهل المفتاح الخاص إذا كان يستطيع الوصول إليه غير صاحبه»، وسيرفر SSH يفحص صلاحيات مجلد المستخدم وملفاته قبل أن يقبل الدخول بسبب الخيار [StrictModes](https://man.openbsd.org/sshd%5Fconfig?ref=arabroot.io) المفعل افتراضياً، وهذا أحد أسباب الخطأ الذي شرحناه في [Permission denied (publickey)](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/#permission-denied-publickey).

والطريقة الصحيحة أن تسأل: من الذي يحتاج الوصول؟ ثم تعطيه هو فقط: غير المالك إلى المستخدم الذي يعمل به البرنامج، أو أضفه إلى مجموعة الملف وأعط المجموعة ما تحتاجه، أو استخدم ACL لاستثناء واحد. وللبحث عن الملفات التي يكتب فيها الجميع على سيرفرك:

```bash
sudo find / -xdev -type f -perm -0002 2>/dev/null
sudo find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/null
```

الأمر الأول يعرض الملفات التي يكتب فيها الجميع، والثاني يعرض المجلدات التي يكتب فيها الجميع دون البت اللاصق، وكلاهما يجب أن يكون فارغاً أو أن تعرف سبب كل سطر فيه.

### Permission denied داخل Docker Volume

هذا الخطأ يظهر كثيراً عند تثبيت التطبيقات بالحاويات، مثل ما شرحناه في [مشكلة Mattermost مع /mattermost/config](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-mattermost-%D9%88%D8%AA%D8%B1%D9%82%D9%8A%D8%AA%D9%87/#t-permission)، وسببه دائماً واحد: كثير من ال Images لا تعمل بحساب root وإنما بمستخدم له رقم محدد، والمجلد أو ال Volume ملك رقم آخر، والنواة كما قلنا لا تعرف إلا الأرقام. ولنصنع الخطأ بأنفسنا، أنشأنا Volume وأنشأنا فيه مجلداً بحساب root، ثم شغلنا Container بالمستخدم رقم 2000 يحاول الكتابة فيه:

```bash
docker volume create lab-linux-perm-data
docker run --rm -v lab-linux-perm-data:/data --entrypoint sh postgres:18 -c 'mkdir -p /data/uploads && ls -ln /data'
docker run --rm --user 2000:2000 -v lab-linux-perm-data:/data --entrypoint sh postgres:18 -c 'id; touch /data/uploads/photo.jpg'
```

والمخرج سوف يكون كما يلي:

```text
total 4
drwxr-xr-x 2 0 0 4096 Oct  7 05:43 uploads
uid=2000 gid=2000 groups=2000
touch: cannot touch '/data/uploads/photo.jpg': Permission denied
```

المجلد ملك الرقم 0 أي root وصلاحياته 755، والتطبيق يعمل بالرقم 2000، فطبقت عليه ثلاثية الآخرين `r-x` التي لا تسمح بالكتابة. والحل ليس 777، وإنما أن تجعل المجلد ملك الرقم الذي يعمل به التطبيق، عبر Container مؤقت بحساب root حتى لا تحتاج إلى معرفة مسار ال Volume على القرص:

```bash
docker run --rm -v lab-linux-perm-data:/data --entrypoint chown postgres:18 -R 2000:2000 /data/uploads
docker run --rm --user 2000:2000 -v lab-linux-perm-data:/data --entrypoint sh postgres:18 -c 'touch /data/uploads/photo.jpg && ls -ln /data/uploads'
```

والمخرج سوف يكون كما يلي:

```text
total 0
-rw-r--r-- 1 2000 2000 0 Oct  7 05:44 photo.jpg
```

في الإعداد أعلاه لاحظ التالي:

- الخيار `-n` مع `ls` يعرض الأرقام بدل الأسماء، وهو ما تحتاجه دائماً مع ال Volumes، لأن الرقم 2000 داخل ال Container قد لا يكون له اسم على السيرفر، أو يكون له اسم مستخدم آخر لا علاقة له بالتطبيق.
- لمعرفة الرقم الذي يعمل به تطبيق، شغل `docker compose exec app id`، أو اقرأ التعليمة [USER](https://docs.docker.com/reference/dockerfile/?ref=arabroot.io) في Dockerfile الخاص به، أو ابحث في توثيقه، كما فعلنا مع Mattermost الذي يعمل بالرقم 2000.
- مع المجلدات المربوطة Bind Mounts المشكلة نفسها والحل نفسه، فتنفذ `sudo chown -R 2000:2000 ./data` على المجلد في السيرفر.

والخطأ نفسه يظهر بعد نقل ال Volumes إلى سيرفر جديد إذا تغيرت ملكية الملفات أثناء النقل، وقد شرحنا ذلك في [التطبيق لا يستطيع الكتابة بعد الاستعادة](https://arabroot.io/articles/%D9%86%D9%82%D9%84-containers-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%AC%D8%AF%D9%8A%D8%AF/#not-writable).

### المالك Owner الخطأ بعد النسخ بحساب root

عندما ينسخ root ملفاً بالأمر `cp`، فإن النسخة الجديدة ملك root وليست ملك صاحب المجلد الذي وضعت فيه. ولنفرض أن المسؤول جهز ملف إعداد لسارة ونسخه إلى مجلدها بحساب root:

```bash
echo "DB_PASSWORD=change-me" > /root/app.env
cp /root/app.env /home/sara/app3.env
```

ثم حاولت سارة أن تعدله:

```text
$ ls -l app3.env
-rw-r--r-- 1 root root 22 Oct  7 05:43 app3.env
$ echo x >> app3.env
bash: line 1: app3.env: Permission denied
$ rm -f app3.env
$ ls app3.env
ls: cannot access 'app3.env': No such file or directory
```

لاحظ شيئين: سارة لا تستطيع تعديل الملف لأنه ملك root، لكنها استطاعت حذفه، لأن الحذف كما رأينا يحتاج w على المجلد، والمجلد مجلدها. ولاحظ أيضاً أن الملف 644، أي أن كلمة المرور فيه يقرؤها أي مستخدم يصل إلى المجلد. والحل أن يصلح root الملكية بعد النسخ، أو الأفضل أن ينسخ بالأمر `install` الذي يحدد المالك والمجموعة والصلاحيات في خطوة واحدة:

```text
$ cp /root/app.env /home/sara/app.env
$ ls -l /home/sara/app.env
-rw-r--r-- 1 root root 22 Oct  7 05:43 /home/sara/app.env
$ chown sara:sara /home/sara/app.env
$ install -o sara -g sara -m 600 /root/app.env /home/sara/app2.env
$ ls -l /home/sara/app.env /home/sara/app2.env
-rw------- 1 sara sara 22 Oct  7 05:43 /home/sara/app2.env
-rw-r--r-- 1 sara sara 22 Oct  7 05:43 /home/sara/app.env
```

وعندما تنسخ مجلداً كاملاً وتريد أن تبقى الملكية والصلاحيات كما هي، كما في النسخ الاحتياطي أو النقل بين سيرفرين، فاستخدم [cp -a](https://man7.org/linux/man-pages/man1/cp.1.html?ref=arabroot.io) أو [rsync -a](https://download.samba.org/pub/rsync/rsync.1?ref=arabroot.io) بحساب root، أو `tar` مع `--numeric-owner` حتى تحفظ الأرقام لا الأسماء.

### السكربت لا يعمل لغياب صلاحية التشغيل Execute

كتبت سكربتاً أو نزلته أو سحبته من Git، ثم شغلته فظهر Permission denied، والسبب أن الملف الجديد يأخذ 644 بسبب القناع كما رأينا، أي بدون x. والمثال التالي من المختبر:

```text
$ ./deploy.sh; echo "exit code: $?"
deploying...
exit code: 0
$ chmod -x deploy.sh
$ ./deploy.sh; echo "exit code: $?"
bash: line 1: ./deploy.sh: Permission denied
exit code: 126
$ bash deploy.sh
deploying...
$ chmod +x deploy.sh
```

في الإعداد أعلاه لاحظ التالي:

- رمز الخروج 126 يعني أن الملف موجود لكنه غير قابل للتشغيل، وهو الرقم الذي شرحناه في [مقال سطر الأوامر](https://arabroot.io/articles/%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A7%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-linux-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#exit-codes).
- الأمر `bash deploy.sh` يعمل دون x، لأن الذي يشغل هنا هو `bash`، وهو يقرأ السكربت كملف نصي يحتاج r فقط. وهذا يعني أن نزع x ليس وسيلة حماية، فمن يستطيع قراءة السكربت يستطيع تشغيله.
- Git يحفظ صلاحية التشغيل مع الملف، فإذا أضفت السكربت من Windows حيث لا توجد هذه الصلاحية، فاضبطها في المستودع نفسه بالأمر [git update-index --chmod=+x deploy.sh](https://git-scm.com/docs/git-update-index?ref=arabroot.io) ثم Commit، حتى يصل السكربت قابلاً للتشغيل إلى كل من يسحبه، وانتبه إلى الإعداد [core.fileMode](https://git-scm.com/docs/git-config?ref=arabroot.io) الذي يحدد هل يلاحظ Git تغيير هذه الصلاحية أصلاً.

## قائمة تحقق Checklist للصلاحيات على سيرفرك

- لا يوجد ملف يكتب فيه الجميع، ولا مجلد يكتب فيه الجميع دون البت اللاصق، والأمران في قسم chmod 777 يرجعان فارغين.
- ملفات الأسرار مثل `.env` والمفاتيح الخاصة 600 وملك المستخدم الذي يحتاجها فقط، و`~/.ssh` 700.
- تعرف قائمة برامج setuid على السيرفر من `find / -xdev -perm -4000`، ولم تضف إليها شيئاً.
- مجلدات بيانات ال Containers ملك الرقم الذي يعمل به التطبيق، وتفحصها ب `ls -ln`.
- المجلدات المشتركة بين فريق لها مجموعة و setgid، وليست 777.
- كل مسؤول يدخل بحسابه ويستخدم sudo، ولا أحد يدخل بحساب root مباشرة.
- السكربتات في المستودع محفوظة بصلاحية التشغيل، ولا تحتاج `chmod +x` بعد كل سحب.

## حذف المختبر Cleanup

```bash
docker rm -f lab-linux-perm
docker volume rm lab-linux-perm-data
```

## الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

- الصلاحيات ثلاث ثلاثيات للمالك والمجموعة والآخرين، والنواة تطبق واحدة فقط، أولها الذي ينطبق، وتعمل بالأرقام UID وGID لا بالأسماء.
- على المجلد r تعني قراءة الأسماء، وx الدخول والوصول إلى الملفات، وw الإنشاء والحذف وإعادة التسمية، لذلك فالحذف يتبع صلاحية المجلد لا صلاحية الملف.
- r=4 وw=2 وx=1، فالقيم التي سوف تستخدمها أغلب الوقت 644 و600 للملفات و755 و750 و700 للمجلدات، و`chmod -R` يحتاج `X` الكبير حتى لا يغلق المجلدات.
- القناع umask يحذف من الصلاحيات التي يطلبها البرنامج ولا يضيف شيئاً، و022 تعطي 644 و755، و077 تجعل الجديد لصاحبه وحده.
- setuid يجعل البرنامج يعمل بصلاحيات مالكه، وكل برنامج setuid يملكه root باب محتمل إلى root كما في PwnKit، وsetgid على المجلد يناسب مجلدات الفريق، والبت اللاصق يحمي الأسماء في `/tmp` ولا يحمي المحتوى.
- لا تحل Permission denied ب 777 أبداً، وإنما اعرف من يحتاج الوصول وأعطه هو، سواءً بتغيير المالك أو المجموعة أو ب ACL.

[![](https://arabroot.io/content/images/2026/10/linux-cli-cover-cover.webp)دليلسطر الأوامر في Linux للمبتدئين: أول ما تحتاجه على السيرفركيف تتنقل بين الملفات على السيرفر، وتربط الأوامر ببعضها، وتتحكم في العمليات Processes دون أن تحذف شيئاً بالخطأ.](https://arabroot.io/articles/%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A7%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-linux-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/secure-vps-cover-cover-2.webp)دليلتأمين سيرفر VPS على Ubuntu من أول دخولقبل أن تثبت أي تطبيق على سيرفرك الجديد، هذه الخطوات تغلق أبرز الثغرات وأولها الدخول بمفتاح SSH بدل كلمة المرور.](https://arabroot.io/articles/%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-vps-%D9%85%D9%86-%D8%A3%D9%88%D9%84-%D8%AF%D8%AE%D9%88%D9%84/)[![](https://arabroot.io/content/images/2026/10/iam-pam-cover-cover.webp)دليلإدارة الهوية والوصول IAM والوصول المميز PAMمن يملك صلاحية root على سيرفراتك ومنذ متى، وكيف تضبط حسابات المديرين بصلاحيات مؤقتة وجلسات مسجلة.](https://arabroot.io/articles/%D8%A7%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%87%D9%88%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-iam-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%85%D9%8A%D8%B2-pam/)[![](https://arabroot.io/content/images/2026/10/docker-cover-cover-1.webp)دليلتثبيت Docker Engine وCompose على Ubuntuكيف تثبت Docker على Ubuntu من المستودع الرسمي، وتضبطه من البداية حتى لا يمتلئ القرص أو تنكشف منافذك للإنترنت.](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-docker-%D8%B9%D9%84%D9%89-ubuntu/)[![](https://arabroot.io/content/images/2026/10/mattermost-cover-cover.webp)دليلتثبيت Mattermost Team Edition مع PostgreSQL وترقيته بأمانمساحة محادثة لفريقك على سيرفرك مع Mattermost، تبقى فيها الرسائل والملفات كاملة، فلا يحذفها حد للرسائل ولا خطة مجانية.](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-mattermost-%D9%88%D8%AA%D8%B1%D9%82%D9%8A%D8%AA%D9%87/)[![](https://arabroot.io/content/images/2026/10/docker-migrate-server-cover-cover.webp)دليلنقل Containers إلى خادم جديد دون فقدان البياناتكيف تنقل ال Containers مع بياناتها إلى سيرفر جديد، دفعة واحدة أو تطبيقاً بعد تطبيق، مع خطة للتراجع إذا تعثر النقل.](https://arabroot.io/articles/%D9%86%D9%82%D9%84-containers-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%AC%D8%AF%D9%8A%D8%AF/)

## سجل التحديثات

- أكتوبر 2026: كتابة المقال، وتنفيذ التجارب في Container من Docker Image ‏postgres:18 (Debian 13، GNU coreutils 9.7) على Docker Engine 29.8.0، دون تجربة ACL لعدم وجود getfacl وsetfacl في ال Image.