2.5-18.1
[jlayton/glibc.git] / sysdeps / unix / sysv / linux / readonly-area.c
1 /* Copyright (C) 2004, 2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdio_ext.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "libio/libioP.h"
26
27 /* Return 1 if the whole area PTR .. PTR+SIZE is not writable.
28    Return -1 if it is writable.  */
29
30 int
31 __readonly_area (const char *ptr, size_t size)
32 {
33   const void *ptr_end = ptr + size;
34
35   FILE *fp = fopen ("/proc/self/maps", "rc");
36   if (fp == NULL)
37     {
38       /* It is the system administrator's choice to not have /proc
39          available to this process (e.g., because it runs in a chroot
40          environment.  Don't fail in this case.  */
41       if (errno == ENOENT
42           /* The kernel has a bug in that a process is denied access
43              to the /proc filesystem if it is set[ug]id.  There has
44              been no willingness to change this in the kernel so
45              far.  */
46           || errno == EACCES)
47         return 1;
48       return -1;
49     }
50
51   /* We need no locking.  */
52   __fsetlocking (fp, FSETLOCKING_BYCALLER);
53
54   char *line = NULL;
55   size_t linelen = 0;
56
57   while (! feof_unlocked (fp))
58     {
59       if (_IO_getdelim (&line, &linelen, '\n', fp) <= 0)
60         break;
61
62       char *p;
63       uintptr_t from = strtoul (line, &p, 16);
64
65       if (p == line || *p++ != '-')
66         break;
67
68       char *q;
69       uintptr_t to = strtoul (p, &q, 16);
70
71       if (q == p || *q++ != ' ')
72         break;
73
74       if (from < (uintptr_t) ptr_end && to > (uintptr_t) ptr)
75         {
76           /* Found an entry that at least partially covers the area.  */
77           if (*q++ != 'r' || *q++ != '-')
78             break;
79
80           if (from <= (uintptr_t) ptr && to >= (uintptr_t) ptr_end)
81             {
82               size = 0;
83               break;
84             }
85           else if (from <= (uintptr_t) ptr)
86             size -= to - (uintptr_t) ptr;
87           else if (to >= (uintptr_t) ptr_end)
88             size -= (uintptr_t) ptr_end - from;
89           else
90             size -= to - from;
91
92           if (!size)
93             break;
94         }
95     }
96
97   fclose (fp);
98   free (line);
99
100   /* If the whole area between ptr and ptr_end is covered by read-only
101      VMAs, return 1.  Otherwise return -1.  */
102   return size == 0 ? 1 : -1;
103 }