Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

"rvmsudo rvm get" does not apply the right permissions #1124

Closed
lemoinem opened this Issue · 9 comments

2 participants

@lemoinem
Collaborator

Hello,

Follow up last comment in #1123:

standard umask (supposed to be): 067, /etc/rvmrc not modified

The user is not in the rvm group, and is in not in gemset mixed mode.

after doing rvmsudo rvm get stable --auto, when I login back:

bash: /usr/local/rvm/hooks/after_cd: Permission denied
mlemoine@my-server:~$ ls -l /usr/local/rvm/hooks/after_cd
-rw--w---- 1 root rvm 274 Sep 22 00:23 /usr/local/rvm/hooks/after_cd
mlemoine@my-server:~$ rvmsudo rvm get head --auto
bash: /usr/local/rvm/bin/rvmsudo: Permission denied
mlemoine@my-server:~$ ls -l /usr/local/rvm/bin/rvmsudo
-rwx-wx--- 1 root rvm 960 Sep 22 00:23 /usr/local/rvm/bin/rvmsudo
mlemoine@my-server:~$ sudo chmod a+rx /usr/local/rvm/bin/rvmsudo
[sudo] password for mlemoine:  ***********

Installing head:

mlemoine@my-server:~$ rvmsudo rvm get head --auto
[... no error during installation, no trace information, nothing useful ...]
[logout/re-login]
bash: /usr/local/rvm/scripts/functions/support: Permission denied
bash: /usr/local/rvm/scripts/functions/checksum: Permission denied
is_a_function: command not found
__function_on_stack: command not found
__function_on_stack: command not found
mlemoine@my-server:~$ ls -l /usr/local/rvm/scripts/functions/{support,checksum}
-rwx-wx--- 1 root rvm 3680 Sep 22 10:14 /usr/local/rvm/scripts/functions/checksum
-rw--w---- 1 root rvm 2006 Sep 22 10:14 /usr/local/rvm/scripts/functions/support
mlemoine@my-server:~$ rvmsudo rvm get stable --auto
bash: /usr/local/rvm/bin/rvmsudo: Permission denied
mlemoine@my-server:~$ ls -l /usr/local/rvm/bin/rvmsudo
-rwx-wx--- 1 root rvm 1465 Sep 22 10:14 /usr/local/rvm/bin/rvmsudo
@lemoinem
Collaborator

Well, it looks like the permissions are messed up a bit when using a restrictive umask (0??7) and rvmsudo...

I guess, this would need a chmod g+rwX,o+rX /usr/local/rvm after updating/installing rvm or a ruby (any operation modifying /usr/local/rvm actually :P)

@mpapis mpapis closed this in aa54db9
@mpapis
Collaborator

I was thinking about this, it's hard to tell what should be done here, one of the solutions would be u=rwx,g=rwx,o=rx in /etc/rvmrc - which basically resets your setup ... but it seams to be required for rvm to work correctly for all users, also the code got updated so you can now comment it out and it will be not updated.

@mpapis mpapis was assigned
@lemoinem
Collaborator

Well, I agree, but won't that reset the umask for the whole system, all the time, not only for user using rvm? (Even users not in the rvm group are sourcing /etc/rvmrc as far as I can tell)...

I understand this a complex issue, however, I still think this is a huge security issue...
I guess the whole umask issue is actually broken by design and would be very hard to fix "cleanly"... And it would be useless to do so, since RVM2 in currently in development.

I may be wrong here, not having time to deeply study the RVM source code. However here is why I think it's broken and also a temporary fix avoiding the umask issue completely, if you think this explanation is not worth reading (as it may very well be), please read at least the part titled "Short term fixes/moderately clean solutions" since I think it would be easily implemented and fixes the problem in, at least, the case of mixed-mode gemsets installation.

Why RVM process to modify the filesystem is broken by design:

I think the problem is because rvm is basically a shell function, sourcing all the files it's using in order to be able to modify the environment of the current shell - which, I agree, is the most basic requirement for RVM to work at all.

However, the umask issue arises because there is no isolation process implemented for working on the FS. So that means the shell calling rvm currently MUST have to use the right umask otherwise the rvm function won't be able to modify /usr/local/rvm properly.

What I think would be a long term fix and a clean design solution is:

The rvm shell function or any file directly or indirectly sourced by it, is allowed to ONLY:

  • Read files from the FS
  • Modify the current shell's environment variables: rvm_*, PATH, Ruby related one, etc.

However, if it needs to affect the FS in any way at all (including, but not limited to, creating, copying, moving, touching and deleting, permanent or temporary, files or directories), it MUST call (fork-and-exec style) a wrapper script, which would then modify its own umask, before calling the actual script/function/wtv modifying the filesystem.

This umask modification would ensure that the files created that way always have the right permissions, but would propagate only from the process created for the wrapper script, not for the calling shell itself and thus preserve the umask of the shell.

Of course this looks like a major modification to RVM and, once again, could be put aside as obsolete considering the development of RVM2. Moreover, there are other shortcomings in the case of Multi-User installations or shared gemsets (see below).

Short term fixes/moderately clean solutions
However, in the case of Mixed-Mode with user gemsets, the only operations that could impact the filesystem (or more precisely, /usr/local/rvm), are either updating RVM itself or installing a new Ruby (which includes updating one, too). They are all performed by invoking then rvm function directly.

This means, we could avoid having to set the umask at all if:

  • These operations are always made by someone in the rvm group or via rvmsudo
  • These operations call chmod command to fix the permissions at the end of the operation.

This seems to ensure we always have the right permissions in /usr/local/rvm without messing with the umask. If we are in the case of a user with total Mixed-Mode (the one with personal Ruby installations, too) the only operation that need the chmod is updating RVM itself. I think this use-case can be detected by checking on the environment variables while a a new Ruby is installed.

This is more complex in the case of Multi-User because installing a Gem is also going to write into /usr/local/bin. This could however be taken care of by having an suid executable to fix the permissions. This would be run when switching the current gemset. (or the dirty way, with a cronjob, or a recursive inotify tool such as https://github.com/greggoryhz/Watcher which probably has a port in Ruby [or would not be too hard to do using rb-inotify]) This seems to be seamless enough, the only problem arise if one of the manager updates a gemset that someone else is currently using. But I don't think this is a recommended use case anyway (and even then, the manager would only have to switch out and back to the newly updated gemset to fix the permissions).

Sorry for the long comment, but I feel this is really an issue that should be completely discussed once and for all...

[edit: fix typos]

@mpapis
Collaborator

Correct me if I'm wrong:

  • currently umask from /etc/rvmrc is in effect only when running rvm, when out of rvm it's not in effect, there are only two use cases affected by this: rvm rvmrc create ... and rvm ... do ...
  • when running rvm commands to install rvm/ ruby/ gems it is required to change the umask or use chmod to change the permissions accordingly, for my understanding the umask approach is better as it makes files/dirs have proper rights when created from any programs, contrary to chmod which would require autodetection of what was created and fixing rights after it was created
  • rvmsudo inherits rights from running user which makes it worthless as installation/update tool without umask / chmod fix

I think we are trying to solve two conflicting problems:

  • increase security by restricting umask
  • allow use of rvm for multiple users by loosening the permissions

As you already mentioned changing umask handling in RVM 1.x would be quite big an useless effort as RVM 2 is in development and RVM 2 is supposed to handle the problem properly.

In my opinion current implementation gives you enough flexibility and allows you to handle the rights manually if you have special requirements like umask 0067 ...

A solution for your problem could be:

  1. comment out umask in /etc/rvmrc
  2. create separate users for managing rvm/rubies/gems
  3. give this "rvm administrators" umask 0002
  4. for users that will be only using rubies keep umask 0067
@lemoinem
Collaborator

Thanks for your reply.

  • currently umask from /etc/rvmrc is in effect only when running rvm, when out of rvm it's not in effect, there are only two use cases affected by this: rvm rvmrc create ... and rvm ... do ...

Well, actually, no. To make sure of that and have a fresh start for my tests, I tried to delete RVM from my system (using sudo rm -Rf /etc/rvmrc /etc/profile.d/rvm.sh /usr/local/rvm) and then doing a clean install from head, the permissions were still not right:

mlemoine@my-server:~$ ls -ld /usr/local/rvm/
drwx-ws--- 23 root rvm 4096 Sep 23 14:58 /usr/local/rvm/
mlemoine@my-server:~$ type rvm | head
bash: type: rvm: not found

Which does not allow me to use rvm in Mixed-mode.

Moreover, after doing chmod -R ug+rwX,o+rX /etc/rvmrc /etc/profile.d/rvm.sh /usr/local/rvm, logout/re-login, my umask is still wrong:

mlemoine@my-server:~$ umask
0002

And this, all the time, not only when using rvm (actually, it looks like the installation process of RVM does not use the right umask itself, which ends up setting weird permissions on the RVM installation). Your fix seems to have been doing nothing at all. Sorry.

  • when running rvm commands to install rvm/ ruby/ gems it is required to change the umask or use chmod to change the permissions accordingly, for my understanding the umask approach is better as it makes files/dirs have proper rights when created from any programs, contrary to chmod which would require autodetection of what was created and fixing rights after it was created

Well, a simple, assertive chmod could be enough, no need to be fancy and try to auto-detect created files and stuff like that. Except in the case of shared gemsets (for which I also submitted an idea at the end of my previous comment), any modification to system-wide RVM files can/should be made only via direct call to the rvm function itself (this is not a restriction I intend to add to RVM, but that is here with the current setup already), so we can make sure to always fix the permissions after a management operation.

Moreover, the permission set is not really complex (u=rwX,g=rwX,o=rX). Plus, everything RVM is concerned with system-wide is in /usr/local/rvm (with a very few exceptions such as /etc/rvmrc and /etc/profile.d/rvm.sh) AND this directory is exclusive to RVM.
Thanks to that, we don't have to be afraid of side-effects by running the permission fix several times on the whole RVM installation.
This implies that a simple chgrp -R rvm /usr/local/rvm ; chmod -R ug+rwX,o+rX /usr/local/rvm would be quite effective. It is also, IMO, very efficient and secure.

  • rvmsudo inherits rights from running user which makes it worthless as installation/update tool without umask / chmod fix

Hum... I guess by "rights" you meant "umask", not "permissions": rvmsudo is using sudo, hence has root-level permissions. The running user permissions are completely irrelevant to it (as long as said user is allowed to use sudo).
The goal of rvmsudo is simply to avoid using the rvm group and requiring privilege escalation to do management related stuff (A personal choice on my end, by no mean required).
A user member of the rvm group don't need rvmsudo, but will still need a umask/chmod fix. Both are independent.

As I said, I think the way the umask is manipulated by RVM is broken by design. Trying to fix it while still using umask manipulation will be very hard (that's the part I meant was useless because of RVM2).

I think we are trying to solve two conflicting problems:

  • increase security by restricting umask
  • allow use of rvm for multiple users by loosening the permissions

Well this is the problem every system package manager has to deal with, so I don't think this is actually conflicting. How to solve that is relatively easy:

  1. Perform the installation process using a privileged user (root most of the time)
  2. Make sure all created file have the right permissions (writable by root, readable/executable by everybody).

Regarding the first point, using the rvm group instead of privilege escalation is still valid and simply a matter of choice, and personal preference. I think the both are equally valid tools to achieve the same end: restricting the write access to the core of the system in order to avoid potential security issues.

This second point is usually achieved by extracting the files from a tarball along with their required permissions or making sure the installation program is temporarily using a different umask.
I don't think any of these two options are acceptable in the case or RVM:

  • The tarball is not because RVM seems to be compiling it's Ruby installations most of time. Moreover, tarballs usually requires quite a tighter control on the overall environment. But it'd could probably be used in the RVM installation/upgrade process. However that may be a huge modification of the installation process too.
  • The umask solution is the one currently intended but its design is broken.

Since we are lucky to have a simple-enough RVM file spreading on the FS and a simple set of permissions, we could simply force them, as suggested above.

In my opinion current implementation gives you enough flexibility and allows you to handle the rights manually if you have special requirements like umask 0067 [...]

Well, sure, this solution could work, but it kind of defeat the point of having the rvm group, and allowing standard person-scope users to manage RVM. In this case we are defining a new user, with a very loose umask, used for the sole purpose of manually managing RVM. That does not seems sound from a sysadmin point of view: Why would RVM be the only software having this requirement?

PS: Another point I didn't consider: trusting an rvmrc file seems to require management level rights (I know it's in the documentation, I just have forgotten it and remembered it only now)... I guess this should be split in two: an admin could choose to have a system trust globally a specific rvmrc, but each user should also be able to trust rvmrcs of their choice for their own account. If you could point me toward the rvmrc trust primitives within the RVM code, I'd be glad to PR a patch to that end.

PPS: I apologize if my English sounds sophisticated or hard to read some time. This is not my mother tongue and I tend to use overcomplicated and useless fancy wordings once in a while. Just like that one :P...

@mpapis mpapis reopened this
@mpapis
Collaborator

You missed to mention earlier that it's still broken, could you continue to provide the new dump of environment?

As for RVM1 - the current mechanism will stay unless someone wants to step up and provide something better (without breaking existing code), I will do my best to fix the existing mechanism as it is essential to make RVM1 stable.

With RVM2 on horizon which is supposed to do it the right way, it seams extra and useless effort to rework it.

As for rvmrc trusting - this one will be also reworked with RVM2 giving a lot more flexibility ... the whole effort for RVM2 is to make it flexible and easy to maintain, if you really care for RVM, maybe you would like to help with RVM2 tasks?

@lemoinem
Collaborator

Sure, I'll be glad to help on RVM2, if I you'd like too and I have the ability and time to do so. (I must say I'm a bit curious too since it seems to be a complete rewriting!)

I didn't post back on #1123, because I was actually focusing on one issue at the time.

Ok, so to do back to the issue at hand, rvm get head --auto seems to be applying the right permissions now.
However the first RVM installation from a clean environment with restricted umask doesn't, do you want me to create a new issue for that or are you OK with the informations in my last post?

I posted back in #1123 regarding the umask affected system-wide.

PS: I still think it would be easier to setup a chgrp/chmod patch than trying to fix the current umask process. But that's just my own opinion, and I'll do my best to help you fixing the current mechanism.

@mpapis
Collaborator

yes rvm get head --auto will work properly because of the umask in /etc/rvmrc, the first call needs to be fixed, I was thinking to just add a umask 0002 in rvm-installer.

chgrp/chmod change although might seam to be trivial, either requires some logic to detect what was done and apply to only small part of filesystem, or to be run on whole rvm tree - which might get very slow on large amount of files like 30GB+ which I quite often hear about.

I do not think comparing RVM to system package manager is fair, in package manager you put list of known files into a know location, rvm allows users to select gemset and change installation paths of gems, this makes the process very dynamic, and somehow unpredictable as rubygems gem installation or ruby compilation process are out of rvm control, additionally rvm supports installation of multiple rubies which every one of them has it's own installer.

If you are interested in contributing to RVM talk to me on rvm irc channel, it's a lot faster to talk live ;)

@mpapis mpapis closed this
@lemoinem
Collaborator

Thanks, I joined the IRC channel, I hope we'll be able to spend some time discussing that tomorrow.

@lemoinem lemoinem referenced this issue from a commit in lemoinem/rvm
@lemoinem lemoinem installer did not create files with right permissions in case of para…
…noiac umask, fix #1124
cdd25cf
@lemoinem lemoinem referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.