Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / env_cleanser.c
1 /*
2  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "native_client/src/include/portability.h"
12 #include "native_client/src/include/nacl_macros.h"
13
14 #include "native_client/src/trusted/service_runtime/env_cleanser.h"
15 #include "native_client/src/trusted/service_runtime/env_cleanser_test.h"
16
17 /*
18  * Everything that starts with this prefix is allowed (but the prefix is
19  * stripped away).
20 */
21 #define NACL_ENV_PREFIX "NACLENV_"
22 #define NACL_ENV_PREFIX_LENGTH 8
23
24 void NaClEnvCleanserCtor(struct NaClEnvCleanser *self, int with_whitelist) {
25   self->with_whitelist = with_whitelist;
26   self->cleansed_environ = (char const **) NULL;
27 }
28
29 /*
30  * Environment variables names are from IEEE Std 1003.1-2001, with
31  * additional ones from locale(7) from glibc / linux.  The entries
32  * must be sorted, in ASCII order, for the bsearch to run correctly.
33  */
34 /* static -- not static for testing */
35 char const *const kNaClEnvWhitelist[] = {
36   "LANG",
37   "LC_ADDRESS",
38   "LC_ALL",
39   "LC_COLLATE",
40   "LC_CTYPE",
41   "LC_IDENTIFICATION",
42   "LC_MEASUREMENT",
43   "LC_MESSAGES",
44   "LC_MONETARY",
45   "LC_NAME",
46   "LC_NUMERIC",
47   "LC_PAPER",
48   "LC_TELEPHONE",
49   "LC_TIME",
50   "NACLVERBOSITY",
51   "NACL_PLUGIN_DEBUG",      /* src/trusted/plugin/srpc/utility.cc */
52   "NACL_SRPC_DEBUG",        /* src/shared/srpc/utility.c */
53   NULL,
54 };
55
56 /* left arg is key, right arg is table entry */
57 static int EnvCmp(void const *vleft, void const *vright) {
58   char const *left = *(char const *const *) vleft;
59   char const *right = *(char const *const *) vright;
60   char cleft, cright;
61
62   while ((cleft = *left) == (cright = *right)
63          && '\0' != cleft
64          && '\0' != cright) {
65     ++left;
66     ++right;
67   }
68   if ('=' == cleft && '\0' == cright) {
69     return 0;
70   }
71   return (0xff & cleft) - (0xff & cright);
72 }
73
74 int NaClEnvIsPassThroughVar(char const *env_entry) {
75   return strlen(env_entry) > NACL_ENV_PREFIX_LENGTH &&
76       0 == strncmp(env_entry, NACL_ENV_PREFIX,
77           NACL_ENV_PREFIX_LENGTH);
78 }
79
80 int NaClEnvInWhitelist(char const *env_entry) {
81   return NULL != bsearch((void const *) &env_entry,
82                          (void const *) kNaClEnvWhitelist,
83                          NACL_ARRAY_SIZE(kNaClEnvWhitelist) - 1,  /* NULL */
84                          sizeof kNaClEnvWhitelist[0],
85                          EnvCmp);
86 }
87
88 /* PRE: sizeof(char *) is a power of 2 */
89
90 /*
91  * Initializes the object with a filtered environment.
92  *
93  * May return false on errors, e.g., out-of-memory.
94  */
95 int NaClEnvCleanserInit(struct NaClEnvCleanser *self, char const *const *envp,
96     char const * const *extra_env) {
97   char const *const *p;
98   size_t num_env = 0;
99   size_t ptr_bytes = 0;
100   const size_t kMaxSize = ~(size_t) 0;
101   const size_t ptr_size_mult_overflow_mask = ~(kMaxSize / sizeof *envp);
102   char const **ptr_tbl;
103   size_t env;
104
105   /*
106    * let n be a size_t.  if n & ptr_size_mult_overflow_mask is set,
107    * then n*sizeof(void *) will have an arithmetic overflow.
108    */
109
110   if (NULL == envp || NULL == *envp) {
111     self->cleansed_environ = NULL;
112     return 1;
113   }
114   for (p = envp; NULL != *p; ++p) {
115     if (!(self->with_whitelist && NaClEnvInWhitelist(*p)) &&
116         !NaClEnvIsPassThroughVar(*p)) {
117       continue;
118     }
119     if (num_env == kMaxSize) {
120       /* would overflow */
121       return 0;
122     }
123     ++num_env;
124   }
125
126   if (extra_env) {
127     for (p = extra_env; NULL != *p; ++p) {
128       if (num_env == kMaxSize) {
129         /* would overflow */
130         return 0;
131       }
132       ++num_env;
133     }
134   }
135
136   /* pointer table -- NULL pointer terminated */
137   if (0 != ((1 + num_env) & ptr_size_mult_overflow_mask)) {
138     return 0;
139   }
140   ptr_bytes = (1 + num_env) * sizeof(*envp);
141
142   ptr_tbl = (char const **) malloc(ptr_bytes);
143   if (NULL == ptr_tbl) {
144     return 0;
145   }
146
147   /* this assumes no other thread is tweaking envp */
148   for (env = 0, p = envp; NULL != *p; ++p) {
149     if (NaClEnvIsPassThroughVar(*p)) {
150       ptr_tbl[env] = *p + NACL_ENV_PREFIX_LENGTH;
151     } else if (self->with_whitelist && NaClEnvInWhitelist(*p)) {
152       ptr_tbl[env] = *p;
153     } else {
154       continue;
155     }
156     ++env;
157   }
158   if (extra_env) {
159     for (p = extra_env; NULL != *p; ++p) {
160       ptr_tbl[env] = *p;
161       ++env;
162     }
163   }
164   if (num_env != env) {
165     free((void *) ptr_tbl);
166     return 0;
167   }
168   ptr_tbl[env] = NULL;
169   self->cleansed_environ = ptr_tbl;
170
171   return 1;
172 }
173
174 char const *const *NaClEnvCleanserEnvironment(struct NaClEnvCleanser *self) {
175   return (char const *const *) self->cleansed_environ;
176 }
177
178 void NaClEnvCleanserDtor(struct NaClEnvCleanser *self) {
179   free((void *) self->cleansed_environ);
180   self->cleansed_environ = NULL;
181 }