Messages in this thread | | | Date | Fri, 30 Jun 2023 21:43:07 -0400 | From | "Liam R. Howlett" <> | Subject | Re: [PATCH v6 6/6] connector/cn_proc: Selftest for proc connector |
| |
* Anjali Kulkarni <anjali.k.kulkarni@oracle.com> [230614 19:41]: > Run as ./proc_filter -f to run new filter code. Run without "-f" to run > usual proc connector code without the new filtering code. > > Signed-off-by: Anjali Kulkarni <anjali.k.kulkarni@oracle.com> > --- > tools/testing/selftests/Makefile | 1 + > tools/testing/selftests/connector/Makefile | 6 + > .../testing/selftests/connector/proc_filter.c | 308 ++++++++++++++++++ > 3 files changed, 315 insertions(+) > create mode 100644 tools/testing/selftests/connector/Makefile > create mode 100644 tools/testing/selftests/connector/proc_filter.c > > diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile > index 90a62cf75008..7c9673951f9a 100644 > --- a/tools/testing/selftests/Makefile > +++ b/tools/testing/selftests/Makefile > @@ -7,6 +7,7 @@ TARGETS += breakpoints > TARGETS += capabilities > TARGETS += cgroup > TARGETS += clone3 > +TARGETS += connector > TARGETS += core > TARGETS += cpufreq > TARGETS += cpu-hotplug > diff --git a/tools/testing/selftests/connector/Makefile b/tools/testing/selftests/connector/Makefile > new file mode 100644 > index 000000000000..21c9f3a973a0 > --- /dev/null > +++ b/tools/testing/selftests/connector/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > +CFLAGS += -Wall > + > +TEST_GEN_PROGS = proc_filter > + > +include ../lib.mk > diff --git a/tools/testing/selftests/connector/proc_filter.c b/tools/testing/selftests/connector/proc_filter.c > new file mode 100644 > index 000000000000..99a382ea2544 > --- /dev/null > +++ b/tools/testing/selftests/connector/proc_filter.c > @@ -0,0 +1,308 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include <sys/types.h> > +#include <sys/epoll.h> > +#include <sys/socket.h> > +#include <linux/netlink.h> > +#include <linux/connector.h> > +#include <linux/cn_proc.h> > + > +#include <stddef.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <strings.h> > +#include <errno.h> > +#include <signal.h> > +#include <string.h> > + > +#include "../kselftest.h" > + > +#define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \ > + sizeof(struct proc_input)) > +#define NL_MESSAGE_SIZE_NF (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \ > + sizeof(int)) > + > +#define MAX_EVENTS 1 > + > +volatile static int interrupted; > +static int nl_sock, ret_errno, tcount; > +static struct epoll_event evn; > + > +static int filter; > + > +#ifdef ENABLE_PRINTS > +#define Printf printf > +#else > +#define Printf ksft_print_msg > +#endif > + > +int send_message(void *pinp) > +{ > + char buff[NL_MESSAGE_SIZE]; > + struct nlmsghdr *hdr; > + struct cn_msg *msg; > + > + hdr = (struct nlmsghdr *)buff; > + if (filter) > + hdr->nlmsg_len = NL_MESSAGE_SIZE; > + else > + hdr->nlmsg_len = NL_MESSAGE_SIZE_NF; > + hdr->nlmsg_type = NLMSG_DONE; > + hdr->nlmsg_flags = 0; > + hdr->nlmsg_seq = 0; > + hdr->nlmsg_pid = getpid(); > + > + msg = (struct cn_msg *)NLMSG_DATA(hdr); > + msg->id.idx = CN_IDX_PROC; > + msg->id.val = CN_VAL_PROC; > + msg->seq = 0; > + msg->ack = 0; > + msg->flags = 0; > + > + if (filter) { > + msg->len = sizeof(struct proc_input); > + ((struct proc_input *)msg->data)->mcast_op = ((struct proc_input *)pinp)->mcast_op; > + ((struct proc_input *)msg->data)->event_type = ((struct proc_input *)pinp)->event_type;
These lines exceed 80 characters.
> + } else { > + msg->len = sizeof(int); > + *(int *)msg->data = *(enum proc_cn_mcast_op *)pinp; > + } > + > + if (send(nl_sock, hdr, hdr->nlmsg_len, 0) == -1) { > + ret_errno = errno; > + perror("send failed"); > + return -3; > + } > + return 0; > +} > + > +int register_proc_netlink(int *efd, void *input) > +{ > + struct sockaddr_nl sa_nl; > + int err = 0, epoll_fd; > + > + nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); > + > + if (nl_sock == -1) { > + ret_errno = errno; > + perror("socket failed"); > + return -1; > + } > + > + bzero(&sa_nl, sizeof(sa_nl)); > + sa_nl.nl_family = AF_NETLINK; > + sa_nl.nl_groups = CN_IDX_PROC; > + sa_nl.nl_pid = getpid(); > + > + if (bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl)) == -1) { > + ret_errno = errno; > + perror("bind failed"); > + return -2; > + } > + > + epoll_fd = epoll_create1(EPOLL_CLOEXEC); > + if (epoll_fd < 0) { > + ret_errno = errno; > + perror("epoll_create1 failed"); > + return -2; > + } > + > + err = send_message(input); > + > + if (err < 0) > + return err; > + > + evn.events = EPOLLIN; > + evn.data.fd = nl_sock; > + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, nl_sock, &evn) < 0) { > + ret_errno = errno; > + perror("epoll_ctl failed"); > + return -3; > + } > + *efd = epoll_fd; > + return 0; > +} > + > +static void sigint(int sig) > +{ > + interrupted = 1; > +} > + > +int handle_packet(char *buff, int fd, struct proc_event *event) > +{ > + struct nlmsghdr *hdr; > + > + hdr = (struct nlmsghdr *)buff; > + > + if (hdr->nlmsg_type == NLMSG_ERROR) { > + perror("NLMSG_ERROR error\n"); > + return -3; > + } else if (hdr->nlmsg_type == NLMSG_DONE) { > + event = (struct proc_event *) > + ((struct cn_msg *)NLMSG_DATA(hdr))->data; > + tcount++; > + switch (event->what) { > + case PROC_EVENT_EXIT: > + Printf("Exit process %d (tgid %d) with code %d, signal %d\n", > + event->event_data.exit.process_pid, > + event->event_data.exit.process_tgid, > + event->event_data.exit.exit_code, > + event->event_data.exit.exit_signal); > + break; > + case PROC_EVENT_FORK: > + Printf("Fork process %d (tgid %d), parent %d (tgid %d)\n", > + event->event_data.fork.child_pid, > + event->event_data.fork.child_tgid, > + event->event_data.fork.parent_pid, > + event->event_data.fork.parent_tgid); > + break; > + case PROC_EVENT_EXEC: > + Printf("Exec process %d (tgid %d)\n", > + event->event_data.exec.process_pid, > + event->event_data.exec.process_tgid); > + break; > + case PROC_EVENT_UID: > + Printf("UID process %d (tgid %d) uid %d euid %d\n", > + event->event_data.id.process_pid, > + event->event_data.id.process_tgid, > + event->event_data.id.r.ruid, > + event->event_data.id.e.euid); > + break; > + case PROC_EVENT_GID: > + Printf("GID process %d (tgid %d) gid %d egid %d\n", > + event->event_data.id.process_pid, > + event->event_data.id.process_tgid, > + event->event_data.id.r.rgid, > + event->event_data.id.e.egid); > + break; > + case PROC_EVENT_SID: > + Printf("SID process %d (tgid %d)\n", > + event->event_data.sid.process_pid, > + event->event_data.sid.process_tgid); > + break; > + case PROC_EVENT_PTRACE: > + Printf("Ptrace process %d (tgid %d), Tracer %d (tgid %d)\n", > + event->event_data.ptrace.process_pid, > + event->event_data.ptrace.process_tgid, > + event->event_data.ptrace.tracer_pid, > + event->event_data.ptrace.tracer_tgid); > + break; > + case PROC_EVENT_COMM: > + Printf("Comm process %d (tgid %d) comm %s\n", > + event->event_data.comm.process_pid, > + event->event_data.comm.process_tgid, > + event->event_data.comm.comm); > + break; > + case PROC_EVENT_COREDUMP: > + Printf("Coredump process %d (tgid %d) parent %d, (tgid %d)\n", > + event->event_data.coredump.process_pid, > + event->event_data.coredump.process_tgid, > + event->event_data.coredump.parent_pid, > + event->event_data.coredump.parent_tgid); > + break; > + default: > + break; > + } > + } > + return 0; > +} > + > +int handle_events(int epoll_fd, struct proc_event *pev) > +{ > + char buff[CONNECTOR_MAX_MSG_SIZE]; > + struct epoll_event ev[MAX_EVENTS]; > + int i, event_count = 0, err = 0; > + > + event_count = epoll_wait(epoll_fd, ev, MAX_EVENTS, -1); > + if (event_count < 0) { > + ret_errno = errno; > + if (ret_errno != EINTR) > + perror("epoll_wait failed"); > + return -3; > + } > + for (i = 0; i < event_count; i++) { > + if (!(ev[i].events & EPOLLIN)) > + continue; > + if (recv(ev[i].data.fd, buff, sizeof(buff), 0) == -1) { > + ret_errno = errno; > + perror("recv failed"); > + return -3; > + } > + err = handle_packet(buff, ev[i].data.fd, pev); > + if (err < 0) > + return err; > + } > + return 0; > +} > + > +int main(int argc, char *argv[]) > +{ > + int epoll_fd, err; > + struct proc_event proc_ev; > + struct proc_input input; > + > + signal(SIGINT, sigint); > + > + if (argc > 2) { > + printf("Expected 0(assume no-filter) or 1 argument(-f)\n"); > + exit(1); > + } > + > + if (argc == 2) { > + if (strcmp(argv[1], "-f") == 0) { > + filter = 1; > + } else { > + printf("Valid option : -f (for filter feature)\n"); > + exit(1); > + } > + } > + > + if (filter) { > + input.event_type = PROC_EVENT_NONZERO_EXIT; > + input.mcast_op = PROC_CN_MCAST_LISTEN; > + err = register_proc_netlink(&epoll_fd, (void*)&input); > + } else { > + enum proc_cn_mcast_op op = PROC_CN_MCAST_LISTEN; > + err = register_proc_netlink(&epoll_fd, (void*)&op); > + } > + > + if (err < 0) {
-2 is ENOENT, -3 is ESRCH (no such process), so I think you won't have collisions with the send_message() returns. Ah, but this is test code so it's probably fine.
> + if (err == -2) > + close(nl_sock); > + if (err == -3) { > + close(nl_sock); > + close(epoll_fd); > + } > + exit(1); > + } > + > + while (!interrupted) { > + err = handle_events(epoll_fd, &proc_ev); > + if (err < 0) { > + if (ret_errno == EINTR) > + continue; > + if (err == -2) > + close(nl_sock); > + if (err == -3) { > + close(nl_sock); > + close(epoll_fd); > + } > + exit(1); > + } > + } > + > + if (filter) { > + input.mcast_op = PROC_CN_MCAST_IGNORE; > + send_message((void*)&input); > + } else { > + enum proc_cn_mcast_op op = PROC_CN_MCAST_IGNORE; > + send_message((void*)&op); > + } > + > + close(epoll_fd); > + close(nl_sock); > + > + printf("Done total count: %d\n", tcount); > + exit(0); > +} > -- > 2.41.0 >
| |