There's a security feature on El Capitan that essentially makes certain files and directories on your host system immutable. Presumably it's some set of filesystem flags, but not even root can change them. There's a magic nvram command you can use to disable the security feature (which if you're a developer you'll have to do eventually since you can't touch anything in /lib or /usr/bin or /bin). The command in question is:
nvram boot-args="rootless=0"
It seems to me that this is related to that feature. Although, I don't get why it looks like the two files are hardlinked but you can modify one -- maybe it's because this magic was only applied to the /usr/bin directory (and thus a hardlink to the file can still be modified). That's a bit dumb IMO, but I can imagine this being a bug in the OS X kernel.
Unfortunately, I'm not sure how to actually create such files (maybe if I disable System Integrity Protection, create a file and hardlink to it and then re-enable SIP). If I figure it out on my friends' MacBook I'll comment below.
EDIT: Okay, so it might not be what I said earlier. If I do something along the lines of:
1. Disable SIP (csrutil disable in recovery).
2. Create a file in /usr/bin and hardlink it to a non-SIP location (like $HOME).
3. Re-enable SIP (csrutil enable).
4. Try to change the permissions on either of the hardlinks.
It will fail. So presumably SIP correctly propagates permissions to all dentries. I'm not sure what's happening then.
> It will fail. So presumably SIP correctly propagates permissions to all dentries. I'm not sure what's happening then.
/usr/bin/git is a small wrapper that invokes the actual git from either the command line developer tools or from xcode (whatever you have selected with `xcode-select`)
I don't think it's intentional subversion. AFAIR, having command line wrappers in /usr/bin pointing to command line tools or xcode tool chain predates SIP. If anything, protecting developer tools was either neglected, or changing the concept of how it works to suit SIP was deemed not worth the cost.
I mean, SIP is generally only partial protection anyway, isn't it?
I meant installing the actual binary executed into a non-protected directory. What is the point of having SIP if the only process that can bypass it (the App Store installer) doesn't break the code.
Yes, I know that wrappers isn't new. But if they wanted to secure it they could've kept the actual binary in a SIP-protected directory.
SIP relies on the sandboxing rules in /System/Library/Sandbox (notably rootless.conf iirc; I am on 10.10 still for locally important if slightly idiosyncratic reasons). Below /S/L/S/ is the Profiles directory which is full of .sb files which are descriptions in a restricted R5RS Scheme of what system calls are allowed under what circumstances.
One of the features of SIP is that barring interference (e.g. using csrutil in the recovery boot mode) one can be fairly confident about the contents of a number of directories to the extent that one can (in the boot time trampoline that system upgrading uses) delete everything in them and install in their place the contents of signed installation media, with no worries that this accidentally conflicts with local state (e.g. locally installed versions of system software or dynamic libraries or the like).
Actually doing a "Reinstall the SIP-protected parts of Mac OS X" thus has some pretty good guarantees of non-destructiveness and thoroughness, and "Safe Mode" can ignore anything that isn't SIP-protected, thus producing a much more predictable post-boot environment than in previous version of Mac OS X.
Some thought went into the initial design and SIP evolved during the beta process; until fairly late, one could subvert SIP with union mounts for example, and there was to-and-fro on what third party things one could could simply move from /System/Library to /Library (notably from /S/L/Filesystems to /Library/Filesystems).
It's interesting to compare with the approach taken by SmartOS (for example; https://wiki.smartos.org/display/DOC/Zones), which in the global zone and in Solaris zones is strictly read only for everything under /usr, and which in the global zone refuses to persist changes under /etc and a few other places. Some of the reasoning is the same (known state can make for safer version upgrading); but some of the reasoning is to take advantage of other virtues too, specific to SmartOS's focus on hosting VMs.
Going back further, network-mounted read-only filesystems like /usr was fairly commonplace in environments where UNIX workstations were plentiful, with per-workstation customization often made user-specific (e.g. via moira, back in the day... http://kb.mit.edu/confluence/pages/viewpage.action?pageId=39...) and non-persisted, along the lines of the guest login in modern Mac OS X.
Back to your last sentence: Apple tools (including the App Store) can't work around the sandboxing without a system restart -- once the sandboxing service is running, it stays running and cannot be disabled, and a complex trampoline is needed in single user mode to work around sandboxing early in the startup process (even in single user mode). XCode does not install anything that really requires a reboot, and is wholly optional, so forcing a reboot to install or uninstall it seems heavy-handed compared to trampolines that rely on xcode-select. (Similar to other optional installs like X11). Moreover, XCode itself is signed and by default you will still get warned (and your tool will not be run) if something under XCode has been modified or substituted.
Nothing really prevents them from protecting optional installs using SIP if they decide it's better that way. And indeed, local admins familiar with Sandboxing can extend SIP protections to them themselves via /Library/Sandbox, where one can add further (but not weaker than /S/L/S) rules.
Unfortunately, I'm not sure how to actually create such files (maybe if I disable System Integrity Protection, create a file and hardlink to it and then re-enable SIP). If I figure it out on my friends' MacBook I'll comment below.
EDIT: Okay, so it might not be what I said earlier. If I do something along the lines of:
1. Disable SIP (csrutil disable in recovery).
2. Create a file in /usr/bin and hardlink it to a non-SIP location (like $HOME).
3. Re-enable SIP (csrutil enable).
4. Try to change the permissions on either of the hardlinks.
It will fail. So presumably SIP correctly propagates permissions to all dentries. I'm not sure what's happening then.