diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2015-01-06 00:31:40 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2015-01-06 00:31:40 +0000 |
commit | aa081897ac57658482143f29f4b88b1ebbddede3 (patch) | |
tree | cc16f9e77185652899ed7ea798b56031c69ece80 /src | |
parent | 5b4cf1798bfaf7be1dfaea36614757db80cae23d (diff) | |
download | skalibs-aa081897ac57658482143f29f4b88b1ebbddede3.tar.gz skalibs-aa081897ac57658482143f29f4b88b1ebbddede3.tar.xz skalibs-aa081897ac57658482143f29f4b88b1ebbddede3.zip |
- Bugfixes in unixmessage/skaclient (short writes / fd leakage / DoS) v2.1.0.0
- ABI change: unixmessage protocol header is now 6 bytes (was 8) - API change: skaclient_start(_async) now takes an "options" argument - version increase to 2.1.0.0
Diffstat (limited to 'src')
-rw-r--r-- | src/include/skalibs/skaclient.h | 52 | ||||
-rw-r--r-- | src/include/skalibs/unixmessage.h | 25 | ||||
-rw-r--r-- | src/libunixonacid/skaclient-internal.h | 4 | ||||
-rw-r--r-- | src/libunixonacid/skaclient_start.c | 4 | ||||
-rw-r--r-- | src/libunixonacid/skaclient_start_async.c | 7 | ||||
-rw-r--r-- | src/libunixonacid/skaclient_start_cb.c | 16 | ||||
-rw-r--r-- | src/libunixonacid/skaclient_startf_async.c | 3 | ||||
-rw-r--r-- | src/libunixonacid/unixmessage_put.c | 3 | ||||
-rw-r--r-- | src/libunixonacid/unixmessage_receive.c | 56 | ||||
-rw-r--r-- | src/libunixonacid/unixmessage_receiver_free.c | 19 | ||||
-rw-r--r-- | src/libunixonacid/unixmessage_receiver_init.c | 1 | ||||
-rw-r--r-- | src/libunixonacid/unixmessage_sender_flush.c | 65 |
12 files changed, 182 insertions, 73 deletions
diff --git a/src/include/skalibs/skaclient.h b/src/include/skalibs/skaclient.h index 2875304..5b73852 100644 --- a/src/include/skalibs/skaclient.h +++ b/src/include/skalibs/skaclient.h @@ -25,23 +25,13 @@ extern int skaclient_server_init (unixmessage_receiver_t *, unixmessage_sender_t #define SKACLIENT_KOLBAK_SIZE 64 #define SKACLIENT_OPTION_WAITPID 0x00000001U +#define SKACLIENT_OPTION_ASYNC_ACCEPT_FDS 0x00000002U +#define SKACLIENT_OPTION_SYNC_ACCEPT_FDS 0x00000004U #define skaclient_buffer_type(bufsn, auxbufsn, bufan, auxbufan, qlen) struct { char bufs[bufsn] ; char auxbufs[auxbufsn] ; char bufa[bufan] ; char auxbufa[auxbufan] ; kolbak_closure_t q[qlen] ; } typedef skaclient_buffer_type(UNIXMESSAGE_BUFSIZE, UNIXMESSAGE_AUXBUFSIZE, UNIXMESSAGE_BUFSIZE, UNIXMESSAGE_AUXBUFSIZE, SKACLIENT_KOLBAK_SIZE) skaclient_buffer_t, *skaclient_buffer_t_ref ; - /* Callback data for init */ - -typedef struct skaclient_cbdata_s skaclient_cbdata_t, *skaclient_cbdata_t_ref ; -struct skaclient_cbdata_s -{ - unixmessage_receiver_t *asyncin ; - unixmessage_sender_t *asyncout ; - char const *after ; - unsigned int afterlen ; -} ; - - /* User structure */ typedef struct skaclient_s skaclient_t, *skaclient_t_ref ; @@ -58,23 +48,40 @@ struct skaclient_s #define SKACLIENT_ZERO { .syncin = UNIXMESSAGE_RECEIVER_ZERO, .syncout = UNIXMESSAGE_SENDER_ZERO, .kq = KOLBAK_QUEUE_ZERO, .asyncin = UNIXMESSAGE_RECEIVER_ZERO, .asyncout = UNIXMESSAGE_SENDER_ZERO, .pid = 0, .options = 0 } extern skaclient_t const skaclient_zero ; + + /* Callback data for init */ + +typedef struct skaclient_cbdata_s skaclient_cbdata_t, *skaclient_cbdata_t_ref ; +struct skaclient_cbdata_s +{ + skaclient_t *a ; + char const *after ; + unsigned int afterlen ; +} ; + + + /* Starting and ending */ + extern void skaclient_end (skaclient_t *) ; -extern int skaclient_start_async (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int, char const *, unsigned int, skaclient_cbdata_t *) ; -#define skaclient_start_async_b(a, sb, path, before, beforelen, after, afterlen, blah) skaclient_start_async(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), path, before, beforelen, after, afterlen, blah) +extern int skaclient_start_async (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, uint32, char const *, unsigned int, char const *, unsigned int, skaclient_cbdata_t *) ; +#define skaclient_start_async_b(a, sb, path, options, before, beforelen, after, afterlen, blah) skaclient_start_async(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), path, options, before, beforelen, after, afterlen, blah) extern int skaclient_startf_async (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int, char const *, unsigned int, skaclient_cbdata_t *) ; #define skaclient_startf_async_b(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, blah) skaclient_startf_async(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q) / sizeof(kolbak_closure_t), prog, argv, envp, options, before, beforelen, after, afterlen, blah) -extern int skaclient_start (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ; -#define skaclient_start_b(a, sb, path, before, beforelen, after, afterlen, deadline, stamp) skaclient_start(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q) / sizeof(kolbak_closure_t), path, before, beforelen, after, afterlen, deadline, stamp) -#define skaclient_start_g(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, before, beforelen, after, afterlen, deadline) skaclient_start(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, before, beforelen, after, afterlen, (deadline), &STAMP) -#define skaclient_start_b_g(a, sb, path, before, beforelen, after, afterlen, deadline) skaclient_start_b(a, sb, path, before, beforelen, after, afterlen, (deadline), &STAMP) +extern int skaclient_start (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, uint32, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ; +#define skaclient_start_b(a, sb, path, options, before, beforelen, after, afterlen, deadline, stamp) skaclient_start(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q) / sizeof(kolbak_closure_t), path, options, before, beforelen, after, afterlen, deadline, stamp) +#define skaclient_start_g(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, options, before, beforelen, after, afterlen, deadline) skaclient_start(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, options, before, beforelen, after, afterlen, (deadline), &STAMP) +#define skaclient_start_b_g(a, sb, path, options, before, beforelen, after, afterlen, deadline) skaclient_start_b(a, sb, path, options, before, beforelen, after, afterlen, (deadline), &STAMP) extern int skaclient_startf (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ; #define skaclient_startf_b(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, deadline, stamp) skaclient_startf(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q) / sizeof(kolbak_closure_t), prog, argv, envp, options, before, beforelen, after, afterlen, deadline, stamp) #define skaclient_startf_g(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, prog, argv, envp, options, before, beforelen, after, afterlen, deadline) skaclient_startf(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, prog, argv, envp, options, before, beforelen, after, afterlen, (deadline), &STAMP) #define skaclient_startf_b_g(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, deadline) skaclient_startf_b(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, (deadline), &STAMP) + + /* Writing */ + extern int skaclient_putmsg_and_close (skaclient_t *, unixmessage_t const *, unsigned char const *, unixmessage_handler_func_t *, void *) ; #define skaclient_putmsg(a, m, cb, result) skaclient_putmsg_and_close(a, m, unixmessage_bits_closenone, cb, result) extern int skaclient_putmsgv_and_close (skaclient_t *, unixmessage_v_t const *, unsigned char const *, unixmessage_handler_func_t *, void *) ; @@ -83,6 +90,9 @@ extern int skaclient_putmsgv_and_close (skaclient_t *, unixmessage_v_t const *, extern int skaclient_put (skaclient_t *, char const *, unsigned int, unixmessage_handler_func_t *, void *) ; extern int skaclient_putv (skaclient_t *, siovec_t const *, unsigned int, unixmessage_handler_func_t *, void *) ; + + /* Writing and flushing */ + extern int skaclient_sendmsg_and_close (skaclient_t *, unixmessage_t const *, unsigned char const *, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ; #define skaclient_sendmsg_and_close_g(a, m, bits, cb, result, deadline) skaclient_sendmsg_and_close(a, m, bits, cb, result, (deadline), &STAMP) #define skaclient_sendmsg(a, m, cb, result, deadline, stamp) skaclient_sendmsg_and_close(a, m, unixmessage_bits_closenone, cb, result, deadline, stamp) @@ -98,6 +108,9 @@ extern int skaclient_send (skaclient_t *, char const *, unsigned int, unixmessag extern int skaclient_sendv (skaclient_t *, siovec_t const *, unsigned int, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ; #define skaclient_sendv_g(a, v, vlen, cb, result, deadline) skaclient_sendv(a, v, vlen, cb, result, (deadline), &STAMP) + + /* Helpers for full async */ + #define skaclient_sfd(a) unixmessage_receiver_fd(&(a)->syncin) #define skaclient_siswritable(a) (!unixmessage_sender_isempty(&(a)->syncout)) #define skaclient_flush(a) unixmessage_sender_flush(&(a)->syncout) @@ -117,6 +130,9 @@ extern int skaclient_syncify (skaclient_t *, tain_t const *, tain_t *) ; extern unixmessage_handler_func_t skaclient_default_cb ; + + /* When asyncout is actually used (skabus...) */ + #define skaclient_aiswritable(a) (!unixmessage_sender_isempty(&(a)->asyncout)) #define skaclient_aput_and_close(a, m, bits) unixmessage_put_and_close(&(a)->asyncout, m, bits) #define skaclient_aputv_and_close(a, m, bits) unixmessage_putv_and_close(&(a)->asyncout, m, bits) diff --git a/src/include/skalibs/unixmessage.h b/src/include/skalibs/unixmessage.h index eaf66c5..3252a50 100644 --- a/src/include/skalibs/unixmessage.h +++ b/src/include/skalibs/unixmessage.h @@ -3,6 +3,8 @@ #ifndef UNIXMESSAGE_H #define UNIXMESSAGE_H +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> #include <skalibs/buffer.h> #include <skalibs/cbuffer.h> #include <skalibs/gccattributes.h> @@ -39,8 +41,9 @@ struct unixmessage_v_s #define UNIXMESSAGE_V_ZERO { .v = 0, .vlen = 0, .fds = 0, .nfds = 0 } extern unixmessage_v_t const unixmessage_v_zero ; -#define UNIXMESSAGE_BUFSIZE 2048 +#define UNIXMESSAGE_MAXSIZE (2U << 27) #define UNIXMESSAGE_MAXFDS 255 +#define UNIXMESSAGE_BUFSIZE 2048 #define UNIXMESSAGE_AUXBUFSIZE (sizeof(int) * UNIXMESSAGE_MAXFDS + 1) #define UNIXMESSAGE_MAXREADS 32 @@ -55,9 +58,10 @@ struct unixmessage_sender_s genalloc fds ; /* int */ genalloc offsets ; /* diuint */ unsigned int head ; + unsigned int shorty ; } ; #define UNIXMESSAGE_SENDER_ZERO UNIXMESSAGE_SENDER_INIT(-1) -#define UNIXMESSAGE_SENDER_INIT(s) { .fd = (s), .data = STRALLOC_ZERO, .fds = GENALLOC_ZERO, .offsets = GENALLOC_ZERO, .head = 0 } +#define UNIXMESSAGE_SENDER_INIT(s) { .fd = (s), .data = STRALLOC_ZERO, .fds = GENALLOC_ZERO, .offsets = GENALLOC_ZERO, .head = 0, .shorty = 0 } extern unixmessage_sender_t const unixmessage_sender_zero ; extern void unixmessage_sender_init (unixmessage_sender_t *, int) ; @@ -87,21 +91,23 @@ struct unixmessage_receiver_s int fd ; cbuffer_t mainb ; cbuffer_t auxb ; - unsigned int mainlen ; - unsigned int auxlen ; stralloc maindata ; stralloc auxdata ; + uint32 mainlen ; + uint16 auxlen ; + unsigned int fds_ok : 2 ; } ; -#define UNIXMESSAGE_RECEIVER_ZERO { .fd = -1, .mainb = CBUFFER_ZERO, .auxb = CBUFFER_ZERO, .mainlen = 0, .auxlen = 0, .maindata = STRALLOC_ZERO, .auxdata = STRALLOC_ZERO } +#define UNIXMESSAGE_RECEIVER_ZERO { .fd = -1, .mainb = CBUFFER_ZERO, .auxb = CBUFFER_ZERO, .maindata = STRALLOC_ZERO, .auxdata = STRALLOC_ZERO, .mainlen = 0, .auxlen = 0, .fds_ok = 3 } #define UNIXMESSAGE_RECEIVER_INIT(d, mains, mainn, auxs, auxn) \ { \ .fd = d, \ .mainb = CBUFFER_INIT(mains, mainn), \ .auxb = CBUFFER_INIT(auxs, auxn), \ + .maindata = STRALLOC_ZERO, \ + .auxdata = STRALLOC_ZERO, \ .mainlen = 0, \ .auxlen = 0, \ - .maindata = STRALLOC_ZERO, \ - .auxdata = STRALLOC_ZERO \ + .fds_ok = 3 \ } extern int unixmessage_receiver_init (unixmessage_receiver_t *, int, char *, unsigned int, char *, unsigned int) ; extern void unixmessage_receiver_free (unixmessage_receiver_t *) ; @@ -113,6 +119,10 @@ extern int unixmessage_receive (unixmessage_receiver_t *, unixmessage_t *) ; extern int unixmessage_timed_receive (unixmessage_receiver_t *, unixmessage_t *, tain_t const *, tain_t *) ; #define unixmessage_timed_receive_g(receiver, msg, deadline) unixmessage_timed_receive(receiver, msg, (deadline), &STAMP) +#define unixmessage_receiver_accept_fds(b) ((b)->fds_ok = 3) +#define unixmessage_receiver_refuse_fds(b) ((b)->fds_ok = 1) +#define unixmessage_receiver_ignore_fds(b) ((b)->fds_ok = 0) + typedef int unixmessage_handler_func_t (unixmessage_t const *, void *) ; typedef unixmessage_handler_func_t *unixmessage_handler_func_t_ref ; @@ -121,6 +131,7 @@ extern int unixmessage_timed_handle (unixmessage_receiver_t *, unixmessage_handl #define unixmessage_timed_handle_g(b, f, p, deadline) unixmessage_timed_handle(b, f, p, (deadline), &STAMP) + /* Globals */ extern unixmessage_receiver_t unixmessage_receiver_0_ ; diff --git a/src/libunixonacid/skaclient-internal.h b/src/libunixonacid/skaclient-internal.h index f0a9bfe..3c73d1f 100644 --- a/src/libunixonacid/skaclient-internal.h +++ b/src/libunixonacid/skaclient-internal.h @@ -4,12 +4,10 @@ #define SKACLIENT_INTERNAL_H #include <skalibs/kolbak.h> -#include <skalibs/skaclient.h> #include <skalibs/unixmessage.h> +#include <skalibs/skaclient.h> extern int skaclient_init (skaclient_t *, int, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, unsigned int) ; -extern int skaclient_start_async_th (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int) ; -extern int skaclient_startf_async_th (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int) ; extern int skaclient_start_cb (unixmessage_t const *, skaclient_cbdata_t *) ; #endif diff --git a/src/libunixonacid/skaclient_start.c b/src/libunixonacid/skaclient_start.c index a7e3e67..85021cb 100644 --- a/src/libunixonacid/skaclient_start.c +++ b/src/libunixonacid/skaclient_start.c @@ -1,6 +1,7 @@ /* ISC license. */ #include <errno.h> +#include <skalibs/uint32.h> #include <skalibs/kolbak.h> #include <skalibs/skaclient.h> #include <skalibs/tai.h> @@ -19,6 +20,7 @@ int skaclient_start ( kolbak_closure_t *q, unsigned int qlen, char const *path, + uint32 options, char const *before, unsigned int beforelen, char const *after, @@ -29,7 +31,7 @@ int skaclient_start ( skaclient_cbdata_t blah ; unixmessage_t m ; register int r ; - if (!skaclient_start_async(a, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, path, before, beforelen, after, afterlen, &blah)) return 0 ; + if (!skaclient_start_async(a, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, path, options, before, beforelen, after, afterlen, &blah)) return 0 ; if (!skaclient_timed_flush(a, deadline, stamp)) { register int e = errno ; diff --git a/src/libunixonacid/skaclient_start_async.c b/src/libunixonacid/skaclient_start_async.c index 4dbbf1c..79ea5df 100644 --- a/src/libunixonacid/skaclient_start_async.c +++ b/src/libunixonacid/skaclient_start_async.c @@ -1,6 +1,7 @@ /* ISC license. */ #include <errno.h> +#include <skalibs/uint32.h> #include <skalibs/error.h> #include <skalibs/kolbak.h> #include <skalibs/skaclient.h> @@ -21,6 +22,7 @@ int skaclient_start_async ( kolbak_closure_t *q, unsigned int qlen, char const *path, + uint32 options, char const *before, unsigned int beforelen, char const *after, @@ -38,14 +40,13 @@ int skaclient_start_async ( return 0 ; } a->pid = 0 ; - a->options = 0 ; + a->options = options & ~SKACLIENT_OPTION_WAITPID ; if (!kolbak_enqueue(&a->kq, (unixmessage_handler_func_t_ref)&skaclient_start_cb, blah)) { skaclient_end(a) ; return 0 ; } - blah->asyncin = &a->asyncin ; - blah->asyncout = &a->asyncout ; + blah->a = a ; blah->after = after ; blah->afterlen = afterlen ; return 1 ; diff --git a/src/libunixonacid/skaclient_start_cb.c b/src/libunixonacid/skaclient_start_cb.c index 4a82b9b..ff11a21 100644 --- a/src/libunixonacid/skaclient_start_cb.c +++ b/src/libunixonacid/skaclient_start_cb.c @@ -3,16 +3,24 @@ #include <errno.h> #include <skalibs/bytestr.h> #include <skalibs/error.h> -#include <skalibs/skaclient.h> #include <skalibs/unixmessage.h> +#include <skalibs/skaclient.h> #include "skaclient-internal.h" int skaclient_start_cb (unixmessage_t const *m, skaclient_cbdata_t *blah) { if (m->len != blah->afterlen || byte_diff(m->s, m->len, blah->after) - || m->nfds != 1) return (errno = EPROTO, 0) ; - blah->asyncin->fd = m->fds[0] ; - blah->asyncout->fd = m->fds[0] ; + || m->nfds != 1) + { + unixmessage_drop(m) ; + return (errno = EPROTO, 0) ; + } + blah->a->asyncin.fd = m->fds[0] ; + blah->a->asyncout.fd = m->fds[0] ; + if (!(blah->a->options & SKACLIENT_OPTION_ASYNC_ACCEPT_FDS)) + unixmessage_receiver_refuse_fds(&blah->a->asyncin) ; + if (!(blah->a->options & SKACLIENT_OPTION_SYNC_ACCEPT_FDS)) + unixmessage_receiver_refuse_fds(&blah->a->syncin) ; return 1 ; } diff --git a/src/libunixonacid/skaclient_startf_async.c b/src/libunixonacid/skaclient_startf_async.c index eaeba6c..dd1688e 100644 --- a/src/libunixonacid/skaclient_startf_async.c +++ b/src/libunixonacid/skaclient_startf_async.c @@ -53,8 +53,7 @@ int skaclient_startf_async ( skaclient_end(a) ; return 0 ; } - blah->asyncin = &a->asyncin ; - blah->asyncout = &a->asyncout ; + blah->a = a ; blah->after = after ; blah->afterlen = afterlen ; return 1 ; diff --git a/src/libunixonacid/unixmessage_put.c b/src/libunixonacid/unixmessage_put.c index f6db23b..908bc31 100644 --- a/src/libunixonacid/unixmessage_put.c +++ b/src/libunixonacid/unixmessage_put.c @@ -8,6 +8,7 @@ #include <skalibs/bitarray.h> #include <skalibs/bytestr.h> #include <skalibs/diuint.h> +#include <skalibs/error.h> #include <skalibs/stralloc.h> #include <skalibs/genalloc.h> #include <skalibs/siovec.h> @@ -49,6 +50,8 @@ static inline int copyfds (char *s, int const *fds, unsigned int n, unsigned cha static int reserve_and_copy (unixmessage_sender_t *b, unsigned int len, int const *fds, unsigned int nfds, unsigned char const *bits) { diuint cur = { .left = b->data.len, .right = b->fds.len } ; + if (len > UNIXMESSAGE_MAXSIZE || nfds > UNIXMESSAGE_MAXFDS) + return (errno = EPROTO, 0) ; if (!genalloc_readyplus(diuint, &b->offsets, 1) || !genalloc_readyplus(int, &b->fds, nfds) || !stralloc_readyplus(&b->data, len)) diff --git a/src/libunixonacid/unixmessage_receive.c b/src/libunixonacid/unixmessage_receive.c index 21491fa..5fa16c4 100644 --- a/src/libunixonacid/unixmessage_receive.c +++ b/src/libunixonacid/unixmessage_receive.c @@ -5,7 +5,8 @@ #include <errno.h> #include <sys/socket.h> #include <sys/uio.h> -#include <skalibs/uint.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> #include <skalibs/cbuffer.h> #include <skalibs/djbunix.h> #include <skalibs/error.h> @@ -45,12 +46,12 @@ static int unixmessage_receiver_fill (unixmessage_receiver_t *b) .msg_iov = iov, .msg_iovlen = 2, .msg_flags = 0, - .msg_control = ancilbuf, - .msg_controllen = sizeof(ancilbuf) + .msg_control = b->fds_ok & 1 ? ancilbuf : 0, + .msg_controllen = b->fds_ok & 1 ? sizeof(ancilbuf) : 0 } ; unsigned int auxlen ; int r = -1 ; - if (cbuffer_isfull(&b->mainb) || cbuffer_isfull(&b->auxb)) + if (cbuffer_isfull(&b->mainb) || ((b->fds_ok & 1) && cbuffer_isfull(&b->auxb))) return (errno = ENOBUFS, -1) ; { siovec_t v[2] ; @@ -62,6 +63,7 @@ static int unixmessage_receiver_fill (unixmessage_receiver_t *b) r = recvmsg(b->fd, &msghdr, awesomeflags) ; if (!r || (r < 0 && errno != EINTR)) return r ; } + if (b->fds_ok & 1) { struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ; if (c) @@ -69,16 +71,32 @@ static int unixmessage_receiver_fill (unixmessage_receiver_t *b) if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SCM_RIGHTS) return (errno = EPROTO, -1) ; auxlen = (unsigned int)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) ; + if (auxlen && !(b->fds_ok & 2)) + { + register unsigned int i = auxlen/sizeof(int) ; + while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; + return (errno = EPROTO, -1) ; + } #ifndef SKALIBS_HASCMSGCLOEXEC { register unsigned int i = 0 ; for (; i < auxlen/sizeof(int) ; i++) - if (coe(((int *)CMSG_DATA(c))[i]) < 0) return -1 ; + if (coe(((int *)CMSG_DATA(c))[i]) < 0) + { + int e = errno ; + i++ ; + while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; + errno = e ; + return -1 ; + } } #endif - if (msghdr.msg_flags & MSG_CTRUNC) return (errno = EPROTO, -1) ; - if (cbuffer_put(&b->auxb, (char *)CMSG_DATA(c), auxlen) < auxlen) + if ((msghdr.msg_flags & MSG_CTRUNC) || cbuffer_put(&b->auxb, (char *)CMSG_DATA(c), auxlen) < auxlen) + { + register unsigned int i = auxlen/sizeof(int) ; + while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; return (errno = ENOBUFS, -1) ; + } } } cbuffer_WSEEK(&b->mainb, r) ; @@ -89,21 +107,25 @@ int unixmessage_receive (unixmessage_receiver_t *b, unixmessage_t *m) { if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) { - char pack[sizeof(unsigned int) << 1] ; - if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1) + char pack[6] ; + if (cbuffer_len(&b->mainb) < 6) { register int r = sanitize_read(unixmessage_receiver_fill(b)) ; if (r <= 0) return r ; - if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1) - return (errno = EWOULDBLOCK, 0) ; + if (cbuffer_len(&b->mainb) < 6) return (errno = EWOULDBLOCK, 0) ; } - cbuffer_get(&b->mainb, pack, sizeof(unsigned int) << 1) ; - uint_unpack_big(pack, &b->mainlen) ; - uint_unpack_big(pack + sizeof(unsigned int), &b->auxlen) ; + cbuffer_get(&b->mainb, pack, 6) ; + uint32_unpack_big(pack, &b->mainlen) ; + if (b->fds_ok & 1) uint16_unpack_big(pack + 4, &b->auxlen) ; + else b->auxlen = 0 ; b->auxlen *= sizeof(int) ; - if (!stralloc_ready(&b->maindata, b->mainlen)) return -1 ; + if (b->mainlen > UNIXMESSAGE_MAXSIZE + || b->auxlen > ((b->fds_ok & 2) ? UNIXMESSAGE_MAXFDS * sizeof(int) : 0)) + return (errno = EPROTO, -1) ; + if (!stralloc_ready(&b->maindata, b->mainlen) + || !stralloc_ready(&b->auxdata, b->auxlen)) + return -1 ; b->maindata.len = 0 ; - if (!stralloc_ready(&b->auxdata, b->auxlen)) return -1 ; b->auxdata.len = 0 ; } @@ -124,6 +146,6 @@ int unixmessage_receive (unixmessage_receiver_t *b, unixmessage_t *m) m->s = b->maindata.s ; m->len = b->maindata.len ; m->fds = (int *)b->auxdata.s ; - m->nfds = b->auxlen / sizeof(int) ; + m->nfds = b->auxdata.len / sizeof(int) ; return 1 ; } diff --git a/src/libunixonacid/unixmessage_receiver_free.c b/src/libunixonacid/unixmessage_receiver_free.c index 353797b..74654d0 100644 --- a/src/libunixonacid/unixmessage_receiver_free.c +++ b/src/libunixonacid/unixmessage_receiver_free.c @@ -1,12 +1,29 @@ /* ISC license. */ #include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> #include <skalibs/unixmessage.h> void unixmessage_receiver_free (unixmessage_receiver_t *b) { + register unsigned int h = b->maindata.len ; b->fd = -1 ; stralloc_free(&b->maindata) ; + h = h != b->mainlen || b->auxdata.len != b->auxlen || cbuffer_len(&b->auxb) ; + if (h) + { + register unsigned int n = b->auxdata.len / sizeof(int) ; + while (n--) fd_close(((int *)b->auxdata.s)[n]) ; + } stralloc_free(&b->auxdata) ; - b->mainlen = b->auxlen = 0 ; + if (h) + { + register unsigned int n = cbuffer_len(&b->auxb) / sizeof(int) ; + if (n) + { + int fds[n] ; + cbuffer_get(&b->auxb, (char *)fds, n * sizeof(int)) ; + while (n--) fd_close(fds[n]) ; + } + } } diff --git a/src/libunixonacid/unixmessage_receiver_init.c b/src/libunixonacid/unixmessage_receiver_init.c index 5f702cf..430ccac 100644 --- a/src/libunixonacid/unixmessage_receiver_init.c +++ b/src/libunixonacid/unixmessage_receiver_init.c @@ -13,5 +13,6 @@ int unixmessage_receiver_init (unixmessage_receiver_t *b, int fd, char *mainbuf, b->mainlen = b->auxlen = 0 ; b->maindata = stralloc_zero ; b->auxdata = stralloc_zero ; + b->fds_ok = 3 ; return 1 ; } diff --git a/src/libunixonacid/unixmessage_sender_flush.c b/src/libunixonacid/unixmessage_sender_flush.c index bd4c704..bea3585 100644 --- a/src/libunixonacid/unixmessage_sender_flush.c +++ b/src/libunixonacid/unixmessage_sender_flush.c @@ -6,9 +6,10 @@ #include <sys/uio.h> #include <unistd.h> #include <errno.h> -#include <skalibs/uint.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> #include <skalibs/diuint.h> -#include <skalibs/stralloc.h> +#include <skalibs/allreadwrite.h> #include <skalibs/genalloc.h> #include <skalibs/djbunix.h> #include <skalibs/unixmessage.h> @@ -18,21 +19,51 @@ #define MSG_NOSIGNAL 0 #endif + /* + XXX: sendmsg/recvmsg is badly, badly specified. + XXX: We assume ancillary data is attached to the first byte. + */ + int unixmessage_sender_flush (unixmessage_sender_t *b) { - diuint last = { .left = b->data.len, .right = genalloc_len(int, &b->fds) } ; + diuint last = { .left = (uint32)b->data.len, .right = genalloc_len(int, &b->fds) } ; diuint *offsets = genalloc_s(diuint, &b->offsets) ; unsigned int n = genalloc_len(diuint, &b->offsets) ; - unsigned int oldhead = b->head ; + register int r ; + + if (b->shorty) /* we had a short write, gotta send the remainder first */ + { + diuint *next = b->head+1 < n ? offsets + b->head+1 : &last ; + unsigned int len = next->left - offsets[b->head].left ; + if (b->shorty <= len) + r = fd_write(b->fd, b->data.s + offsets[b->head].left + (len - b->shorty), b->shorty) ; + else + { + unsigned int nfds = next->right - offsets[b->head].right ; + char pack[6] ; + struct iovec v[2] = + { + { .iov_base = pack + 6 - (b->shorty - len), .iov_len = b->shorty - len }, + { .iov_base = b->data.s + offsets[b->head].left, .iov_len = len } + } ; + uint32_pack_big(pack, (uint32)len) ; + uint16_pack_big(pack + 4, (uint16)nfds) ; + r = fd_writev(b->fd, v, 2) ; + } + if (r <= 0) return 0 ; + b->shorty -= r ; + if (b->shorty) return (errno = EWOULDBLOCK, 0) ; + } + for (; b->head < n ; b->head++) { diuint *next = b->head+1 < n ? offsets + b->head+1 : &last ; unsigned int len = next->left - offsets[b->head].left ; unsigned int nfds = next->right - offsets[b->head].right ; - char pack[sizeof(unsigned int) << 1] ; + char pack[6] ; struct iovec v[2] = { - { .iov_base = pack, .iov_len = sizeof(unsigned int) << 1 }, + { .iov_base = pack, .iov_len = 6 }, { .iov_base = b->data.s + offsets[b->head].left, .iov_len = len } } ; char ancilbuf[CMSG_SPACE(nfds * sizeof(int))] ; @@ -45,8 +76,8 @@ int unixmessage_sender_flush (unixmessage_sender_t *b) .msg_control = nfds ? ancilbuf : 0, .msg_controllen = nfds ? sizeof(ancilbuf) : 0 } ; - uint_pack_big(pack, len) ; - uint_pack_big(pack + sizeof(unsigned int), nfds) ; + uint32_pack_big(pack, (uint32)len) ; + uint16_pack_big(pack + 4, (uint16)nfds) ; if (nfds) { struct cmsghdr *cp = CMSG_FIRSTHDR(&hdr) ; @@ -60,14 +91,9 @@ int unixmessage_sender_flush (unixmessage_sender_t *b) ((int *)CMSG_DATA(cp))[i] = fd < 0 ? -(fd+1) : fd ; } } - for (;;) - { - register int r = sendmsg(b->fd, &hdr, MSG_NOSIGNAL) ; - if (r == -1 && errno == EINTR) continue ; - if (r < (int)(len + (sizeof(unsigned int) << 1))) - return -(int)(b->head-oldhead)-1 ; - break ; - } + do r = sendmsg(b->fd, &hdr, MSG_NOSIGNAL) ; + while (r < 0 && errno == EINTR) ; + if (r <= 0) return 0 ; #ifndef SKALIBS_HASANCILAUTOCLOSE if (nfds) { @@ -79,10 +105,15 @@ int unixmessage_sender_flush (unixmessage_sender_t *b) } } #endif + if ((unsigned int)r < 6 + len) + { + b->shorty = 6 + len - r ; + return (errno = EWOULDBLOCK, 0) ; + } } b->data.len = 0 ; genalloc_setlen(int, &b->fds, 0) ; genalloc_setlen(diuint, &b->offsets, 0) ; b->head = 0 ; - return (int)(n - oldhead) ; + return 1 ; } |