source: rtems/cpukit/libcsupport/src/sup_fs_eval_path.c @ 66fac03

5
Last change on this file since 66fac03 was 66fac03, checked in by Sebastian Huber <sebastian.huber@…>, on 03/16/17 at 10:54:29

libio: Fix deadlock in location management

Perform a context-dependent deferred location release to avoid a
deadlock on the file system instance locks, for example during a
chdir().

Update #2936.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief RTEMS File Sysyem Path Eval Support
5 *  @ingroup LibIOInternal
6 */
7
8/*
9 * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
10 *
11 *  embedded brains GmbH
12 *  Obere Lagerstr. 30
13 *  82178 Puchheim
14 *  Germany
15 *  <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.org/license/LICENSE.
20 */
21
22#if HAVE_CONFIG_H
23  #include "config.h"
24#endif
25
26#include <rtems/libio_.h>
27
28#include <string.h>
29
30static size_t get_parentpathlen(const char *path, size_t pathlen)
31{
32  while (pathlen > 0) {
33    size_t i = pathlen - 1;
34
35    if (rtems_filesystem_is_delimiter(path [i])) {
36      return pathlen;
37    }
38
39    pathlen = i;
40  }
41
42  return 0;
43}
44
45static void set_startloc(
46  rtems_filesystem_eval_path_context_t *ctx,
47  rtems_filesystem_global_location_t *const *global_root_ptr,
48  rtems_filesystem_global_location_t *const *global_current_ptr
49)
50{
51  if (ctx->pathlen > 0) {
52    char c = ctx->path [0];
53
54    ctx->rootloc = rtems_filesystem_global_location_obtain(global_root_ptr);
55
56    if (rtems_filesystem_is_delimiter(c)) {
57      ++ctx->path;
58      --ctx->pathlen;
59      ctx->startloc = rtems_filesystem_global_location_obtain(
60        &ctx->rootloc
61      );
62    } else {
63      ctx->startloc = rtems_filesystem_global_location_obtain(
64        global_current_ptr
65      );
66    }
67  } else {
68    ctx->rootloc = rtems_filesystem_global_location_obtain_null();
69    ctx->startloc = rtems_filesystem_global_location_obtain_null();
70    errno = ENOENT;
71  }
72}
73
74static void check_access(
75  rtems_filesystem_eval_path_context_t *ctx,
76  int eval_flags
77)
78{
79  const rtems_filesystem_location_info_t *currentloc = &ctx->currentloc;
80  const rtems_filesystem_mount_table_entry_t *mt_entry = currentloc->mt_entry;
81
82  if ((eval_flags & RTEMS_FS_PERMS_WRITE) == 0 || mt_entry->writeable) {
83    struct stat st;
84    int rv;
85
86    st.st_mode = 0;
87    st.st_uid = 0;
88    st.st_gid = 0;
89    rv = (*currentloc->handlers->fstat_h)(currentloc, &st);
90    if (rv == 0) {
91      bool access_ok = rtems_filesystem_check_access(
92        eval_flags,
93        st.st_mode,
94        st.st_uid,
95        st.st_gid
96      );
97
98      if (!access_ok) {
99        rtems_filesystem_eval_path_error(ctx, EACCES);
100      }
101    } else {
102      rtems_filesystem_eval_path_error(ctx, 0);
103    }
104  } else {
105    rtems_filesystem_eval_path_error(ctx, EROFS);
106  }
107}
108
109void rtems_filesystem_eval_path_continue(
110  rtems_filesystem_eval_path_context_t *ctx
111)
112{
113  int eval_flags;
114
115  while (ctx->pathlen > 0) {
116    (*ctx->currentloc.mt_entry->ops->eval_path_h)(ctx);
117  }
118
119  eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
120  if (rtems_filesystem_eval_path_has_token(ctx)) {
121    bool make = (eval_flags & RTEMS_FS_MAKE) != 0;
122
123    if (make) {
124      check_access(ctx, RTEMS_FS_PERMS_WRITE);
125    } else {
126      rtems_filesystem_eval_path_error(ctx, ENOENT);
127    }
128  } else {
129    bool exclusive = (eval_flags & RTEMS_FS_EXCLUSIVE) != 0;
130
131    if (!exclusive) {
132      check_access(ctx, ctx->flags);
133    } else {
134      rtems_filesystem_eval_path_error(ctx, EEXIST);
135    }
136  }
137}
138
139rtems_filesystem_location_info_t *
140rtems_filesystem_eval_path_start_with_root_and_current(
141  rtems_filesystem_eval_path_context_t *ctx,
142  const char *path,
143  size_t pathlen,
144  int eval_flags,
145  rtems_filesystem_global_location_t *const *global_root_ptr,
146  rtems_filesystem_global_location_t *const *global_current_ptr
147)
148{
149  memset(ctx, 0, sizeof(*ctx));
150
151  ctx->path = path;
152  ctx->pathlen = pathlen;
153  ctx->flags = eval_flags;
154
155  set_startloc(ctx, global_root_ptr, global_current_ptr);
156
157  rtems_filesystem_instance_lock(&ctx->startloc->location);
158
159  rtems_filesystem_location_clone(
160    &ctx->currentloc,
161    &ctx->startloc->location
162  );
163
164  rtems_filesystem_eval_path_continue(ctx);
165
166  return &ctx->currentloc;
167}
168
169rtems_filesystem_location_info_t *
170rtems_filesystem_eval_path_start(
171  rtems_filesystem_eval_path_context_t *ctx,
172  const char *path,
173  int eval_flags
174)
175{
176  return rtems_filesystem_eval_path_start_with_root_and_current(
177    ctx,
178    path,
179    strlen(path),
180    eval_flags,
181    &rtems_filesystem_root,
182    &rtems_filesystem_current
183  );
184}
185
186rtems_filesystem_location_info_t *
187rtems_filesystem_eval_path_start_with_parent(
188  rtems_filesystem_eval_path_context_t *ctx,
189  const char *path,
190  int eval_flags,
191  rtems_filesystem_location_info_t *parentloc,
192  int parent_eval_flags
193)
194{
195  size_t pathlen = strlen(path);
196  const char *parentpath = path;
197  size_t parentpathlen = get_parentpathlen(path, pathlen);
198  const char *name = NULL;
199  size_t namelen = 0;
200  const rtems_filesystem_location_info_t *currentloc = NULL;
201
202  if (pathlen > 0) {
203    if (parentpathlen == 0) {
204      parentpath = ".";
205      parentpathlen = 1;
206      name = path;
207      namelen = pathlen;
208    } else {
209      name = path + parentpathlen;
210      namelen = pathlen - parentpathlen;
211    }
212  }
213
214  currentloc = rtems_filesystem_eval_path_start_with_root_and_current(
215    ctx,
216    parentpath,
217    parentpathlen,
218    parent_eval_flags,
219    &rtems_filesystem_root,
220    &rtems_filesystem_current
221  );
222
223  rtems_filesystem_location_clone(parentloc, currentloc);
224
225  ctx->path = name;
226  ctx->pathlen = namelen;
227  ctx->flags = eval_flags;
228
229  rtems_filesystem_eval_path_continue(ctx);
230
231  return &ctx->currentloc;
232}
233
234void rtems_filesystem_eval_path_recursive(
235  rtems_filesystem_eval_path_context_t *ctx,
236  const char *path,
237  size_t pathlen
238)
239{
240  if (pathlen > 0) {
241    if (ctx->recursionlevel < RTEMS_FILESYSTEM_SYMLOOP_MAX) {
242      const char *saved_path = ctx->path;
243      size_t saved_pathlen = ctx->pathlen;
244
245      if (rtems_filesystem_is_delimiter(path [0])) {
246        rtems_filesystem_eval_path_restart(ctx, &ctx->rootloc);
247      }
248
249      ctx->path = path;
250      ctx->pathlen = pathlen;
251
252      ++ctx->recursionlevel;
253      while (ctx->pathlen > 0) {
254        (*ctx->currentloc.mt_entry->ops->eval_path_h)(ctx);
255      }
256      --ctx->recursionlevel;
257
258      ctx->path = saved_path;
259      ctx->pathlen = saved_pathlen;
260    } else {
261      rtems_filesystem_eval_path_error(ctx, ELOOP);
262    }
263  } else {
264    rtems_filesystem_eval_path_error(ctx, ENOENT);
265  }
266}
267
268void rtems_filesystem_eval_path_error(
269  rtems_filesystem_eval_path_context_t *ctx,
270  int eno
271)
272{
273  ctx->path = NULL;
274  ctx->pathlen = 0;
275  ctx->token = NULL;
276  ctx->tokenlen = 0;
277
278  if (!rtems_filesystem_location_is_null(&ctx->currentloc)) {
279    if (eno != 0) {
280      errno = eno;
281    }
282
283    rtems_filesystem_location_detach(&ctx->currentloc);
284  }
285}
286
287static void free_location(rtems_filesystem_location_info_t *loc)
288{
289  rtems_filesystem_mt_entry_declare_lock_context(lock_context);
290
291  (*loc->mt_entry->ops->freenod_h)(loc);
292
293  rtems_filesystem_mt_entry_lock(lock_context);
294  rtems_chain_extract_unprotected(&loc->mt_entry_node);
295  rtems_filesystem_mt_entry_unlock(lock_context);
296}
297
298void rtems_filesystem_eval_path_cleanup(
299  rtems_filesystem_eval_path_context_t *ctx
300)
301{
302  free_location(&ctx->currentloc);
303  rtems_filesystem_instance_unlock(&ctx->startloc->location);
304  rtems_filesystem_global_location_release(ctx->startloc, false);
305  rtems_filesystem_global_location_release(ctx->rootloc, false);
306}
307
308void rtems_filesystem_eval_path_cleanup_with_parent(
309  rtems_filesystem_eval_path_context_t *ctx,
310  rtems_filesystem_location_info_t *parentloc
311)
312{
313  free_location(parentloc);
314  rtems_filesystem_eval_path_cleanup(ctx);
315}
316
317void rtems_filesystem_eval_path_restart(
318  rtems_filesystem_eval_path_context_t *ctx,
319  rtems_filesystem_global_location_t **newstartloc_ptr
320)
321{
322  free_location(&ctx->currentloc);
323  rtems_filesystem_instance_unlock(&ctx->startloc->location);
324  rtems_filesystem_global_location_assign(
325    &ctx->startloc,
326    rtems_filesystem_global_location_obtain(newstartloc_ptr)
327  );
328  rtems_filesystem_instance_lock(&ctx->startloc->location);
329  rtems_filesystem_location_clone(&ctx->currentloc, &ctx->startloc->location);
330}
Note: See TracBrowser for help on using the repository browser.