Project

General

Profile

hidepulse.c

Source code of utility for hiding Pulseaudio libraries from any process - kspflo, 04/02/2016 01:17 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
        return strdup(info.dli_fname);
55
}
56

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

64
        if((dfd = opendir(sdir)) == NULL)
65
                err(1, "Failed to open source directory '%s'", sdir);
66

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

71
                if(lstat(sbuf, &stbuf) < 0)
72
                         err(1, "Failed to stat '%s'", sbuf);
73

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

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

92
                        //printf("creat '%s'\n", dbuf);
93
                        if((fd = creat(dbuf, stbuf.st_mode)) < 0)
94
                                err(1, "Failed to create file mount point '%s'", dbuf);
95
                        close(fd);
96
                }
97

98
                mount(sbuf, dbuf, NULL, MS_BIND, NULL);
99
        }
100
}
101

102
int main(int argc, char **argv) {
103
        int r;
104
        uid_t ruid, euid, suid;
105
        char *libdir, *newlibdir, **args;
106
        char libdir_template[] = "/tmp/hidepulse.XXXXXX";
107

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

111
        libdir = get_libdir();
112

113
        if(unshare(CLONE_NEWNS) < 0)
114
                err(1, "Failed to unshare mount namespace");
115

116
        if(mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL) < 0)
117
                err(1, "Failed to set mount propagation on /");
118

119
        newlibdir = mkdtemp(libdir_template);
120

121
        if(mount("tmpfs", newlibdir, "tmpfs", 0, NULL) < 0)
122
                err(1, "Failed to mount new libdir");
123

124
        bind_libs(libdir, newlibdir);
125

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

129
        if(mount(newlibdir, libdir, NULL, MS_MOVE, NULL) < 0)
130
                err(1, "Failed to move new libdir");
131

132
        free(libdir);
133

134
        if(rmdir(newlibdir) < 0)
135
                warn("Failed to remove new libdir");
136

137
        if(fork()) {
138
                wait(NULL);
139
                return 0;
140
        }
141

142
        getresuid(&ruid, &euid, &suid);
143
        if(seteuid(ruid) < 0)
144
                err(1, "Failed to drop privileges");
145

146
        args = malloc(sizeof(char *) * argc);
147
        if(!args)
148
                err(1, "Failed to allocate argument vector");
149

150
        for(int i = 1; i < argc; ++i)
151
                args[i - 1] = strdup(argv[i]);
152

153
        args[argc - 1] = NULL;
154

155
        warnx("Executing: '%s'", argv[1]);
156

157
        execv(argv[1], args);
158
        err(1, "Failed to exec '%s'.", argv[1]);
159
}