Skip to content

Commit 10b63eb

Browse files
committed
Initial commit.
0 parents  commit 10b63eb

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.so

Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
LIBS = -ldl
2+
CFLAGS =
3+
4+
CFLAGS += -DDEBUG
5+
6+
libenviable.so: enviable.c
7+
$(CC) $(CFLAGS) -fPIC -shared -o $@ $< $(LIBS)
8+
9+
clean:
10+
rm -f libenviable.so
11+
12+
.PHONY: clean

enviable.c

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* enviable - An LD_PRELOAD to set environment variables at runtime.
2+
* Usage: LD_PRELOAD=./libenviable.so bash
3+
*
4+
*
5+
* Copyright (c) 2013 Geoffrey Thomas <[email protected]>
6+
* All rights reserved.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
* 1. Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in the
15+
* documentation and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27+
* SUCH DAMAGE.
28+
*/
29+
30+
#define _GNU_SOURCE
31+
#include <sys/inotify.h>
32+
#include <dlfcn.h>
33+
#include <fcntl.h>
34+
#include <signal.h>
35+
#include <stdlib.h>
36+
#include <string.h>
37+
#include <unistd.h>
38+
39+
#ifdef DEBUG
40+
#include <stdio.h>
41+
#define maybe_perror(s) perror(s)
42+
#else
43+
#define maybe_perror(s)
44+
#endif
45+
46+
static int (*real___libc_current_sigrtmin)(void) = NULL;
47+
48+
static char *watchfile = "/tmp/vars";
49+
50+
int
51+
__libc_current_sigrtmin(void)
52+
{
53+
return real___libc_current_sigrtmin() + 1;
54+
}
55+
56+
static void
57+
enviable_callback(int signum, siginfo_t *si, void *context)
58+
{
59+
struct inotify_event event;
60+
if (read(si->si_fd, &event, sizeof(event)) != sizeof(event))
61+
return;
62+
63+
FILE *fd = fopen(watchfile, "r");
64+
if (!fd) {
65+
return;
66+
}
67+
char *buf = NULL;
68+
size_t n = 0;
69+
ssize_t len;
70+
while ((len = getline(&buf, &n, fd)) > 0) {
71+
if (buf[len - 1] == '\n') {
72+
buf[len - 1] = '\0';
73+
} else {
74+
/* Conservatively reject partial lines. */
75+
continue;
76+
}
77+
char *eq = strchr(buf, '=');
78+
*eq = '\0';
79+
setenv(buf, eq + 1, 1);
80+
}
81+
free(buf);
82+
fclose(fd);
83+
}
84+
85+
void __attribute__((constructor))
86+
enviable_init(void)
87+
{
88+
real___libc_current_sigrtmin = dlsym(RTLD_NEXT, "__libc_current_sigrtmin");
89+
if (!real___libc_current_sigrtmin) {
90+
/* Give up; we can't safely claim a signal. */
91+
maybe_perror("enviable: incompatible libc");
92+
return;
93+
}
94+
95+
int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
96+
if (fd == -1) {
97+
maybe_perror("enviable: inotify_init");
98+
return;
99+
}
100+
101+
int watch = inotify_add_watch(fd, watchfile, IN_CLOSE_WRITE);
102+
if (watch == -1) {
103+
maybe_perror("enviable: inotify_add_watch");
104+
goto err;
105+
}
106+
107+
int sigrtmin = real___libc_current_sigrtmin();
108+
109+
struct sigaction act = {
110+
.sa_sigaction = enviable_callback,
111+
.sa_mask = 0,
112+
.sa_flags = SA_SIGINFO,
113+
}, oldact;
114+
115+
if (sigaction(sigrtmin, &act, &oldact) == -1) {
116+
maybe_perror("enviable: sigaction");
117+
goto err;
118+
}
119+
120+
if ((oldact.sa_flags & SA_SIGINFO) ||
121+
(oldact.sa_handler != SIG_DFL)) {
122+
/* Oops. Someone else already claimed a handler! */
123+
goto err_sig;
124+
}
125+
126+
int flags = fcntl(fd, F_GETFL);
127+
if (flags == -1) {
128+
maybe_perror("enviable: fcntl F_GETFL");
129+
goto err_sig;
130+
}
131+
if (fcntl(fd, F_SETFL, flags | O_ASYNC) == -1) {
132+
maybe_perror("enviable: fcntl F_SETFL O_ASYNC");
133+
goto err_sig;
134+
}
135+
if (fcntl(fd, F_SETOWN, getpid()) == -1) {
136+
maybe_perror("enviable: fcntl F_SETOWN");
137+
goto err_sig;
138+
}
139+
if (fcntl(fd, F_SETSIG, sigrtmin) == -1) {
140+
maybe_perror("enviable: fcntl F_SETSIG");
141+
goto err_sig;
142+
}
143+
144+
return;
145+
err_sig:
146+
sigaction(sigrtmin, &oldact, NULL);
147+
err:
148+
close(fd);
149+
}

0 commit comments

Comments
 (0)