]> git.alsa-project.org Git - alsa-lib.git/commitdiff
aserver: add 'gid' config item to set IPC SHM group ID HEAD master
authorJaroslav Kysela <perex@perex.cz>
Wed, 29 Jul 2026 09:19:01 +0000 (11:19 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 29 Jul 2026 09:53:45 +0000 (11:53 +0200)
The default permissions 0666 are too open. Change default permissions
to 0660 and allow specifying a GID in the server configuration.

The group can be specified as a numeric GID or a group name via a
'gid' item in the server's config block, falling back to the 'audio'
group when not specified.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
aserver/aserver.c

index 1ef6ef5677f3d73bde99c28120802ea759e0413f..499c422d8432bd31d8fd96a93149d2b398966b2d 100644 (file)
 #include <netdb.h>
 #include <limits.h>
 #include <signal.h>
+#include <grp.h>
+#include <ctype.h>
 
 
-char *command;
+static char *command;
+static gid_t shm_gid = (gid_t)-1;
+
+static int shm_set_gid(int shmid)
+{
+       struct shmid_ds ds;
+       if (shmctl(shmid, IPC_STAT, &ds) < 0)
+               return -errno;
+       ds.shm_perm.gid = shm_gid;
+       ds.shm_perm.mode = 0660;
+       if (shmctl(shmid, IPC_SET, &ds) < 0)
+               return -errno;
+       return 0;
+}
+
+/* parse a numeric gid or a group name into *result */
+static int parse_gid(const char *str, gid_t *result)
+{
+       char *endp;
+
+       if (isdigit((unsigned char)*str)) {
+               long gid = strtol(str, &endp, 10);
+               if (*endp != '\0')
+                       return -EINVAL;
+               *result = (gid_t)gid;
+       } else {
+               struct group *grp = getgrnam(str);
+               if (!grp)
+                       return -EINVAL;
+               *result = grp->gr_gid;
+       }
+       return 0;
+}
 
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
 #define ERROR(...) do {\
@@ -296,12 +330,18 @@ static int pcm_shm_open(client_t *client, int *cookie)
        pcm->appl.private_data = client;
        pcm->appl.changed = pcm_shm_appl_ptr_changed;
 
-       shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
+       shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0660);
        if (shmid < 0) {
                result = -errno;
                SYSERROR("shmget failed");
                goto _err;
        }
+       result = shm_set_gid(shmid);
+       if (result < 0) {
+               SYSERROR("shmctl IPC_SET failed");
+               shmctl(shmid, IPC_RMID, 0);
+               goto _err;
+       }
        client->transport.shm.ctrl_id = shmid;
        client->transport.shm.ctrl = shmat(shmid, 0, 0);
        if (client->transport.shm.ctrl == (void*) -1) {
@@ -559,12 +599,18 @@ static int ctl_shm_open(client_t *client, int *cookie)
        client->device.ctl.handle = ctl;
        client->device.ctl.fd = _snd_ctl_poll_descriptor(ctl);
 
-       shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
+       shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0660);
        if (shmid < 0) {
                result = -errno;
                SYSERROR("shmget failed");
                goto _err;
        }
+       result = shm_set_gid(shmid);
+       if (result < 0) {
+               SYSERROR("shmctl IPC_SET failed");
+               shmctl(shmid, IPC_RMID, 0);
+               goto _err;
+       }
        client->transport.shm.ctrl_id = shmid;
        client->transport.shm.ctrl = shmat(shmid, 0, 0);
        if (!client->transport.shm.ctrl) {
@@ -1018,7 +1064,7 @@ static void usage(void)
 {
        fprintf(stderr,
                "Usage: %s [OPTIONS] server\n"
-               "--help                 help\n",
+               "--help/-h              help\n",
                command);
 }
 
@@ -1091,6 +1137,21 @@ int main(int argc, char **argv)
                        }
                        continue;
                }
+               if (strcmp(id, "gid") == 0) {
+                       char *group;
+                       err = snd_config_get_ascii(n, &group);
+                       if (err < 0) {
+                               ERROR("Invalid type for %s", id);
+                               return 1;
+                       }
+                       if (*group && parse_gid(group, &shm_gid) < 0) {
+                               ERROR("unknown group: %s", group);
+                               free(group);
+                               return 1;
+                       }
+                       free(group);
+                       continue;
+               }
                ERROR("Unknown field %s", id);
                return 1;
        }
@@ -1098,6 +1159,14 @@ int main(int argc, char **argv)
                ERROR("either socket or port need to be defined");
                return 1;
        }
+       if (shm_gid == (gid_t)-1) {
+               struct group *grp = getgrnam("audio");
+               if (!grp) {
+                       ERROR("'audio' group not found; use the 'gid' config item to specify a group");
+                       return 1;
+               }
+               shm_gid = grp->gr_gid;
+       }
        server(sockname, port);
        return 0;
 }