diff --git a/.github/workflows/code-test.yml b/.github/workflows/code-test.yml index 8e22842f45..56d164120b 100644 --- a/.github/workflows/code-test.yml +++ b/.github/workflows/code-test.yml @@ -12,7 +12,7 @@ jobs: - name: Set up Android NDK uses: nttld/setup-ndk@v1 with: - ndk-version: r27c + ndk-version: r28c - name: Install dependencies run: | @@ -21,10 +21,30 @@ jobs: pipx ensurepath pipx install meson==0.61 pipx install ninja + + - name: Download Dependencies + run: | + libssl=$(curl -s https://api.github.com/repos/android-dev-stub/libssl-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libssl_file=$(curl -s https://api.github.com/repos/android-dev-stub/libssl-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libssl} && sudo unzip -q -o ${libssl_file} -d / && echo 1/4 ${libssl} ${libssl_file} + + libcap=$(curl -s https://api.github.com/repos/android-dev-stub/libcap-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libcap_file=$(curl -s https://api.github.com/repos/android-dev-stub/libcap-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libcap} && sudo unzip -q -o ${libcap_file} -d / && echo 2/4 ${libcap} ${libcap_file} + + libselinux=$(curl -s https://api.github.com/repos/android-dev-stub/libselinux-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libselinux_file=$(curl -s https://api.github.com/repos/android-dev-stub/libselinux-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libselinux} && sudo unzip -q -o ${libselinux_file} -d / && echo 3/4 ${libselinux} ${libselinux_file} + libminijail=$(curl -s https://api.github.com/repos/android-dev-stub/libminijail-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libminijail_file=$(curl -s https://api.github.com/repos/android-dev-stub/libminijail-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libminijail} && sudo unzip -q -o ${libminijail_file} -d / && echo 4/4 ${libminijail} ${libminijail_file} + - name: Test build run: | sed -i "s|android-ndk-r27c|$ANDROID_NDK_HOME|g" aarch64-android-api30.txt + export PKG_CONFIG_PATH=/data/sysroot/lib/pkgconfig:$PKG_CONFIG_PATH + export LDFLAGS="-L/data/sysroot/lib -lcap -lselinux -lminijail -lssl" meson setup build \ -Dprefix=/data/share \ @@ -38,11 +58,12 @@ jobs: --localstatedir=/data/share/var \ -Dmemfd-rexec=true \ --buildtype debug \ - -Dcapabilities=false \ + -Dcapabilities=true \ -Dseccomp=false \ - -Dselinux=false \ + -Dseccomp-minijail=true \ + -Dselinux=true \ -Dapparmor=false \ - -Dopenssl=false \ + -Dopenssl=true \ -Ddbus=false \ -Dandroid-log=true \ -Dandroid-audio=true \ @@ -59,8 +80,3 @@ jobs: name: android-aarch64-lxc-shared-api30 path: /data/share/* - - name: Upload artifacts lxc-module - uses: actions/upload-artifact@v4.3.1 - with: - name: android-lxc-module - path: lxc-module.zip diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ddbc226146..a51a03949c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ on: ndk_version: description: 'Android NDK version' required: false - default: 'r27c' + default: 'r29c' jobs: build: @@ -30,30 +30,27 @@ jobs: - name: Download Dependencies run: | - libssl=$(curl -s https://api.github.com/repos/DreamConnected/libopenssl-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') - libssl_file=$(curl -s https://api.github.com/repos/DreamConnected/libopenssl-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') - wget -q ${libssl} && sudo unzip -q -o ${libssl_file} -d / && echo 1/5 ${libssl} ${libssl_file} + libssl=$(curl -s https://api.github.com/repos/android-dev-stub/libssl-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libssl_file=$(curl -s https://api.github.com/repos/android-dev-stub/libssl-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libssl} && sudo unzip -q -o ${libssl_file} -d / && echo 1/4 ${libssl} ${libssl_file} - libcap=$(curl -s https://api.github.com/repos/DreamConnected/AndroidLibcapBuild/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') - libcap_file=$(curl -s https://api.github.com/repos/DreamConnected/AndroidLibcapBuild/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') - wget -q ${libcap} && sudo unzip -q -o ${libcap_file} -d / && echo 2/5 ${libcap} ${libcap_file} + libcap=$(curl -s https://api.github.com/repos/android-dev-stub/libcap-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libcap_file=$(curl -s https://api.github.com/repos/android-dev-stub/libcap-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libcap} && sudo unzip -q -o ${libcap_file} -d / && echo 2/4 ${libcap} ${libcap_file} - libapparmor=$(curl -s https://api.github.com/repos/DreamConnected/libapparmor-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') - libapparmor_file=$(curl -s https://api.github.com/repos/DreamConnected/libapparmor-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') - wget -q ${libapparmor} && sudo unzip -q -o ${libapparmor_file} -d / && echo 3/5 ${libapparmor} ${libapparmor_file} - - libselinux=$(curl -s https://api.github.com/repos/DreamConnected/libselinux-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') - libselinux_file=$(curl -s https://api.github.com/repos/DreamConnected/libselinux-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') - wget -q ${libselinux} && sudo unzip -q -o ${libselinux_file} -d / && echo 4/5 ${libselinux} ${libselinux_file} - - libseccomp=$(curl -s https://api.github.com/repos/DreamConnected/libseccomp-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') - libseccomp_file=$(curl -s https://api.github.com/repos/DreamConnected/libseccomp-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') - wget -q ${libseccomp} && sudo unzip -q -o ${libseccomp_file} -d / && echo 5/5 ${libseccomp} ${libseccomp_file} + libselinux=$(curl -s https://api.github.com/repos/android-dev-stub/libselinux-android-stub-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libselinux_file=$(curl -s https://api.github.com/repos/android-dev-stub/libselinux-android-stub-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libselinux} && sudo unzip -q -o ${libselinux_file} -d / && echo 3/4 ${libselinux} ${libselinux_file} + libminijail=$(curl -s https://api.github.com/repos/android-dev-stub/libminijail-dev/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'zip$') + libminijail_file=$(curl -s https://api.github.com/repos/android-dev-stub/libminijail-dev/releases/latest | grep name | cut -d'"' -f4 |grep -E 'zip$') + wget -q ${libminijail} && sudo unzip -q -o ${libminijail_file} -d / && echo 4/4 ${libminijail} ${libminijail_file} + - name: Build lxc run: | sed -i "s|android-ndk-r27c|$ANDROID_NDK_HOME|g" aarch64-android-api30.txt - export PKG_CONFIG_PATH=/data/sysroot/lib/pkgconfig:/data/sysroot/lib64/pkgconfig:$PKG_CONFIG_PATH + export PKG_CONFIG_PATH=/data/sysroot/lib/pkgconfig:$PKG_CONFIG_PATH + export LDFLAGS="-L/data/sysroot/lib -lcap -lselinux -lminijail -lssl" meson setup build \ -Dprefix=/data/share \ @@ -68,12 +65,15 @@ jobs: -Dmemfd-rexec=false \ --buildtype release \ -Dcapabilities=true \ - -Dseccomp=true \ + -Dseccomp=false \ + -Dseccomp-minijail=true \ -Dselinux=true \ - -Dapparmor=true \ + -Dapparmor=false \ -Dopenssl=true \ -Ddbus=false \ -Dandroid-log=true \ + -Dandroid-audio=false \ + -Dandroid-network=false \ -Dlandlock-monitor=false \ -Dinstall-state-dirs=true \ --cross-file aarch64-android-api30.txt @@ -82,16 +82,10 @@ jobs: sudo /usr/local/bin/ninja -C build install echo "RELEASE_TAG=$(meson introspect meson.build --projectinfo | jq -r '.version')-$(git log -1 --format=%h)" >> $GITHUB_ENV - - name: Upload artifacts sysroot - uses: actions/upload-artifact@v4.3.1 - with: - name: android-${{ github.event.inputs.target_arch || 'aarch64' }}-deps - path: /data/sysroot/* - - name: Upload artifacts lxc uses: actions/upload-artifact@v4.3.1 with: - name: android-${{ github.event.inputs.target_arch || 'aarch64' }}-lxc + name: android-aarch64-lxc path: /data/share/* - name: Upload artifacts lxc-module @@ -102,8 +96,7 @@ jobs: - name: Create a TAR file for artifact run: | - tar -czvf android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-lxc.tar.gz -C /data/share . - tar -czvf android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-sysroot.tar.gz -C /data/sysroot . + tar -czvf android-aarch64-api30-lxc.tar.gz -C /data/share . - name: Create Release and Upload Release Asset uses: softprops/action-gh-release@v1 @@ -114,6 +107,5 @@ jobs: draft: false prerelease: false files: | - android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-lxc.tar.gz - android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-sysroot.tar.gz + android-aarch64-api30-lxc.tar.gz lxc-module.zip diff --git a/config/templates/common.minijail.seccomp b/config/templates/common.minijail.seccomp new file mode 100644 index 0000000000..0d6288a37b --- /dev/null +++ b/config/templates/common.minijail.seccomp @@ -0,0 +1,364 @@ +# Copyright 2026 The ChromiumOS Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +umount2: arg1 in ~0x1 +kexec_load: return 1 +open_by_handle_at: return 1 +init_module: return 1 +finit_module: return 1 +delete_module: return 1 + +read: 1 +write: 1 +open: 1 +close: 1 +stat: 1 +fstat: 1 +lstat: 1 +poll: 1 +lseek: 1 +mmap: 1 +mprotect: 1 +munmap: 1 +brk: 1 +rt_sigaction: 1 +rt_sigprocmask: 1 +rt_sigreturn: 1 +ioctl: 1 +pread64: 1 +pwrite64: 1 +readv: 1 +writev: 1 +access: 1 +pipe: 1 +select: 1 +sched_yield: 1 +mremap: 1 +msync: 1 +mincore: 1 +madvise: 1 +shmget: 1 +shmat: 1 +shmctl: 1 +dup: 1 +dup2: 1 +pause: 1 +nanosleep: 1 +getitimer: 1 +alarm: 1 +setitimer: 1 +getpid: 1 +sendfile: 1 +socket: 1 +connect: 1 +accept: 1 +sendto: 1 +recvfrom: 1 +sendmsg: 1 +recvmsg: 1 +shutdown: 1 +bind: 1 +listen: 1 +getsockname: 1 +getpeername: 1 +socketpair: 1 +setsockopt: 1 +getsockopt: 1 +clone: 1 +fork: 1 +vfork: 1 +execve: 1 +exit: 1 +wait4: 1 +kill: 1 +uname: 1 +semget: 1 +semop: 1 +semctl: 1 +shmdt: 1 +msgget: 1 +msgsnd: 1 +msgrcv: 1 +msgctl: 1 +fcntl: 1 +flock: 1 +fsync: 1 +fdatasync: 1 +truncate: 1 +ftruncate: 1 +getdents: 1 +getcwd: 1 +chdir: 1 +fchdir: 1 +rename: 1 +mkdir: 1 +rmdir: 1 +creat: 1 +link: 1 +unlink: 1 +symlink: 1 +readlink: 1 +chmod: 1 +fchmod: 1 +chown: 1 +fchown: 1 +lchown: 1 +umask: 1 +gettimeofday: 1 +getrlimit: 1 +getrusage: 1 +sysinfo: 1 +times: 1 +ptrace: 1 +getuid: 1 +syslog: 1 +getgid: 1 +setuid: 1 +setgid: 1 +geteuid: 1 +getegid: 1 +setpgid: 1 +getppid: 1 +getpgrp: 1 +setsid: 1 +setreuid: 1 +setregid: 1 +getgroups: 1 +setgroups: 1 +setresuid: 1 +getresuid: 1 +setresgid: 1 +getresgid: 1 +getpgid: 1 +setfsuid: 1 +setfsgid: 1 +getsid: 1 +capget: 1 +capset: 1 +rt_sigpending: 1 +rt_sigtimedwait: 1 +rt_sigqueueinfo: 1 +rt_sigsuspend: 1 +sigaltstack: 1 +utime: 1 +mknod: 1 +uselib: 1 +personality: 1 +ustat: 1 +statfs: 1 +fstatfs: 1 +sysfs: 1 +getpriority: 1 +setpriority: 1 +sched_setparam: 1 +sched_getparam: 1 +sched_setscheduler: 1 +sched_getscheduler: 1 +sched_get_priority_max: 1 +sched_get_priority_min: 1 +sched_rr_get_interval: 1 +mlock: 1 +munlock: 1 +mlockall: 1 +munlockall: 1 +vhangup: 1 +modify_ldt: 1 +pivot_root: 1 +_sysctl: 1 +prctl: 1 +arch_prctl: 1 +adjtimex: 1 +setrlimit: 1 +chroot: 1 +sync: 1 +acct: 1 +settimeofday: 1 +mount: 1 +swapon: 1 +swapoff: 1 +reboot: 1 +sethostname: 1 +setdomainname: 1 +iopl: 1 +ioperm: 1 +create_module: 1 +get_kernel_syms: 1 +query_module: 1 +quotactl: 1 +nfsservctl: 1 +getpmsg: 1 +putpmsg: 1 +afs_syscall: 1 +tuxcall: 1 +security: 1 +gettid: 1 +readahead: 1 +setxattr: 1 +lsetxattr: 1 +fsetxattr: 1 +getxattr: 1 +lgetxattr: 1 +fgetxattr: 1 +listxattr: 1 +llistxattr: 1 +flistxattr: 1 +removexattr: 1 +lremovexattr: 1 +fremovexattr: 1 +tkill: 1 +time: 1 +futex: 1 +sched_setaffinity: 1 +sched_getaffinity: 1 +set_thread_area: 1 +io_setup: 1 +io_destroy: 1 +io_getevents: 1 +io_submit: 1 +io_cancel: 1 +get_thread_area: 1 +lookup_dcookie: 1 +epoll_create: 1 +epoll_ctl_old: 1 +epoll_wait_old: 1 +remap_file_pages: 1 +getdents64: 1 +set_tid_address: 1 +restart_syscall: 1 +semtimedop: 1 +fadvise64: 1 +timer_create: 1 +timer_settime: 1 +timer_gettime: 1 +timer_getoverrun: 1 +timer_delete: 1 +clock_settime: 1 +clock_gettime: 1 +clock_getres: 1 +clock_nanosleep: 1 +exit_group: 1 +epoll_wait: 1 +epoll_ctl: 1 +tgkill: 1 +utimes: 1 +vserver: 1 +mbind: 1 +set_mempolicy: 1 +get_mempolicy: 1 +mq_open: 1 +mq_unlink: 1 +mq_timedsend: 1 +mq_timedreceive: 1 +mq_notify: 1 +mq_getsetattr: 1 +waitid: 1 +add_key: 1 +request_key: 1 +keyctl: 1 +ioprio_set: 1 +ioprio_get: 1 +inotify_init: 1 +inotify_add_watch: 1 +inotify_rm_watch: 1 +migrate_pages: 1 +openat: 1 +mkdirat: 1 +mknodat: 1 +fchownat: 1 +futimesat: 1 +newfstatat: 1 +unlinkat: 1 +renameat: 1 +linkat: 1 +symlinkat: 1 +readlinkat: 1 +fchmodat: 1 +faccessat: 1 +pselect6: 1 +ppoll: 1 +unshare: 1 +set_robust_list: 1 +get_robust_list: 1 +splice: 1 +tee: 1 +vmsplice: 1 +move_pages: 1 +utimensat: 1 +epoll_pwait: 1 +signalfd: 1 +timerfd_create: 1 +eventfd: 1 +fallocate: 1 +timerfd_settime: 1 +timerfd_gettime: 1 +accept4: 1 +signalfd4: 1 +eventfd2: 1 +epoll_create1: 1 +dup3: 1 +pipe2: 1 +inotify_init1: 1 +preadv: 1 +pwritev: 1 +rt_tgsigqueueinfo: 1 +perf_event_open: 1 +recvmmsg: 1 +fanotify_init: 1 +fanotify_mark: 1 +prlimit64: 1 +name_to_handle_at: 1 +clock_adjtime: 1 +syncfs: 1 +sendmmsg: 1 +setns: 1 +getcpu: 1 +process_vm_readv: 1 +process_vm_writev: 1 +kcmp: 1 +sched_setattr: 1 +sched_getattr: 1 +renameat2: 1 +seccomp: 1 +getrandom: 1 +memfd_create: 1 +bpf: 1 +execveat: 1 +userfaultfd: 1 +membarrier: 1 +mlock2: 1 +copy_file_range: 1 +preadv2: 1 +pwritev2: 1 +statx: 1 +io_pgetevents: 1 +rseq: return 1 +pidfd_send_signal: 1 +io_uring_setup: 1 +io_uring_enter: 1 +io_uring_register: 1 +open_tree: 1 +move_mount: 1 +fsopen: 1 +fsconfig: 1 +fsmount: 1 +fspick: 1 +pidfd_open: 1 +clone3: 1 +close_range: 1 +openat2: 1 +pidfd_getfd: 1 +faccessat2: 1 +process_madvise: 1 +epoll_pwait2: 1 +mount_setattr: 1 +quotactl_fd: 1 +landlock_create_ruleset: 1 +landlock_add_rule: 1 +landlock_restrict_self: 1 +memfd_secret: 1 +process_mrelease: 1 +futex_waitv: 1 +set_mempolicy_home_node: 1 +fchmodat2: 1 +sync_file_range: 1 diff --git a/config/templates/meson.build b/config/templates/meson.build index 55fa2f87ed..4263b40029 100644 --- a/config/templates/meson.build +++ b/config/templates/meson.build @@ -1,11 +1,22 @@ # SPDX-License-Identifier: LGPL-2.1+ +if not want_seccomp_minijail lxc_conf_common_seccomp = configure_file( configuration: conf, input: 'common.seccomp', output: 'common.seccomp', install: true, install_dir: lxctemplateconfdir) +endif + +if want_seccomp_minijail +lxc_conf_common_seccomp_minijail = configure_file( + configuration: conf, + input: 'common.minijail.seccomp', + output: 'common.seccomp', + install: true, + install_dir: lxctemplateconfdir) +endif lxc_conf_common_main = configure_file( configuration: conf, diff --git a/meson.build b/meson.build index 4866958fd8..ebbd560053 100644 --- a/meson.build +++ b/meson.build @@ -146,6 +146,7 @@ want_openssl = get_option('openssl') want_selinux = get_option('selinux') want_oss_fuzz = get_option('oss-fuzz') want_seccomp = get_option('seccomp') +want_seccomp_minijail = get_option('seccomp-minijail') want_spec = get_option('specfile') want_state_dirs = get_option('install-state-dirs') want_thread_safety = get_option('thread-safety') @@ -399,8 +400,12 @@ endif threads = dependency('threads') liblxc_dependencies += threads +if want_seccomp and want_seccomp_minijail + error('Cannot enable both seccomp and seccomp_minijail') +endif + ## Seccomp. -if want_seccomp +if want_seccomp and not want_seccomp_minijail libseccomp = dependency('libseccomp', required: false) srcconf.set10('HAVE_SECCOMP', libseccomp.found()) pkgconfig_libs += libseccomp @@ -442,6 +447,16 @@ else srcconf.set10('HAVE_SECCOMP', false) endif +## Seccomp-minijail. +if want_seccomp_minijail and not want_seccomp + libminijail = dependency('libminijail', required: false) + srcconf.set10('HAVE_SECCOMP_MINIJAIL', libminijail.found()) + pkgconfig_libs += libminijail + liblxc_dependencies += libminijail +else + srcconf.set10('HAVE_SECCOMP_MINIJAIL', false) +endif + ## SELinux. if want_selinux libselinux = dependency('libselinux', required: false) diff --git a/meson_options.txt b/meson_options.txt index e1fe6c47b5..393c901ffe 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -84,6 +84,9 @@ option('android-network', type: 'boolean', value: true, option('android-audio', type: 'boolean', value: false, description: 'Use android audio system, for container PulseAudio/PipeWire') +option('seccomp-minijail', type: 'boolean', value: false, + description: 'Using libminijail for seccomp filter instead of libseccomp') + # Paths # was --apparmor-cache-dir in autotools option('apparmor-cache-path', type: 'string', value: 'cache/lxc/apparmor', diff --git a/src/lxc/confile.c b/src/lxc/confile.c index b313114ae5..8985f15b79 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -1246,7 +1246,7 @@ static int set_config_seccomp_notify_proxy(const char *key, const char *value, static int set_config_seccomp_profile(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { -#if HAVE_SECCOMP +#if HAVE_SECCOMP || HAVE_SECCOMP_MINIJAIL return set_config_path_item(&lxc_conf->seccomp.seccomp, value); #else return ret_errno(ENOSYS); diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c index 28269a1650..7b2ec6278a 100644 --- a/src/lxc/lsm/selinux.c +++ b/src/lxc/lsm/selinux.c @@ -35,7 +35,11 @@ static char *selinux_process_label_get(struct lsm_ops *ops, pid_t pid) { char *label; +#if IS_BIONIC + if (getpidcon(pid, &label) < 0) +#else if (getpidcon_raw(pid, &label) < 0) +#endif return log_error_errno(NULL, errno, "failed to get SELinux context for pid %d", pid); return label; @@ -93,9 +97,15 @@ static int selinux_process_label_set(struct lsm_ops *ops, const char *inlabel, return 0; if (on_exec) +#if IS_BIONIC + ret = setexeccon((char *)label); + else + ret = setcon((char *)label); +#else ret = setexeccon_raw((char *)label); else ret = setcon_raw((char *)label); +#endif if (ret < 0) return log_error_errno(-1, errno, "Failed to set SELinux%s context to \"%s\"", on_exec ? " exec" : "", label); @@ -113,7 +123,11 @@ static int selinux_process_label_set(struct lsm_ops *ops, const char *inlabel, */ static int selinux_keyring_label_set(struct lsm_ops *ops, const char *label) { +#if IS_BIONIC + return syswarn_ret(0, "Skiped to set keyring context");; +#else return setkeycreatecon_raw(label); +#endif } static int selinux_prepare(struct lsm_ops *ops, struct lxc_conf *conf, const char *lxcpath) diff --git a/src/lxc/lxcseccomp.h b/src/lxc/lxcseccomp.h index 93ff19ca0e..3d531e7e6c 100644 --- a/src/lxc/lxcseccomp.h +++ b/src/lxc/lxcseccomp.h @@ -17,6 +17,10 @@ #include #endif +#if HAVE_SECCOMP_MINIJAIL +#include +#endif + #include "compiler.h" #include "conf.h" #include "memory_utils.h" @@ -29,7 +33,7 @@ struct lxc_handler; #define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) #endif -#if HAVE_SECCOMP +#if HAVE_SECCOMP || HAVE_SECCOMP_MINIJAIL #if HAVE_DECL_SECCOMP_NOTIFY_FD @@ -74,6 +78,10 @@ struct lxc_seccomp { #if HAVE_DECL_SECCOMP_NOTIFY_FD struct seccomp_notify notifier; #endif /* HAVE_DECL_SECCOMP_NOTIFY_FD */ + +#if HAVE_SECCOMP_MINIJAIL + struct minijail *minijail; +#endif /* HAVE_SECCOMP_MINIJAIL */ }; __hidden extern int lxc_seccomp_load(struct lxc_conf *conf); diff --git a/src/lxc/meson.build b/src/lxc/meson.build index 94629aa9f6..3ece8e25b4 100644 --- a/src/lxc/meson.build +++ b/src/lxc/meson.build @@ -194,6 +194,10 @@ if want_seccomp and libseccomp.found() liblxc_sources += files('seccomp.c') endif +if want_seccomp_minijail and libminijail.found() + liblxc_sources += files('seccomp_minijail.c') +endif + if want_selinux and libselinux.found() liblxc_sources += files('lsm/selinux.c') endif diff --git a/src/lxc/seccomp_minijail.c b/src/lxc/seccomp_minijail.c new file mode 100644 index 0000000000..d424142afc --- /dev/null +++ b/src/lxc/seccomp_minijail.c @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "config.h" + +#include + +#include "log.h" +#include "mainloop.h" +#include "lxcseccomp.h" + +#undef ARRAY_SIZE +#include + +lxc_log_define(seccomp_minijail, lxc); + +#define MAX_CGROUPS 10 /* 10 different controllers supported by Linux. */ +#define MAX_RLIMITS 32 /* Currently there are 15 supported by Linux. */ +#define MAX_PRESERVED_FDS 128U + +struct minijail_rlimit { + int type; + rlim_t cur; + rlim_t max; +}; + +struct preserved_fd { + int parent_fd; + int child_fd; +}; + +struct minijail { + /* + * WARNING: new bool flags should always be added to this struct, + * unless you’re certain they don’t need to remain after marshaling. + * If you add a flag here you need to make sure it's + * accounted for in minijail_pre{enter|exec}() below. + */ + struct { + bool uid : 1; + bool gid : 1; + bool inherit_suppl_gids : 1; + bool set_suppl_gids : 1; + bool keep_suppl_gids : 1; + bool use_caps : 1; + bool capbset_drop : 1; + bool set_ambient_caps : 1; + bool vfs : 1; + bool enter_vfs : 1; + bool pids : 1; + bool ipc : 1; + bool uts : 1; + bool net : 1; + bool net_loopback : 1; + bool enter_net : 1; + bool ns_cgroups : 1; + bool userns : 1; + bool disable_setgroups : 1; + bool seccomp : 1; + bool remount_proc_ro : 1; + bool no_new_privs : 1; + bool seccomp_filter : 1; + bool seccomp_filter_tsync : 1; + bool seccomp_filter_logging : 1; + bool seccomp_filter_allow_speculation : 1; + bool chroot : 1; + bool pivot_root : 1; + bool mount_dev : 1; + bool mount_tmp : 1; + bool do_init : 1; + bool run_as_init : 1; + bool pid_file : 1; + bool cgroups : 1; + bool alt_syscall : 1; + bool reset_signal_mask : 1; + bool reset_signal_handlers : 1; + bool close_open_fds : 1; + bool new_session_keyring : 1; + bool forward_signals : 1; + bool setsid : 1; + bool using_minimalistic_mountns : 1; + bool enable_fs_restrictions : 1; + bool enable_profile_fs_restrictions : 1; + bool enable_default_runtime : 1; + bool enable_new_sessions : 1; + } flags; + uid_t uid; + gid_t gid; + gid_t usergid; + char *user; + size_t suppl_gid_count; + gid_t *suppl_gid_list; + uint64_t caps; + uint64_t cap_bset; + pid_t initpid; + int mountns_fd; + int netns_fd; + int fs_rules_fd; + int fs_rules_landlock_abi; + char *chrootdir; + char *pid_file_path; + char *uidmap; + char *gidmap; + char *hostname; + char *preload_path; + /* + * Filename that will be executed, unless an ELF fd is used instead. + * This field is only used for logs and isn't included in marshaling. + */ + char *filename; + size_t filter_len; + struct sock_fprog *filter_prog; + char *alt_syscall_table; + struct mountpoint *mounts_head; + struct mountpoint *mounts_tail; + size_t mounts_count; + unsigned long remount_mode; + struct minijail_remount *remounts_head; + struct minijail_remount *remounts_tail; + size_t tmpfs_size; + struct fs_rule *fs_rules_head; + struct fs_rule *fs_rules_tail; + size_t fs_rules_count; + char *cgroups[MAX_CGROUPS]; + size_t cgroup_count; + struct minijail_rlimit rlimits[MAX_RLIMITS]; + size_t rlimit_count; + uint64_t securebits_skip_mask; + struct hook *hooks_head; + struct hook *hooks_tail; + struct preserved_fd preserved_fds[MAX_PRESERVED_FDS]; + size_t preserved_fd_count; + char *seccomp_policy_path; +}; + +void seccomp_conf_init(struct lxc_conf *conf) +{ + conf->seccomp.seccomp = NULL; + conf->seccomp.minijail = minijail_new(); +} + +int parse_config(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf) +{ + int ret = 0; + char cn[256]; + + while (fgets(line, 1024, f) != NULL) { + if (line[0] == '#' || line[0] == '\n') + continue; + + if (sscanf(line, "%255[^:]", cn) >= 2) { + ERROR("Failed to parse line: %s", line); + ret = -1; + break; + } + + int syscall_nr = lookup_syscall(cn, NULL); + if (syscall_nr < 0) { + WARN("Unknown syscall '%s' in seccomp policy", cn); + continue; + } + } + + return ret; +} + +int lxc_read_seccomp_config(struct lxc_conf *conf) +{ + __do_fclose FILE *f = NULL; + char line[1024]; + size_t line_bufsz = 0; + + if (!conf->seccomp.seccomp) + return 0; + + if (!conf->seccomp.minijail) { + ERROR("Failed initializing seccomp"); + return -1; + } + + f = fopen(conf->seccomp.seccomp, "re"); + if (!f) { + SYSERROR("Failed to open seccomp policy file %s", conf->seccomp.seccomp); + return -1; + } + + if (parse_config(f, line, &line_bufsz, conf) != 0) { + ERROR("Failed parse seccomp conf"); + return -1; + } + + rewind(f); + + minijail_log_to_fd(STDERR_FILENO, ANDROID_LOG_UNKNOWN); + minijail_log_seccomp_filter_failures(conf->seccomp.minijail); + //minijail_set_seccomp_filter_tsync(conf->seccomp.minijail); + minijail_use_seccomp_filter(conf->seccomp.minijail); + minijail_parse_seccomp_filters(conf->seccomp.minijail, conf->seccomp.seccomp); + + conf->seccomp.minijail->flags.no_new_privs = 1; + //conf->seccomp.minijail->flags.seccomp_filter_logging = 1; + conf->seccomp.minijail->flags.setsid = 1; + conf->seccomp.minijail->flags.enable_new_sessions = 1; + + return 0; +} + +int lxc_seccomp_load(struct lxc_conf *conf) +{ + if (!conf->seccomp.seccomp) + return 0; + + minijail_enter(conf->seccomp.minijail); + return 0; +} + +void lxc_seccomp_free(struct lxc_seccomp *seccomp) +{ + free_disarm(seccomp->seccomp); + minijail_destroy(seccomp->minijail); +} + +int seccomp_notify_handler(int fd, uint32_t events, void *data, + struct lxc_async_descr *descr) +{ + return LXC_MAINLOOP_CONTINUE; +} + +int seccomp_notify_cleanup_handler(int fd, void *data) +{ + return 0; +} + +int lxc_seccomp_setup_proxy(struct lxc_seccomp *seccomp, + struct lxc_async_descr *descr, + struct lxc_handler *handler) +{ + return 0; +} + +int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd) +{ + return 0; +} + +int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd) +{ + return 0; +} + +int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, + struct lxc_seccomp *seccomp) +{ + return 0; +}