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 1 : void NaClEnvCleanserCtor(struct NaClEnvCleanser *self, int with_whitelist) {
25 1 : self->with_whitelist = with_whitelist;
26 1 : self->cleansed_environ = (char const **) NULL;
27 1 : }
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 1 : static int EnvCmp(void const *vleft, void const *vright) {
58 1 : char const *left = *(char const *const *) vleft;
59 1 : char const *right = *(char const *const *) vright;
60 : char cleft, cright;
61 :
62 : while ((cleft = *left) == (cright = *right)
63 : && '\0' != cleft
64 1 : && '\0' != cright) {
65 1 : ++left;
66 1 : ++right;
67 1 : }
68 1 : if ('=' == cleft && '\0' == cright) {
69 1 : return 0;
70 : }
71 1 : return (0xff & cleft) - (0xff & cright);
72 1 : }
73 :
74 1 : int NaClEnvIsPassThroughVar(char const *env_entry) {
75 : return strlen(env_entry) > NACL_ENV_PREFIX_LENGTH &&
76 : 0 == strncmp(env_entry, NACL_ENV_PREFIX,
77 1 : NACL_ENV_PREFIX_LENGTH);
78 1 : }
79 :
80 1 : 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 1 : EnvCmp);
86 1 : }
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 1 : char const * const *extra_env) {
97 : char const *const *p;
98 1 : size_t num_env = 0;
99 1 : size_t ptr_bytes = 0;
100 1 : const size_t kMaxSize = ~(size_t) 0;
101 1 : 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 1 : if (NULL == envp || NULL == *envp) {
111 0 : self->cleansed_environ = NULL;
112 0 : return 1;
113 : }
114 1 : for (p = envp; NULL != *p; ++p) {
115 : if (!(self->with_whitelist && NaClEnvInWhitelist(*p)) &&
116 1 : !NaClEnvIsPassThroughVar(*p)) {
117 1 : continue;
118 : }
119 1 : if (num_env == kMaxSize) {
120 : /* would overflow */
121 0 : return 0;
122 : }
123 1 : ++num_env;
124 1 : }
125 :
126 1 : if (extra_env) {
127 0 : for (p = extra_env; NULL != *p; ++p) {
128 0 : if (num_env == kMaxSize) {
129 : /* would overflow */
130 0 : return 0;
131 : }
132 0 : ++num_env;
133 0 : }
134 : }
135 :
136 : /* pointer table -- NULL pointer terminated */
137 1 : if (0 != ((1 + num_env) & ptr_size_mult_overflow_mask)) {
138 0 : return 0;
139 : }
140 1 : ptr_bytes = (1 + num_env) * sizeof(*envp);
141 :
142 1 : ptr_tbl = (char const **) malloc(ptr_bytes);
143 1 : if (NULL == ptr_tbl) {
144 0 : return 0;
145 : }
146 :
147 : /* this assumes no other thread is tweaking envp */
148 1 : for (env = 0, p = envp; NULL != *p; ++p) {
149 1 : if (NaClEnvIsPassThroughVar(*p)) {
150 1 : ptr_tbl[env] = *p + NACL_ENV_PREFIX_LENGTH;
151 1 : } else if (self->with_whitelist && NaClEnvInWhitelist(*p)) {
152 1 : ptr_tbl[env] = *p;
153 1 : } else {
154 1 : continue;
155 : }
156 1 : ++env;
157 1 : }
158 1 : if (extra_env) {
159 0 : for (p = extra_env; NULL != *p; ++p) {
160 0 : ptr_tbl[env] = *p;
161 0 : ++env;
162 0 : }
163 : }
164 1 : if (num_env != env) {
165 0 : free((void *) ptr_tbl);
166 0 : return 0;
167 : }
168 1 : ptr_tbl[env] = NULL;
169 1 : self->cleansed_environ = ptr_tbl;
170 :
171 1 : return 1;
172 1 : }
173 :
174 1 : char const *const *NaClEnvCleanserEnvironment(struct NaClEnvCleanser *self) {
175 1 : return (char const *const *) self->cleansed_environ;
176 1 : }
177 :
178 1 : void NaClEnvCleanserDtor(struct NaClEnvCleanser *self) {
179 1 : free((void *) self->cleansed_environ);
180 1 : self->cleansed_environ = NULL;
181 1 : }
|