1. 15
  1.  

  2. 5

    As noted in another comment, the issue isn’t that /usr/bin/gem overwrites any part of Ruby that comes with the system; it doesn’t have permissions to do that under SIP. Instead, it’s installing a new version of rubygems into /Library/Ruby, which takes precedence over the copy in /System if it exists.

    I think the underlying problem is that Apple patched the wrong file. Apple patched rubygems/defaults.rb, but that’s a file that comes with rubygems, so it’ll be overridden by a /usr/bin/gem update --system. Rubygems supports customizations via a different file, rubygems/defaults/operating_system.rb. That file isn’t installed by default, but if it exists it always takes precedence over rubygems/defaults; that would have prevented this problem. Homebrew uses that to customize the gem bindir in exactly the same way OS X does.

    1. 4

      From IRC:

      <willsalz_> r.e. https://lobste.rs/s/tgnykh/how_to_brick_os_x_el_capitan_ruby_gem: the author doesn’t need to ‘reinstall’ the OS they can just ‘upgrade’ over the existing OS and SIP should self-correct. Also a great way to fix other, potentelly messy OS X issues.

      1. 3

        I actually had an OS X update pending and applied that, but it didn’t touch gem. Unless they meant something more specific?

      2. 3

        Someone on Twitter pointed out to me that this is surprising (and maybe even a bug of sorts): Apparently Apple patches gem in such a way that it doesn’t install binaries to /usr/bin by default any longer.

        But that is surprising because your post-update gem was trying to install to /usr/bin. Out of curiosity, what is the default install directory for gems in the defaults file (grep for if defined? RUBY_FRAMEWORK_VERSION):

        /System/Library/Frameworks/Ruby.framework/Versions/<version>/usr/lib/ruby/<version>/rubygems/defaults.rb

        I’m just wondering if the update to gem overwrote this patch. If so, that seems to be a bug: Apple tried to protect users from this kind of problem, but it should also forbid updating that defaults file.

        Update A few people tried the same global gem update and reported that the it installs a new defaults.rb file in /Library/Ruby/Gems. That defaults file is then read before the one patched by Apple, and boom: breakage when gem tries to install to /usr/bin. A relatively easy fix might be to patch the new defaults.rb by hand, so that it matches the Apple patch. It’s trivial change. I mention all this for future Googlers, but it may also help you now. Good luck!

        1. 5

          I looked into this, found that the /usr/bin/gem update --system isn’t installing anywhere inside /usr/bin or within the system Ruby at /System; it doesn’t have permissions to do that. Instead, the rubygems update is installing a new rubygems at /Library/Ruby/Site/2.0.0/, which is a sudo-writeable location under SIP; that is loaded by Ruby first before the version that comes with the OS, and it includes a version of rubygems/defaults.rb which lists /usr/bin as the default gem bindir. If you remove /Library/Ruby/Site/2.0.0/rubygems and /Library/Ruby/Site/2.0.0/rubygems.rb, gem will go back to using the original system-installed version and all will be fine; alternately, you can patch /Library/Ruby/Site/2.0.0/rubygems/defaults.rb to change the bindir.

          Before:

          $ /usr/bin/ruby -e 'require "rubygems/defaults"; puts Gem.default_bindir'
          /usr/bin
          

          After:

          $ /usr/bin/ruby -e 'require "rubygems/defaults"; puts Gem.default_bindir'
          /usr/local/bin
          
        2. 1

          tl;dr: don’t execute commands using sudo unless you know what you are doing. OS X already has some preinstalled gems, upgrading gems or gem itself could result in breakage of software that uses OS X-specific versions. You are basically modifying the base system.

          Install Ruby from Homebrew, or even better: use rbenv, rvm, or chruby.

          1. 4

            don’t execute commands using sudo unless you know what you are doing.

            You are basically modifying the base system.

            Funny because SIP is in place to prevent you from breaking the base system, even with sudo.