Project

General

Profile

pulsenomore.c

Source code of utility for hot-removal of "libpulse-simple.so.0" reference from executable - kspflo, 04/03/2016 10:49 AM

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

19
// Build using: gcc -std=gnu99 -O2 -o pulsenomore pulsenomore.c -ldl
20

21
#define _GNU_SOURCE
22
#include <dlfcn.h>
23
#include <err.h>
24
#include <fcntl.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <linux/memfd.h>
29
#include <sys/mman.h>
30
#include <sys/sendfile.h>
31
#include <sys/syscall.h>
32
#include <sys/types.h>
33
#include <sys/stat.h>
34
#include <unistd.h>
35

36
#define LIBPULSE_SIMPLE                "libpulse-simple.so.0"
37

38
#ifdef __NR_memfd_create
39
static inline int memfd_create(const char *name, unsigned int flags) {
40
        return syscall(__NR_memfd_create, name, flags);
41
}
42
#else
43
#error "memfd_create syscall missing!"
44
#endif
45

46
static int check_pulseaudio_running(void) {
47
        void *h;
48
        pid_t pid;
49
        int (*pa_pid_file_check_running)(pid_t *, const char *), running;
50

51
        if(!(h = dlopen(LIBPULSE_SIMPLE, RTLD_LAZY))) {
52
                warnx("Failed to resolve " LIBPULSE_SIMPLE);
53

54
                return 0;
55
        }
56

57
        if(!(pa_pid_file_check_running = dlsym(h, "pa_pid_file_check_running")))
58
                errx(1, "Failed to resolve symbol pa_pid_file_check_running");
59

60
        running = (pa_pid_file_check_running(&pid, "pulseaudio") < 0) ? 0 : 1;
61

62
        dlclose(h);
63

64
        return running;
65
}
66

67
int main(int argc, char **argv) {
68
        int fd, mfd;
69
        char **args, *mem, *p;
70
        ssize_t s;
71
        struct stat stbuf;
72

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

76
        args = malloc(sizeof(char *) * argc);
77
        if(!args)
78
                err(1, "Failed to allocate argument vector");
79

80
        for(int i = 1; i < argc; ++i)
81
                args[i - 1] = strdup(argv[i]);
82

83
        args[argc - 1] = NULL;
84

85
        if(check_pulseaudio_running()) {
86
                warnx("Pulseaudio is running");
87

88
                execv(argv[1], args);
89
                err(1, "Failed to exec '%s'", argv[1]);
90
        }
91
        else {
92
                warnx("Pulseaudio is NOT running");
93

94
                if((fd = open(argv[1], O_RDONLY | O_CLOEXEC)) < 0)
95
                        err(1, "Failed to open executable '%s'", argv[1]);
96

97
                if(fstat(fd, &stbuf) < 0)
98
                        err(1, "Failed to stat executable");
99

100
                if((mfd = memfd_create(argv[1], MFD_CLOEXEC)) < 0)
101
                        err(1, "Failed to create memfd");
102

103
                if(ftruncate(mfd, stbuf.st_size) < 0)
104
                        err(1, "Failed to truncate memfd");
105

106
                if((p = mem = mmap(NULL, stbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0)) == MAP_FAILED)
107
                        err(1, "Failed to mmap memfd");
108

109
                while((s = read(fd, p, 64 * 1024 * 1024)) > 0)
110
                        p += s;
111

112
                if(s < 0)
113
                        err(1, "Failed to load executable into memory");
114

115
                if((p = memmem(mem, stbuf.st_size, LIBPULSE_SIMPLE, strlen(LIBPULSE_SIMPLE))) != NULL) {
116
                        strcpy(p, "/dev/null");
117
                        p += strlen("/dev/null") + 1;
118
                        while(*p)
119
                                *p++ = '\0';
120

121
                        warnx(LIBPULSE_SIMPLE " reference replaced");
122
                }
123
                else
124
                        warnx(LIBPULSE_SIMPLE " reference not found");
125

126
                munmap(mem, stbuf.st_size);
127

128
                fexecve(mfd, args, environ);
129
                err(1, "Failed to exec '%s'", argv[1]);
130
        }
131
}