Skip to content

[macOS sandbox mode] Application group name mangling for semaphores #1167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ set(app_android_SRCS
src/uuid.cc)
set(app_ios_SRCS
src/app_ios.mm
src/util_apple.mm
src/util_ios.mm
src/invites/ios/invites_receiver_internal_ios.mm
src/invites/ios/invites_ios_startup.mm
Expand Down Expand Up @@ -220,7 +221,8 @@ else()
src/secure/user_secure_darwin_internal.mm
src/filesystem_apple.mm
src/locale_apple.mm
src/uuid_ios_darwin.mm)
src/uuid_ios_darwin.mm
src/util_apple.mm)
else()
# Linux requires libsecret.
pkg_check_modules(LIBSECRET libsecret-1)
Expand Down
4 changes: 4 additions & 0 deletions app/src/app_desktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "app/src/include/firebase/internal/common.h"
#include "app/src/include/firebase/version.h"
#include "app/src/log.h"
#include "app/src/semaphore.h"
#include "app/src/util.h"

namespace firebase {
Expand Down Expand Up @@ -131,6 +132,9 @@ App* App::Create(const AppOptions& options, const char* name) { // NOLINT
return app;
}
LogDebug("Creating Firebase App %s for %s", name, kFirebaseVersionString);
LogDebug("Validating semaphore creation.");
{ firebase::Semaphore sem_test(0); }

AppOptions options_with_defaults = options;
if (options_with_defaults.PopulateRequiredWithDefaults()) {
app = new App();
Expand Down
42 changes: 34 additions & 8 deletions app/src/semaphore.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <errno.h>

#include "app/src/assert.h"
#include "app/src/include/firebase/internal/platform.h"
#include "app/src/time.h"

Expand All @@ -39,6 +40,9 @@
#if FIREBASE_PLATFORM_OSX || FIREBASE_PLATFORM_IOS || FIREBASE_PLATFORM_TVOS
#include "app/src/include/firebase/internal/mutex.h"
#include "app/src/pthread_condvar.h"
#include "app/src/util_apple.h"

#define FIREBASE_SEMAPHORE_DEFAULT_PREFIX "/firebase-"
#endif // FIREBASE_PLATFORM_OSX || FIREBASE_PLATFORM_IOS ||
// FIREBASE_PLATFORM_TVOS

Expand All @@ -50,29 +54,50 @@ class Semaphore {
#if FIREBASE_PLATFORM_OSX || FIREBASE_PLATFORM_IOS || FIREBASE_PLATFORM_TVOS
// MacOS requires named semaphores, and does not support unnamed.
// Generate a unique string for the semaphore name:
static const char kPrefix[] = "/firebase-";
// String length of the name prefix.
static const int kPprefixLen = sizeof(kPrefix);

// String length of the pointer, when printed to a string.
static const int kPointerStringLength = 16;
// Buffer size. the +1 is for the null terminator.
static const int kBufferSize = kPprefixLen + kPointerStringLength + 1;
static const int kBufferSize = kPointerStringLength + 1;

char buffer[kBufferSize];
snprintf(buffer, kBufferSize, "%s%016llx", kPrefix,
snprintf(buffer, kBufferSize, "%016llx",
static_cast<unsigned long long>( // NOLINT
reinterpret_cast<intptr_t>(this)));
#if FIREBASE_PLATFORM_OSX
// Append custom semaphore names, if present, to support macOS Sandbox
// mode.
std::string semaphore_name = util::GetSandboxModeSemaphorePrefix();
if (semaphore_name.empty()) {
semaphore_name = FIREBASE_SEMAPHORE_DEFAULT_PREFIX;
}
#else
std::string semaphore_name = FIREBASE_SEMAPHORE_DEFAULT_PREFIX;
#endif // FIREBASE_PLATFORM_OSX

semaphore_ = sem_open(buffer,
semaphore_name.append(buffer);
semaphore_ = sem_open(semaphore_name.c_str(),
O_CREAT | O_EXCL, // Create if it doesn't exist.
S_IRUSR | S_IWUSR, // Only the owner can read/write.
initial_count);

// Check for errors.
#if FIREBASE_PLATFORM_OSX
FIREBASE_ASSERT_MESSAGE(
semaphore_ != SEM_FAILED,
"Failed to create semaphore. If running in sandbox mode be sure to "
"configure FBAppGroupEntitlementName in your app's Info.plist.");
#endif // FIREBASE_PLATFORM_OSX

assert(semaphore_ != SEM_FAILED);
assert(semaphore_ != nullptr);

// Remove the semaphore from the system registry, so other processes can't
// grab it. (These are designed to just be passed around internally by
// pointer, like unnamed semaphores. Mac OSX targets don't support unnamed
// semaphores though, so we have to use named, and just treat them like
// unnamed.
bool success = (sem_unlink(buffer) == 0);
bool success = (sem_unlink(semaphore_name.c_str()) == 0);
assert(success);
(void)success;
#elif !FIREBASE_PLATFORM_WINDOWS
Expand All @@ -81,13 +106,14 @@ class Semaphore {
bool success = sem_init(semaphore_, 0, initial_count) == 0;
assert(success);
(void)success;
assert(semaphore_ != nullptr);
#else
semaphore_ = CreateSemaphore(nullptr, // default security attributes
initial_count, // initial count
LONG_MAX, // maximum count
nullptr); // unnamed semaphore
#endif
assert(semaphore_ != nullptr);
#endif
}

~Semaphore() {
Expand Down
33 changes: 33 additions & 0 deletions app/src/util_apple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FIREBASE_APP_SRC_UTIL_APPLE_H_
#define FIREBASE_APP_SRC_UTIL_APPLE_H_

#include <string>

namespace firebase {
namespace util {

// Attempts to query the custom semaphore prefix from the application's
// Info.plist file. Returns an empty string if a custom semahpore prefix
// wasn't conifgured.
std::string GetSandboxModeSemaphorePrefix();

} // namespace util
} // namespace firebase

#endif // FIREBASE_APP_SRC_UTIL_APPLE_H_
39 changes: 39 additions & 0 deletions app/src/util_apple.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "app/src/util_apple.h"

#import <Foundation/Foundation.h>

namespace firebase {
namespace util {

std::string GetSandboxModeSemaphorePrefix() {
NSBundle* mainBundle = [NSBundle mainBundle];
if (mainBundle != nil) {
NSDictionary<NSString*, id>* dictionary = [mainBundle infoDictionary];
if (dictionary != nil) {
NSString* customPrefix = [dictionary valueForKey:@"FBAppGroupEntitlementName"];
if (customPrefix != nil) {
return std::string(customPrefix.UTF8String).append("/");
}
}
}
return std::string();
}

} // namespace util
} // namespace firebase
6 changes: 6 additions & 0 deletions release_build_files/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,12 @@ code.
### Upcoming Release
- Changes
- Analytics: Add `analytics::SetConsent()` API.
- General (macOS): In order to support sandbox mode, apps can define a
key/value pair for FBAppGroupEntitlementName in Info.plist. The value
associated with this key will be used to prefix semaphore names
created internally by the Firebase C++ SDK so that they conform with
[macOS sandbox
requirements](https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24).

### 10.3.0
- Changes
Expand Down