mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Merge tests: add attach_disconnected tests
This test uses unix_fd_server to open a file and pass its file descriptor to the attach_disconnected tests, which then mounts, pivots root and then tries to open the file. Since the server execs the client, this MR also inverts the order of the parameters to allow the server to forward the client's args along with the unix_socket path. I'm also refactoring out the unix_fd_client logic into unix_fd_common, so we can use this implementation when creating other clients, which is the case for the test binary attach_disconnected MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/810 Acked-by: Approved-by: John Johansen <john@jjmx.net> Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
commit
64703c7158
10 changed files with 441 additions and 94 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -216,9 +216,11 @@ utils/vim/apparmor.vim
|
|||
utils/vim/apparmor.vim.5
|
||||
utils/vim/apparmor.vim.5.html
|
||||
utils/vim/pod2htmd.tmp
|
||||
tests/regression/apparmor/*.o
|
||||
tests/regression/apparmor/aa_policy_cache
|
||||
tests/regression/apparmor/access
|
||||
tests/regression/apparmor/at_secure
|
||||
tests/regression/apparmor/attach_disconnected
|
||||
tests/regression/apparmor/changehat
|
||||
tests/regression/apparmor/changehat_fail
|
||||
tests/regression/apparmor/changehat_fork
|
||||
|
@ -233,7 +235,6 @@ tests/regression/apparmor/chgrp
|
|||
tests/regression/apparmor/chmod
|
||||
tests/regression/apparmor/chown
|
||||
tests/regression/apparmor/clone
|
||||
tests/regression/apparmor/dbus_common.o
|
||||
tests/regression/apparmor/dbus_eavesdrop
|
||||
tests/regression/apparmor/dbus_message
|
||||
tests/regression/apparmor/dbus_service
|
||||
|
@ -292,7 +293,6 @@ tests/regression/apparmor/unix_fd_client
|
|||
tests/regression/apparmor/unix_fd_server
|
||||
tests/regression/apparmor/unix_socket
|
||||
tests/regression/apparmor/unix_socket_client
|
||||
tests/regression/apparmor/unix_socket_common.o
|
||||
tests/regression/apparmor/unlink
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
|
|
|
@ -74,6 +74,7 @@ CFLAGS += -g -O0 $(EXTRA_WARNINGS)
|
|||
|
||||
SRC=access.c \
|
||||
at_secure.c \
|
||||
attach_disconnected.c \
|
||||
introspect.c \
|
||||
changeprofile.c \
|
||||
changehat.c \
|
||||
|
@ -200,6 +201,7 @@ EXEC=$(SRC:%.c=%)
|
|||
|
||||
TESTS=aa_exec \
|
||||
access \
|
||||
attach_disconnected \
|
||||
at_secure \
|
||||
introspect \
|
||||
capabilities \
|
||||
|
@ -317,6 +319,15 @@ unix_socket_client: unix_socket_client.c unix_socket_common.o
|
|||
unix_socket: unix_socket.c unix_socket_common.o unix_socket_client
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $(filter-out unix_socket_client, $^) -o $@ ${LDLIBS}
|
||||
|
||||
unix_fd_common.o: unix_fd_common.c unix_fd_common.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $< -c ${LDLIBS}
|
||||
|
||||
unix_fd_client: unix_fd_client.c unix_fd_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
attach_disconnected: attach_disconnected.c unix_fd_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||
|
||||
build-dep:
|
||||
@if [ `whoami` = "root" ] ;\
|
||||
then \
|
||||
|
@ -377,6 +388,6 @@ alltests: all
|
|||
fi
|
||||
|
||||
clean:
|
||||
rm -f $(EXEC) dbus_common.o unix_socket_common.o uservars.inc
|
||||
rm -f $(EXEC) dbus_common.o unix_socket_common.o uservars.inc unix_fd_common.o
|
||||
|
||||
regex.sh: open exec
|
||||
|
|
180
tests/regression/apparmor/attach_disconnected.c
Normal file
180
tests/regression/apparmor/attach_disconnected.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include "unix_fd_common.h"
|
||||
|
||||
struct clone_arg {
|
||||
const char *socket;
|
||||
const char *disk_img;
|
||||
const char *new_root;
|
||||
const char *put_old;
|
||||
};
|
||||
|
||||
static int _pivot_root(const char *new_root, const char *put_old)
|
||||
{
|
||||
#ifdef __NR_pivot_root
|
||||
return syscall(__NR_pivot_root, new_root, put_old);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pivot_and_get_unix_clientfd(void *arg)
|
||||
{
|
||||
int rc;
|
||||
const char *socket = ((struct clone_arg *)arg)->socket;
|
||||
const char *disk_img = ((struct clone_arg *)arg)->disk_img;
|
||||
const char *new_root = ((struct clone_arg *)arg)->new_root;
|
||||
const char *put_old = ((struct clone_arg *)arg)->put_old;
|
||||
|
||||
char *tmp = strdup(put_old);
|
||||
char *put_old_bname = basename(tmp); // don't free
|
||||
|
||||
char *socket_put_old;
|
||||
rc = asprintf(&socket_put_old, "/%s/%s", put_old_bname, socket);
|
||||
if (rc < 0) {
|
||||
perror("FAIL - asprintf socket_put_old");
|
||||
rc = errno;
|
||||
socket_put_old = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mkdir(new_root, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
perror("FAIL - mkdir new_root");
|
||||
rc = 100;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mount(disk_img, new_root, "ext2", 0, NULL);
|
||||
if (rc < 0) {
|
||||
perror("FAIL - mount disk_img");
|
||||
rc = 101;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = chdir(new_root);
|
||||
if (rc < 0) {
|
||||
perror("FAIL - chdir");
|
||||
rc = 102;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mkdir(put_old, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
perror("FAIL - mkdir put_old");
|
||||
rc = 103;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _pivot_root(new_root, put_old);
|
||||
if (rc < 0) {
|
||||
perror("FAIL - pivot_root");
|
||||
rc = 104;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Actual test - it tries to open the socket which is detached.
|
||||
* Only allowed when there's the flag attach_disconnected and/or
|
||||
* attach_disconnected.path is defined.
|
||||
*/
|
||||
rc = get_unix_clientfd(socket_put_old);
|
||||
|
||||
out:
|
||||
free(tmp);
|
||||
free(socket_put_old);
|
||||
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
static pid_t _clone(int (*fn)(void *), void *arg)
|
||||
{
|
||||
size_t stack_size = sysconf(_SC_PAGESIZE);
|
||||
void *stack = alloca(stack_size);
|
||||
|
||||
#ifdef __ia64__
|
||||
return __clone2(fn, stack, stack_size,
|
||||
CLONE_NEWNS | SIGCHLD, arg);
|
||||
#else
|
||||
return clone(fn, stack + stack_size,
|
||||
CLONE_NEWNS | SIGCHLD, arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct clone_arg arg;
|
||||
pid_t child;
|
||||
int child_status, rc;
|
||||
|
||||
if (argc != 5) {
|
||||
fprintf(stderr,
|
||||
"FAIL - usage: %s <UNIX_SOCKET_PATH> <DISK_IMG> <NEW_ROOT> <PUT_OLD>\n\n"
|
||||
" <UNIX_SOCKET_PATH>\tThe path of the unix socket the server will connect to\n"
|
||||
" <DISK_IMG>\t\tThe loop device pointing to the disk image\n"
|
||||
" <NEW_ROOT>\t\tThe new_root param of pivot_root()\n"
|
||||
" <PUT_OLD>\t\tThe put_old param of pivot_root()\n\n"
|
||||
"This program clones itself in a new mount namespace, \n"
|
||||
"does a pivot and then connects to the <UNIX_SOCKET_PATH>.\n"
|
||||
"The test fails if the program does not have attach_disconnected\n"
|
||||
"permission to access the unix_socket which is disconnected.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
arg.socket = argv[1];
|
||||
arg.disk_img = argv[2];
|
||||
arg.new_root = argv[3];
|
||||
arg.put_old = argv[4];
|
||||
|
||||
child = _clone(pivot_and_get_unix_clientfd, &arg);
|
||||
if (child < 0) {
|
||||
perror("FAIL - clone");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
rc = waitpid(child, &child_status, 0);
|
||||
if (rc < 0) {
|
||||
perror("FAIL - waitpid");
|
||||
exit(3);
|
||||
} else if (!WIFEXITED(child_status)) {
|
||||
fprintf(stderr, "FAIL - child didn't exit\n");
|
||||
exit(4);
|
||||
} else if (WEXITSTATUS(child_status)) {
|
||||
/* The child has already printed a FAIL message */
|
||||
exit(WEXITSTATUS(child_status));
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
exit(0);
|
||||
}
|
118
tests/regression/apparmor/attach_disconnected.sh
Normal file
118
tests/regression/apparmor/attach_disconnected.sh
Normal file
|
@ -0,0 +1,118 @@
|
|||
#! /bin/bash
|
||||
# Copyright (C) 2021 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, version 2 of the
|
||||
# License.
|
||||
|
||||
#=NAME attach_disconnected
|
||||
#=DESCRIPTION
|
||||
# This test verifies that the attached_disconnected flag is indeed restricting
|
||||
# access to disconnected paths.
|
||||
#=END
|
||||
|
||||
pwd=`dirname $0`
|
||||
pwd=`cd $pwd ; /bin/pwd`
|
||||
|
||||
bin=$pwd
|
||||
|
||||
. $bin/prologue.inc
|
||||
|
||||
settest unix_fd_server
|
||||
disk_img=$tmpdir/disk_img
|
||||
new_root=$tmpdir/new_root/
|
||||
put_old=${new_root}put_old/
|
||||
root_was_shared="no"
|
||||
fstype="ext2"
|
||||
file=$tmpdir/file
|
||||
socket=$tmpdir/unix_fd_test
|
||||
att_dis_client=$pwd/attach_disconnected
|
||||
|
||||
attach_disconnected_cleanup() {
|
||||
if [ ! -z "$loop_device" ]; then
|
||||
losetup -d $loop_device
|
||||
fi
|
||||
|
||||
mountpoint -q "$new_root"
|
||||
if [ $? -eq 0 ] ; then
|
||||
umount "$new_root"
|
||||
fi
|
||||
|
||||
if [ "$root_was_shared" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as shared'
|
||||
mount --make-shared /
|
||||
fi
|
||||
}
|
||||
do_onexit="attach_disconnected_cleanup"
|
||||
|
||||
if [ ! -b /dev/loop0 ] ; then
|
||||
modprobe loop
|
||||
fi
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root entirely, so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
# no findmnt or findmnt doesn't know the PROPAGATION column,
|
||||
# but init is systemd so assume rootfs is shared
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as private'
|
||||
mount --make-private /
|
||||
fi
|
||||
|
||||
dd if=/dev/zero of="$disk_img" bs=1024 count=512 2> /dev/null
|
||||
/sbin/mkfs -t "$fstype" -F "$disk_img" > /dev/null 2> /dev/null
|
||||
# mounting will be done by the test binary
|
||||
loop_device=$(losetup -fP --show "${disk_img}")
|
||||
|
||||
# content generated with:
|
||||
# dd if=/dev/urandom bs=32 count=4 2> /dev/null | od -x | head -8 | sed -e 's/^[[:xdigit:]]\{7\}//g' -e 's/ //g'
|
||||
# required by unix_fd_server which this test is based on
|
||||
cat > ${file} << EOM
|
||||
4bcd0f741e97195c57f1ff72dbdf2dd9
|
||||
8284a4cd56699628c185f6f647805a1c
|
||||
8bdee094b7e73f9834ada004c570ad49
|
||||
a9a92856edb4a206f271b537fe73081f
|
||||
ac62547499fffd79021898cc8653e36b
|
||||
c943fd5f8f4cfa4690a08505e44b0906
|
||||
7532527375fb6dc0ddadfcb2f1bcdd82
|
||||
150223d965fefe996f8a6c602cc1b514
|
||||
EOM
|
||||
|
||||
do_test()
|
||||
{
|
||||
local desc="ATTACH_DISCONNECTED ($1)"
|
||||
shift
|
||||
runchecktest "$desc" "$@"
|
||||
}
|
||||
|
||||
# Needed for clone(CLONE_NEWNS) and pivot_root()
|
||||
cap=capability:sys_admin
|
||||
file_perm="$file:rw /put_old/$file:rw"
|
||||
create_dir="$new_root:w $put_old:w"
|
||||
|
||||
# Ensure everything works as expected when unconfined
|
||||
do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
genprofile $file_perm unix:create $socket:rw $att_dis_client:px -- image=$att_dis_client $file_perm unix:create $socket:rw $create_dir $cap "pivot_root:ALL" "mount:ALL" flag:attach_disconnected
|
||||
|
||||
do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
genprofile $file_perm unix:create $socket:rw $att_dis_client:px -- image=$att_dis_client $file_perm unix:create $socket:rw $create_dir $cap "pivot_root:ALL" "mount:ALL" flag:no_attach_disconnected
|
||||
|
||||
do_test "no_attach_disconnected" fail $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
# Ensure default is no_attach_disconnected - no flags set
|
||||
genprofile $file_perm unix:create $socket:rw $att_dis_client:px -- image=$att_dis_client $file_perm unix:create $socket:rw $create_dir $cap "pivot_root:ALL" "mount:ALL"
|
||||
|
||||
do_test "no_attach_disconnected" fail $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
# TODO: Add .path to the attach_disconnected flag
|
|
@ -89,7 +89,7 @@ rm -f ${socket}
|
|||
|
||||
genprofile $af_unix $file:$okperm $socket:rw $fd_client:ux
|
||||
|
||||
runchecktest "fd passing; unconfined client" pass $file $socket $fd_client "delete_file"
|
||||
runchecktest "fd passing; unconfined client" pass $file $fd_client $socket "delete_file"
|
||||
|
||||
sleep 1
|
||||
cat > ${file} << EOM
|
||||
|
@ -106,7 +106,7 @@ rm -f ${socket}
|
|||
|
||||
# PASS - confined client, rw access to the file
|
||||
genprofile $af_unix $file:$okperm $socket:rw $fd_client:px -- image=$fd_client $af_unix $file:$okperm $socket:rw
|
||||
runchecktest "fd passing; confined client w/ rw" pass $file $socket $fd_client "delete_file"
|
||||
runchecktest "fd passing; confined client w/ rw" pass $file $fd_client $socket "delete_file"
|
||||
|
||||
sleep 1
|
||||
cat > ${file} << EOM
|
||||
|
@ -123,7 +123,7 @@ rm -f ${socket}
|
|||
# FAIL - confined client, w access to the file
|
||||
|
||||
genprofile $af_unix $file:$okperm $socket:rw $fd_client:px -- image=$fd_client $af_unix $file:$badperm $socket:rw
|
||||
runchecktest "fd passing; confined client w/ w only" fail $file $socket $fd_client "delete_file"
|
||||
runchecktest "fd passing; confined client w/ w only" fail $file $fd_client $socket "delete_file"
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
|
|
@ -9,74 +9,9 @@
|
|||
* License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <alloca.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include "unix_fd_common.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int sock, fd, len;
|
||||
struct sockaddr_un remote;
|
||||
char read_buffer[17], f_buf[255];
|
||||
struct iovec vect;
|
||||
struct msghdr mesg;
|
||||
struct cmsghdr *ctrl_mesg;
|
||||
|
||||
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
fprintf(stderr, "FAIL CLIENT - sock %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
remote.sun_family = AF_UNIX;
|
||||
strcpy(remote.sun_path, argv[1]);
|
||||
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
|
||||
if (connect(sock, (struct sockaddr *)&remote, len) == -1) {
|
||||
fprintf(stderr, "FAIL CLIENT - connect %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vect.iov_base = f_buf;
|
||||
vect.iov_len = 255;
|
||||
|
||||
mesg.msg_name = NULL;
|
||||
mesg.msg_namelen=0;
|
||||
mesg.msg_iov = &vect;
|
||||
mesg.msg_iovlen = 1;
|
||||
|
||||
ctrl_mesg = alloca(sizeof (struct cmsghdr) + sizeof(fd));
|
||||
ctrl_mesg->cmsg_len = sizeof(struct cmsghdr) + sizeof(fd);
|
||||
mesg.msg_control = ctrl_mesg;
|
||||
mesg.msg_controllen = ctrl_mesg->cmsg_len;
|
||||
|
||||
if (!recvmsg(sock, &mesg,0 )) {
|
||||
fprintf(stderr, "FAIL CLIENT - recvmsg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get mr. file descriptor */
|
||||
|
||||
memcpy(&fd, CMSG_DATA(ctrl_mesg), sizeof(fd));
|
||||
|
||||
if (pread(fd, read_buffer, 16, 0) <= 0) {
|
||||
/* Failure */
|
||||
fprintf(stderr, "FAIL CLIENT - could not read\n");
|
||||
send(sock, "FAILFAILFAILFAIL", 16, 0);
|
||||
exit(1);
|
||||
} else {
|
||||
send(sock, read_buffer, strlen(read_buffer),0);
|
||||
}
|
||||
|
||||
/* looks like it worked */
|
||||
exit(0);
|
||||
exit(get_unix_clientfd(argv[1]));
|
||||
}
|
||||
|
|
85
tests/regression/apparmor/unix_fd_common.c
Normal file
85
tests/regression/apparmor/unix_fd_common.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <alloca.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int get_unix_clientfd(char *sun_path) {
|
||||
int sock, fd, len;
|
||||
struct sockaddr_un remote;
|
||||
char read_buffer[17], f_buf[255];
|
||||
struct iovec vect;
|
||||
struct msghdr mesg;
|
||||
struct cmsghdr *ctrl_mesg;
|
||||
|
||||
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
fprintf(stderr, "FAIL CLIENT - sock %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
remote.sun_family = AF_UNIX;
|
||||
strcpy(remote.sun_path, sun_path);
|
||||
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
|
||||
if (connect(sock, (struct sockaddr *)&remote, len) == -1) {
|
||||
fprintf(stderr, "FAIL CLIENT - connect %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
vect.iov_base = f_buf;
|
||||
vect.iov_len = 255;
|
||||
|
||||
mesg.msg_name = NULL;
|
||||
mesg.msg_namelen=0;
|
||||
mesg.msg_iov = &vect;
|
||||
mesg.msg_iovlen = 1;
|
||||
|
||||
ctrl_mesg = alloca(sizeof (struct cmsghdr) + sizeof(fd));
|
||||
ctrl_mesg->cmsg_len = sizeof(struct cmsghdr) + sizeof(fd);
|
||||
mesg.msg_control = ctrl_mesg;
|
||||
mesg.msg_controllen = ctrl_mesg->cmsg_len;
|
||||
|
||||
if (!recvmsg(sock, &mesg,0 )) {
|
||||
fprintf(stderr, "FAIL CLIENT - recvmsg\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get mr. file descriptor */
|
||||
|
||||
memcpy(&fd, CMSG_DATA(ctrl_mesg), sizeof(fd));
|
||||
|
||||
if (pread(fd, read_buffer, 16, 0) <= 0) {
|
||||
/* Failure */
|
||||
fprintf(stderr, "FAIL CLIENT - could not read\n");
|
||||
send(sock, "FAILFAILFAILFAIL", 16, 0);
|
||||
return -1;
|
||||
} else {
|
||||
send(sock, read_buffer, strlen(read_buffer),0);
|
||||
}
|
||||
return 0;
|
||||
}
|
17
tests/regression/apparmor/unix_fd_common.h
Normal file
17
tests/regression/apparmor/unix_fd_common.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Canonical, Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
int get_unix_clientfd(char *sun_path);
|
|
@ -40,8 +40,9 @@ int main (int argc, char * argv[]) {
|
|||
struct cmsghdr *ctrl_mesg;
|
||||
struct pollfd pfd;
|
||||
|
||||
if (argc < 4 || argc > 5 || (argc == 5 && (strcmp(argv[4], "delete_file") != 0))) {
|
||||
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
|
||||
/* The server forwards the client's arguments */
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: %s <file> <client> <unix_socket> [client args ...]\n", argv[0]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
@ -57,7 +58,7 @@ int main (int argc, char * argv[]) {
|
|||
return(1);
|
||||
}
|
||||
|
||||
if (argc == 5) {
|
||||
if (argc == 5 && strcmp(argv[4], "delete_file") == 0) {
|
||||
if (unlink(argv[1]) == -1){
|
||||
fprintf(stderr, "FAIL: unlink before passing fd - %s\n",
|
||||
strerror(errno));
|
||||
|
@ -73,7 +74,7 @@ int main (int argc, char * argv[]) {
|
|||
}
|
||||
|
||||
local.sun_family = AF_UNIX;
|
||||
strcpy(local.sun_path, argv[2]);
|
||||
strcpy(local.sun_path, argv[3]);
|
||||
unlink(local.sun_path);
|
||||
len = strlen(local.sun_path) + sizeof(local.sun_family);
|
||||
|
||||
|
@ -92,7 +93,7 @@ int main (int argc, char * argv[]) {
|
|||
/* exec the client */
|
||||
int pid = fork();
|
||||
if (!pid) {
|
||||
execlp(argv[3], argv[3], argv[2], NULL);
|
||||
execvp(argv[2], &(argv[2]));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -108,8 +109,8 @@ int main (int argc, char * argv[]) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
vect.iov_base = argv[2];
|
||||
vect.iov_len = strlen(argv[2]) + 1;
|
||||
vect.iov_base = argv[3];
|
||||
vect.iov_len = strlen(argv[3]) + 1;
|
||||
|
||||
mesg.msg_name = NULL;
|
||||
mesg.msg_namelen = 0;
|
||||
|
|
|
@ -49,7 +49,7 @@ rm -f ${socket}
|
|||
|
||||
# PASS - unconfined -> unconfined
|
||||
|
||||
runchecktest "fd passing; unconfined -> unconfined" pass $file $socket $fd_client
|
||||
runchecktest "fd passing; unconfined -> unconfined" pass $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -58,7 +58,7 @@ rm -f ${socket}
|
|||
|
||||
genprofile $file:$okperm $af_unix $socket:rw $fd_client:ux
|
||||
|
||||
runchecktest "fd passing; confined -> unconfined" pass $file $socket $fd_client
|
||||
runchecktest "fd passing; confined -> unconfined" pass $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -67,7 +67,7 @@ rm -f ${socket}
|
|||
|
||||
genprofile $file:$badperm $af_unix $socket:rw $fd_client:ux
|
||||
|
||||
runchecktest "fd passing; confined (bad perm) -> unconfined" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined (bad perm) -> unconfined" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -76,7 +76,7 @@ rm -f ${socket}
|
|||
|
||||
genprofile $af_unix $socket:rw $fd_client:ux
|
||||
|
||||
runchecktest "fd passing; confined (no perm) -> unconfined" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined (no perm) -> unconfined" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -84,7 +84,7 @@ rm -f ${socket}
|
|||
# PASS (due to delegation) - unconfined -> confined
|
||||
|
||||
genprofile image=$fd_client $file:$okperm $af_unix $socket:rw
|
||||
runchecktest "fd passing; unconfined -> confined" pass $file $socket $fd_client
|
||||
runchecktest "fd passing; unconfined -> confined" pass $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -92,23 +92,23 @@ rm -f ${socket}
|
|||
# PASS (due to delegation) - unconfined -> confined (no perm)
|
||||
|
||||
genprofile image=$fd_client $af_unix $socket:rw
|
||||
runchecktest "fd passing; unconfined -> confined (no perm)" pass $file $socket $fd_client
|
||||
runchecktest "fd passing; unconfined -> confined (no perm)" pass $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
||||
# PASS - confined -> confined
|
||||
|
||||
echo "PASS-----------------------------------------"
|
||||
genprofile $file:$okperm $af_unix $socket:rw $fd_client:px -- image=$fd_client $file:$okperm $af_unix $socket:rw
|
||||
runchecktest "fd passing; confined -> confined" pass $file $socket $fd_client
|
||||
runchecktest "fd passing; confined -> confined" pass $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
||||
exit
|
||||
# FAIL - confined (bad perm) -> confined
|
||||
|
||||
genprofile $file:$badperm $af_unix $socket:rw $fd_client:px -- image=$fd_client $file:$okperm $af_unix $socket:rw
|
||||
runchecktest "fd passing; confined (bad perm) -> confined" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined (bad perm) -> confined" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -116,7 +116,7 @@ rm -f ${socket}
|
|||
# FAIL - confined (no perm) -> confined
|
||||
|
||||
genprofile $af_unix $socket:rw $fd_client:px -- image=$fd_client $file:$okperm $af_unix $socket:rw
|
||||
runchecktest "fd passing; confined (no perm) -> confined" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined (no perm) -> confined" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -124,7 +124,7 @@ rm -f ${socket}
|
|||
# FAIL - confined -> confined (bad perm)
|
||||
|
||||
genprofile $file:$okperm $af_unix $socket:rw $fd_client:px -- image=$fd_client $file:$badperm $af_unix $socket:rw
|
||||
runchecktest "fd passing; confined -> confined (bad perm)" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined -> confined (bad perm)" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -132,7 +132,7 @@ rm -f ${socket}
|
|||
# FAIL - confined -> confined (no perm)
|
||||
|
||||
genprofile $file:$okperm $af_unix $socket:rw $fd_client:px -- image=$fd_client $af_unix $socket:rw
|
||||
runchecktest "fd passing; confined -> confined (no perm)" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined -> confined (no perm)" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
@ -141,7 +141,7 @@ if [ "$(kernel_features policy/network/af_unix)" == "true" -a "$(parser_supports
|
|||
# FAIL - confined client, no access to the socket file
|
||||
|
||||
genprofile $file:$okperm $af_unix $socket:rw $fd_client:px -- image=$fd_client $file:$okperm $af_unix
|
||||
runchecktest "fd passing; confined client w/o socket access" fail $file $socket $fd_client
|
||||
runchecktest "fd passing; confined client w/o socket access" fail $file $fd_client $socket
|
||||
|
||||
sleep 1
|
||||
rm -f ${socket}
|
||||
|
|
Loading…
Add table
Reference in a new issue