-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure osxphotos is responsible process by launching disclaimed (#1587)
When osxphotos accesses the Photos library the macOS TCC system will check the responsible process for permission to access the library, and if none has been given, the user is asked to give permission via a dialog. Normally, when an executable is launched from Terminal or iTerm, the responsible app is the terminal app itself, not osxphotos, which means the user needs to give the terminal app the permission to access the Photos library, effectively giving any command executed in the terminal at any point access to the library. Worse yet, if the user has on some prior occasion denied the terminal app this access, then osxphotos will not get the needed access either, which has been a source for confusion and failures for users. We now re-launch osxphotos at startup with a special spawn flag that ensures that osxphotos is the responsible process. This will result in TCC dialogs and permissions specific to osxphotos.
- Loading branch information
Showing
4 changed files
with
90 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <spawn.h> | ||
#include <signal.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
extern "C" { | ||
int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim) | ||
__attribute__((availability(macos,introduced=10.14),weak_import)); | ||
char ***_NSGetArgv(); | ||
} | ||
|
||
#define CHECK_SPAWN(expr) \ | ||
if (int err = (expr)) { \ | ||
posix_spawnattr_destroy(&attr); \ | ||
fprintf(stderr, "[disclaim] %s: %s", #expr, strerror(err)); \ | ||
exit(err); \ | ||
} | ||
|
||
/* | ||
Re-launches the process with disclaimed responsibilities, | ||
effectively making it responsible for its own permissions. | ||
Based on https://www.qt.io/blog/the-curious-case-of-the-responsible-process | ||
*/ | ||
extern "C" void disclaim() | ||
{ | ||
posix_spawnattr_t attr; | ||
CHECK_SPAWN(posix_spawnattr_init(&attr)); | ||
|
||
// Behave as exec | ||
short flags = POSIX_SPAWN_SETEXEC; | ||
|
||
// Reset signal mask | ||
sigset_t no_signals; | ||
sigemptyset(&no_signals); | ||
CHECK_SPAWN(posix_spawnattr_setsigmask(&attr, &no_signals)); | ||
flags |= POSIX_SPAWN_SETSIGMASK; | ||
|
||
// Reset all signals to their default handlers | ||
sigset_t all_signals; | ||
sigfillset(&all_signals); | ||
CHECK_SPAWN(posix_spawnattr_setsigdefault(&attr, &all_signals)); | ||
flags |= POSIX_SPAWN_SETSIGDEF; | ||
|
||
CHECK_SPAWN(posix_spawnattr_setflags(&attr, flags)); | ||
|
||
if (__builtin_available(macOS 10.14, *)) { | ||
// Disclaim TCC responsibilities for parent, making | ||
// the launched process the responsible process. | ||
if (responsibility_spawnattrs_setdisclaim) | ||
CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1)); | ||
} | ||
|
||
pid_t pid = 0; | ||
char **argv = *_NSGetArgv(); | ||
extern char **environ; | ||
CHECK_SPAWN(posix_spawnp(&pid, argv[0], nullptr, &attr, argv, environ)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
def _pyi_rthook(): | ||
import sys | ||
if sys.platform != 'darwin': | ||
return | ||
|
||
# Avoid redundant disclaims | ||
import os | ||
if os.environ.get('PYI_DISCLAIMED'): | ||
return | ||
os.environ['PYI_DISCLAIMED'] = '1' | ||
|
||
# The bootloader has cleared the _MEIPASS2 environment variable by the | ||
# time we get here, which means re-launching the executable disclaimed | ||
# will unpack the binary again. To avoid this we reset _MEIPASS2 again, | ||
# so that our re-launch will pick up at second stage of the bootstrap. | ||
os.environ['_MEIPASS2'] = sys._MEIPASS | ||
|
||
import ctypes | ||
library_path = os.path.join(sys._MEIPASS, 'libdisclaim.dylib') | ||
libdisclaim = ctypes.cdll.LoadLibrary(library_path) | ||
libdisclaim.disclaim() | ||
|
||
_pyi_rthook() | ||
del _pyi_rthook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters