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

מה החולשה?

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

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

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

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

התיקון מנתק את האיבר מהרשימה לפני שהצומת משוחרר. תיקון קטן במקום הנכון.

את התקלה דיווח Kyle Zeng, וכך היא מיוחסת ברשומה.

מי מושפע?

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

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

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

האם מנוצלת בפועל?

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

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

מה עושים?

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

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

אם אתם צריכים לוודא שהתיקון אכן נמצא בליבה שאתם מריצים, ארבעת הקישורים ל-git.kernel.org שברשומה מראים לאיזה ענף יציב הוא נכנס ובאיזה commit. זו הדרך לבדוק אותו מול הגרסה המדויקת שההפצה שלכם מספקת, במקום להסתמך על מספר הגרסה לבדו.

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

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