זמן פעילות ארוך מוכיח רק שההפעלה הצליחה עם ההרשאות שהיו לדמון באותו רגע. הכשלים שחשובים כאן מגיעים מאוחר יותר: לקוח חדש מתחבר, רשימת ביטולים מוחלפת, סקריפט עזר צריך לכתוב קובץ. כל אחד מהם הוא פתיחה חדשה שמבצע החשבון חסר ההרשאות, עם שאלת ההרשאות שלו והודעת השגיאה שלו. שלוש החלטות מפרידות הגדרה שממשיכה לעבוד מהגדרה שנכשלת באירוע הבא.

הפרידו בין מה שנטען מוקדם לבין מה שנפתח מאוחר יותר

מתאר הוא ידית על תיאור קובץ פתוח, ומצב הגישה נקבע בעת יצירת אותו תיאור. שינוי משתמש התהליך אחר כך אינו סוגר את הידית, ולכן קובץ מפתח שנקרא כ root ממשיך לעבוד אחרי ההורדה. גם המצב אינו משתנה: ידית שנפתחה לקריאה אינה הופכת לכתיבה, וידית לכתיבה אינה נשללת רק מפני שהחשבון איבד את זכויותיו על הנתיב. שתי העובדות האלה מסבירות את רוב ההתנהגות המפתיעה בדוחות האלה.

החצי השני הוא זיכרון. הדמון יכול לנתח תעודה, לשמור את החומר המנותח ולסגור את הקובץ; מה שנשאר בשימוש הוא נתונים, לא קובץ פתוח. לכן תעבורה נמשכת אינה מוכיחה לא שהידית פתוחה ולא ששם הנתיב נגיש. היא מוכיחה רק שהחומר הדרוש להפעלה הנוכחית הושג קודם.

פתיחה מאוחרת היא עסקה אחרת. היא רצה תחת האישורים הנוכחיים, ההקשר הביטחוני הנוכחי ותצוגת העיגון הנוכחית, ולכן נתיב שהיה קריא באתחול יכול להידחות בחיבור הבא. סיבוב מוסיף מלכודת: כתיבת קובץ חדש על אותו שם נתיב משאירה ידית קיימת קשורה לאובייקט הישן, ולכן טעינה מחדש יכולה להיראות מוצלחת בשעה שהדמון עדיין משתמש בתוכן הקודם. השוו את ה inode שהתהליך מחזיק לזה שעל הדיסק לפני שאתם מאמינים שסיבוב נכנס לתוקף.

נקבו בשמות שלוש הקריאות בזמן ריצה ומתי כל אחת מתרחשת

שלושה משאבים נפתחים בדרך כלל הרבה אחרי האתחול, והם נכשלים בעיתות שונות. קובץ הגדרה של לקוח מסוים נקרא כשהלקוח הזה מתחבר, ולכן הוא יכול להישבר אצל משתמש אחד בשעה שהשאר ממשיכים. נתוני ביטול נבדקים בזמן אימות העמית ושוב כשהקובץ מוחלף. תיקייה זמנית נגעת רק כשסקריפט או תוסף כותב משהו.

אף אחד מהשלושה אינו שייך לנתיב האתחול, ולכן שרת שהיה בריא במשך שבועות יכול להיכשל בחיבור הבא. הקטגוריה גם מכנה את בעל התיקון: הראשון והשני הם הרשאות קריאה על ההגדרה תחת חשבון הדמון, והשלישי הוא מקום לכתיבה עם מטרה צרה.

Path reopened laterWhat triggers the openFirst sign when it fails
Client configuration fileA connection for that client identityOne client rejected while others connect
Revocation dataPeer authentication, including after replacementRevoked and valid peers both refused
Script or plugin temporary directoryA helper needs to create a fileThe helper exits with a path error

persist-key עונה על שאלה צרה יותר מכפי שרוב האנשים מניחים. הוא מחזיק את קובץ המפתח פתוח לאורך איפוסי SIGUSR1 ו ping-restart המתועדים, והוא אינו עושה דבר לקבצי CCD, לנתוני ביטול, לקובצי הרצה של עזרים או לאתחול מלא של התהליך. אלה ממשיכים לפי נתיבי הפתיחה שלהם, תחת החשבון שרץ באותו רגע.

אמתו את החשבון ואת התצוגה שיש לו באמת

שאלו את הדמון הרץ איזה חשבון הוא משתמש בו במקום לסמוך על קובץ ה unit, ואחר כך השוו את התשובה למה שה unit קובע. אי התאמה היא הדבר הראשון לפתור, מפני שכל בדיקת הרשאות מאוחרת רצה כמי שהתהליך באמת. אחר כך עברו על הנתיב רכיב אחר רכיב; המעבר מוערך בכל רמה, ולכן קובץ קריא בתוך תיקייה שאי אפשר לעבור בה נשאר בלתי קריא. מצב הקובץ הסופי הוא השאלה האחרונה, לא הראשונה.

מרחבי שמות וארגזי חול של שירות מוסיפים גבולות שבעלות וביטי מצב אינם מתארים. נתיב שנראה ב shell שלכם יכול להיעדר או להיות לקריאה בלבד בתוך chroot, מרחב שמות עיגון או unit שמסתיר תיקיות בית. מודולי אבטחה מוסיפים שכבה נוספת, ולכן קובץ שנראה קריא יכול להידחות בפתיחה.

ps -o user:12,pid,args -C openvpn
systemctl show -p User -p Group -p ProtectHome -p RootDirectory [email protected]
sudo -u openvpn namei -l /etc/openvpn/ccd/alice

קריאה מוצלחת ב shell של המנהל אינה בודקת אף אחד מהתנאים המשולבים האלה. הריצו את הבדיקה כחשבון הדמון, עם אותו מרחב שמות ואותו ארגז חול, או השלימו עם כך שהתוצאה מתארת את ה shell שלכם ולא את השרת. הפקודה השלישית היא הגרסה הזולה של הבדיקה הזאת: היא מדפיסה את המצב של כל רכיב ונכשלת בראשון שחשבון הדמון אינו יכול לעבור בו.

תנו לכתיבה בזמן ריצה תיקייה משל עצמה

קריאה היא רק חצי מהמלאי. סקריפט עזר עשוי להזדקק ליצירת קובץ מצב, תוסף עשוי להזדקק לכתיבת מצב לצד ההגדרה שלו, והכתיבות האלה אינן מכוסות על ידי הפיכת עץ ההגדרה לכתיב. תנו לתיקייה המסוימת את הרשאת הכתיבה שהתפקוד שלה דורש, עם בעלים ומצב שתוכלו להסביר. העדיפו גישה לקריאה בלבד לכל מה שנקרא בלבד.

החזיקו את הרשאות המפתח הפרטי בנפרד מקבצי המדיניות. מפתח שחייב להיקרא שוב אחרי איפוס דורש תנאי שונה מקובץ לקוח שנקרא בכל חיבור, ומצב מתירני אחד לשניהם נותן גישה רבה ממה שהבעיה מבקשת. חשבון דמון ייעודי עם בעלות צרה קל יותר לביקורת מאשר קבוצה רחבה. כשהמפתח חייב לשרוד איפוסים, persist-key הוא מסיר את הקריאה החוזרת במקום להרחיב את התיקייה.

החליטו לפי האירוע שתוכלו לשחזר

מנהרה חיה מוכיחה נתיב אחד בקוד. האירוע שזקוק לקובץ הוא המבחן היחיד שמכסה את הפתיחה שמעניינת אתכם, יהיה זה חיבור לקוח חדש, קובץ ביטול מוחלף, איפוס רך מורשה או אתחול מתוכנן. בחרו את האירוע, הריצו אותו, ושמרו את השגיאה הראשונה ולא את האחרונה.

לאיפוס רך, אות אחד ויומן ה unit מראים אם המפתח נקרא שוב. שלחו את האות, ואחר כך קראו את השורות האחרונות שה unit כתב:

systemctl kill -s SIGUSR1 [email protected]
journalctl -u [email protected] -n 40 --no-pager

אל תסיקו שדמון שנפרץ אינו יכול עוד לשנות קבצים רק מפני שההרשאות הורדו. מה שהוא עוד יכול לעשות תלוי באישורים שנותרו, ביכולות שלו, בתיקיות שבהן הוא יכול לכתוב ובכל ידית כתיבה שהוא עדיין מחזיק. הורדת הרשאות מצמצמת את הסמכות, ומלאי הפתיחות בזמן ריצה הוא שמראה עד כמה. כתבו את הגבול הזה לצד ההגדרה כדי שהאדם הבא לא יצטרך לגלות אותו מחדש.

מאמרים קשורים