*nix Documentation Project
·  Home
 +   man pages
·  Linux HOWTOs
·  FreeBSD Tips
·  *niX Forums

  man pages->Tru64 Unix man pages -> safe_open (3)              



NAME    [Toc]    [Back]

       safe_open - Open a file for I/O with comprehensive or customized
 security checks

SYNOPSIS    [Toc]    [Back]

       #include <safe_open.h>

       int safe_open(
               char const *pathname,
               int oflags,
               ulong_t sflags,
               ...  );

LIBRARY    [Toc]    [Back]

       Standard C Library (libc)

PARAMETERS    [Toc]    [Back]

       Identifies the file or  other  file  system  object  being
       opened.  Includes the flags (such as O_RDONLY, O_CREAT, or
       O_APPEND) that one would specify to an  open()  call.  The
       flags  actually  passed  by safe_open() to open() may vary
       from these; see DESCRIPTION for details.   Includes  flags
       that  can  relax  20  of the restrictions that safe_open()
       enforces by default. You can specify one or  more  of  the
       following  flags,  each  of which tells safe_open() not to
       enforce a  particular  restriction:  Accept  the  risk  of
       blocking  for off-line modems or named pipes (fifos). This
       flag is often appropriate when intending  to  write  to  a
       named  pipe, since a non-blocking open of a named pipe for
       writing fails when there is no reader.  Allow opening file
       system  objects  under  /dev/fd  (or any other file system
       mounted as type fdfs).  Allow opening file system  objects
       that  are the targets of file-on-file mounts.  Allow opening
 file system objects under /proc  (or  any  other  file
       system  mounted  as  type procfs).  Allow opening files on
       non-local file systems. Not setting this flag excludes (at
       least)  NFS  and DCE file systems. For support of dataless
       client configurations, the /,  /usr,  /usr/var,  and  /var
       file  systems  are always accepted, even when this flag is
       not specified.

              Local file systems are currently  defined  as  MFS,
              CFS, and any others that set the M_LOCAL bit in the
              m_flags field of their mount  structures.  (At  the
              time this reference page was written, the full list
              of local file systems included  AdvFS,  CDFS,  CFS,
              DVDFS,  MFS, and UFS.)  Allow relative paths in the
              pathname parameter.  When creating a new  file,  do
              not  check  for  a  possibly-inappropriate  default
              access control list (ACL) on the new file. If  this
              flag is omitted, newly-created files are checked to
              see whether they have inherited a default ACL  from
              the  containing  directory. If so, and if the owner
              of that directory is neither UID 0 nor  the  effective
  UID  of  the  process,  an attempt is made to
              delete the ACL from the file. If any other  readers
              or  writers of the file are detected after removing
              the ACL, the file is closed and safe_open()  fails,
              setting  errno  to  [EMLINK].   When  resolving the
              pathname parameter, accept symbolic links that have
              the  same  UID  as  the directory in which they are
              found. If this flag is omitted, only symbolic links
              owned by the effective UID of the process or by UID
              0 will be accepted.  Do not check for  other  links
              to  the  same  file. If this flag is omitted, named
              pipes and regular files with  link  counts  greater
              than  one  will be rejected, causing safe_open() to
              fail with errno set to [EMLINK].   Limit  "writable
              directory"  checks  to making sure that directories
              do not have world write permission. If this flag is
              omitted,  safe_open()  makes  sure that directories
              have neither world write nor  group  write  permission.
   Limit  "writable directory" checking to the
              immediate parent directory of pathname (and of  any
              symbolic links traversed to the final symbolic link
              target, when relevant). If this  flag  is  omitted,
              safe_open()  will  also  traverse  upward  from the
              immediate parent directory, checking each directory
              until reaching (and testing) the root directory, as
              well  as  checking  each  directory  traversed   to
              resolve  any symbolic links.  Skip "writable directory"
 checks for  the  starting  directory  of  the
              pathname  parameter. See RESTRICTIONS for a limited
              number of cases when this flag  is  ignored.   Skip
              "writable  directory"  checks  for directories with
              the "sticky bit" (S_ISVTX) set in their mode  bits.
              Skip the checks for symbolic link ownership.  Allow
              block-special files to be opened.  Allow characterspecial
  files  to be opened.  Allow directories to
              be opened for reading.  Allow named  pipes  (fifos)
              to  be opened.  Allow symbolic links to be followed
              if all other constraints are met.  Even  with  this
              flag  set,  the  object type of the symbolic link's
              target must be acceptable.  On  systems  where  the
              open() call supports the O_NOFOLLOW flag, including
              O_NOFOLLOW in oflags  overrides  the  inclusion  of
              OPN_TYPE_SYMLINK  in sflags.  Allow files not owned
              by the effective UID to be  opened.   Reserved  for
              future expansion.

DESCRIPTION    [Toc]    [Back]

       The  safe_open() function attempts to open the file system
       object identified by  its  pathname  parameter  and  makes
       validity  checks,  as  controlled by the oflags and sflags
       parameters. The validity checking that this function  performs
  helps  to protect against some common security vulnerabilities,
 such as "time of check, time of  use"  (TOCTOU)
  race  conditions,  that can be created when programs
       manipulate arbitrary file system objects.

       If successful, safe_open() returns a file descriptor.   On
       failure,  the  function returns -1 and sets errno to indicate
 the error.

       For many applications that want to protect  against  security
  vulnerabilities  when opening files, the safe_open()
       function will be a drop-in replacement for an open() call,
       after  selecting  a  suitable set of values for the sflags
       parameter.  However, the oflags parameter is not necessarily
  passed to the open() call or passed exactly as specified
 in order to protect against security vulnerabilities.
       The  safe_open() function differs from the open() function
       with respect to oflags values in the following  ways:  The
       safe_open()  function  never implements O_CREAT without an
       implicit O_EXCL.

              When called with only O_CREAT in its oflags parameter,
  safe_open() always passes 0600 to open() as a
              mode parameter.  Therefore, applications that  need
              to  use  an oflags parameter that specifies O_CREAT
              without O_EXCL will need to add some retry logic in
              addition  to  the safe_open() call. (See EXAMPLES.)
              If the  pathname  parameter  is  a  symbolic  link,
              safe_open()  will  never  create  a file, even when
              O_CREAT is  specified.   The  safe_open()  function
              never passes O_TRUNC to open().

              When  called  with O_TRUNC in its oflags parameter,
              safe_open()  simulates  the  O_TRUNC  operation  by
              using a call to ftruncate().  The safe_open() function
 always adds both O_NONBLOCK  and  O_NDELAY  to
              any  open()  calls (even if O_CREAT is specified in
              oflags) unless OPN_BLOCKING is included in  sflags.

       This  function  makes  the following checks before opening
       the specified pathname parameter whether or not a  new  or
       existing  file  system object is being opened. There is no
       guaranteed order in which these checks are made. If a file
       system  or  the target object fails any of the checks, the
       function will return  failure  (unless  otherwise  noted).
       Because  of the potential for race conditions, some of the
       checks may be made more than once.  Validate the  type  of
       the  target  file  system,  depending  on the OPN_FSTYPE_*
       flags that are provided for  sflags.  If  no  OPN_FSTYPE_*
       flags  are set, only local file systems (as defined in the
       description of the OPN_FSTYPE_REMOTE flag)  are  permitted
       and  they cannot be one of the "pseudo" local file systems
       (FDFS, FFM, or PROCFS).  Validate the  type  of  the  file
       system  object, depending on the OPN_TYPE_* flags that are
       provided for sflags. If no OPN_TYPE_* flags are set,  only
       a  regular  file  may  be opened.  Confirm that the target
       file does not exist if O_CREAT and O_EXCL are included  in
       oflags Validate that no component of the resolved pathname
       parameter  is  in  an  untrustworthy  (world-  or   groupwritable)
  directory,  depending  on the OPN_TRUST_* flags
       that  are  provided  for  sflags.  Regardless  of  whether
       OPN_TRUST_* flags are set, safe_open() always subjects any
       symbolic link component found in pathname to the writabledirectory
  check.  Other directory components are checked,
       depending      on      whether      OPN_TRUST_PARENT_DIRS,
       OPN_TRUST_STARTING_DIRS,  or  both are set. Symbolic links
       are also subject to proper  ownership  checking,  as  controlled

              If no OPN_TRUST_* flags are present:  All  directories
  in  the  absolute pathname of the file system
              object being opened will be checked None  of  those
              directories may be group-writable or world-writable
              All symbolic links found during pathname  traversal
              must  be owned by UID 0 or the effective UID of the
              calling process If the pathname  parameter  identifies
 a symbolic link and OPN_TYPE_SYMLINK is specified,
 the link's target must also pass  the  object
              type  validation, depending on any other OPN_TYPE_*
              flags that are included.

       To open the file system object, safe_open()  may  use  the
       resolved  pathname that was obtained during the per-component,
 access-checking  traversal  of  pathname.  (This  is
       always  done  on  file  creation.) If OPN_BLOCKING was not
       included in sflags, the open is  always  done  as  a  nonblocking
  open  and  fcntl()  is  called to clear the nonblocking
 bits. If an existing file was opened, safe_open()
       makes  additional  checks as follows: Verify that pathname
       was successfully opened and that the  opened  file  system
       object is what was expected based on the earlier checks on
       the type or types of file system objects that are  allowed
       to be opened.  Check to make sure that the call to fcntl()
       succeeded if OPN_BLOCKING was not specified in sflags, and
       O_NONBLOCK and O_NDELAY were not both specified in oflags.
       Verify that the call to ftruncate() succeeded  if  O_TRUNC
       was  specified in oflags.  (This step is skipped for named
       pipes and objects opened  through  file  systems  of  type
       FDFS.)  Confirm that the object being opened does not have
       a link count greater than one if OPN_TRUST_NLINKS was  not
       specified  in  sflags,  and  the  file system object being
       opened is a named pipe or a regular file.

       For a newly created file, assuming  OPN_TRUST_DEFAULT_ACLS
       was  not  specified in sflags, safe_open() makes sure that
       at  least  one  of  the  following  additional  conditions
       applies:  The file was created in a directory owned by UID
       0 or the effective UID of the calling process The file did
       not inherit a default ACL from its directory

              For  more  information,  see  the "ACL Inheritance"
              section in acl(4).  Deleting the default ACL on the
              new  file  and resetting its mode to 0600 must succeed
 and, after doing so, there must  be  no  other
              processes accessing the file.

       On  failure  of  any  check  after  a  file  descriptor is
       obtained, safe_open() closes the  file  descriptor  before
       returning failure status.

NOTES    [Toc]    [Back]

       HP  reserves the right to revise the safe_open() implementation
 to address additional security  vulnerabilities  in
       the  future.  It  is possible that these future additional
       checks might cause application code that is   designed  to
       use  the current implementation and that has a previouslyundetected
 vulnerability to fail under circumstances  that
       exercise  that  vulnerability.   This  is  appropriate for
       privileged programs that must maintain the  highest  level
       of  safe  operation.  For the benefit of applications with
       looser security requirements, the validity checking on the
       sflags  mask  only  rejects bits in the range reserved for
       future expansion of the argument list. The start  of  that
       reserved  range  of  bit  numbers  is  identified  by  the
       OPN_first_reserved symbol. Those bits that  are  currently
       unassigned,  but  which  may  be assigned in the future to
       disable new checks, are accepted by the current  implementation.
  The  start of the unassigned range of bit numbers
       is identified by the OPN_num_flags symbol.  The full  mask
       of  acceptable unassigned bits can thus be obtained by the
       following expression:

       ((1UL<<OPN_first_reserved) - (1UL<<OPN_num_flags))

RESTRICTIONS    [Toc]    [Back]

       Even if OPN_TRUST_STARTING_DIRS is included in sflags,  it
       is  possible  that  the starting directory of the pathname
       parameter will be subject to "writable directory" testing.
       This happens if the pathname resolution process encounters
       a sequence like subdir/../file. This behavior  is  considered
  a restriction rather than a bug due to the possibility
 of races with other processes in the handling of pathnames
 and directory modes.

       For  similar  reasons,  the  target  of a symbolic link is
       always subject to the "writable  directory"  checks,  even
       when it is the same as the starting directory.

RETURN VALUES    [Toc]    [Back]

       Success.  The returned value is the file descriptor of the
       file system object that  was  opened.   Failure.  In  this
       case,  errno  is set to indicate the condition that caused
       the failure.

ERRORS    [Toc]    [Back]

       Except for a few cases,  error  conditions  documented  in
       this  reference page are specific to the safe_open() function.
 However, the safe_open() function can also set errno
       in  response  to failure conditions returned by any of the
       following  calls:  acl_get_fd(),  acl_set_fd(),   fcntl(),
       fstat(),  ftruncate(),  fuser(),  lstat(),  open(),  readlink(),
 realpath(), stat(), and statfs().   Refer  to  SEE
       ALSO  find  the  reference pages for these functions.  The
       oflags parameter had O_TRUNC set, but the  access  portion
       of  that parameter was O_RDONLY. (This error is propagated
       from an ftruncate() call.)  The type of  the  file  system
       object was rejected based on the OPN_TYPE_* values omitted
       from sflags, or the type of file system type in which  the
       object  was  to  be  opened  was  rejected,  based  on the
       OPN_FSTYPE_* values omitted  from  sflags.   The  pathname
       parameter was NULL or did not start with a / character and
       the sflags parameter did not include OPN_RELATIVE, or  the
       sflags  parameter  included  bits  that  are  reserved for
       future argument expansion.  One of  the  following  conditions
  was  encountered:  OPN_TRUST_NLINKS  flag  was  not
       included in sflags, an existing  file  system  object  was
       found  that was either a named pipe or a regular file, and
       its    link    count     was     greater     than     one.
       OPN_TRUST_DEFAULT_ACLS  was  not  included  in  sflags,  a
       newly-created file was found to have inherited  a  default
       access  control list from a directory owned by an inappropriate
 UID, and other processes were found to be accessing
       the  new file after resetting its ACL.  One of the following
 conditions was encountered: The pathname parameter was
       an  empty string.  The pathname parameter had at least one
       trailing / character. If  the  intent  was  to  specify  a
       directory,  it should be done by appending a dot (.) character.
  O_CREAT was specified without O_EXCL in oflags and
       a  file system object associated with the pathname parameter
 existed at the start of the call but no longer existed
       when  an  attempt  was made to open the existing file. The
       safe_open() routine will have  retried  this  sequence  of
       operations at least once before returning this error.  One
       of the following conditions was encountered:  Some  directory
  permissions  found were overly permissive (given the
       constraints not relaxed by  the  OPN_TRUST_*  flags).   An
       attempt was made to create a new file by traversing a symbolic
 link.  One of the following conditions  was  encountered:
  OPN_UNOWNED  was  not  included in sflags, and the
       file found was not owned by the effective UID of the  process.
    OPN_TRUST_SYMLINK_OWNERS   was  not  included  in
       sflags, and a symbolic link was found that failed the symbolic
 link ownership checks during resolution of pathname.
       Either some check on the pathname parameter or on symbolic
       links  that  needed  to  be  resolved  for  that parameter
       returned inconsistent  results,  or  the  file  originally
       tested  (by means of the pathname parameter) did not match
       the file object returned by an internal call to open().

EXAMPLES    [Toc]    [Back]

       The following replacement example shows how  file  opening
       might  be  updated for an application that intends to display
 a notice file to a user.  This example  assumes  that
       the application is not in complete control of the pathname
       to be displayed, but that it is running  with  the  user's
       own  UID, and that the application displays a regular file
       (however it was found).

              Original code:

              int fd = open(pathname, O_RDONLY);

              Replacement code:

              const   ulong_t   soflags    =    (OPN_UNOWNED    |
              OPN_TRUST_STICKY_BIT |
                                       OPN_TRUST_NLINKS         |
              OPN_TYPE_SYMLINK |
                                       OPN_RELATIVE             |
              OPN_FSTYPE_REMOTE);  int  fd  = safe_open(pathname,
              O_RDONLY, soflags); The following replacement example
 shows how adding data to a user-specified pathname
 can be done more safely. This example  assumes
              that  the application has no control over the userprovided
 pathname, but that it is running with  the
              user's  credentials.  It  further  assumes that the
              application is running as a daemon, so the practice
              of  accepting  relative  pathnames  is inadvisable.
              Finally, it assumes that the expected location  for
              the  user's  file is in either /tmp or /var/tmp, so
              the use of the OPN_TRUST_STICKY_BIT is appropriate.

              Original code:

              int  fd = open(pathname, O_CREAT|O_APPEND|O_WRONLY,

              Replacement code:

              The replacement code is complicated slightly by the
              need  to  retry file creation attempts and to reset
              the file's mode if it was newly created.

              const ulong_t soflags = (OPN_TRUST_STICKY_BIT); int
              loop_limit = 3, fd; do {
                  fd             =            safe_open(pathname,
              O_CREAT|O_APPEND|O_WRONLY,soflags); } while (-1  ==
              fd  &&  ENOENT == errno && --loop_limit); if (fd >=
                  (void) fchmod(fd, 0644);

              (The retry for [ENOENT] errors is only  needed  for
              robustness  because  safe_open() does its own retry
              in this case.)  The following  replacement  example
              shows  how  an operation similar to the >> redirection
 of the shells can be made safer against  inadvertent
 file substitution, while still allowing the
              user to write to a hardcopy  terminal,  a  magnetic
              tape,  a  named  pipe, a file in /tmp, or a file in
              the user's (possibly NFS-mounted) home directory.

              Original code:

              int fd  =  open(pathname,  O_CREAT|O_EXCL|O_WRONLY,
              0666); if (-1 == fd && EEXIST == errno)
                  fd = open(pathname, O_APPEND|O_WRONLY);

              Replacement code:

              The replacement code uses the process umask setting
              to (possibly) open up the permissions on  a  newlycreated
 file beyond the 0600 mode always applied by
              the safe_open() routine. This  code  also  deliberately
  excludes  block-special devices because they
              are not suitable for text output.

              const        ulong_t        soflags_append        =
                                              OPN_TRUST_NLINKS  |
              OPN_RELATIVE |
                                              OPN_FSTYPE_REMOTE |
              OPN_TYPE_CHR |
                                              OPN_TYPE_FIFO     |
              OPN_TYPE_SYMLINK |
              const        ulong_t        soflags_create        =
                                              OPN_FSTYPE_REMOTE |
              OPN_BLOCKING |
              int        fd         =         safe_open(pathname,
              O_CREAT|O_EXCL|O_WRONLY, soflags_create); if (fd >=
              0) {
                  mode_t cmask = umask(077);  /*  Get  prevailing
              umask. */
                  (void) umask(cmask);        /* Restore it. */
                  (void)  fchmod(fd, 0666 & ~cmask); /* Apply it.
              */ } else
                  fd  =  safe_open(pathname,   O_APPEND|O_WRONLY,

              (It  should  be noted that this method of obtaining
              the process  umask  value,  while  simple,  is  not
              thread  safe.  A  multi-threaded application should
              use the TBL_UAREA function of  the  table()  system
              call,  and  examine the u_cmask structure member to
              obtain the umask value.)

SEE ALSO    [Toc]    [Back]

       Functions:  fcntl(2),  ftruncate(2),  fuser(2),   open(2),
       readlink(2),   stat(2),   statfs(2),  table(2),  umask(2),
       acl_get_fd(3), acl_set_fd(3), fdopen(3), realpath(3)

       Files: acl(4), fd(4), ffm(4), proc(4)

[ Back ]
 Similar pages
Name OS Title
authck Tru64 Checks internal consistency of the authentication databases (Enhanced Security)
updmv Tru64 Moves customized, user, and inventory data files to or from storage.
pxfaccess IRIX Checks the accessibility of a named file
quotacheck Tru64 Checks file system quota consistency
setfsgid Linux set group identity used for file system checks
setfsuid Linux set user identity used for file system checks
AFidentifyfd IRIX retrieve the audio file format of a file descriptor / open AFfilehandle
SlaToIv IRIX convert an SLA format file into an Open Inventor 2.0 file.
IvToRib IRIX convert an Open Inventor 2.0 file to a Renderman .rib file
eof IRIX Check for end-of-file condition on open file
Copyright © 2004-2005 DeniX Solutions SRL
newsletter delivery service