לדלג לתוכן

פתרון שירות מול משתמש

פתרון התרגיל הראשון

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

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

auto job = jobs.find_and_hold(request.job_id);
if (!job) return reply_not_found();
if (!client_owns_job(pipe, job->immutable_owner_sid()))
    return reply_denied();
return reply_cancel_result(job->cancel_if_active());

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

פתרון התרגיל השני

נזריק את החריגה בתוך client_owns_job, אחרי שהguard הושלם. הdestructor של token נסגר קודם, ואז הdestructor של ההתחזות מחזיר את הthread לזהות התהליך. בקוד השרת, מחוץ לscope הזה ואחרי catch, אפשר לבדוק כך.

HANDLE unexpected = nullptr;
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &unexpected)) {
    CloseHandle(unexpected);
    throw std::runtime_error("identity leaked to the next request");
}
DWORD error = GetLastError();
if (error != ERROR_NO_TOKEN)
    throw std::runtime_error("could not verify thread identity");

כשל אחר מERROR_NO_TOKEN אינו הוכחה שהthread נקי. נרצה לדעת שהבדיקה עצמה הצליחה לברר את המצב. אם RevertToSelf נכשל, המשך העבודה עלול להשתמש בזהות שלא התכוונו אליה; לכן דוגמת המעבדה מסיימת במקום להחזיר thread כזה לpool.

פתרון התרגיל השלישי

התזמון הוא בדיקת עבודה 17 של המשתמש הראשון, מחיקתה, יצירת עבודה חדשה של המשתמש השני עם מזהה 17, ואז lookup בworker. ההרשאה הישנה אינה חלה על האובייקט החדש.

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

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