Project

General

Profile

Actions

Bug #13554

closed

Running system with different gid fails on Linux if host has group with lots of members

Added by ssgelm (Stephen Gelman) almost 7 years ago. Updated almost 7 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
[ruby-core:81084]

Description

In #9600, it was pointed out that groups can be larger than sysconf(SC_GETGR_R_SIZE_MAX) in Linux. This was fixed in r45290 by enlarging the buffer and retrying. That worked well, but it was broken again in r51492. Ever since, when trying to run the following ruby code:

begin
  system("/bin/ls", gid: "adm")
rescue => exception
  puts exception.backtrace
  raise
end

I get the backtrace:

gid.rb:2:in `system'
gid.rb:2:in `<main>'
gid.rb:2:in `system': can't modify frozen false (RuntimeError)
        from gid.rb:2:in `<main>'

In this case the "adm" group has about 200 members. It's worth noting that because of the way getgrnam_r works this happens if I pick any group listed after adm. It seems that the change in r51492 causes the buffer that is allocated for getgrnam_r to be marked as frozen, so when it's not big enough and it gets resized using rb_str_modify_expand ruby raises an exception.

This occurs in any release of ruby 2.3 or 2.4 and also on the trunk on either debian wheezy or jessie.

I don't have a deep enough knowledge of the ruby C API to know the best fix, but I was able to work around the problem with the following change:

diff --git a/process.c b/process.c
index 9191051..721dd4c 100644
--- a/process.c
+++ b/process.c
@@ -5126,9 +5126,9 @@ obj2gid(VALUE id
                rb_free_tmp_buffer(getgr_tmp);
                rb_syserr_fail(e, "getgrnam_r");
            }
-           rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
-           getgr_buf = RSTRING_PTR(*getgr_tmp);
-           getgr_buf_len = rb_str_capacity(*getgr_tmp);
+           rb_free_tmp_buffer(getgr_tmp);
+           getgr_buf_len = getgr_buf_len * 2;
+           getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len);
        }
 #elif defined(HAVE_GETGRNAM)
        grptr = getgrnam(grpname);

Alternatively, I assume the better way to fix this would be to allocate the tmp buffer in a way that allows it to be resized but I didn't see an obvious way to do that.

Actions #1

Updated by nobu (Nobuyoshi Nakada) almost 7 years ago

  • Description updated (diff)
  • Backport changed from 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN to 2.2: DONTNEED, 2.3: REQUIRED, 2.4: REQUIRED
Actions #2

Updated by nobu (Nobuyoshi Nakada) almost 7 years ago

  • Status changed from Open to Closed

Applied in changeset trunk|r58658.


process.c: temporary string for buffer

  • process.c (obj2uid, obj2gid): use temporary string as the buffer
    instead of rb_alloc_tmp_buffer, which is NODE_ALLOCA since
    r51492. [ruby-core:81084] [Bug #13554]

Updated by usa (Usaku NAKAMURA) almost 7 years ago

  • Backport changed from 2.2: DONTNEED, 2.3: REQUIRED, 2.4: REQUIRED to 2.2: DONTNEED, 2.3: DONE, 2.4: REQUIRED

ruby_2_3 r59220 merged revision(s) 58658.

Updated by nagachika (Tomoyuki Chikanaga) almost 7 years ago

  • Backport changed from 2.2: DONTNEED, 2.3: DONE, 2.4: REQUIRED to 2.2: DONTNEED, 2.3: DONE, 2.4: DONE

ruby_2_4 r59293 merged revision(s) 58658.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0