mirror of
https://github.com/troglobit/finit.git
synced 2026-11-03 13:28:27 +00:00
libink/dbus: identify the caller behind a broker
On the local bus SO_PEERCRED says who is calling and the kernel is the one saying it. Behind a broker one connection carries every caller, so that credential describes dbus-daemon and nothing else, and every privileged method was refused there, root included. Ask the bus driver instead. libink parks the call and hands us the sender; we ask GetConnectionUnixUser and answer when the reply lands, through the same event loop as everything else. Nothing blocks: blocking in PID 1 is why libuEv exists. That needs calls libink can make on a connection it already has, so it gained those too. Answers are cached, since a bus never reuses a unique name while it runs. Not across a restart though: a new dbus-daemon numbers from scratch and :1.7 becomes somebody else, so the cache goes when the broker does. A sender name too long to key on is refused rather than truncated, two callers sharing a truncated key would share an identity. Privilege is no longer uid 0 alone. The socket is already owned by the --with-group group, so refusing its members every method that changes anything left a wheel user able to open the bus and unable to reboot. Both gates now say the same thing. Group membership needs NSS, which the C library loads with dlopen(), so the lookup is compiled out where Finit is built to link statically. That leaves such a build root-only, which is worth saying out loud rather than leaving to be discovered. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
d710a23513
commit
63aabaa6df
17 files changed
+774
-90
No files matched your search
+54
-4
@@ -24,9 +24,22 @@ typedef enum {
|
||||
#define LINK_AUTH_LINEBUF_SIZE 256
|
||||
#define LINK_RX_BUF_SIZE (64 * 1024)
|
||||
#define LINK_TX_BUF_SIZE (16 * 1024)
|
||||
#define LINK_UNIQUE_NAME_LEN 16
|
||||
#define LINK_UNIQUE_NAME_LEN LINK_SENDER_MAX
|
||||
#define LINK_MATCH_RULE_MAX 256 /* per-peer match rule cap */
|
||||
#define LINK_MATCH_PEER_CAP 16 /* max active match rules per peer */
|
||||
#define LINK_PENDING_CAP 4 /* outbound calls awaiting a reply */
|
||||
/* Staging for an outgoing method call. Generous on purpose: headers
|
||||
* for the calls libink makes run to ~150 B, and both the synchronous
|
||||
* and the connection-side path build into these, so one answer rather
|
||||
* than a number per call site. */
|
||||
#define LINK_CALL_HDR_MAX 1024
|
||||
#define LINK_CALL_BODY_MAX 1024
|
||||
#define LINK_PARKED_CAP 4 /* inbound calls awaiting a uid */
|
||||
/* A call parked for authorization is a privileged one: an object path
|
||||
* and at most a service name. Finit's per-service paths alone run to
|
||||
* 512 bytes, so leave room for the header around one. Anything that
|
||||
* does not fit is denied rather than held. */
|
||||
#define LINK_PARKED_MSG_MAX 1024
|
||||
|
||||
/* Per-vtable record attached to an object's interface list. */
|
||||
struct link_vtable_entry {
|
||||
@@ -46,19 +59,44 @@ struct link_object {
|
||||
|
||||
TAILQ_HEAD(link_object_list, link_object);
|
||||
|
||||
/* An inbound method call held while we find out who sent it. The
|
||||
* message is copied because rxbuf is reused as soon as we return to
|
||||
* the read loop. `tok` is the handle the resolver answers with, and
|
||||
* zero when the slot is free. */
|
||||
struct link_parked {
|
||||
link_authz_t tok;
|
||||
link_connection_t *conn;
|
||||
size_t len;
|
||||
uint8_t buf[LINK_PARKED_MSG_MAX];
|
||||
};
|
||||
|
||||
struct link_server {
|
||||
int fd;
|
||||
char path[LINK_PATH_MAX];
|
||||
struct link_object_list objects;
|
||||
uint32_t next_unique_id; /* for ":1.N" names */
|
||||
|
||||
/* Set by link_server_set_uid_resolver(); see link.h. */
|
||||
link_uid_resolver_t uid_resolver;
|
||||
void *uid_userdata;
|
||||
|
||||
/* Set by link_server_set_authorizer(); see link.h. */
|
||||
link_authorizer_t authorizer;
|
||||
void *authz_userdata;
|
||||
struct link_parked parked[LINK_PARKED_CAP];
|
||||
link_authz_t next_tok;
|
||||
};
|
||||
|
||||
/* The reply being assembled inside a method handler.
|
||||
*
|
||||
* The reply body lives in conn->txbuf, not on this struct, so a
|
||||
* stack-allocated link_call (in dispatch) stays small. Sharing the
|
||||
* connection's txbuf is safe: the event loop is single-threaded and
|
||||
* a connection only ever has one in-flight method call at a time. */
|
||||
* connection's txbuf is safe because a reply is marshalled and sent
|
||||
* without yielding. Note that parking means several calls can be in
|
||||
* flight on one connection: what is held is the request, and
|
||||
* link_uid_resolved() resumes from a copy, so txbuf is still only
|
||||
* ever used by one reply at a time. An async handler that returned
|
||||
* before writing its reply would break that. */
|
||||
struct link_call {
|
||||
link_connection_t *conn;
|
||||
struct link_msg incoming;
|
||||
@@ -66,6 +104,7 @@ struct link_call {
|
||||
struct link_writer reply_writer; /* writes into conn->txbuf */
|
||||
int reply_consumed;
|
||||
int error_sent;
|
||||
uid_t uid; /* caller, resolved for a broker peer */
|
||||
};
|
||||
|
||||
/* A parsed AddMatch rule. Fields are NULL when the rule omits the
|
||||
@@ -108,6 +147,16 @@ struct link_connection {
|
||||
|
||||
uint32_t next_serial;
|
||||
|
||||
/* Outbound calls we made on this connection, awaiting replies.
|
||||
* Only a broker connection uses these today, to ask the bus
|
||||
* driver who a sender is. */
|
||||
struct {
|
||||
int used;
|
||||
uint32_t serial;
|
||||
link_reply_cb_t cb;
|
||||
void *userdata;
|
||||
} pending[LINK_PENDING_CAP];
|
||||
|
||||
struct link_server *server; /* back-pointer for dispatch */
|
||||
};
|
||||
|
||||
@@ -121,7 +170,8 @@ void __auth_generate_guid(char out[33]);
|
||||
int __auth_client(int fd, uid_t uid);
|
||||
|
||||
/* dispatch.c */
|
||||
int __dispatch_message(link_connection_t *conn, const struct link_msg *m);
|
||||
int __dispatch_message(link_connection_t *conn, const struct link_msg *m, size_t framelen);
|
||||
void __dispatch_forget_conn(link_connection_t *conn);
|
||||
int __send_error(link_connection_t *conn, const struct link_msg *req,
|
||||
const char *error_name, const char *text);
|
||||
int __send_method_return(link_connection_t *conn, const struct link_msg *req,
|
||||
|
||||
Reference in new issue
Block a user