"Required Reason" API - stat()

I've just been looking at this list of APIs for which we will be soon be required to declare a "required reason" in the app's privacy manifest:

https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api

One of the listed functions is stat().

The rationale seems to be that a malicious app can use stat to get the timestamps of files outside the app container, thereby "fingerprinting" the device.

The allowed reasons that we can declare are :

  1. To get timestamps that are displayed to the user.
  2. To get timestamps of files that are within the app's container.
  3. To get timestamps of files that the user has granted access to.

I am concerned that this does not include many of the legitimate non-timestamp uses of stat(). For example, it can be used simply to test if a file exists, or to test whether a path refers to a file or a directory, or to check if two paths refer to the same file (e.g. via different symlinks), or to get the size of a file.

Some of these things can be achieved in other ways; for example, I can check if a file exists by trying to open() it and checking for an error, and I can get the file size by opening it and calling lseek(SEEK_END). Maybe I can check if two paths are equivalent by using readlink() to form canonical paths for both and comparing them. But I bet there are other things that can't be done.

I could probably fix all of my code to not call stat() for non-timestamp reasons in a few hours. It would be more difficult to fix the various open-source libraries that I use.

What do you think we should all be doing?:

  1. "File a bug" asking for an additional reason for using stat(), i.e. to get non-timestamp information about files in the app's container.
  2. Deliberately mis-read allowed reason C617.1, "to access the timestamps of files inside the app container", as " to access the timestamps and other metadata of files inside the app container", and declare that in the privacy manifest.
  3. Change code to not call stat().
  4. Any other suggestions?

P.S. I guess that libc++ std::filesystem calls stat(). What is the status of using that? The std::filesystem functions that access file timestamps are not listed on the page linked above. If I call std::exists() to check if a file exists, and assuming that is implemented using stat(), will that trigger the new filter?

use methods intended for your specific need (ie fileExistsAtPath to check if file exists)

use methods intended for your specific need (ie fileExistsAtPath to check if file exists)

Right, so "change all the code" then; is that what you're going to do?

I've submitted a request for an additional reason using the form here:

https://developer.apple.com/contact/request/privacy-manifest-reason/

I've suggested that an additional reason be added for stat() etc., "to read non-timestamp metadata". I'll update this if I get a reply.

I've also submitted a bug (FB12798615) saying that C++ timestamp-reading functions aren't on the list. Of course there isn't a suitable Feedback category for that so it's under "something else". I'll update here if I get a reply.

@endecotp I'm puzzled by this new requirement as much as you are, notably if there are API we use for a purpose which is not listed.

Yes, it's a good idea to file bugs, it is important to let them know the issues they are creating.

I fear there are little option but change the code, unless you can add a warning to the user at start to fall in case 1 ?

I also think of UserDefaults which is very common (and recommended) API to just store user preferences in the app ; being forced to detail the use of it is a boring task.

And finally, I understand that will force to use Xcode 15, hence at least Montana (and in some cases obsolete some iMac…)

I also submitted a request and filed the following bug report (suggestion): Aug 2, 2023 at 5:10 PM – FB12832242

If I understand correctly, Privacy Manifest will be required as soon as some API are used, including UserDefaults.

This seems a useless burden if the app does never connect to a server and hence cannot send back or give access to any user information.

It would simplify developers work if Privacy Manifest was not required in such a case.

I'll update here if I get a reply.

I got a reply saying that my feedback "has been noted".

I'll update here if I get a reply.

My bug report has now been closed: "we believe this issue is resolved". Of course they don't tell me what the resolution actually is; the web page hasn't been changed, it still doesn't contain any C++ functions in the list, nor is there a reason code for using stat() to retrieve non-timestamp file information.

My bug report has now been closed

What bug was that specifically?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

What bug was that specifically?

FB12798615

Here's the body of the bug report:


Regarding the list of APIs for which a declared reason will shortly be required, as described at https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api

I note that no C++ functions are included in this list. For example, libc++'s std::filesystem::last_write_time., std::filesystem::space_info, etc.

I can see a couple of possible reasons for this:

(a) You've overlooked these functions and they should be included. (b) Because these functions are actually thin wrappers around C APIs such as stat(), you consider that the inclusion of stat() (etc.) in that list extends to these C++ functions.

If (b) applies, this is going to cause problems because many non-timestamp-related std::filesystem functions actually call stat(), ignoring the returned timestamps. For example, simply checking if a file exists using std::filesystem::exists() calls stat. You don't want to be rejecting an app that calls std::filesystem::exists() by sending the developer a message telling them that they are using stat(), that will just cause a lot of confusion for everyone.


@endecotp Hi, What was your final approach in this situation?

There has been an update to the reasons listed on the web page. Where it used to say "to access the timestamps of files inside the app container", it now says "to access the timestamps, size, or other metadata of files inside the app container" (emphasis added). So using stat() to check if a file exists, to read its size, etc. is now allowed, but you do need to declare the usage, and you can't explore outside your container (and group containers, your iCloud containers, etc.).

Still no mention of C++ std::filesystem functions. I don't think the app store checking has been turned on yet, so we don't know if they will be detected or not.

What was your final approach in this situation?

I don't have a "final approach". As we can now see, it would have been a waste of time to remove all of my stat()-based std::filesystem calls when this was first announced!

"Required Reason" API - stat()
 
 
Q