Bug 206810 - "OOPS: cannot open config file" caused by incorrect use of str_stat()
Summary: "OOPS: cannot open config file" caused by incorrect use of str_stat()
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: vsftpd
Version: rawhide
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Maros Barabas
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2006-09-16 21:54 UTC by Ted Rule
Modified: 2007-11-30 22:11 UTC (History)
0 users

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2007-05-28 11:52:43 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)
Repaired version of vsftpd-1.2.1-nonrootconf.patch for vsftpd-2.0.5 (2.29 KB, patch)
2006-09-16 21:54 UTC, Ted Rule
no flags Details | Diff

Description Ted Rule 2006-09-16 21:54:39 UTC
On a very very very rare number of occasions, we have seen an OOPS of this form:

500 OOPS: cannot open config file:/etc/vsftpd/vsftpd.conf.localhost

when all the file permissions are seemingly correct. This was seen when using
the tcp_wrappers env option VSFTPD_LOAD_CONF to load a secondary configuration
file above and beyond /etc/vsftpd/vsftpd.conf.

The result - on one occasion - was that vsftpd effectively refused ALL new
connection attempts, always returning the same OOPS. Restarting vsftpd worked
round the problem. No error logs of any kind - other than the OOPS on the FTP
control connection - were seen.


Hunting round the source code for explanations, I found that the RedHat version
of vsftpd used this line in parseconf.c:

(int)str_stat(&config_file_str, &p_statbuf);

It appears that &config_file_str ACTUALLY contains a string containing the
CONTENTS of the configuration file, rather than the filename itself.

My supposition is that this is the more correct function to use:

(int)vsf_sysutil_stat(p_filename, &p_statbuf);

The invocation of str_stat() is included in the "nonrootconf" patch included in
the RedHat releases, and is NOT part of vsftpd source itself.

The broken code fragment, in my view, reads like this:

  retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX);
  (int)str_stat(&config_file_str, &p_statbuf);
  /* Security - die unless the conf file is owned by root */
  if (vsf_sysutil_retval_is_error(retval) ||
vsf_sysutil_statbuf_get_uid(p_statbuf) != VSFTP_ROOT_UID)
  {
    if (errs_fatal)
    {
      die2("cannot open config file:", p_filename);
    }
    else
    {
      return;
    }
  }

What seems to be happening is that the config file contents are read into
config_file_str, and then str_stat tries to use the file contents as a filename
so as to return a p_statbuf.

My reasoning is that somehow ( heaven knows how ) vsf_sysutil_statbuf_get_uid()
almost always returns zero despite being passed an invalid p_statbuf, and the
configuration file is accepted. On very very rare occasions, probably due to
subtle changes in malloc'ed memory usage, vsf_sysutil_statbuf_get_uid() returns
non-zero, and the configuration file raises an OOPS.

I've seen this explicitly on Fedora Core 4, but the source code bug - if it is a
bug - is still in the FC6 Devel tree.

I attached a revised nonrootconf patch against the FC6 v2.0.5 SRPM which uses
vsf_sysutil_stat instead.

Comment 1 Ted Rule 2006-09-16 21:54:39 UTC
Created attachment 136448 [details]
Repaired version of vsftpd-1.2.1-nonrootconf.patch for vsftpd-2.0.5

Comment 2 Ted Rule 2006-09-17 13:35:27 UTC
The orignal vsftpd RPM DOES appear to detect changes of ownership of
configuration files, despite the broken call to str_stat(). This was completely
bizarre, and explaining this had me very confused.

Musing on the matter a bit longer, I think I have an hypothesis which fits the
observed behaviour:

My reasoning goes that str_stat() is indeed passed a string
containing the contents of the p_filename file rather than its filename.
This is garbage, and hence str_stat() actually returns < 0, but the code
fragment IGNORES the return value from str_stat() - even executing str_stat()
when str_fileread() returns < 0. Meanwhile, vfs_sysutil_stat() which is called
by str_stat() has already allocated memory for a statbuf, and has called the
kernel via stat() itself.

Now if stat() were to temporarily, and very wrongly, return a
buffer filled with the last successful stat() call, AND that last stat()
call to the kernel referred to the same p_filename configuration file,
then p_statbuf would miraculously contain the correct statbuf even
though stat() itself returned an error code.

This would then mean that the only way for p_statbuf to contain the
wrong inode's statbuf would be if another process called stat() between
the call to str_fileread() and str_stat().

This would then mean we had a race condition which nearly always
succeeded, which fits in with the observed behaviour.

If this is true, it also implies that there maybe a sort of "information leakage
bug" in the kernel itself, as stat() probably shouldn't share inode information
between processes, and should also return "cleansed memory" in the statbuf if
the stat() call fails overall.

I hope this help to clear the muddy waters a little more...


Comment 3 Maros Barabas 2007-05-23 21:52:45 UTC
Try please the last version of vsftpd (2.0.5-16) if problems still present. Thanks

Comment 4 Ted Rule 2007-05-26 13:26:56 UTC
Whilst I haven't had a chance to try the 2.0.5-16 version, I'm happy that the
new vsftpd-2.0.5-file_stat.patch fixes the bug; I've had several machines
running chroot'ed configurations with no ill-effects since I applied my
corresponding version of the fix.

Please feel free to close the bug, but please also create an FC6-Updates version
of the RPM.

Thanks,

Ted



Comment 5 Maros Barabas 2007-05-28 11:52:43 UTC
Thanks, update for FC6 will be pushed soon, now closing as rawhide fix.


Note You need to log in before you can comment on or make changes to this bug.