Sandboxing and calling Launchctl

  • Hi all,

    I posted this to the developer forums yesterday but I think this list probably gets a good bit more eyeball than the forum, so I'm sending here too. Sorry for the cross-post if you're seeing it twice.  Anyway...

    I'm trying to put together the last bits and pieces of sandboxing my app but I've just hit a problem.  I don't appear to be able to use launchctl to schedule tasks any more.

    With my app sandboxed, I'm launching an NSTask with the following launch path and arguments:
    > /bin/launchctl load -w /Users/mark/Library/Containers/<my app identifier>/Data/Library/LaunchAgents/<my app identifier>.helpername.plist

    I'm using the correct APIs to get the path and read/write the helpername.plist file.  As per other command line tools I launch via NSTask, launchctl is presumably inheriting the same entitlements as my main application, but launchctl obviously needs to modify other files to which my app normally wouldn't have access - namely:
    /private/var/db/launchd.db/com.apple.launchd.peruser.501/overrides.plist


    The inherited entitlements don't allow access to that file, so I'm seeing this from sandboxd in the log file:
    > launchctl(4831) deny file-read-data /private/var/db/launchd.db/com.apple.launchd.peruser.501/overrides.plist
    and
    > launchctl(4831) deny job-creation

    I'm also seeing this in Xcode's run log:
    > Bug: launchctl.c:2425 (25957):1: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1
    > launch_msg(): Socket is not connected

    As the user ID in the filename which launchctl is trying to write will be different for different users, I don't think I can set a temporary entitlement for it (haven't tried yet, that's today's task!), and even if I can, it doesn't seem like the right answer for long-term use.

    Has anyone else come across this problem?  If so, how did you solve it?

    Many thanks
    Mark
  • On Tue, May 29, 2012 at 10:52 AM, Mark Allan
    <markjallan...> wrote:
    > Hi all,
    >
    > I posted this to the developer forums yesterday but I think this list probably gets a good bit more eyeball than the forum, so I'm sending here too. Sorry for the cross-post if you're seeing it twice.  Anyway...
    >
    > I'm trying to put together the last bits and pieces of sandboxing my app but I've just hit a problem.  I don't appear to be able to use launchctl to schedule tasks any more.
    >
    > With my app sandboxed, I'm launching an NSTask with the following launch path and arguments:
    >> /bin/launchctl load -w /Users/mark/Library/Containers/<my app identifier>/Data/Library/LaunchAgents/<my app identifier>.helpername.plist
    >
    >
    > I'm using the correct APIs to get the path and read/write the helpername.plist file.  As per other command line tools I launch via NSTask, launchctl is presumably inheriting the same entitlements as my main application, but launchctl obviously needs to modify other files to which my app normally wouldn't have access - namely:[...]

    SMLoginItemSetEnabled can be a solution.

    https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BP
    SystemStartup/Chapters/CreatingLoginItems.html
  • On 29 May 2012, at 12:24, Stephane Sudre wrote:
    > On Tue, May 29, 2012 at 10:52 AM, Mark Allan
    > Hi all,
    >>
    >> I posted this to the developer forums yesterday but I think this list probably gets a good bit more eyeball than the forum, so I'm sending here too. Sorry for the cross-post if you're seeing it twice.  Anyway...
    >>
    >> I'm trying to put together the last bits and pieces of sandboxing my app but I've just hit a problem.  I don't appear to be able to use launchctl to schedule tasks any more.
    >>
    >> With my app sandboxed, I'm launching an NSTask with the following launch path and arguments:
    >>> /bin/launchctl load -w /Users/mark/Library/Containers/<my app identifier>/Data/Library/LaunchAgents/<my app identifier>.helpername.plist
    >>
    >>
    >> I'm using the correct APIs to get the path and read/write the helpername.plist file.  As per other command line tools I launch via NSTask, launchctl is presumably inheriting the same entitlements as my main application, but launchctl obviously needs to modify other files to which my app normally wouldn't have access - namely:[...]
    >
    > SMLoginItemSetEnabled can be a solution.
    >
    > https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BP
    SystemStartup/Chapters/CreatingLoginItems.html


    Hi Stephane,

    Thanks for your reply, but that's not quite what I'm looking for.  I'm not using launchctl to set a startup/login item, I'm using it to allow the user to specify a schedule to perform various tasks based on a particular time and day of the week.  While I could write a login item which ran indefinitely and took care of the timing myself, it seems like I'd be reinventing the wheel!

    I already moved from cron to launchd to support the AppStore, which was a pain, so I really hope Apple doesn't want me to roll my own timing mechanism just to support sandboxing!

    Still, it's an option which I'll bear in mind, so thanks for that.

    Mark
  • > SMLoginItemSetEnabled can be a solution.

    Again "fabulous" documentation on that one.

    I tried my best to get the usual "start on login" wrapped up in a helper

      https://github.com/tcurdt/TCLoginItemHelper

    ...but in the end just left it out of the app.

    cheers,
    Torsten
  • For anyone following, using temporary entitlements only gets rid of two of the four errors, so I still can't make scheduling via launchd work.

    sandboxd still spits out:
    launchctl(14634) deny job-creation

    and Xcode/run log still gives:
    launch_msg(): Socket is not connected

    Other than rolling my own scheduling and writing a helper app which runs constantly in the background, can anyone think of a way around this?

    Thanks
    Mark

    On 29 May 2012, at 09:52, Mark Allan wrote:

    > The inherited entitlements don't allow access to that file, so I'm seeing this from sandboxd in the log file:
    >> launchctl(4831) deny file-read-data /private/var/db/launchd.db/com.apple.launchd.peruser.501/overrides.plist
    > and
    >> launchctl(4831) deny job-creation
    >
    > I'm also seeing this in Xcode's run log:
    >> Bug: launchctl.c:2425 (25957):1: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1
    >> launch_msg(): Socket is not connected
  • On 29 May 2012, at 15:42, Mark Allan wrote:

    > For anyone following, using temporary entitlements only gets rid of two of the four errors, so I still can't make scheduling via launchd work.
    >
    > sandboxd still spits out:
    > launchctl(14634) deny job-creation
    >
    > and Xcode/run log still gives:
    > launch_msg(): Socket is not connected
    >
    > Other than rolling my own scheduling and writing a helper app which runs constantly in the background, can anyone think of a way around this?
    >
    > Thanks
    > Mark

    OK.  After nearly a week of head-banging, I'm just about ready to throw in the towel, dump sandboxing and potentially the Mac App Store altogether.

    I spent the best part of yesterday reinventing the wheel and implementing my own scheduling mechanism to put into a helper app which would run in the background constantly as a login item... the timing/scheduling bit works fine, but the helper app can't actually DO anything because it runs in a different sandbox from the main app!!  This means I can't access the user's preferences without a temporary entitlement, and can't access the resources within my main app at all.

    My helper app sits in Main.app/Contents/Library/LoginItems/MainHelper.app and is launched (based on user prefs) by calling
    SMLoginItemSetEnabled((CFStringRef)[NSString stringWithString:@"<my app identifier>.helpername"], true)

    I've tried giving the helper the same bundle identifier as the main app, but that doesn't work (as expected, but I wanted to try anyway!).

    I've even tried getting the path of the helper app ([[NSBundle mainBundle] bundlePath]) and removing the last 4 path components to get the path to the main application and launching it via NSWorkspace, so that I could then launch my helper that way and inherit the sandbox, but sandboxd gives more permission violations when attempting to launch the main application.  I suspect that would have been cause for appstore rejection anyway!

    I feel like I've missed something obvious, but I just can't see it.  Is there a way to make the helper app run in the same sandbox as the main app?

    Many thanks for your help.

    Mark
  • If you haven't watched the video for Session 204 - "App Sandbox and the Mac App Store" from the WWDC 2011 videos, there might be some info in there that will help you around the 9 minute mark.

    Search for the 2011 WWDC videos on developer.apple.com

    GL,
    - Alex Zavatone

    On May 31, 2012, at 6:35 AM, Mark Allan wrote:

    > On 29 May 2012, at 15:42, Mark Allan wrote:
    >
    >> For anyone following, using temporary entitlements only gets rid of two of the four errors, so I still can't make scheduling via launchd work.
    >>
    >> sandboxd still spits out:
    >> launchctl(14634) deny job-creation
    >>
    >> and Xcode/run log still gives:
    >> launch_msg(): Socket is not connected
    >>
    >> Other than rolling my own scheduling and writing a helper app which runs constantly in the background, can anyone think of a way around this?
    >>
    >> Thanks
    >> Mark
    >
    > OK.  After nearly a week of head-banging, I'm just about ready to throw in the towel, dump sandboxing and potentially the Mac App Store altogether.
    >
    > I spent the best part of yesterday reinventing the wheel and implementing my own scheduling mechanism to put into a helper app which would run in the background constantly as a login item... the timing/scheduling bit works fine, but the helper app can't actually DO anything because it runs in a different sandbox from the main app!!  This means I can't access the user's preferences without a temporary entitlement, and can't access the resources within my main app at all.
    >
    > My helper app sits in Main.app/Contents/Library/LoginItems/MainHelper.app and is launched (based on user prefs) by calling
    > SMLoginItemSetEnabled((CFStringRef)[NSString stringWithString:@"<my app identifier>.helpername"], true)
    >
    > I've tried giving the helper the same bundle identifier as the main app, but that doesn't work (as expected, but I wanted to try anyway!).
    >
    > I've even tried getting the path of the helper app ([[NSBundle mainBundle] bundlePath]) and removing the last 4 path components to get the path to the main application and launching it via NSWorkspace, so that I could then launch my helper that way and inherit the sandbox, but sandboxd gives more permission violations when attempting to launch the main application.  I suspect that would have been cause for appstore rejection anyway!
    >
    > I feel like I've missed something obvious, but I just can't see it.  Is there a way to make the helper app run in the same sandbox as the main app?
    >
    > Many thanks for your help.
    >
    > Mark
  • Thanks Alex,

    Thanks for your reply.

    If you're talking about the com.apple.security.inherit entitlement, that only works for helper apps which are launched via fork/exec from the main application.  When the helper app is launched by LaunchServices (via SMLoginItemSetEnabled) it crashes immediately as it can't inherit a sandbox from anywhere.

    In a last-ditch attempt, I was trying to get around that by:
    Have my helper app launch the main app at startup.
    The main app could then launch a second helper (with com.apple.security.inherit entitlement) to do the scheduling.
    Main app then terminates immediately.

    The two problems with that approach are firstly, the sandbox wouldn't let the helper launch my primary app because it's in a different sandbox, and secondly, my understanding of forking is that even if I could do that, when the main app terminates, any process it forked also gets terminated doesn't it?

    Mark

    On 1 Jun 2012, at 02:30, Alex Zavatone wrote:

    > If you haven't watched the video for Session 204 - "App Sandbox and the Mac App Store" from the WWDC 2011 videos, there might be some info in there that will help you around the 9 minute mark.
    >
    > Search for the 2011 WWDC videos on developer.apple.com
    >
    > GL,
    > - Alex Zavatone
    >
    > On May 31, 2012, at 6:35 AM, Mark Allan wrote:
    >
    >> On 29 May 2012, at 15:42, Mark Allan wrote:
    >>
    >>> For anyone following, using temporary entitlements only gets rid of two of the four errors, so I still can't make scheduling via launchd work.
    >>>
    >>> sandboxd still spits out:
    >>> launchctl(14634) deny job-creation
    >>>
    >>> and Xcode/run log still gives:
    >>> launch_msg(): Socket is not connected
    >>>
    >>> Other than rolling my own scheduling and writing a helper app which runs constantly in the background, can anyone think of a way around this?
    >>>
    >>> Thanks
    >>> Mark
    >>
    >> OK.  After nearly a week of head-banging, I'm just about ready to throw in the towel, dump sandboxing and potentially the Mac App Store altogether.
    >>
    >> I spent the best part of yesterday reinventing the wheel and implementing my own scheduling mechanism to put into a helper app which would run in the background constantly as a login item... the timing/scheduling bit works fine, but the helper app can't actually DO anything because it runs in a different sandbox from the main app!!  This means I can't access the user's preferences without a temporary entitlement, and can't access the resources within my main app at all.
    >>
    >> My helper app sits in Main.app/Contents/Library/LoginItems/MainHelper.app and is launched (based on user prefs) by calling
    >> SMLoginItemSetEnabled((CFStringRef)[NSString stringWithString:@"<my app identifier>.helpername"], true)
    >>
    >> I've tried giving the helper the same bundle identifier as the main app, but that doesn't work (as expected, but I wanted to try anyway!).
    >>
    >> I've even tried getting the path of the helper app ([[NSBundle mainBundle] bundlePath]) and removing the last 4 path components to get the path to the main application and launching it via NSWorkspace, so that I could then launch my helper that way and inherit the sandbox, but sandboxd gives more permission violations when attempting to launch the main application.  I suspect that would have been cause for appstore rejection anyway!
    >>
    >> I feel like I've missed something obvious, but I just can't see it.  Is there a way to make the helper app run in the same sandbox as the main app?
    >>
    >> Many thanks for your help.
    >>
    >> Mark
    >
  • On Jun 1, 2012, at 4:33 PM, Mark Allan wrote:

    > Thanks Alex,
    >
    > Thanks for your reply.
    >
    > If you're talking about the com.apple.security.inherit entitlement, that only works for helper apps which are launched via fork/exec from the main application.  When the helper app is launched by LaunchServices (via SMLoginItemSetEnabled) it crashes immediately as it can't inherit a sandbox from anywhere.
    >
    > In a last-ditch attempt, I was trying to get around that by:
    > Have my helper app launch the main app at startup.
    > The main app could then launch a second helper (with com.apple.security.inherit entitlement) to do the scheduling.
    > Main app then terminates immediately.
    >
    > The two problems with that approach are firstly, the sandbox wouldn't let the helper launch my primary app because it's in a different sandbox, and secondly, my understanding of forking is that even if I could do that, when the main app terminates, any process it forked also gets terminated doesn't it?
    >
    > Mark

    Got to admire your determination with this, I just can't believe that nobody knows how to do it but I've googled around and hunted the dev forums and either nobody does know how to do it, hasn't tried it, or they all managed it with zero effort and thus didn't post, I doubt it's the latter.

    As to fork(), if your parent dies you live on, just get reparented (to init I think). The question is usually asked the other way around, people wanting child processes to get killed when the parent dies and it can be quite hard.
  • This helped me thanks!  Unfortunately I wasn't try to launch my helper app via launchd so it was a bit different.  But had to say thanks! :-)

    rc

    On Jun 1, 2012, at 9:30 AM, Alex Zavatone wrote:

    > If you haven't watched the video for Session 204 - "App Sandbox and the Mac App Store" from the WWDC 2011 videos, there might be some info in there that will help you around the 9 minute mark.
    >
    > Search for the 2011 WWDC videos on developer.apple.com
    >
    > GL,
    > - Alex Zavatone
    >
    > On May 31, 2012, at 6:35 AM, Mark Allan wrote:
    >
    >> On 29 May 2012, at 15:42, Mark Allan wrote:
    >>
    >>> For anyone following, using temporary entitlements only gets rid of two of the four errors, so I still can't make scheduling via launchd work.
    >>>
    >>> sandboxd still spits out:
    >>> launchctl(14634) deny job-creation
    >>>
    >>> and Xcode/run log still gives:
    >>> launch_msg(): Socket is not connected
    >>>
    >>> Other than rolling my own scheduling and writing a helper app which runs constantly in the background, can anyone think of a way around this?
    >>>
    >>> Thanks
    >>> Mark
    >>
    >> OK.  After nearly a week of head-banging, I'm just about ready to throw in the towel, dump sandboxing and potentially the Mac App Store altogether.
    >>
    >> I spent the best part of yesterday reinventing the wheel and implementing my own scheduling mechanism to put into a helper app which would run in the background constantly as a login item... the timing/scheduling bit works fine, but the helper app can't actually DO anything because it runs in a different sandbox from the main app!!  This means I can't access the user's preferences without a temporary entitlement, and can't access the resources within my main app at all.
    >>
    >> My helper app sits in Main.app/Contents/Library/LoginItems/MainHelper.app and is launched (based on user prefs) by calling
    >> SMLoginItemSetEnabled((CFStringRef)[NSString stringWithString:@"<my app identifier>.helpername"], true)
    >>
    >> I've tried giving the helper the same bundle identifier as the main app, but that doesn't work (as expected, but I wanted to try anyway!).
    >>
    >> I've even tried getting the path of the helper app ([[NSBundle mainBundle] bundlePath]) and removing the last 4 path components to get the path to the main application and launching it via NSWorkspace, so that I could then launch my helper that way and inherit the sandbox, but sandboxd gives more permission violations when attempting to launch the main application.  I suspect that would have been cause for appstore rejection anyway!
    >>
    >> I feel like I've missed something obvious, but I just can't see it.  Is there a way to make the helper app run in the same sandbox as the main app?
    >>
    >> Many thanks for your help.
    >>
    >> Mark

previous month may 2012 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today