Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

irule crashes when handling a poorly written rule #7704

Open
MartinFlores751 opened this issue Apr 18, 2024 · 4 comments
Open

irule crashes when handling a poorly written rule #7704

MartinFlores751 opened this issue Apr 18, 2024 · 4 comments
Assignees
Labels
Milestone

Comments

@MartinFlores751
Copy link
Contributor

Bug Report

iRODS Version, OS and Version

Main branch (working towards 4.3.2), Ubuntu 20.04 docker container

What did you try to do?

I tried to make a simple rule from memory, and ended up with the following non.r rule:

bleh {
        writeLine("Did I do this right?");
}
OUTPUT

Then ran the following command to invoke irule: irule -F /tmp/non.r

Expected behavior

irule gets upset at the improper rule, logs a message if possible, and then exits with a non-zero code.

Observed behavior (including steps to reproduce, if applicable)

irule segfaults.

Following is some detailed information from the core dump:

Backtrace:

(lldb) bt
* thread #1, name = 'irule', stop reason = signal SIGSEGV
  * frame #0: 0x000072214324fdfd libc.so.6`___lldb_unnamed_symbol2869 + 589
    frame #1: 0x0000722143c39e19 libirods_common.so.4.90.0`::trimPrefix(str="OUTPUT") at rcMisc.cpp:4421:5
    frame #2: 0x000000000042ead4 irule`main(argc=0, argv=0x0000000000000003) at irule.cpp:329:37

There is no info for frame 0.


Frame 1:

(lldb) frame select 1
frame #1: 0x0000722143c39e19 libirods_common.so.4.90.0`::trimPrefix(str="OUTPUT") at rcMisc.cpp:4421:5
   4418     while ( str[i] == ' ' ) {
   4419         i++;
   4420     }
-> 4421     memmove( str, str + i, strlen( str ) + 1 - i );
   4422     return str;
   4423 }
   4424
(lldb) frame variable
(char *) str = 0x00007ffc6bdceb10 "OUTPUT"
(int) i = 8

Frame 2:

(lldb) frame select 2
frame #2: 0x000000000042ead4 irule`main(argc=0, argv=0x0000000000000003) at irule.cpp:329:37
   326                      }
   327                      else if ( startsWith( buf, "OUTPUT" ) || startsWith( buf, "output" ) ) {
   328                          gotRule = 2;
-> 329                          trimSpaces( trimPrefix( buf ) );
   330                      }
   331                  }
   332 
(lldb) frame variable
(int) argc = 0
(char **) argv = 0x0000000000000003
(int) status = 32764
(rodsEnv) myEnv = {
  rodsUserName = ""
  rodsHost = ""
  rodsPort = 0
  rodsHome = ""
  rodsCwd = ""
  rodsAuthScheme = "!r"
  rodsDefResource = "\xfc\U0000007f"
  rodsZone = ""
  rodsLogLevel = 29217
  rodsAuthFile = "\U00000001"
  rodsDebug = "#"
  rodsClientServerPolicy = ""
  rodsClientServerNegotiation = ""
  rodsEncryptionKeySize = 33905152
  rodsEncryptionSaltSize = 0
  rodsEncryptionNumHashRounds = 33905168
  rodsEncryptionAlgorithm = ""
  rodsDefaultHashScheme = ""
  rodsMatchHashPolicy = ""
  irodsSSLCACertificatePath = ""
  irodsSSLCACertificateFile = "\xfc\U0000007f"
  irodsSSLVerifyServer = "!\U00000003"
  irodsSSLCertificateChainFile = "N"
  irodsSSLCertificateKeyFile = "DATA\x80\U00000016\U00000003\U00000002"
  irodsSSLDHParamsFile = ""
  irodsCtrlPlaneKey = ""
  irodsCtrlPlanePort = 0
  irodsCtrlPlaneEncryptionNumHashRounds = 1809699768
  irodsCtrlPlaneEncryptionAlgorithm = "\xfc\U0000007f"
  irodsMaxSizeForSingleBuffer = 32764
  irodsDefaultNumberTransferThreads = 33859616
  irodsTransBufferSizeForParaTrans = 0
  irodsConnectionPoolRefreshTime = 20
  irodsPluginHome = ""
  tcp_keepalive_intvl = 0
  tcp_keepalive_probes = 4377744
  tcp_keepalive_time = 0
}
(rErrMsg_t) errMsg = (status = 0, msg = "")
(rcComm_t *) conn = nullptr
(boost::program_options::variables_map) argsMap = {
  boost::program_options::abstract_variables_map = {
    m_next = nullptr
  }
  std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> >, boost::program_options::variable_value, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > >, std::allocator<std::pair<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> >, boost::program_options::variable_value> > > = error: summary string parsing error {
    _M_t = {
      _M_impl = {
        std::_Rb_tree_key_compare<std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > > = (_M_key_compare = std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > @ 0x00007ffc6bdd9d30)
        std::_Rb_tree_header = {
          _M_header = {
            _M_color = 0x2056190
            _M_parent = 0x0000000002056190
            _M_left = 0x0000000002056190
            _M_right = 0x0000000000000001
          }
          _M_node_count = 0
        }
      }
    }
  }
  m_final = {
    _M_t = {
      _M_impl = {
        std::_Rb_tree_key_compare<std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > > = (_M_key_compare = std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > @ 0x00007ffc6bdd9d60)
        std::_Rb_tree_header = {
          _M_header = {
            _M_color = 0x2056270
            _M_parent = 0x0000000002056270
            _M_left = 0x0000000002056270
            _M_right = 0x0000000000000001
          }
          _M_node_count = 0
        }
      }
    }
  }
  m_required = error: summary string parsing error {
    _M_t = {
      _M_impl = {
        std::_Rb_tree_key_compare<std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > > = (_M_key_compare = std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<> > > @ 0x00007ffc6bdd9d90)
        std::_Rb_tree_header = {
          _M_header = {
            _M_color = _S_red
            _M_parent = 0x00007ffc6bdd9d98
            _M_left = 0x00007ffc6bdd9d98
            _M_right = nullptr
          }
          _M_node_count = 0
        }
      }
    }
  }
}
(irods::error) err = {}
(bool) useSaveFile = false
(execMyRuleInp_t) execMyRuleInp = {
  myRule = "l\nbleh {\n        writeLine(\"Did I do this right?\");\n}\n"
  addr = (hostAddr = "", zoneName = "", portNum = 0, dummyInt = 0)
  condInput = {
    len = 0
    keyWord = 0x0000000000000000
    value = 0x0000000000000000
  }
  outParamDesc = ""
  inpParamArray = nullptr
}
(msParamArray_t *) outParamArray = 0x616e726574786540
(msParamArray_t) msParamArray = {
  len = 0
  oprType = 0
  msParam = nullptr
}
(int) rulegen = 0
(int) connFlag = 0
(char [1088]) saveFile = ""
(char [1088]) ruleFile = ""
(char [1088]) cmdLineInput = ""
(FILE *) fptr = nullptr
(int) len = 0
(int) gotRule = 34076960
(char [20480]) buf = "OUTPUT"
(const char *) fileName = 0x000000000204a128 "non.r"
(boost::bad_any_cast &) e = 0x0000000000000000
(std::out_of_range &) e = 0x0000000000000000
(const char *) fileType = 0x00007ffc6bdd4113 ""

@trel trel added the bug label Apr 18, 2024
@alanking
Copy link
Contributor

So, irule itself segfaults, not the connected server agent?

Also noting here the lack of use of -r option with irule, just in case.

@alanking alanking added this to the 4.3.3 milestone Apr 18, 2024
@MartinFlores751
Copy link
Contributor Author

Took a look at this while away.

The error is caused by trimPrefix(...):

irods/lib/core/src/rcMisc.cpp

Lines 4413 to 4423 in 5e5057b

char *trimPrefix( char * str ) {
int i = 0;
while ( str[i] != ' ' ) {
i++;
}
while ( str[i] == ' ' ) {
i++;
}
memmove( str, str + i, strlen( str ) + 1 - i );
return str;
}

I think adding a simple check to the while loops that go over the string should avoid this situation. Basically, make sure we don't go past the end of the string.


For why, you can see in frame 1 of the backtrace, both str and i. Notice is that i is greater than the length of the string str, even with a null term included. Checking the third value passed to memmove(...), the function call where the segfault occurred, you can see that it would be passing -1 to a size_t.

"Stopping" at the end of the string should be fine, as this should result in the third value of memmove(...) being zero.

Note: Following functions might not expect an empty string, so there might be more to do.

@trel
Copy link
Member

trel commented Apr 18, 2024

Excellent. A candidate for 4.3.2 if you’re quick.

@korydraughn
Copy link
Collaborator

Nice detective work.

@MartinFlores751 MartinFlores751 self-assigned this Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants