Author: bonefish Date: 2011-05-02 15:39:22 +0200 (Mon, 02 May 2011) New Revision: 41302 Changeset: https://dev.haiku-os.org/changeset/41302 Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h haiku/branches/developer/bonefish/signals/headers/private/kernel/usergroup.h haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/usergroup.cpp Log: * Team's user/group members are now protected by the object's lock instead of the global teams spinlock. * Removed no longer needed inherit_parent_user_and_group_locked(). * _user_setgroups(): is_privileged() was called without any lock held (harmless). * load_image_internal(): Fixed race condition: team should not be dereferenced after we create the main thread, since it might be killed by someone else from that point on. Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-02 12:56:39 UTC (rev 41301) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-02 13:39:22 UTC (rev 41302) @@ -282,6 +282,7 @@ bigtime_t dead_threads_kernel_time; bigtime_t dead_threads_user_time; + // user group information; protected by fLock uid_t saved_set_uid; uid_t real_uid; uid_t effective_uid; Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/usergroup.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/usergroup.h 2011-05-02 12:56:39 UTC (rev 41301) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/usergroup.h 2011-05-02 13:39:22 UTC (rev 41302) @@ -25,7 +25,6 @@ // kernel private functions void inherit_parent_user_and_group(Team* team, Team* parent); -void inherit_parent_user_and_group_locked(Team* team, Team* parent); status_t update_set_id_user_and_group(Team* team, const char* file); // syscalls Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp 2011-05-02 12:56:39 UTC (rev 41301) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp 2011-05-02 13:39:22 UTC (rev 41302) @@ -1346,7 +1346,6 @@ port_id errorPort, uint32 errorToken) { char** flatArgs = _flatArgs; - Team* team; const char* threadName; thread_id thread; status_t status; @@ -1354,6 +1353,7 @@ struct team_arg* teamArgs; struct team_loading_info loadingInfo; io_context* parentIOContext = NULL; + team_id teamID; if (flatArgs == NULL || argCount == 0) return B_BAD_VALUE; @@ -1363,9 +1363,10 @@ TRACE(("load_image_internal: name '%s', args = %p, argCount = %ld\n", path, flatArgs, argCount)); - team = Team::Create(path, false); + Team* team = Team::Create(path, false); if (team == NULL) return B_NO_MEMORY; + BReference<Team> teamReference(team, true); if (flags & B_WAIT_TILL_LOADED) { loadingInfo.thread = thread_get_current_thread(); @@ -1374,25 +1375,17 @@ team->loading_info = &loadingInfo; } - InterruptsSpinLocker teamLocker(gTeamSpinlock); - // get the parent team - Team* parent; + Team* parent = Team::Get(parentID); + if (parent == NULL) + return B_BAD_TEAM_ID; + BReference<Team> parentReference(parent, true); - if (parentID == B_CURRENT_TEAM) - parent = thread_get_current_thread()->team; - else - parent = team_get_team_struct_locked(parentID); - - if (parent == NULL) { - teamLocker.Unlock(); - status = B_BAD_TEAM_ID; - goto err0; - } - // inherit the parent's user/group - inherit_parent_user_and_group_locked(team, parent); + inherit_parent_user_and_group(team, parent); + InterruptsSpinLocker teamLocker(gTeamSpinlock); + sTeamHash.Insert(team); insert_team_into_parent(parent, team); insert_team_into_group(parent->group, team); @@ -1450,15 +1443,23 @@ // notify team listeners sNotificationService.Notify(TEAM_ADDED, team); + // In case we start the main thread, we shouldn't access the team object + // afterwards, so cache the team's ID. + teamID = team->id; + // Create a kernel thread, but under the context of the new team // The new thread will take over ownership of teamArgs thread = spawn_kernel_thread_etc(team_create_thread_start, threadName, - B_NORMAL_PRIORITY, teamArgs, team->id, team->id); + B_NORMAL_PRIORITY, teamArgs, teamID, teamID); if (thread < 0) { status = thread; goto err5; } + // The team has been created successfully, so we keep the reference. Or + // more precisely: It's owned by the team's main thread, now. + teamReference.Detach(); + // wait for the loader of the new team to finish its work if ((flags & B_WAIT_TILL_LOADED) != 0) { Thread* mainThread; @@ -1494,7 +1495,7 @@ } // notify the debugger - user_debug_team_created(team->id); + user_debug_team_created(teamID); return thread; @@ -1523,9 +1524,6 @@ RELEASE_TEAM_LOCK(); restore_interrupts(state); -err0: - team->ReleaseReference(); - return status; } @@ -1728,11 +1726,11 @@ strlcpy(team->args, parentTeam->args, sizeof(team->args)); - InterruptsSpinLocker teamLocker(gTeamSpinlock); - // Inherit the parent's user/group. - inherit_parent_user_and_group_locked(team, parentTeam); + inherit_parent_user_and_group(team, parentTeam); + InterruptsSpinLocker teamLocker(gTeamSpinlock); + sTeamHash.Insert(team); insert_team_into_parent(parentTeam, team); insert_team_into_group(parentTeam->group, team); @@ -3930,14 +3928,15 @@ io_context* ioContext; { // get the team structure - InterruptsSpinLocker _(gTeamSpinlock); - Team* team = teamID == B_CURRENT_TEAM - ? thread_get_current_thread()->team - : team_get_team_struct_locked(teamID); + Team* team = Team::Get(teamID); if (team == NULL) return B_BAD_TEAM_ID; + BReference<Team> teamReference(team, true); // copy the data + TeamLocker teamLocker(team); + InterruptsSpinLocker _(gTeamSpinlock); + teamClone->id = team->id; strlcpy(teamClone->name, team->name, sizeof(teamClone->name)); teamClone->group_id = team->group_id; Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/usergroup.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/usergroup.cpp 2011-05-02 12:56:39 UTC (rev 41301) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/usergroup.cpp 2011-05-02 13:39:22 UTC (rev 41302) @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include <usergroup.h> #include <errno.h> @@ -39,7 +40,7 @@ { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker _(gTeamSpinlock); + TeamLocker teamLocker(team); bool privileged = kernel || is_privileged(team); @@ -102,7 +103,7 @@ { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker _(gTeamSpinlock); + TeamLocker teamLocker(team); bool privileged = kernel || is_privileged(team); @@ -165,7 +166,7 @@ { Team* team = thread_get_current_thread()->team; - InterruptsSpinLocker _(gTeamSpinlock); + TeamLocker teamLocker(team); const gid_t* groups = team->supplementary_groups; int actualCount = team->supplementary_group_count; @@ -223,15 +224,15 @@ } } - InterruptsSpinLocker locker(gTeamSpinlock); - Team* team = thread_get_current_thread()->team; + TeamLocker teamLocker(team); + gid_t* toFree = team->supplementary_groups; team->supplementary_groups = newGroups; team->supplementary_group_count = groupCount; - locker.Unlock(); + teamLocker.Unlock(); malloc_referenced_release(toFree); @@ -243,8 +244,11 @@ void -inherit_parent_user_and_group_locked(Team* team, Team* parent) +inherit_parent_user_and_group(Team* team, Team* parent) { + TeamLocker parentLocker(parent); + TeamLocker teamLocker(team); + team->saved_set_uid = parent->saved_set_uid; team->real_uid = parent->real_uid; team->effective_uid = parent->effective_uid; @@ -258,14 +262,6 @@ } -void -inherit_parent_user_and_group(Team* team, Team* parent) -{ - InterruptsSpinLocker _(gTeamSpinlock); - inherit_parent_user_and_group_locked(team, parent); -} - - status_t update_set_id_user_and_group(Team* team, const char* file) { @@ -274,7 +270,7 @@ if (status != B_OK) return status; - InterruptsSpinLocker _(gTeamSpinlock); + TeamLocker teamLocker(team); if ((st.st_mode & S_ISUID) != 0) { team->saved_set_uid = st.st_uid; @@ -381,8 +377,13 @@ ssize_t _user_setgroups(int groupCount, const gid_t* groupList) { - if (!is_privileged(thread_get_current_thread()->team)) - return EPERM; + // check privilege + { + Team* team = thread_get_current_thread()->team; + TeamLocker teamLocker(team); + if (!is_privileged(team)) + return EPERM; + } return common_setgroups(groupCount, groupList, false); }