Alexandre Ratchov wrote:

> Initially aucat was designed to handle one device only so multiple
> audio devices used to be supported simply by starting multiple aucat
> processes (one per device), very simple. Then (~1.5 years ago) we
> added support for multiple audio devices (ie multiple -f options), and
> now it's time to finish the job and add a "device number" component in
> sndio(7) device names. Since this partially breaks compatibility, this
> is a opportunitiy to fix few other design mistakes (eg ':' being used
> by inet6, type name vs api name confusion, etc..). This leads to the
> following names:
> 
> type[@hostname][,unit]/devnum[.option]
> 

Hi Alexandre,

The highlighted code at the bottom of this mail contains comparisons like
this: strncmp("snd", str, len) == 0

This makes it possible to do things like:
$ aucat -fsnds/0 -i${HOME}/them.wav 
snd0: snds/0: failed to open audio device => Ok, this should fail
$ aucat -fsn/0 -i${HOME}/them.wav => Not Ok ???, this plays the music

The second call doesn't fail because if len is smaller then strlen("snd")
than it potentially matches a partial "snd", allowing device types like "s"
and "sn" (in the case of type "snd"). I suppose this is not what you
intended.

I tend to do comparisons like this as follows,
strncmp(str, "snd", sizeof("snd")) == 0,
using the NUL character in "snd" as a sort of boundary check.
I'm not 100% sure though that this is always safe when strlen(str) <
sizeof("snd").

Maybe the safest option is to check if len == strlen("snd") before making
the comparison. This mail includes a PoC patch using this method.

After applying the patch aucat should behave like this:
$ aucat -fsnds/0 -i${HOME}/them.wav 
snd0: snds/0: failed to open audio device
$ aucat -fsnd/0 -i${HOME}/them.wav => Ok, playing music
$ aucat -fsn/0 -i${HOME}/them.wav  
snd0: sn/0: failed to open audio device
$ aucat -fs/0 -i${HOME}/them.wav  
snd0: s/0: failed to open audio device
$ aucat -f/0 -i${HOME}/them.wav  
snd0: /0: failed to open audio device
$ aucat -f0 -i${HOME}/them.wav  
snd0: 0: failed to open audio device

Though I patched mio.c I didn't actually test midicat.
For this proof-of-concept I only tested aucat with device types snd and
rsnd, which seem to work for me.

Some other more or less random weirdness I found is that I can specify either 
sun, sun: or sun:0 for the device and all three of them will play sound.
I'd expect only sun:0 to work. Device aucat hasn't got this problem. I haven't 
tracked this down but I suspect some additional checking is going on outside 
the sio_open function.

P.S.:
I added a comparison function sio_is_type. But I didn't know how to share it 
properly between sio.c and mio.c so my solution might look a bit quick and 
dirty. (especially the extern sio_is_type declaration in mio.c)

> 
> Index: lib/libsndio/mio.c
> ===================================================================
> RCS file: /cvs/src/lib/libsndio/mio.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 mio.c
> --- lib/libsndio/mio.c        17 Oct 2011 21:09:11 -0000      1.12
> +++ lib/libsndio/mio.c        8 Nov 2011 19:18:19 -0000
> @@ -49,26 +46,23 @@ mio_open(const char *str, unsigned mode,
>  if (str == NULL && !issetugid())
>  str = getenv("MIDIDEVICE");
>  if (str == NULL) {
> -             hdl = mio_aucat_open("0", mode, nbio);
> +             hdl = mio_aucat_open("/0", mode, nbio, 1);
>  if (hdl != NULL)
>  return hdl;
> -             return mio_rmidi_open("0", mode, nbio);
> +             return mio_rmidi_open("/0", mode, nbio);
>  }
> -     sep = strchr(str, ':');
> -     if (sep == NULL) {
> -             DPRINTF("mio_open: %s: ':' missing in device name\n", str);
> -             return NULL;
> +     for (len = 0; (c = str[len]) != '\0'; len++) {
> +             /* XXX: remove ':' compat bits */
> +             if (c == ':' || c == '@' || c == '/' || c == ',')
> +                     break;
>  }
> -     len = sep - str;
> -     if (len == (sizeof(prefix_midithru) - 1) &&
> -         memcmp(str, prefix_midithru, len) == 0)
> -             return mio_aucat_open(sep + 1, mode, nbio);
> -     if (len == (sizeof(prefix_aucat) - 1) &&
> -         memcmp(str, prefix_aucat, len) == 0)
> -             return mio_aucat_open(sep + 1, mode, nbio);
> -     if (len == (sizeof(prefix_rmidi) - 1) &&
> -         memcmp(str, prefix_rmidi, len) == 0)
> -             return mio_rmidi_open(sep + 1, mode, nbio);
> +     if (strncmp("snd", str, len) == 0 ||
> +         strncmp("aucat", str, len) == 0)
> +             return mio_aucat_open(str + len, mode, nbio, 0);
> +     if (strncmp("midithru", str, len) == 0)
> +             return mio_aucat_open(str + len, mode, nbio, 1);
> +     if (strncmp("rmidi", str, len) == 0)
> +             return mio_rmidi_open(str + len, mode, nbio);
>  DPRINTF("mio_open: %s: unknown device type\n", str);
>  return NULL;
>  }
> Index: lib/libsndio/sio.c
> ===================================================================
> RCS file: /cvs/src/lib/libsndio/sio.c,v
> retrieving revision 1.6
> diff -u -p -r1.6 sio.c
> --- lib/libsndio/sio.c        9 May 2011 17:34:14 -0000       1.6
> +++ lib/libsndio/sio.c        8 Nov 2011 19:18:20 -0000
> @@ -67,22 +55,22 @@ sio_open(const char *str, unsigned mode,
>  if (str == NULL && !issetugid())
>  str = getenv("AUDIODEVICE");
>  if (str == NULL) {
> -             for (b = backends; b->prefix != NULL; b++) {
> -                     hdl = b->open(NULL, mode, nbio);
> -                     if (hdl != NULL)
> -                             return hdl;
> -             }
> -             return NULL;
> +             hdl = sio_aucat_open("/0", mode, nbio);
> +             if (hdl != NULL)
> +                     return hdl;
> +             return sio_sun_open("", mode, nbio);
>  }
> -     sep = strchr(str, ':');
> -     if (sep == NULL) {
> -             DPRINTF("sio_open: %s: ':' missing in device name\n", str);
> -             return NULL;
> +     for (len = 0; (c = str[len]) != '\0'; len++) {
> +             /* XXX: remove ':' compat bits */
> +             if (c == ':' || c == '@' || c == '/' || c == ',')
> +                     break;
>  }
> -     len = sep - str;
> -     for (b = backends; b->prefix != NULL; b++) {
> -             if (strlen(b->prefix) == len && memcmp(b->prefix, str, len) == 
> 0)
> -                     return b->open(sep + 1, mode, nbio);
> +     if (strncmp("snd", str, len) == 0 ||
> +         strncmp("aucat", str, len) == 0)
> +             return sio_aucat_open(str + len, mode, nbio);
> +     if (strncmp("rsnd", str, len) == 0 ||
> +         strncmp("sun", str, len) == 0) {
> +             return sio_sun_open(str + len, mode, nbio);
>  }
>  DPRINTF("sio_open: %s: unknown device type\n", str);
>  return NULL;



--- sio.c       Wed Nov  9 14:21:24 2011
+++ sio.c.new   Wed Nov  9 14:09:44 2011
@@ -40,6 +40,17 @@
        par->__magic = SIO_PAR_MAGIC;
 }
 
+
+int
+sio_is_type(const char *str, size_t nstr, const char *type)
+{
+       if (nstr != strlen(type))
+               return (0);
+
+       return (strncmp(str, type, nstr) == 0);
+}
+
+
 struct sio_hdl *
 sio_open(const char *str, unsigned mode, int nbio)
 {
@@ -65,13 +76,12 @@
                if (c == ':' || c == '@' || c == '/' || c == ',')
                        break;
        }
-       if (strncmp("snd", str, len) == 0 ||
-           strncmp("aucat", str, len) == 0)
+       if (sio_is_type(str, len, "snd") ||
+           sio_is_type(str, len, "aucat"))
                return sio_aucat_open(str + len, mode, nbio);
-       if (strncmp("rsnd", str, len) == 0 ||
-           strncmp("sun", str, len) == 0) {
+       if (sio_is_type(str, len, "rsnd") ||
+           sio_is_type(str, len, "sun"))
                return sio_sun_open(str + len, mode, nbio);
-       }
        DPRINTF("sio_open: %s: unknown device type\n", str);
        return NULL;
 }
--- mio.c       Wed Nov  9 14:21:24 2011
+++ mio.c.new   Wed Nov  9 14:24:25 2011
@@ -31,6 +31,8 @@
 #include "debug.h"
 #include "mio_priv.h"
 
+extern int sio_is_type(const char *, size_t, const char *);
+
 struct mio_hdl *
 mio_open(const char *str, unsigned mode, int nbio)
 {
@@ -56,12 +58,12 @@
                if (c == ':' || c == '@' || c == '/' || c == ',')
                        break;
        }
-       if (strncmp("snd", str, len) == 0 ||
-           strncmp("aucat", str, len) == 0)
+       if (sio_is_type(str, len, "snd") ||
+           sio_is_type(str, len, "aucat"))
                return mio_aucat_open(str + len, mode, nbio, 0);
-       if (strncmp("midithru", str, len) == 0)
+       if (sio_is_type(str, len, "midithru"))
                return mio_aucat_open(str + len, mode, nbio, 1);
-       if (strncmp("rmidi", str, len) == 0)
+       if (sio_is_type(str, len, "rmidi"))
                return mio_rmidi_open(str + len, mode, nbio);
        DPRINTF("mio_open: %s: unknown device type\n", str);
        return NULL;

Reply via email to