Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 672918 | Differences between
and this patch

Collapse All | Expand All

(-)a/libsandbox/wrapper-funcs/__wrapper_exec.c (-38 / +71 lines)
Lines 83-90 static bool sb_check_exec(const char *filename, char *const argv[]) Link Here
83
({ \
83
({ \
84
	Elf##n##_Ehdr *ehdr = (void *)elf; \
84
	Elf##n##_Ehdr *ehdr = (void *)elf; \
85
	Elf##n##_Phdr *phdr = (void *)(elf + ehdr->e_phoff); \
85
	Elf##n##_Phdr *phdr = (void *)(elf + ehdr->e_phoff); \
86
	Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0, vhash = 0, vliblist = 0; \
86
	Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0, vhash = 0, vgnuhash = 0; \
87
	Elf##n##_Off offset, symoff = 0, stroff = 0, hashoff = 0, liblistoff = 0; \
87
	Elf##n##_Off offset, symoff = 0, stroff = 0, hashoff = 0, gnuhashoff = 0; \
88
	Elf##n##_Dyn *dyn; \
88
	Elf##n##_Dyn *dyn; \
89
	Elf##n##_Sym *sym, *symend; \
89
	Elf##n##_Sym *sym, *symend; \
90
	uint##n##_t ent_size = 0, str_size = 0; \
90
	uint##n##_t ent_size = 0, str_size = 0; \
Lines 107-113 static bool sb_check_exec(const char *filename, char *const argv[]) Link Here
107
				case DT_STRTAB:      vstr = dyn->d_un.d_val; break; \
107
				case DT_STRTAB:      vstr = dyn->d_un.d_val; break; \
108
				case DT_STRSZ:       str_size = dyn->d_un.d_val; break; \
108
				case DT_STRSZ:       str_size = dyn->d_un.d_val; break; \
109
				case DT_HASH:        vhash = dyn->d_un.d_val; break; \
109
				case DT_HASH:        vhash = dyn->d_un.d_val; break; \
110
				case DT_GNU_LIBLIST: vliblist = dyn->d_un.d_val; break; \
110
				case DT_GNU_HASH:    vgnuhash = dyn->d_un.d_val; break; \
111
				} \
111
				} \
112
				++dyn; \
112
				++dyn; \
113
			} \
113
			} \
Lines 127-134 static bool sb_check_exec(const char *filename, char *const argv[]) Link Here
127
				stroff = offset + (vstr - vaddr); \
127
				stroff = offset + (vstr - vaddr); \
128
			if (vhash >= vaddr && vhash < vaddr + filesz) \
128
			if (vhash >= vaddr && vhash < vaddr + filesz) \
129
				hashoff = offset + (vhash - vaddr); \
129
				hashoff = offset + (vhash - vaddr); \
130
			if (vliblist >= vaddr && vliblist < vaddr + filesz) \
130
			if (vgnuhash >= vaddr && vgnuhash < vaddr + filesz) \
131
				liblistoff = offset + (vliblist - vaddr); \
131
				gnuhashoff = offset + (vgnuhash - vaddr); \
132
		} \
132
		} \
133
		\
133
		\
134
		/* Finally walk the symbol table.  This should generally be fast as \
134
		/* Finally walk the symbol table.  This should generally be fast as \
Lines 137-183 static bool sb_check_exec(const char *filename, char *const argv[]) Link Here
137
		 */ \
137
		 */ \
138
		if (symoff && stroff) { \
138
		if (symoff && stroff) { \
139
			/* Nowhere is the # of symbols recorded, or the size of the symbol \
139
			/* Nowhere is the # of symbols recorded, or the size of the symbol \
140
			 * table.  Instead, we do what glibc does: use the sysv hash table \
140
			 * table.  Instead, we do what glibc does: use the gnu or sysv hash \
141
			 * if it exists, else assume that the string table always directly \
141
			 * table if it exists, else assume that the string table always directly \
142
			 * follows the symbol table.  This seems like a poor assumption to \
142
			 * follows the symbol table.  This seems like a poor assumption to \
143
			 * make, but glibc has gotten by this long.  See determine_info in \
143
			 * make, but glibc has gotten by this long.  See determine_info in \
144
			 * glibc's elf/dl-addr.c. \
144
			 * glibc's elf/dl-addr.c. \
145
			 * \
145
			 * \
146
			 * Turns out prelink will violate that assumption.  Fortunately it \
147
			 * will insert its liblist at the same location all the time -- it \
148
			 * replaces the string table with its liblist table. \
149
			 * \
150
			 * Long term, we should behave the same as glibc and walk the gnu \
151
			 * hash table first before falling back to the raw symbol table. \
152
			 * \
153
			 * We don't sanity check the ranges here as you aren't executing \
146
			 * We don't sanity check the ranges here as you aren't executing \
154
			 * corrupt programs in the sandbox. \
147
			 * corrupt programs in the sandbox. \
155
			 */ \
148
			 */ \
156
			sym = (void *)(elf + symoff); \
149
			sym = (void *)(elf + symoff); \
157
			if (vhash) { \
150
			if (vgnuhash) { \
158
				/* Hash entries are always 32-bits. */ \
151
				uint32_t *hash32 = (void *)(elf + gnuhashoff); \
159
				uint32_t *hashes = (void *)(elf + hashoff); \
152
				/* use glibc's elf/dl-lookup.c:_dl_setup_hash() as a reference */ \
160
				symend = sym + hashes[1]; \
153
				/*   DT_GNU_HASH header: */ \
161
			} else if (vliblist) \
154
				uint32_t nbuckets = *hash32++; \
162
				symend = (void *)(elf + liblistoff); \
155
				uint32_t symbias = *hash32++; \
163
			else \
156
				uint32_t bitmask_nwords = *hash32++; \
164
				symend = (void *)(elf + stroff); \
157
				hash32++; /* gnu_shift */ \
165
			\
158
				hash32 += n / 32 * bitmask_nwords; /* gnu_bitmask */ \
166
			while (sym < symend) { \
159
				uint32_t *gnu_buckets = hash32; \
167
				char *symname = (void *)(elf + stroff + sym->st_name); \
160
				hash32 += nbuckets; \
168
				if (ELF##n##_ST_VISIBILITY(sym->st_other) == STV_DEFAULT && \
161
				uint32_t *gnu_chain_zero = hash32 - symbias; \
169
				    sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && \
162
				\
170
				    sym->st_name && \
163
				uint32_t bucket; \
171
				    /* Minor optimization to avoid strcmp. */ \
164
				\
172
				    symname[0] == '_' && symname[1] == '_') { \
165
				for (bucket = 0; bucket < nbuckets; bucket++) { \
173
					/* Blacklist internal C library symbols. */ \
166
					uint32_t symndx = gnu_buckets[bucket]; \
174
					for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
167
					if (symndx != 0) { \
175
						if (!strcmp(symname, libc_alloc_syms[i])) { \
168
						const uint32_t *hasharr = &gnu_chain_zero[symndx]; \
176
							run_in_process = false; \
169
						do { \
177
							goto use_trace; \
170
							Elf##n##_Sym * s = &sym[symndx]; \
178
						} \
171
							\
172
							/* keep in sync with 'vhash' case */ \
173
							char *symname = (void *)(elf + stroff + s->st_name); \
174
							if (ELF##n##_ST_VISIBILITY(s->st_other) == STV_DEFAULT && \
175
							    s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE && \
176
							    s->st_name && \
177
							    /* Minor optimization to avoid strcmp. */ \
178
							    symname[0] == '_' && symname[1] == '_') { \
179
								/* Blacklist internal C library symbols. */ \
180
								for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
181
									if (!strcmp(symname, libc_alloc_syms[i])) { \
182
										run_in_process = false; \
183
										goto use_trace; \
184
									} \
185
							} \
186
							++symndx; \
187
						} while ((*hasharr++ & 1u) == 0); \
188
					} \
189
				} \
190
			} else { \
191
				if (vhash) { \
192
					/* Hash entries are always 32-bits. */ \
193
					uint32_t *hashes = (void *)(elf + hashoff); \
194
					symend = sym + hashes[1]; \
195
				} else \
196
					symend = (void *)(elf + stroff); \
197
				\
198
				while (sym < symend) { \
199
					/* keep insync with 'vgnuhash' case */ \
200
					char *symname = (void *)(elf + stroff + sym->st_name); \
201
					if (ELF##n##_ST_VISIBILITY(sym->st_other) == STV_DEFAULT && \
202
					    sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && \
203
					    sym->st_name && \
204
					    /* Minor optimization to avoid strcmp. */ \
205
					    symname[0] == '_' && symname[1] == '_') { \
206
						/* Blacklist internal C library symbols. */ \
207
						for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
208
							if (!strcmp(symname, libc_alloc_syms[i])) { \
209
								run_in_process = false; \
210
								goto use_trace; \
211
							} \
212
					} \
213
					++sym; \
179
				} \
214
				} \
180
				++sym; \
181
			} \
215
			} \
182
		} \
216
		} \
183
		\
217
		\
184
- 

Return to bug 672918