11 #include <sys/capability.h>
15 #include "kdbus-api.h"
16 #include "kdbus-util.h"
17 #include "kdbus-enum.h"
18 #include "kdbus-test.h"
20 #define KDBUS_SYSNAME_MAX_LEN 63
22 static wur int install_name_add_match(struct kdbus_conn *conn, const char *name)
25 struct kdbus_cmd_match cmd;
29 struct kdbus_notify_name_change chg;
35 /* install the match rule */
36 memset(&buf, 0, sizeof(buf));
37 buf.item.type = KDBUS_ITEM_NAME_ADD;
38 buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
39 buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
40 strncpy(buf.name, name, sizeof(buf.name) - 1);
41 buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
42 buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
44 ret = kdbus_cmd_match_add(conn->fd, &buf.cmd);
51 static wur int create_endpoint(const char *buspath, uid_t uid, const char *name,
61 /* max should be KDBUS_SYSNAME_MAX_LEN */
67 fd = open(buspath, O_RDWR);
71 memset(&ep_make, 0, sizeof(ep_make));
73 snprintf(ep_make.name.str,
74 /* Use the KDBUS_SYSNAME_MAX_LEN or sizeof(str) */
75 KDBUS_SYSNAME_MAX_LEN > strlen(name) ?
76 KDBUS_SYSNAME_MAX_LEN : sizeof(ep_make.name.str),
79 ep_make.name.type = KDBUS_ITEM_MAKE_NAME;
80 ep_make.name.size = KDBUS_ITEM_HEADER_SIZE +
81 strlen(ep_make.name.str) + 1;
83 ep_make.cmd.flags = flags;
84 ep_make.cmd.size = sizeof(ep_make.cmd) + ep_make.name.size;
86 ret = kdbus_cmd_endpoint_make(fd, &ep_make.cmd);
88 kdbus_printf("error creating endpoint: %d (%m)\n", ret);
95 static wur int unpriv_test_custom_ep(const char *buspath)
97 int ret, ep_fd1, ep_fd2;
98 char *ep1, *ep2, *tmp1, *tmp2;
100 ASSERT_NONZERO(tmp1 = strdup(buspath));
101 ASSERT_NONZERO(tmp2 = strdup(buspath));
103 ret = asprintf(&ep1, "%s/%u-%s", dirname(tmp1), getuid(), "apps1");
104 ASSERT_RETURN(ret,>,0);
106 ret = asprintf(&ep2, "%s/%u-%s", dirname(tmp2), getuid(), "apps2");
107 ASSERT_RETURN(ret,>,0);
112 /* endpoint only accessible to current uid */
113 ep_fd1 = create_endpoint(buspath, getuid(), "apps1", 0);
114 ASSERT_RETURN(ep_fd1,>=,0);
116 /* endpoint world accessible */
117 ep_fd2 = create_endpoint(buspath, getuid(), "apps2",
118 KDBUS_MAKE_ACCESS_WORLD);
119 ASSERT_RETURN(ep_fd2,>=,0);
121 RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({
123 struct kdbus_conn *ep_conn;
126 * Make sure that we are not able to create custom
129 ep_fd = create_endpoint(buspath, getuid(),
130 "unpriv_costum_ep", 0);
131 ASSERT_EXIT(ep_fd,==,-EPERM);
134 * Endpoint "apps1" only accessible to same users,
135 * that own the endpoint. Access denied by VFS
137 ep_conn = kdbus_hello(ep1, 0, NULL, 0);
138 ASSERT_EXIT(errno,==,EACCES);
139 ASSERT_EXIT_ZERO(ep_conn);
141 /* Endpoint "apps2" world accessible */
142 ASSERT_EXIT_NONZERO(ep_conn = kdbus_hello(ep2, 0, NULL, 0));
144 kdbus_conn_free(ep_conn);
158 static wur int update_endpoint(int fd, const char *name)
160 int len = strlen(name) + 1;
162 struct kdbus_cmd cmd;
168 char str[KDBUS_ALIGN8(len)];
174 struct kdbus_policy_access access;
179 memset(&ep_update, 0, sizeof(ep_update));
181 ep_update.name.size = KDBUS_ITEM_HEADER_SIZE + len;
182 ep_update.name.type = KDBUS_ITEM_NAME;
183 strncpy(ep_update.name.str, name, sizeof(ep_update.name.str) - 1);
185 ep_update.access.size = sizeof(ep_update.access);
186 ep_update.access.type = KDBUS_ITEM_POLICY_ACCESS;
187 ep_update.access.access.type = KDBUS_POLICY_ACCESS_WORLD;
188 ep_update.access.access.access = KDBUS_POLICY_SEE;
190 ep_update.cmd.size = sizeof(ep_update);
192 ret = kdbus_cmd_endpoint_update(fd, &ep_update.cmd);
194 kdbus_printf("error updating endpoint: %d (%m)\n", ret);
201 wur int kdbus_test_custom_endpoint(struct kdbus_test_env *env)
205 struct kdbus_msg *msg;
206 struct kdbus_conn *ep_conn;
207 struct kdbus_conn *reader;
208 const char *name = "foo.bar.baz";
209 const char *epname = "foo";
210 char fake_ep[KDBUS_SYSNAME_MAX_LEN + 1] = {'\0'};
212 memset(fake_ep, 'X', sizeof(fake_ep) - 1);
214 /* Try to create a custom endpoint with a long name */
215 ASSERT_RETURN(-ENAMETOOLONG,==,create_endpoint(env->buspath, getuid(), fake_ep, 0));
217 /* Try to create a custom endpoint with a different uid */
218 ASSERT_RETURN(-EINVAL,==,create_endpoint(env->buspath, getuid() + 1, "foobar", 0));
220 /* create a custom endpoint, and open a connection on it */
221 ASSERT_RETURN(0,<=,ep_fd = create_endpoint(env->buspath, getuid(), "foo", 0));
223 ASSERT_NONZERO(tmp = strdup(env->buspath));
224 ASSERT_RETURN(0,<=,asprintf(&ep, "%s/%u-%s", dirname(tmp), getuid(), epname));
227 /* Register a connection that listen to broadcasts */
228 ASSERT_NONZERO(reader = kdbus_hello(ep, 0, NULL, 0));
230 /* Register to kernel signals */
231 ASSERT_ZERO(kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, KDBUS_MATCH_ID_ANY));
232 ASSERT_ZERO(kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, KDBUS_MATCH_ID_ANY));
233 ASSERT_ZERO(install_name_add_match(reader, name));
235 /* Monitor connections are not supported on custom endpoints */
236 ep_conn = kdbus_hello(ep, KDBUS_HELLO_MONITOR, NULL, 0);
237 ASSERT_RETURN(errno,==,EOPNOTSUPP);
238 ASSERT_ZERO(ep_conn);
240 ASSERT_NONZERO(ep_conn = kdbus_hello(ep, 0, NULL, 0));
242 /* Check that the reader got the IdAdd notification */
243 ASSERT_ZERO(kdbus_msg_recv(reader, &msg, NULL));
244 ASSERT_RETURN(msg->items[0].type,==,(typeof(msg->items[0].type))KDBUS_ITEM_ID_ADD);
245 ASSERT_RETURN(msg->items[0].id_change.id,==,ep_conn->id);
249 * Add a name add match on the endpoint connection, acquire name from
250 * the unfiltered connection, and make sure the filtered connection
251 * did not get the notification on the name owner change. Also, the
252 * endpoint connection may not be able to call conn_info, neither on
253 * the name nor on the ID.
255 ASSERT_ZERO(install_name_add_match(ep_conn, name));
257 ASSERT_ZERO(kdbus_name_acquire(env->conn, name, NULL));
259 ASSERT_RETURN(ONTIZEN(0,-EAGAIN),==,kdbus_msg_recv(ep_conn, NULL, NULL));
260 ASSERT_RETURN(ONTIZEN(0,-ESRCH),==,kdbus_conn_info(ep_conn, 0, name, 0, NULL));
261 ASSERT_RETURN(-ESRCH,==,kdbus_conn_info(ep_conn, 0, "random.crappy.name", 0, NULL));
262 ASSERT_RETURN(ONTIZEN(0,-ENXIO),==,kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL));
263 ASSERT_RETURN(-ENXIO,==,kdbus_conn_info(ep_conn, 0x0fffffffffffffffULL, NULL, 0, NULL));
265 /* Check that the reader did not receive the name notification */
266 ASSERT_RETURN(ONTIZEN(0,-EAGAIN),==,kdbus_msg_recv(reader, NULL, NULL));
269 * Release the name again, update the custom endpoint policy,
270 * and try again. This time, the connection on the custom endpoint
271 * should have gotten it.
273 ASSERT_ZERO(kdbus_name_release(env->conn, name));
275 /* Check that the reader did not receive the name notification */
276 ASSERT_RETURN(-EAGAIN,==,kdbus_msg_recv(reader, NULL, NULL));
278 ASSERT_ZERO(update_endpoint(ep_fd, name));
280 ASSERT_ZERO(kdbus_name_acquire(env->conn, name, NULL));
282 ASSERT_ZERO(kdbus_msg_recv(ep_conn, &msg, NULL));
283 ASSERT_RETURN(msg->items[0].type,==,(typeof(msg->items[0].type))KDBUS_ITEM_NAME_ADD);
284 ASSERT_ZERO(msg->items[0].name_change.old_id.id);
285 ASSERT_RETURN(msg->items[0].name_change.new_id.id,==,env->conn->id);
286 ASSERT_ZERO(strcmp(msg->items[0].name_change.name, name));
289 ASSERT_ZERO(kdbus_msg_recv(reader, &msg, NULL));
290 ASSERT_ZERO(strcmp(msg->items[0].name_change.name, name));
294 ASSERT_ZERO(kdbus_conn_info(ep_conn, 0, name, 0, NULL));
296 ASSERT_ZERO(kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL));
298 /* If we have privileges test custom endpoints */
299 ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
300 ASSERT_RETURN(ret,>=,0);
303 * All uids/gids are mapped and we have the necessary caps
305 if (ret && all_uids_gids_are_mapped())
306 ASSERT_ZERO(unpriv_test_custom_ep(env->buspath));
308 kdbus_conn_free(reader);
309 kdbus_conn_free(ep_conn);