Commit | Line | Data |
---|---|---|
0fdd1e2c DG |
1 | /* |
2 | * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca> | |
3 | * Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
4 | * | |
d14d33bf AM |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License, version 2 only, | |
7 | * as published by the Free Software Foundation. | |
0fdd1e2c | 8 | * |
d14d33bf AM |
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. | |
0fdd1e2c | 13 | * |
d14d33bf AM |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
0fdd1e2c DG |
17 | */ |
18 | ||
19 | #define _GNU_SOURCE | |
6c1c0768 | 20 | #define _LGPL_SOURCE |
0fdd1e2c DG |
21 | #include <fcntl.h> |
22 | #include <limits.h> | |
23 | #include <sys/mman.h> | |
24 | #include <sys/stat.h> | |
25 | #include <sys/types.h> | |
26 | #include <sys/wait.h> | |
27 | #include <unistd.h> | |
28 | #include <urcu.h> | |
29 | ||
db758600 | 30 | #include <common/error.h> |
0fdd1e2c DG |
31 | |
32 | #include "shm.h" | |
33 | ||
34 | /* | |
35 | * Using fork to set umask in the child process (not multi-thread safe). We | |
36 | * deal with the shm_open vs ftruncate race (happening when the sessiond owns | |
37 | * the shm and does not let everybody modify it, to ensure safety against | |
38 | * shm_unlink) by simply letting the mmap fail and retrying after a few | |
39 | * seconds. For global shm, everybody has rw access to it until the sessiond | |
40 | * starts. | |
41 | */ | |
42 | static int get_wait_shm(char *shm_path, size_t mmap_size, int global) | |
43 | { | |
44 | int wait_shm_fd, ret; | |
0fdd1e2c DG |
45 | mode_t mode; |
46 | ||
0525e9ae DG |
47 | assert(shm_path); |
48 | ||
0fdd1e2c DG |
49 | /* Default permissions */ |
50 | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; | |
51 | ||
7972d619 DG |
52 | /* |
53 | * Change owner of the shm path. | |
54 | */ | |
0fdd1e2c | 55 | if (global) { |
0fdd1e2c | 56 | /* |
7972d619 DG |
57 | * If global session daemon, any application can |
58 | * register. Make it initially writeable so applications | |
59 | * registering concurrently can do ftruncate() by | |
60 | * themselves. | |
0fdd1e2c | 61 | */ |
7972d619 | 62 | mode |= S_IROTH | S_IWOTH; |
0fdd1e2c DG |
63 | } |
64 | ||
65 | /* | |
7d051034 DG |
66 | * We're alone in a child process, so we can modify the process-wide |
67 | * umask. | |
0fdd1e2c | 68 | */ |
7d051034 | 69 | umask(~mode); |
0fdd1e2c | 70 | |
7d051034 DG |
71 | /* |
72 | * Try creating shm (or get rw access). We don't do an exclusive open, | |
73 | * because we allow other processes to create+ftruncate it concurrently. | |
74 | */ | |
75 | wait_shm_fd = shm_open(shm_path, O_RDWR | O_CREAT, mode); | |
76 | if (wait_shm_fd < 0) { | |
df0f840b | 77 | PERROR("shm_open wait shm"); |
7d051034 DG |
78 | goto error; |
79 | } | |
0fdd1e2c | 80 | |
7d051034 DG |
81 | ret = ftruncate(wait_shm_fd, mmap_size); |
82 | if (ret < 0) { | |
df0f840b | 83 | PERROR("ftruncate wait shm"); |
7d051034 DG |
84 | exit(EXIT_FAILURE); |
85 | } | |
0fdd1e2c | 86 | |
409a0c56 | 87 | #ifndef __FreeBSD__ |
7972d619 DG |
88 | if (global) { |
89 | ret = fchown(wait_shm_fd, 0, 0); | |
90 | if (ret < 0) { | |
91 | PERROR("fchown"); | |
92 | exit(EXIT_FAILURE); | |
93 | } | |
94 | /* | |
95 | * If global session daemon, any application can | |
96 | * register so the shm needs to be set in read-only mode | |
97 | * for others. | |
98 | */ | |
99 | mode &= ~S_IWOTH; | |
100 | ret = fchmod(wait_shm_fd, mode); | |
101 | if (ret < 0) { | |
102 | PERROR("fchmod"); | |
103 | exit(EXIT_FAILURE); | |
104 | } | |
105 | } else { | |
106 | ret = fchown(wait_shm_fd, getuid(), getgid()); | |
107 | if (ret < 0) { | |
108 | PERROR("fchown"); | |
109 | exit(EXIT_FAILURE); | |
110 | } | |
0fdd1e2c | 111 | } |
409a0c56 | 112 | #else |
7972d619 | 113 | #warning "FreeBSD does not support setting file mode on shm FD." |
409a0c56 | 114 | #endif |
0fdd1e2c | 115 | |
0fdd1e2c DG |
116 | DBG("Got the wait shm fd %d", wait_shm_fd); |
117 | ||
118 | return wait_shm_fd; | |
119 | ||
120 | error: | |
121 | DBG("Failing to get the wait shm fd"); | |
122 | ||
123 | return -1; | |
124 | } | |
125 | ||
126 | /* | |
127 | * Return the wait shm mmap for UST application notification. The global | |
128 | * variable is used to indicate if the the session daemon is global | |
129 | * (root:tracing) or running with an unprivileged user. | |
130 | * | |
131 | * This returned value is used by futex_wait_update() in futex.c to WAKE all | |
132 | * waiters which are UST application waiting for a session daemon. | |
133 | */ | |
134 | char *shm_ust_get_mmap(char *shm_path, int global) | |
135 | { | |
6c699394 | 136 | size_t mmap_size; |
0fdd1e2c DG |
137 | int wait_shm_fd, ret; |
138 | char *wait_shm_mmap; | |
6c699394 | 139 | long sys_page_size; |
0fdd1e2c | 140 | |
0525e9ae DG |
141 | assert(shm_path); |
142 | ||
6c699394 DG |
143 | sys_page_size = sysconf(_SC_PAGE_SIZE); |
144 | if (sys_page_size < 0) { | |
145 | PERROR("sysconf PAGE_SIZE"); | |
146 | goto error; | |
147 | } | |
148 | mmap_size = sys_page_size; | |
149 | ||
0fdd1e2c DG |
150 | wait_shm_fd = get_wait_shm(shm_path, mmap_size, global); |
151 | if (wait_shm_fd < 0) { | |
152 | goto error; | |
153 | } | |
154 | ||
155 | wait_shm_mmap = mmap(NULL, mmap_size, PROT_WRITE | PROT_READ, | |
156 | MAP_SHARED, wait_shm_fd, 0); | |
7d051034 | 157 | |
0fdd1e2c DG |
158 | /* close shm fd immediately after taking the mmap reference */ |
159 | ret = close(wait_shm_fd); | |
160 | if (ret) { | |
df0f840b | 161 | PERROR("Error closing fd"); |
0fdd1e2c DG |
162 | } |
163 | ||
164 | if (wait_shm_mmap == MAP_FAILED) { | |
165 | DBG("mmap error (can be caused by race with ust)."); | |
166 | goto error; | |
167 | } | |
168 | ||
169 | return wait_shm_mmap; | |
170 | ||
171 | error: | |
172 | return NULL; | |
173 | } |