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 257 : void NaClEnvCleanserCtor(struct NaClEnvCleanser *self, int with_whitelist) {
25 257 : self->with_whitelist = with_whitelist;
26 257 : self->cleansed_environ = (char const **) NULL;
27 257 : }
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_NPAPI_DEBUG", /* src/shared/npruntime/naclnp_util.cc */
52 : "NACL_PLUGIN_DEBUG", /* src/trusted/plugin/srpc/utility.cc */
53 : "NACL_PPAPI_PROXY_DEBUG", /* src/shared/ppapi_proxy/utility.cc */
54 : "NACL_SRPC_DEBUG", /* src/shared/srpc/utility.c */
55 : "NACL_SRPC_STANDALONE", /* src/shared/srpc/nacl_srpc.c */
56 : NULL,
57 : };
58 :
59 : /* left arg is key, right arg is table entry */
60 1594 : static int EnvCmp(void const *vleft, void const *vright) {
61 1594 : char const *left = *(char const *const *) vleft;
62 1594 : char const *right = *(char const *const *) vright;
63 1594 : char cleft, cright;
64 :
65 5525 : while ((cleft = *left) == (cright = *right)
66 : && '\0' != cleft
67 : && '\0' != cright) {
68 772 : ++left;
69 772 : ++right;
70 772 : }
71 1610 : if ('=' == cleft && '\0' == cright) {
72 16 : return 0;
73 : }
74 1578 : return (0xff & cleft) - (0xff & cright);
75 1594 : }
76 :
77 18970 : int NaClEnvIsPassThroughVar(char const *env_entry) {
78 18970 : return strlen(env_entry) > NACL_ENV_PREFIX_LENGTH &&
79 18448 : 0 == strncmp(env_entry, NACL_ENV_PREFIX,
80 : NACL_ENV_PREFIX_LENGTH);
81 18970 : }
82 :
83 353 : int NaClEnvInWhitelist(char const *env_entry) {
84 353 : return NULL != bsearch((void const *) &env_entry,
85 : (void const *) kNaClEnvWhitelist,
86 : NACL_ARRAY_SIZE(kNaClEnvWhitelist) - 1, /* NULL */
87 : sizeof kNaClEnvWhitelist[0],
88 : EnvCmp);
89 : }
90 :
91 : /* PRE: sizeof(char *) is a power of 2 */
92 :
93 : /*
94 : * Initializes the object with a filtered environment.
95 : *
96 : * May return false on errors, e.g., out-of-memory.
97 : */
98 257 : int NaClEnvCleanserInit(struct NaClEnvCleanser *self, char const *const *envp,
99 257 : char const * const *extra_env) {
100 257 : char const *const *p;
101 257 : size_t num_env = 0;
102 257 : size_t ptr_bytes = 0;
103 257 : const size_t kMaxSize = ~(size_t) 0;
104 257 : const size_t ptr_size_mult_overflow_mask = ~(kMaxSize / sizeof *envp);
105 257 : char const **ptr_tbl;
106 257 : size_t env;
107 :
108 : /*
109 : * let n be a size_t. if n & ptr_size_mult_overflow_mask is set,
110 : * then n*sizeof(void *) will have an arithmetic overflow.
111 : */
112 :
113 514 : if (NULL == envp || NULL == *envp) {
114 0 : self->cleansed_environ = NULL;
115 0 : return 1;
116 : }
117 19490 : for (p = envp; NULL != *p; ++p) {
118 9650 : if (!(self->with_whitelist && NaClEnvInWhitelist(*p)) &&
119 9482 : !NaClEnvIsPassThroughVar(*p)) {
120 9478 : continue;
121 : }
122 10 : if (num_env == kMaxSize) {
123 : /* would overflow */
124 0 : return 0;
125 : }
126 10 : ++num_env;
127 10 : }
128 :
129 257 : if (extra_env) {
130 526 : for (p = extra_env; NULL != *p; ++p) {
131 12 : if (num_env == kMaxSize) {
132 : /* would overflow */
133 0 : return 0;
134 : }
135 12 : ++num_env;
136 12 : }
137 251 : }
138 :
139 : /* pointer table -- NULL pointer terminated */
140 257 : if (0 != ((1 + num_env) & ptr_size_mult_overflow_mask)) {
141 0 : return 0;
142 : }
143 257 : ptr_bytes = (1 + num_env) * sizeof(*envp);
144 :
145 257 : ptr_tbl = (char const **) malloc(ptr_bytes);
146 257 : if (NULL == ptr_tbl) {
147 0 : return 0;
148 : }
149 :
150 : /* this assumes no other thread is tweaking envp */
151 19490 : for (env = 0, p = envp; NULL != *p; ++p) {
152 9488 : if (NaClEnvIsPassThroughVar(*p)) {
153 4 : ptr_tbl[env] = *p + NACL_ENV_PREFIX_LENGTH;
154 9648 : } else if (self->with_whitelist && NaClEnvInWhitelist(*p)) {
155 6 : ptr_tbl[env] = *p;
156 6 : } else {
157 9478 : continue;
158 : }
159 10 : ++env;
160 10 : }
161 257 : if (extra_env) {
162 526 : for (p = extra_env; NULL != *p; ++p) {
163 12 : ptr_tbl[env] = *p;
164 12 : ++env;
165 12 : }
166 251 : }
167 257 : if (num_env != env) {
168 0 : free((void *) ptr_tbl);
169 0 : return 0;
170 : }
171 257 : ptr_tbl[env] = NULL;
172 257 : self->cleansed_environ = ptr_tbl;
173 :
174 257 : return 1;
175 257 : }
176 :
177 257 : char const *const *NaClEnvCleanserEnvironment(struct NaClEnvCleanser *self) {
178 257 : return (char const *const *) self->cleansed_environ;
179 : }
180 :
181 257 : void NaClEnvCleanserDtor(struct NaClEnvCleanser *self) {
182 257 : free((void *) self->cleansed_environ);
183 257 : self->cleansed_environ = NULL;
184 257 : }
|