Project

General

Profile

hidepulse.c

[v2] Source code of utility for hiding Pulseaudio libraries from any process - kspflo, 04/02/2016 03:47 PM

 
1
/* Hide Pulseaudio libraries
2
 * Copyright (C) 2016 kspflo
3

4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17

18
// Build one-liner:
19
// sudo rm -f hidepulse; gcc -std=gnu99 -O2 -o hidepulse hidepulse.c -ldl && sudo chown root:root hidepulse; sudo chmod u+s hidepulse
20

21
#define _GNU_SOURCE
22
#include <dirent.h>
23
#include <dlfcn.h>
24
#include <err.h>
25
#include <fcntl.h>
26
#include <sched.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
#include <sys/mount.h>
32
#include <sys/stat.h>
33
#include <sys/types.h>
34
#include <sys/wait.h>
35

36
static char *get_libdir(void) {
37
        Dl_info info;
38
        void *h, *fn;
39
        char *p;
40

41
        if(!(h = dlopen("libpulse.so", RTLD_LAZY)))
42
                errx(1, "Failed to resolve libpulse.so");
43

44

45
        if(!(fn = dlsym(h, "pa_stream_new")))
46
                errx(1, "Failed to resolve symbol pa_stream_new");
47

48
        if(!dladdr(fn, &info))
49
                errx(1, "Failed to retrieve symbol info");
50

51
        if((p = strrchr(info.dli_fname, '/')))
52
                *p = '\0';
53

54
        dlclose(h);
55

56
        return strdup(info.dli_fname);
57
}
58

59
static void bind_libs(char *sdir, char *ddir) {
60
        int fd;
61
        ssize_t len;
62
        char sbuf[4096], dbuf[4096];
63
        DIR *dfd;
64
        struct dirent *dp;
65
        struct stat stbuf;
66

67
        if((dfd = opendir(sdir)) == NULL)
68
                err(1, "Failed to open source directory '%s'", sdir);
69

70
        while((dp = readdir(dfd)) != NULL) {
71
                snprintf(sbuf, sizeof(sbuf), "%s/%s", sdir, dp->d_name);
72
                snprintf(dbuf, sizeof(dbuf), "%s/%s", ddir, dp->d_name);
73

74
                if(lstat(sbuf, &stbuf) < 0)
75
                         err(1, "Failed to stat '%s'", sbuf);
76

77
                if(S_ISDIR(stbuf.st_mode)) {
78
                        if(strcmp(dp->d_name, "pulseaudio") == 0) {
79
                                warnx("Omitting directory '%s'", dp->d_name);
80
                                continue;
81
                        }
82
                        else if(strcmp(dp->d_name, ".") == 0 ||strcmp(dp->d_name, "..") == 0)
83
                                continue;
84

85
                        //printf("mkdir '%s'\n", dbuf);
86
                        if(mkdir(dbuf, stbuf.st_mode) < 0)
87
                                err(1, "Failed to create directory mount point '%s'", dbuf);
88
                }
89
                else if(S_ISLNK(stbuf.st_mode)) {
90
                        if(strstr(dp->d_name, "pulse")) {
91
                                warnx("Omitting symlink '%s'", dp->d_name);
92
                                continue;
93
                        }
94

95
                        if((len = readlink(sbuf, sbuf, sizeof(sbuf) - 1)) < 0)
96
                                err(1, "Failed to read symlink '%s'", sbuf);
97

98
                        sbuf[len] = '\0';
99

100
                        //printf("symlink '%s' -> '%s'\n", dbuf, sbuf);
101
                        if(symlink(sbuf, dbuf) < 0)
102
                                err(1, "Failed to create symlink '%s'", dbuf);
103
                }
104
                else if(S_ISREG(stbuf.st_mode)) {
105
                        if(strstr(dp->d_name, "pulse")) {
106
                                warnx("Omitting file '%s'", dp->d_name);
107
                                continue;
108
                        }
109

110
                        //printf("creat '%s'\n", dbuf);
111
                        if((fd = creat(dbuf, stbuf.st_mode)) < 0)
112
                                err(1, "Failed to create file mount point '%s'", dbuf);
113
                        close(fd);
114
                }
115
                else {
116
                        warnx("Ignoring file '%s'", dp->d_name);
117
                        continue;
118
                }
119

120
                mount(sbuf, dbuf, NULL, MS_BIND, NULL);
121
        }
122
}
123

124
int main(int argc, char **argv) {
125
        int r;
126
        uid_t ruid, euid, suid;
127
        char *libdir, *newlibdir, **args;
128
        char libdir_template[] = "/tmp/hidepulse.XXXXXX";
129

130
        if(argc < 2)
131
                errx(1, "Usage: %s <program> [<arg1> ... <argN>]", argv[0]);
132

133
        libdir = get_libdir();
134

135
        if(unshare(CLONE_NEWNS) < 0)
136
                err(1, "Failed to unshare mount namespace");
137

138
        if(mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL) < 0)
139
                err(1, "Failed to set mount propagation on /");
140

141
        newlibdir = mkdtemp(libdir_template);
142

143
        if(mount("tmpfs", newlibdir, "tmpfs", 0, NULL) < 0)
144
                err(1, "Failed to mount new libdir");
145

146
        bind_libs(libdir, newlibdir);
147

148
        if(mount(newlibdir, newlibdir, NULL, MS_REMOUNT | MS_RDONLY, NULL) < 0)
149
                err(1, "Failed to re-mount new libdir read-only");
150

151
        if(mount(newlibdir, libdir, NULL, MS_MOVE, NULL) < 0)
152
                err(1, "Failed to move new libdir");
153

154
        free(libdir);
155

156
        if(rmdir(newlibdir) < 0)
157
                warn("Failed to remove new libdir");
158

159
        if(fork()) {
160
                wait(NULL);
161
                return 0;
162
        }
163

164
        getresuid(&ruid, &euid, &suid);
165
        if(seteuid(ruid) < 0)
166
                err(1, "Failed to drop privileges");
167

168
        args = malloc(sizeof(char *) * argc);
169
        if(!args)
170
                err(1, "Failed to allocate argument vector");
171

172
        for(int i = 1; i < argc; ++i)
173
                args[i - 1] = strdup(argv[i]);
174

175
        args[argc - 1] = NULL;
176

177
        warnx("Executing: '%s'", argv[1]);
178

179
        execv(argv[1], args);
180
        err(1, "Failed to exec '%s'.", argv[1]);
181
}