# compositor.c -rw-r--r-- 1.5 KiB View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#define _GNU_SOURCE // for ucred
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>

void print_exe_path(pid_t pid) {
	char link_path[512];
	snprintf(link_path, sizeof(link_path), "/proc/%d/exe", pid);

	char exe_path[512];
	ssize_t exe_path_len = readlink(link_path, exe_path, sizeof(exe_path) - 1);
	if (exe_path_len < 0) {
		perror("readlink");
		return;
	}
	exe_path[exe_path_len] = '\0';

	printf("%d: path=%s\n", pid, exe_path);
}

int main(int argc, char *argv[]) {
	int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sfd < 0) {
		perror("socket");
		return 1;
	}

	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
		.sun_path = "socket",
	};
	if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("bind");
		return 1;
	}

	if (listen(sfd, 32) < 0) {
		perror("listen");
		return 1;
	}

	while (1) {
		int cfd = accept(sfd, NULL, NULL);
		if (cfd < 0) {
			perror("accept");
			return 1;
		}

		printf("client connected\n");

		struct ucred peer_ucred;
		socklen_t ucred_size = sizeof(struct ucred);
		if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_ucred, &ucred_size) < 0) {
			perror("getsockopt(SO_PEERCRED)");
			goto next;
		}
		printf("SO_PEERCRED: pid=%d\n", peer_ucred.pid);

		int data;
		ssize_t n = read(cfd, &data, sizeof(data));
		if (n < 0) {
			perror("read");
			goto next;
		} else if (n == 0) {
			fprintf(stderr, "read returned 0\n");
			goto next;
		}

		print_exe_path(peer_ucred.pid);

next:
		close(cfd);
	}

	return 0;
}
# client.c -rw-r--r-- 535 bytes View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fd < 0) {
		perror("socket");
		return 1;
	}

	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
		.sun_path = "socket",
	};
	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("connect");
		return 1;
	}

	int data = 42;
	if (write(fd, &data, sizeof(data)) < 0) {
		perror("write");
		return 1;
	}

	read(fd, &data, sizeof(data));

	return 0;
}
# malicious-client.c -rw-r--r-- 835 bytes View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

int main(int argc, char *argv[]) {
	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fd < 0) {
		perror("socket");
		return 1;
	}

	pid_t conn_pid = fork();
	if (conn_pid < 0) {
		perror("fork");
		return 1;
	} else if (conn_pid == 0) {
		// On Linux, SO_PEERCRED is stashed on connect
		struct sockaddr_un addr = {
			.sun_family = AF_UNIX,
			.sun_path = "socket",
		};
		if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
			perror("connect");
			_exit(1);
		}

		execl("./client", NULL);
		perror("exec");
		_exit(1);
	}

	sleep(1);
	printf("connected with PID %d\n", conn_pid);

	int data = 42;
	write(fd, &data, sizeof(data));

	read(fd, &data, sizeof(data));

	return 0;
}