source: rtems/cpukit/libfs/src/imfs/imfs_eval.c @ ec9d486

4.10
Last change on this file since ec9d486 was ec9d486, checked in by Chris Johns <chrisj@…>, on 04/16/11 at 03:47:32

2011-04-16 Chris Johns <chrisj@…>

PR 1774/filesystem

  • libfs/src/imfs/imfs_eval.c: Fix the IMFS eval and eval for make handlers to not inspect a mounted file sytems path.
  • Property mode set to 100644
File size: 16.5 KB
RevLine 
[07a3253d]1/*
2 *  Evaluation IMFS Node Support Routines
3 *
[08311cc3]4 *  COPYRIGHT (c) 1989-1999.
[07a3253d]5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
[cf0539b1]9 *  http://www.rtems.com/license/LICENSE.
[07a3253d]10 *
11 *  $Id$
12 */
13
[d6b1d73]14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
[07a3253d]18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <assert.h>
25
26#include "imfs.h"
[c058578]27#include <rtems/libio_.h>
[b2709481]28#include <rtems/seterr.h>
[07a3253d]29
30#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ)
31#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE)
32
33#define MAXSYMLINK 5
34
[b6a2d2fa]35int IMFS_Set_handlers(
[07a3253d]36  rtems_filesystem_location_info_t   *loc
37)
38{
[657e1bf6]39  IMFS_jnode_t    *node = loc->node_access;
40  IMFS_fs_info_t  *fs_info;
[07a3253d]41
[657e1bf6]42  fs_info = loc->mt_entry->fs_info;
[07a3253d]43  switch( node->type ) {
44    case IMFS_DIRECTORY:
[657e1bf6]45      loc->handlers = fs_info->directory_handlers;
[07a3253d]46      break;
47    case IMFS_DEVICE:
[51435fc7]48      loc->handlers = &IMFS_device_handlers;
[07a3253d]49      break;
50    case IMFS_SYM_LINK:
51    case IMFS_HARD_LINK:
[94b357c2]52      loc->handlers = &IMFS_link_handlers;
[07a3253d]53      break;
[0ef748fb]54    case IMFS_LINEAR_FILE:
[624867b]55      loc->handlers = fs_info->memfile_handlers;
[0ef748fb]56      break;
[07a3253d]57    case IMFS_MEMORY_FILE:
[657e1bf6]58      loc->handlers = fs_info->memfile_handlers;
[07a3253d]59      break;
[e2324c0]60    case IMFS_FIFO:
61      loc->handlers = &IMFS_fifo_handlers;
62      break;
[07a3253d]63  }
64
65  return 0;
66}
67
68/*
69 *  IMFS_evaluate_permission
70 *
71 *  The following routine evaluates that we have permission
72 *  to do flags on the node.
73 */
74
75int IMFS_evaluate_permission(
76  rtems_filesystem_location_info_t  *node,
77  int                                flags
78)
79{
80  uid_t         st_uid;
81  gid_t         st_gid;
82  IMFS_jnode_t *jnode;
83  int           flags_to_test;
84
[ed4a3f6]85  if ( !rtems_libio_is_valid_perms( flags ) )
86    rtems_set_errno_and_return_minus_one( EPERM );
[07a3253d]87
88  jnode = node->node_access;
89
90#if defined(RTEMS_POSIX_API)
91  st_uid = geteuid();
[a5305f6b]92  st_gid = getegid();
[07a3253d]93#else
94  st_uid = jnode->st_uid;
95  st_gid = jnode->st_gid;
96#endif
[a5305f6b]97
[07a3253d]98  /*
99   * Check if I am owner or a group member or someone else.
100   */
[a5305f6b]101
[07a3253d]102  flags_to_test = flags;
103
104  if ( st_uid == jnode->st_uid )
105    flags_to_test <<= 6;
106  else if ( st_gid == jnode->st_gid )
107    flags_to_test <<= 3;
[77b5aa5]108  else {
[07a3253d]109    /* must be other - do nothing */;
[77b5aa5]110  }
[0a7278e]111
[07a3253d]112  /*
113   * If all of the flags are set we have permission
114   * to do this.
115   */
116  if ( ( flags_to_test & jnode->st_mode) == flags_to_test )
117    return 1;
118
119  return 0;
120}
121
122/*
123 *  IMFS_evaluate_hard_link
124 *
125 *  The following routine evaluates a hardlink to the actual node.
126 */
127
128int IMFS_evaluate_hard_link(
129  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
130  int                                flags   /* IN     */
131)
132{
133  IMFS_jnode_t                     *jnode  = node->node_access;
134  int                               result = 0;
135
136  /*
137   * Check for things that should never happen.
138   */
139
140  if ( jnode->type != IMFS_HARD_LINK )
141    rtems_fatal_error_occurred (0xABCD0000);
142
143  /*
144   * Set the hard link value and the handlers.
145   */
146
147  node->node_access = jnode->info.hard_link.link_node;
[a5305f6b]148
[07a3253d]149  IMFS_Set_handlers( node );
150
151  /*
152   * Verify we have the correct permissions for this node.
153   */
154
[2f87c843]155  if ( !IMFS_evaluate_permission( node, flags ) )
[b2709481]156    rtems_set_errno_and_return_minus_one( EACCES );
[07a3253d]157
158  return result;
159}
160
161
[a5305f6b]162/*
[07a3253d]163 *  IMFS_evaluate_sym_link
164 *
165 *  The following routine evaluates a symbolic link to the actual node.
166 */
167
[a5305f6b]168int IMFS_evaluate_sym_link(
[07a3253d]169  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
170  int                                flags   /* IN     */
171)
172{
173  IMFS_jnode_t                     *jnode  = node->node_access;
174  int                               result = 0;
175  int                               i;
176
177  /*
178   * Check for things that should never happen.
179   */
180
181  if ( jnode->type != IMFS_SYM_LINK )
182    rtems_fatal_error_occurred (0xABCD0000);
183
184  if ( !jnode->Parent )
185    rtems_fatal_error_occurred( 0xBAD00000 );
186
187
188  /*
189   * Move the node_access to either the symbolic links parent or
190   * root depending on the symbolic links path.
191   */
192
193  node->node_access = jnode->Parent;
194
[a5305f6b]195  rtems_filesystem_get_sym_start_loc(
[07a3253d]196    jnode->info.sym_link.name,
197    &i,
198    node
199  );
200
201  /*
202   * Use eval path to evaluate the path of the symbolic link.
203   */
204
[a5305f6b]205  result = IMFS_eval_path(
[07a3253d]206    &jnode->info.sym_link.name[i],
[7baa484]207    strlen( &jnode->info.sym_link.name[i] ),
[07a3253d]208    flags,
209    node
210  );
211
212  IMFS_Set_handlers( node );
213
214  /*
215   * Verify we have the correct permissions for this node.
216   */
217
[2f87c843]218  if ( !IMFS_evaluate_permission( node, flags ) )
[b2709481]219    rtems_set_errno_and_return_minus_one( EACCES );
[07a3253d]220
221  return result;
222}
223
224/*
225 *  IMFS_evaluate_link
226 *
227 *  The following routine returns the real node pointed to by a link.
228 */
229
[a5305f6b]230int IMFS_evaluate_link(
[07a3253d]231  rtems_filesystem_location_info_t  *node,   /* IN/OUT */
232  int                                flags   /* IN     */
233)
234{
235  IMFS_jnode_t                     *jnode;
236  int                               result = 0;
237
238  do {
239    jnode  = node->node_access;
240
241    /*
242     * Increment and check the link counter.
243     */
244
245    rtems_filesystem_link_counts ++;
246    if ( rtems_filesystem_link_counts > MAXSYMLINK ) {
247      rtems_filesystem_link_counts = 0;
[b2709481]248      rtems_set_errno_and_return_minus_one( ELOOP );
[07a3253d]249    }
250
251    /*
252     *  Follow the Link node.
253     */
254
255    if ( jnode->type == IMFS_HARD_LINK )
256      result = IMFS_evaluate_hard_link( node, flags );
257
258    else if (jnode->type == IMFS_SYM_LINK )
259      result = IMFS_evaluate_sym_link( node, flags );
260
[a5305f6b]261  } while ( ( result == 0 ) && ( ( jnode->type == IMFS_SYM_LINK  ) ||
[07a3253d]262                                 ( jnode->type == IMFS_HARD_LINK ) ) );
263
264  /*
265   * Clear link counter.
266   */
267
268  rtems_filesystem_link_counts = 0;
269
270  return result;
[a5305f6b]271}
[07a3253d]272
273
274/*
275 *  IMFS_evaluate_for_make
276 *
277 *  The following routine evaluate path for a new node to be created.
278 *  pathloc is returned with a pointer to the parent of the new node.
[a5305f6b]279 *  name is returned with a pointer to the first character in the
[07a3253d]280 *  new node name.  The parent node is verified to be a directory.
281 */
282
283int IMFS_evaluate_for_make(
284   const char                         *path,       /* IN     */
285   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
286   const char                        **name        /* OUT    */
287)
288{
289  int                                 i = 0;
290  int                                 len;
291  IMFS_token_types                    type;
[3cf8394]292  char                                token[ IMFS_NAME_MAX + 1 ];
[07a3253d]293  rtems_filesystem_location_info_t    newloc;
294  IMFS_jnode_t                       *node;
[88d1c65]295  bool                                done = false;
[7baa484]296  int                                 pathlen;
[a5305f6b]297  int                                 result;
298
[07a3253d]299  /*
[b6a2d2fa]300   * This was filled in by the caller and is valid in the
[07a3253d]301   * mount table.
302   */
303  node = pathloc->node_access;
304
[7baa484]305  /*
306   * Get the path length.
307   */
308  pathlen = strlen( path );
[ec9d486]309
[07a3253d]310  /*
311   *  Evaluate all tokens until we are done or an error occurs.
312   */
[0a7278e]313
[07a3253d]314  while( !done ) {
315
[7baa484]316    type = IMFS_get_token( &path[i], pathlen, token, &len );
317    pathlen -= len;
[07a3253d]318    i +=  len;
[a5305f6b]319
[07a3253d]320    if ( !pathloc->node_access )
[b2709481]321      rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]322
323    /*
324     * I cannot move out of this directory without execute permission.
325     */
326
327    if ( type != IMFS_NO_MORE_PATH )
328      if ( node->type == IMFS_DIRECTORY )
[2f87c843]329        if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
[b2709481]330           rtems_set_errno_and_return_minus_one( EACCES );
[07a3253d]331
332    node = pathloc->node_access;
333
334    switch( type ) {
335
336      case IMFS_UP_DIR:
[b6a2d2fa]337       /*
338        *  Am I at the root of all filesystems? (chroot'ed?)
[ec9d486]339        */
[b6a2d2fa]340
341       if ( pathloc->node_access == rtems_filesystem_root.node_access )
342         break;       /* Throw out the .. in this case */
343
[07a3253d]344
[ec9d486]345       /*
346        * Am I at the root of this mounted filesystem?
347        */
[07a3253d]348
[ec9d486]349        if (pathloc->node_access ==
350            pathloc->mt_entry->mt_fs_root.node_access){
[07a3253d]351
352          /*
[ec9d486]353           *  Am I at the root of all filesystems?
354           */
[07a3253d]355
356          if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
[a5305f6b]357            break;
[ec9d486]358          } else {
[07a3253d]359            newloc = pathloc->mt_entry->mt_point_node;
360            *pathloc = newloc;
[ec9d486]361            return (*pathloc->ops->evalformake_h)( &path[i], pathloc, name );
362          }
363        } else {
[07a3253d]364          if ( !node->Parent )
[b2709481]365            rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]366
367          node = node->Parent;
[ec9d486]368        }
[07a3253d]369
370        pathloc->node_access = node;
371        break;
372
373      case IMFS_NAME:
[ec9d486]374        /*
375         *  If we are at a link follow it.
376         */
[07a3253d]377
[ec9d486]378        if ( node->type == IMFS_HARD_LINK ) {
[07a3253d]379
380          result = IMFS_evaluate_link( pathloc, 0 );
381          if ( result == -1 )
382            return -1;
383
[ec9d486]384        } else if ( node->type == IMFS_SYM_LINK ) {
[07a3253d]385
386          result = IMFS_evaluate_link( pathloc, 0 );
387
388          if ( result == -1 )
389            return -1;
[ec9d486]390        }
[07a3253d]391
392        node = pathloc->node_access;
393        if ( !node )
[a5305f6b]394          rtems_set_errno_and_return_minus_one( ENOTDIR );
[07a3253d]395
396        /*
397         * Only a directory can be decended into.
[ec9d486]398         */
[07a3253d]399
400        if ( node->type != IMFS_DIRECTORY )
[b2709481]401          rtems_set_errno_and_return_minus_one( ENOTDIR );
[07a3253d]402
[ec9d486]403        /*
404         * Otherwise find the token name in the present location.
405         */
[07a3253d]406
407        node = IMFS_find_match_in_dir( node, token );
408
[ec9d486]409        /*
410         * If there is no node we have found the name of the node we
[07a3253d]411         * wish to create.
[ec9d486]412         */
[07a3253d]413
414        if ( ! node )
[88d1c65]415          done = true;
[ec9d486]416        else {
417          /*
418           * If we are at a node that is a mount point. Set loc to the
419           * new fs root node and let them finish evaluating the path.
420           */
[07a3253d]421
[ec9d486]422          if ( node->info.directory.mt_fs != NULL ) {
423            newloc  = node->info.directory.mt_fs->mt_fs_root;
424            *pathloc = newloc;
425            return (*pathloc->ops->evalformake_h)( &path[i], pathloc, name );
426          }
427         
428          pathloc->node_access = node;
429        }
[07a3253d]430        break;
[a5305f6b]431
[07a3253d]432      case IMFS_NO_MORE_PATH:
[b2709481]433        rtems_set_errno_and_return_minus_one( EEXIST );
[07a3253d]434        break;
435
436      case IMFS_INVALID_TOKEN:
[b2709481]437        rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
[07a3253d]438        break;
439
440      case IMFS_CURRENT_DIR:
441        break;
442    }
443  }
444
445  *name = &path[ i - len ];
[a5305f6b]446
[07a3253d]447  /*
448   * We have evaluated the path as far as we can.
[a5305f6b]449   * Verify there is not any invalid stuff at the end of the name.
[07a3253d]450   */
451
452  for( ; path[i] != '\0'; i++) {
[a5305f6b]453    if ( !IMFS_is_separator( path[ i ] ) )
[b2709481]454      rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]455  }
456
[a5305f6b]457  /*
[07a3253d]458   * Verify we can execute and write to this directory.
459   */
460
461  result = IMFS_Set_handlers( pathloc );
462
463  /*
464   * The returned node must be a directory
465   */
466  node = pathloc->node_access;
467  if ( node->type != IMFS_DIRECTORY )
[b2709481]468    rtems_set_errno_and_return_minus_one( ENOTDIR );
[07a3253d]469
470  /*
471   * We must have Write and execute permission on the returned node.
472   */
473
[2f87c843]474  if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_WX ) )
[b2709481]475    rtems_set_errno_and_return_minus_one( EACCES );
[a5305f6b]476
[07a3253d]477  return result;
478}
479
480
481/*
482 *  IMFS_eval_path
483 *
484 *  The following routine evaluate path for a node that wishes to be
485 *  accessed with mode.  pathloc is returned with a pointer to the
486 *  node to be accessed.
487 */
488
[a5305f6b]489int IMFS_eval_path(
[07a3253d]490  const char                        *pathname,     /* IN     */
[cd469f2]491  size_t                             pathnamelen,  /* IN     */
[07a3253d]492  int                                flags,        /* IN     */
493  rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */
[29e92b0]494                   )
[07a3253d]495{
496  int                                 i = 0;
497  int                                 len;
498  IMFS_token_types                    type = IMFS_CURRENT_DIR;
[3cf8394]499  char                                token[ IMFS_NAME_MAX + 1 ];
[07a3253d]500  rtems_filesystem_location_info_t    newloc;
501  IMFS_jnode_t                       *node;
[a5305f6b]502  int                                 result;
[07a3253d]503
[2f87c843]504  if ( !rtems_libio_is_valid_perms( flags ) ) {
[07a3253d]505    assert( 0 );
[a5305f6b]506    rtems_set_errno_and_return_minus_one( EIO );
[07a3253d]507  }
508
509  /*
[a5305f6b]510   *  This was filled in by the caller and is valid in the
[07a3253d]511   *  mount table.
512   */
513
514  node = pathloc->node_access;
515
516  /*
517   *  Evaluate all tokens until we are done or an error occurs.
518   */
519
520  while( (type != IMFS_NO_MORE_PATH) && (type != IMFS_INVALID_TOKEN) ) {
521
[7baa484]522    type = IMFS_get_token( &pathname[i], pathnamelen, token, &len );
523    pathnamelen -= len;
524    i += len;
[a5305f6b]525
[07a3253d]526    if ( !pathloc->node_access )
[b2709481]527      rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]528
529    /*
530     * I cannot move out of this directory without execute permission.
531     */
532    if ( type != IMFS_NO_MORE_PATH )
533      if ( node->type == IMFS_DIRECTORY )
[2f87c843]534        if ( !IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
[29e92b0]535          rtems_set_errno_and_return_minus_one( EACCES );
[07a3253d]536
537    node = pathloc->node_access;
538
539    switch( type ) {
540      case IMFS_UP_DIR:
[29e92b0]541        /*
542         *  Am I at the root of all filesystems? (chroot'ed?)
543         */
[b6a2d2fa]544
[29e92b0]545        if ( pathloc->node_access == rtems_filesystem_root.node_access )
546          break;       /* Throw out the .. in this case */
[07a3253d]547
[29e92b0]548        /*
549         *  Am I at the root of this mounted filesystem?
550         */
[07a3253d]551
[a5305f6b]552        if (pathloc->node_access ==
[07a3253d]553            pathloc->mt_entry->mt_fs_root.node_access) {
554
555          /*
[29e92b0]556           *  Am I at the root of all filesystems?
557           */
[07a3253d]558
559          if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
560            break;       /* Throw out the .. in this case */
[29e92b0]561          } else {
[07a3253d]562            newloc = pathloc->mt_entry->mt_point_node;
563            *pathloc = newloc;
[ec9d486]564            return (*pathloc->ops->evalpath_h)(&(pathname[i]),
565                                               pathnamelen,
[7baa484]566                                               flags,pathloc);
[29e92b0]567          }
568        } else {
[07a3253d]569          if ( !node->Parent )
[b2709481]570            rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]571
572          node = node->Parent;
[29e92b0]573        }
[07a3253d]574
575        pathloc->node_access = node;
576        break;
577
578      case IMFS_NAME:
[29e92b0]579        /*
580         *  If we are at a link follow it.
581         */
[07a3253d]582
[29e92b0]583        if ( node->type == IMFS_HARD_LINK ) {
[07a3253d]584
585          IMFS_evaluate_hard_link( pathloc, 0 );
586
587          node = pathloc->node_access;
588          if ( !node )
[b2709481]589            rtems_set_errno_and_return_minus_one( ENOTDIR );
[07a3253d]590
[29e92b0]591        } else if ( node->type == IMFS_SYM_LINK ) {
[07a3253d]592
593          result = IMFS_evaluate_sym_link( pathloc, 0 );
594
595          node = pathloc->node_access;
596          if ( result == -1 )
597            return -1;
[29e92b0]598        }
[07a3253d]599
[29e92b0]600        /*
601         *  Only a directory can be decended into.
602         */
[07a3253d]603
[29e92b0]604        if ( node->type != IMFS_DIRECTORY )
[b2709481]605          rtems_set_errno_and_return_minus_one( ENOTDIR );
[07a3253d]606
[29e92b0]607        /*
608         *  Otherwise find the token name in the present location.
609         */
[07a3253d]610
611        node = IMFS_find_match_in_dir( node, token );
[ec9d486]612
[07a3253d]613        if ( !node )
[b2709481]614          rtems_set_errno_and_return_minus_one( ENOENT );
[07a3253d]615
[ec9d486]616
[29e92b0]617        /*
618         *  Set the node access to the point we have found.
619         */
[07a3253d]620
621        pathloc->node_access = node;
[ec9d486]622       
623        /*
624         *  If we are at a node that is a mount point. Set loc to the
625         *  new fs root node and let them finish evaluating the path.
626         */
627
628        if ( node->info.directory.mt_fs != NULL ) {
629          newloc   = node->info.directory.mt_fs->mt_fs_root;
630          *pathloc = newloc;
631          return (*pathloc->ops->evalpath_h)( &pathname[i],
632                                              pathnamelen,
633                                              flags, pathloc );
634        }
[07a3253d]635        break;
636
637      case IMFS_NO_MORE_PATH:
638      case IMFS_CURRENT_DIR:
639        break;
640
641      case IMFS_INVALID_TOKEN:
[b2709481]642        rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
[07a3253d]643        break;
644
645    }
646  }
647
648  /*
[13e47e2e]649   *  Always return the root node.
650   *
651   *  If we are at a node that is a mount point. Set loc to the
652   *  new fs root node and let let the mounted filesystem set the handlers.
653   *
654   *  NOTE: The behavior of stat() on a mount point appears to be questionable.
[07a3253d]655   */
656
[13e47e2e]657  if ( node->type == IMFS_DIRECTORY ) {
658    if ( node->info.directory.mt_fs != NULL ) {
659      newloc   = node->info.directory.mt_fs->mt_fs_root;
660      *pathloc = newloc;
[7baa484]661      return (*pathloc->ops->evalpath_h)( &pathname[i-len],
662                                          pathnamelen+len,
663                                          flags, pathloc );
[13e47e2e]664    } else {
665      result = IMFS_Set_handlers( pathloc );
666    }
667  } else {
668    result = IMFS_Set_handlers( pathloc );
[07a3253d]669  }
670
671  /*
672   * Verify we have the correct permissions for this node.
673   */
674
[2f87c843]675  if ( !IMFS_evaluate_permission( pathloc, flags ) )
[b2709481]676    rtems_set_errno_and_return_minus_one( EACCES );
[07a3253d]677
678  return result;
679}
Note: See TracBrowser for help on using the repository browser.