0

My (non-sandboxed) app has an embedded XPC helper which runs as root.

I would like to reference the (real) user's home directory from inside my helper, but these usual suspects simply return /var/root:

FileManager.default.homeDirectoryForCurrentUser
NSHomeDirectory()

I can't simply pass Users/bob to my helper for security reasons — if an exploit managed to call my helper method with any URL it wished, and my helper did things based on that as root, I fear bad things could be achieved.

jeff-h
  • 2,184
  • 1
  • 22
  • 33
  • 1
    The helper runs in the local domain, it has no idea about the *real* user, and what is supposed to happen if multiple users are logged in? My suggestion is to pass the path to the helper in a protocol method. – vadian Mar 11 '21 at 08:29
  • You can change the user a process is running as (from root to bob and back) There are unix methods (in C) for that. Than you can call Filemanager methods or NSHomeDirectory. If you want to that for a single thread only (not the whole program) there are methods for that, too. – Robert Mar 11 '21 at 08:36
  • Perhaps I have an underlying misunderstanding of the [exploitability](https://www.securing.biz/en/presentation/abusing-securing-xpc-in-macos-apps/) risk of XPC. I need the helper to create a file owned by root inside /Users/bob/.somewhere. I'm nervous at the potential risk of something like `func createFile(at url: URL, withContents contents: String)` – jeff-h Mar 11 '21 at 09:06

1 Answers1

1

As vadian commented there are fundamental conceptual issues with what you're asking. What you probably actually want to do is be sure the process communicating with your helper tool is in fact trusted.

To do that you need to use SecCodeCreateWithXPCMessage and then use the resulting SecCode instance to validate the caller. For an example of how to do that, take a look at the acceptMessage function in the SecureXPC framework.


EDIT: Turns out there is a way to do this that does work from a Command Line Tool such as one installed with SMJobBless. This answer is adapted from Apple's Technical Q&A QA1133.

If you for whatever reason want to ignore the above, there's an approach you can take which may produce unexpected results if multiple users have active consoles. From Apple's documentation for SCDynamicStoreCopyConsoleUser: "Note that this function only provides information about the primary console. It does not provide any details about console sessions that have fast user switched out or about other consoles."

import SystemConfiguration

extension FileManager {
    var homeDirectoryForConsoleUser: URL? {
        var homeDirectory: URL?
        if let consoleUser = SCDynamicStoreCopyConsoleUser(nil, nil, nil) as String?,
           consoleUser != "loginwindow" {
            homeDirectory = URL(fileURLWithPath: "/Users/\(consoleUser)")
        }
        
        return homeDirectory
    }
}

And then you can make use of this anywhere in your helper tool:

if let homeDirectory = FileManager.default.homeDirectoryForConsoleUser {
    // Do something useful here
}
Joshua Kaplan
  • 843
  • 5
  • 9
  • Where has `trilemma-dev / SecureXPC` been all my life Might be a bit late for my app, but I will definitely be taking a good look at it. Your "shortcut" above sounds interesting, but you're right — fundamentally I'm just unsure how much I can trust my XPC helper communication channel. – jeff-h Oct 29 '21 at 06:44
  • Updated my answer with code that actually should work for you. That said, I do strongly recommend you secure your XPC connection. To answer your rhetorical question, I only just wrote `SecureXPC` earlier this month - enjoy! – Joshua Kaplan Oct 29 '21 at 11:15