Mac Sandbox: Security fixes for Mac OS 10.6 Snow Leopard

svn path=/trunk/boinc/; revision=18978
This commit is contained in:
Charlie Fenton 2009-09-02 02:11:03 +00:00
parent e82aad226a
commit d34c522d74
5 changed files with 140 additions and 21 deletions

View File

@ -7412,3 +7412,28 @@ Rom 1 Sept 2009
client/
http_curl.cpp,h
Charlie 1 Sept 2009
- Mac Sandbox: Security fixes for Mac OS 10.6 Snow Leopard.
Mac OS 10.6 requires administrator authorization to run setgid
applications if they use the AppKit (Cocoa) framework. The Mac
installer adds all users with admin privileges (members of group
admin) to group boinc_master. Since the Manager doesn't need to
run setgid boinc_master if the user is a member of that group,
we eliminate the setgid.
This means that non-admin users will be able to run the Manager
only if the sysadmin adds them to group boinc_master, so we now
create a login item or set the screensaver only for those users
who are members of group boinc_master.
If a user who is not a member of that group runs the Manager, it
displays an alert saying that in order to administer BOINC, he
needs to ask the sysadmin to add him to group boinc_master.
client/
check_security.cpp
clientgui/
BOINCGUIApp.cpp
mac/
SetupSecurity.cpp
mac_installer/
PostInstall.cpp

View File

@ -32,10 +32,13 @@
#endif
#include "util.h"
#include "str_replace.h"
#include "error_numbers.h"
#include "file_names.h"
#ifdef __WXMAC__ // If Mac BOINC Manager
bool IsUserInGroupBM();
#endif
static int CheckNestedDirectories(char * basepath, int depth, int use_sandbox);
#if (! defined(__WXMAC__) && ! defined(_MAC_INSTALLER))
@ -81,10 +84,6 @@ int use_sandbox, int isManager
ProcessSerialNumber ourPSN;
ProcessInfoRec pInfo;
FSRef ourFSRef;
char *p;
#endif
#ifdef _MAC_INSTALLER
char *p;
#endif
#define NUMBRANDS 3
@ -159,10 +158,14 @@ saverName[2] = "Progress Thru Processors";
boinc_master_uid = sbuf.st_uid;
boinc_master_gid = sbuf.st_gid;
#ifdef __WXMAC__
if (!IsUserInGroupBM())
return -1099;
#endif
} else {
boinc_master_uid = geteuid();
boinc_master_gid = getegid();
}
#ifdef _MAC_INSTALLER
@ -213,6 +216,7 @@ saverName[2] = "Progress Thru Processors";
boinc_project_gid = grp->gr_gid;
}
#if 0 // Manager is no longer setgid
#if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If Mac BOINC Manager or installer
// Get the full path to BOINC Manager executable inside this application's bundle
strlcpy(full_path, dir_path, sizeof(full_path));
@ -238,6 +242,8 @@ saverName[2] = "Progress Thru Processors";
return -1015;
}
#endif
#endif // Manager is no longer setgid
#ifdef _MAC_INSTALLER
// Require absolute owner and group boinc_master:boinc_master
@ -304,12 +310,13 @@ saverName[2] = "Progress Thru Processors";
#else // _MAC_INSTALLER
getcwd(dir_path, sizeof(dir_path)); // Client or Manager
if (! isManager) { // If BOINC Client
if (egid != boinc_master_gid)
return -1019; // Client or Manager should be running setgid boinc_master
return -1019; // Client should be running setgid boinc_master
if (! isManager) // If BOINC Client
if (euid != boinc_master_uid)
return -1020; // BOINC Client should be running setuid boinc_master
}
#endif
retval = stat(dir_path, &sbuf);
@ -650,3 +657,36 @@ static void GetPathToThisProcess(char* outbuf, size_t maxLen) {
*q = '\0';
}
#endif
#ifdef __WXMAC__ // If Mac BOINC Manager
bool IsUserInGroupBM() {
group *grp;
gid_t rgid;
char *userName, *groupMember;
int i;
grp = getgrgid(boinc_master_gid);
if (grp) {
rgid = getgid();
if (rgid == boinc_master_gid) {
return true; // User's primary group is boinc_master
}
userName = getlogin();
if (userName) {
for (i=0; ; i++) { // Step through all users in group boinc_master
groupMember = grp->gr_mem[i];
if (groupMember == NULL)
return false; // User is not a member of group boinc_master
if (strcmp(userName, groupMember) == 0) {
return true; // User is a member of group boinc_master
}
} // for (i)
} // if (userName)
} // if grp
return false;
}
#endif // __WXMAC__

View File

@ -304,11 +304,16 @@ bool CBOINCGUIApp::OnInit() {
ShowApplication(true);
if (iErrorCode == -1099) {
strDialogMessage =
_("You currently are not authorized to manage the client.\nPlease contact your administrator to add you to the 'boinc_master' user group.");
} else {
strDialogMessage.Printf(
wxT("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)\n"),
_("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)\n"),
iErrorCode
);
}
wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT("BOINC Manager"), wxOK);
pDlg->ShowModal();

View File

@ -179,14 +179,14 @@ saverName[2] = "Progress Thru Processors";
#ifdef _DEBUG
// chmod u=rwx,g=rwsx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager
// 02775 = S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH
// setgid-on-execution plus read, write and execute permission for user & group, read & execute for others
err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwsx,o=rx", fullpath, NULL, NULL, NULL);
// 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH
// read, write and execute permission for user & group, read & execute for others
err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL);
#else
// chmod u=rx,g=rsx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager
// 02555 = S_ISGID | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
// setgid-on-execution plus read and execute permission for user, group & others
err = DoPrivilegedExec(chmodPath, "u=rx,g=rsx,o=rx", fullpath, NULL, NULL, NULL);
// 0555 = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
// read and execute permission for user, group & others
err = DoPrivilegedExec(chmodPath, "u=rx,g=rx,o=rx", fullpath, NULL, NULL, NULL);
#endif
if (err)
return err;

View File

@ -657,12 +657,16 @@ OSErr UpdateAllVisibleUsers(long brandID)
Boolean deleteLoginItem;
char skinName[256];
char s[256];
group *grp;
group grpAdmin, *grpAdminPtr;
char adminBuf[32768];
group grpBOINC_master, *grpBOINC_masterPtr;
char bmBuf[32768];
Boolean saverAlreadySet = true;
Boolean found = false;
FILE *f;
OSStatus err;
long response;
Boolean isGroupMember;
#ifdef SANDBOX
char *p;
short i;
@ -671,11 +675,17 @@ OSErr UpdateAllVisibleUsers(long brandID)
if (err != noErr)
return err;
grp = getgrnam("admin");
if (grp == NULL) { // Should never happen
err = getgrnam_r("admin", &grpAdmin, adminBuf, sizeof(adminBuf), &grpAdminPtr);
if (err) { // Should never happen unless buffer too small
puts("getgrnam(\"admin\") failed\n");
return -1;
}
err = getgrnam_r("boinc_master", &grpBOINC_master, bmBuf, sizeof(bmBuf), &grpBOINC_masterPtr);
if (err) { // Should never happen unless buffer too small
puts("getgrnam(\"boinc_master\") failed\n");
return -1;
}
#endif
FindSkinName(skinName, sizeof(skinName));
@ -699,25 +709,45 @@ OSErr UpdateAllVisibleUsers(long brandID)
continue;
#ifdef SANDBOX
isGroupMember = false;
i = 0;
while ((p = grp->gr_mem[i]) != NULL) { // Step through all users in group admin
while ((p = grpAdmin.gr_mem[i]) != NULL) { // Step through all users in group admin
if (strcmp(p, dp->d_name) == 0) {
// User is a member of group admin, so add user to groups boinc_master and boinc_project
err = AddAdminUserToGroups(p);
if (err != noErr)
return err;
isGroupMember = true;
break;
}
++i;
}
if (!isGroupMember) {
i = 0;
while ((p = grpBOINC_master.gr_mem[i]) != NULL) { // Step through all users in group boinc_master
if (strcmp(p, dp->d_name) == 0) {
// User is a member of group boinc_master
isGroupMember = true;
break;
}
++i;
}
}
#else
isGroupMember = true;
#endif
deleteLoginItem = CheckDeleteFile(dp->d_name);
if (!isGroupMember) {
deleteLoginItem = true;
}
saved_uid = geteuid();
seteuid(pw->pw_uid); // Temporarily set effective uid to this user
SetLoginItem(brandID, deleteLoginItem); // Set login item for this user
if (isGroupMember) {
SetSkinInUserPrefs(dp->d_name, skinName);
if (response < 0x1060) {
@ -739,6 +769,7 @@ OSErr UpdateAllVisibleUsers(long brandID)
pclose(f);
if (!found) {
saverAlreadySet = false;
}
}
}
@ -751,8 +782,8 @@ OSErr UpdateAllVisibleUsers(long brandID)
return noErr;
}
if (!ShowMessage(true, "Do you want to set %s as the screensaver for all users on this Mac?",
brandName[brandID])) {
if (!ShowMessage(true, "Do you want to set %s as the screensaver for all %s users on this Mac?",
brandName[brandID], brandName[brandID])) {
return noErr;
}
@ -775,6 +806,24 @@ OSErr UpdateAllVisibleUsers(long brandID)
if (pw == NULL) // "Deleted Users", "Shared", etc.
continue;
#ifdef SANDBOX
isGroupMember = false;
i = 0;
while ((p = grpBOINC_master.gr_mem[i]) != NULL) { // Step through all users in group boinc_master
if (strcmp(p, dp->d_name) == 0) {
// User is a member of group boinc_master
isGroupMember = true;
break;
}
++i;
}
if (!isGroupMember) {
continue;
}
#endif
saved_uid = geteuid();
seteuid(pw->pw_uid); // Temporarily set effective uid to this user