Register for notification I/O function handler

Prototype:

int (*notify) ( resmgr_context_t *ctp,
               io_notify_t *msg,
               RESMGR_OCB_T *ocb )

Classification:

I/O

Default handler:

none

Helper functions:

iofunc_notify(), iofunc_notify_remove(), iofunc_notify_remove_strict(), iofunc_notify_trigger(), iofunc_notify_trigger_strict()

Client functions:

poll(), select(), ionotify()

Messages:

_IO_NOTIFY, _IO_NOTIFY64

Data structure:

struct _io_notify {
    uint16_t                    type;
    uint16_t                    combine_len;
    int32_t                     action;
    int32_t                     flags;
    struct __sigevent32         event;

    /* The fields `mgr` to `timo` are only valid if (flags & _NOTIFY_COND_EXTEN)
     * The full header must be present regardless of the flags.
     */
    int32_t                     mgr[2];    /* For use by manager */
    int32_t                     flags_extra_mask;
    int32_t                     flags_exten;
    int32_t                     nfds;
    int32_t                     fd_first;
    int32_t                     nfds_ready;
    int64_t                     timo;
    /* struct pollfd            fds[nfds]; */
};

struct _io_notify64 {
    uint16_t                    type;
    uint16_t                    combine_len;
    int32_t                     action;
    int32_t                     flags;
    struct __sigevent32         old_event;

    /* The fields `mgr` to `timo` are only valid if (flags & _NOTIFY_COND_EXTEN)
     * The full header must be present regardless of the flags.
     */
    int32_t                     mgr[2];    /* For use by manager */
    int32_t                     flags_extra_mask;
    int32_t                     flags_exten;
    int32_t                     nfds;
    int32_t                     fd_first;
    int32_t                     nfds_ready;
    int64_t                     timo;
    union {
        struct __sigevent32     event32;
        struct __sigevent64     event64;
    };
    /* struct pollfd            fds[nfds]; */
};

struct _io_notify_reply {
    uint32_t                    zero;
    uint32_t                    flags;   /* actions above */
    int32_t                     flags2;  /* flags above */
    struct __sigevent32         event;

    /* Following fields only updated by new managers (if valid) */
    int32_t                     mgr[2];    /* For use by manager */
    int32_t                     flags_extra_mask;
    int32_t                     flags_exten;
    int32_t                     nfds;
    int32_t                     fd_first;
    int32_t                     nfds_ready;
    int64_t                     timo;
    /* struct pollfd            fds[nfds]; */
};

struct _io_notify_reply64 {
    uint32_t                    zero;
    uint32_t                    flags;  /* actions */
    int32_t                     flags2; /* flags above */
    struct __sigevent32         old_event;

    /* Following fields only updated by new managers (if valid) */
    int32_t                     mgr[2];    /* For use by manager */
    int32_t                     flags_extra_mask;
    int32_t                     flags_exten;
    int32_t                     nfds;
    int32_t                     fd_first;
    int32_t                     nfds_ready;
    int64_t                     timo;
    union {
        struct __sigevent32     event32;
        struct __sigevent64     event64;
    };
    /* struct pollfd            fds[nfds]; */
};

typedef union {
    struct _io_notify           i;
    struct _io_notify64         i64;
    struct _io_notify_reply     o;
    struct _io_notify_reply64   o64;
} io_notify_t;

Description:

The handler is responsible for installing, polling, or removing a notification handler. The action and flags determine the kind of notification operation and conditions; the event is a struct sigevent structure that defines the notification event (if any) that the client wishes to be signaled with. You'd use the MsgDeliverEvent() or iofunc_notify_trigger() functions to deliver the event to the client.

Returns:

The status via the helper macro _RESMGR_STATUS(); the flags are returned via message reply.

Referenced by:

resmgr_io_funcs_t I/O table

Permission checking:

The iofunc_notify() helper function does not perform permission checking. However, if an OCB has not been opened for read, it should probably not be allowed to request notification of conditions occurring on that OCB that relate to reading data (e.g., the _NOTIFY_CONDE_RDNORM flag is set). Notifications that are not associated with reading or writing data (e.g., _NOTIFY_CONDE_HUP and _NOTIFY_CONDE_NVAL) do not need to be tied to read or write access. Although the information leakage is quite limited in this case, (e.g., learning when a file descriptor is ready for read or write or has out-of-band data available), it could potentially be used in various attacks such as race conditions. QNX recommends that you deny a notify() call to callers that have not opened the file descriptor for read or write. Thorough permission checking would apply an appropriate decision depending on the flags supplied to the notify() function.

For resource managers that deal with user input (e.g., a keyboard), be careful not to leak timing data through the delivery of notify messages. Attackers can use this timing data to build a profile of what the user is typing. Similarly, do not provide notification for process-specific characteristics such as CPU usage and changes in allocated memory.