Mempools Core: SHM
pa_shm_create_rw()
int pa_shm_create_rw(pa_shm *m, size_t size, bool shared, mode_t mode) {
char fn[32];
int fd = -1;
pa_assert(m);
pa_assert(size > 0);
pa_assert(size <= MAX_SHM_SIZE);
pa_assert(!(mode & ~0777));
pa_assert(mode >= 0600);
/* Each time we create a new SHM area, let's first drop all stale
* ones */
pa_shm_cleanup();
/* Round up to make it page aligned */
size = PA_PAGE_ALIGN(size);
if (!shared) {
...
} else {
struct shm_marker *marker;
pa_random(&m->id, sizeof(m->id));
segment_name(fn, sizeof(fn), m->id);
if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode)) < 0) {
pa_log("shm_open() failed: %s", pa_cstrerror(errno));
goto fail;
}
m->size = size + SHM_MARKER_SIZE;
if (ftruncate(fd, (off_t) m->size) < 0) {
pa_log("ftruncate() failed: %s", pa_cstrerror(errno));
goto fail;
}
if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (off_t) 0)) == MAP_FAILED) {
pa_log("mmap() failed: %s", pa_cstrerror(errno));
goto fail;
}
/* We store our PID at the end of the shm block, so that we
* can check for dead shm segments later */
marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - SHM_MARKER_SIZE);
pa_atomic_store(&marker->pid, (int) getpid());
pa_atomic_store(&marker->marker, SHM_MARKER);
pa_assert_se(pa_close(fd) == 0);
m->do_unlink = true;
}
m->shared = shared;
return 0;
fail:
if (fd >= 0) {
shm_unlink(fn);
pa_close(fd);
}
return -1;
}
Gloab SHM files created by the server
Run daemon with PULSE_LOG=99 PULSE_LOG_BACKTRACE=99
, and inspect all the SHM files it creates globally (not per client). These global SHMs are dangerous
E: [lt-pulseaudio] shm.c: Opening shared memory with name: /pulse-shm-2208121358
(libpulsecommon-6.0.so(pa_log_levelv_meta+0x866)
[0x7fd6140af316]<<libpulsecommon-6.0.so(pa_log_level_meta+0x78)
[0x7fd6140ae758]<<libpulsecommon-6.0.so(pa_shm_create_rw+0x126)
[0x7fd6140c0086]<<libpulsecommon-6.0.so(pa_mempool_new+0x87)
[0x7fd6140b2557]<<libpulsecore-6.0.so(pa_core_new+0x2fd)
[0x7fd614e6e65d]<<lt-pulseaudio(main+0x15da)
[0x40698a]<<libc.so.6(__libc_start_main+0xf0)
[0x7fd61196f610]<<lt-pulseaudio(_start+0x29) [0x407769])
E: [lt-pulseaudio] shm.c: Opening shared memory with name: /pulse-shm-1356534770
(libpulsecommon-6.0.so(pa_log_levelv_meta+0x866)
[0x7fd6140af316]<<libpulsecommon-6.0.so(pa_log_level_meta+0x78)
[0x7fd6140ae758]<<libpulsecommon-6.0.so(pa_shm_create_rw+0x126)
[0x7fd6140c0086]<<libpulsecommon-6.0.so(pa_mempool_new+0x87)
[0x7fd6140b2557]<<libpulsecore-6.0.so(pa_core_new+0x2b5)
[0x7fd614e6e615]<<lt-pulseaudio(main+0x15da)
[0x40698a]<<libc.so.6(__libc_start_main+0xf0)
[0x7fd61196f610]<<lt-pulseaudio(_start+0x29) [0x407769])
The second one is used for recording applications.
As seen by the backtraces, these globale SHM files are created while initializing pa_core
. As stated in src/pulsecore/core.h
:
The core structure of PulseAudio. Every PulseAudio daemon contains exactly one of these. It is used for storing kind of global variables for the daemon.
And in src/pulsecore/core.c
:
pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) {
pa_core* c;
pa_mempool *pool;
int j;
pa_assert(m);
if (shared) {
if (!(pool = pa_mempool_new(shared, shm_size))) {
pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal memory pool.");
shared = false;
}
}
...
if (shared && !(c->rw_mempool = pa_mempool_new(shared, shm_size)))
pa_log_warn("Failed to allocate shared writable memory pool.");
if (c->rw_mempool)
pa_mempool_set_is_remote_writable(c->rw_mempool, true);
...
}
The rw_mempool
is created for the srbchannel support. This is evidenced by src/pulsecore/protocol-native.c
:
static void setup_srbchannel(pa_native_connection *c) {
...
if (!pa_pstream_get_shm(c->pstream)) {
pa_log_debug("Disabling srbchannel, reason: No SHM support");
return;
}
if (!c->protocol->core->rw_mempool) {
pa_log_debug("Disabling srbchannel, reason: No rw memory pool");
return;
}
...
}
Git blaming the source tree also shows that the rw_mempool
was exclusively added by the patch serious introducing srbchannel support. It was created "to keep the data and the ringbuffer separate" mempool just for the ringbuffer(s). That way, the client can open the ringbuffer shm file in rw mode and keep the data in ro mode.
References
- Launchpad bug #1224751: PulseAudio should use app-specific directory for shm files
- Shared RingBuffer patch series - [PATCH 08/12] core: Add a second rw mempool