diff --git a/binfmt/CMakeLists.txt b/binfmt/CMakeLists.txt index 0f0578ebce3..1af4cd3042b 100644 --- a/binfmt/CMakeLists.txt +++ b/binfmt/CMakeLists.txt @@ -41,6 +41,10 @@ list( binfmt_copyactions.c binfmt_dumpmodule.c) +if(CONFIG_SCHED_USER_IDENTITY) + list(APPEND SRCS binfmt_checkexec.c) +endif() + if(CONFIG_BINFMT_LOADABLE) list(APPEND SRCS binfmt_exit.c) endif() diff --git a/binfmt/Makefile b/binfmt/Makefile index e88e1a9c27e..31d84b1d50c 100644 --- a/binfmt/Makefile +++ b/binfmt/Makefile @@ -28,6 +28,10 @@ CSRCS = binfmt_globals.c binfmt_initialize.c binfmt_register.c binfmt_unregiste CSRCS += binfmt_loadmodule.c binfmt_unloadmodule.c binfmt_execmodule.c CSRCS += binfmt_exec.c binfmt_copyargv.c binfmt_copyactions.c binfmt_dumpmodule.c +ifeq ($(CONFIG_SCHED_USER_IDENTITY),y) +CSRCS += binfmt_checkexec.c +endif + ifeq ($(CONFIG_BINFMT_LOADABLE),y) CSRCS += binfmt_exit.c endif diff --git a/binfmt/binfmt.h b/binfmt/binfmt.h index 3cdf07ecbfa..c362bf041c6 100644 --- a/binfmt/binfmt.h +++ b/binfmt/binfmt.h @@ -213,6 +213,26 @@ void binfmt_freeactions(FAR const posix_spawn_file_actions_t *copy); # define binfmt_freeactions(copy) #endif +#ifdef CONFIG_SCHED_USER_IDENTITY +/**************************************************************************** + * Name: binfmt_checkexecperm + * + * Description: + * Verify that the calling task has execute permission on the file + * described by 'bin'. The file owner, group, and mode must already be + * populated in the binary_s structure. + * + * Input Parameters: + * bin - Load structure with uid, gid, and mode populated + * + * Returned Value: + * Zero (OK) on success; -EACCES if execute permission is denied. + * + ****************************************************************************/ + +int binfmt_checkexecperm(FAR struct binary_s *bin); +#endif + #ifdef CONFIG_BUILTIN /**************************************************************************** * Name: builtin_initialize diff --git a/binfmt/binfmt_checkexec.c b/binfmt/binfmt_checkexec.c new file mode 100644 index 00000000000..1436298dc24 --- /dev/null +++ b/binfmt/binfmt_checkexec.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * binfmt/binfmt_checkexec.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "binfmt.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: binfmt_checkexecperm + * + * Description: + * Verify that the calling task has execute permission on the file + * described by 'bin'. The file owner, group, and mode must already be + * populated in the binary_s structure before calling this function. + * + * Input Parameters: + * bin - Pointer to the binary descriptor with uid, gid, and mode set. + * + * Returned Value: + * Zero (OK) on success; -EACCES if execute permission is denied. + * + ****************************************************************************/ + +int binfmt_checkexecperm(FAR struct binary_s *bin) +{ + FAR struct tcb_s *rtcb; + mode_t xbits; + + rtcb = nxsched_self(); + + if (bin == NULL || rtcb == NULL || rtcb->group == NULL) + { + return OK; + } + + if (rtcb->group->tg_euid == 0) + { + /* Root can execute any file that has at least one execute bit set */ + + if ((bin->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) + { + return -EACCES; + } + + return OK; + } + + if (rtcb->group->tg_euid == bin->uid) + { + xbits = S_IXUSR; + } + else if (rtcb->group->tg_egid == bin->gid) + { + xbits = S_IXGRP; + } + else + { + xbits = S_IXOTH; + } + + if ((bin->mode & xbits) == 0) + { + return -EACCES; + } + + return OK; +} diff --git a/binfmt/binfmt_exec.c b/binfmt/binfmt_exec.c index c2c73ee876b..ae3e4643b1e 100644 --- a/binfmt/binfmt_exec.c +++ b/binfmt/binfmt_exec.c @@ -31,7 +31,6 @@ #include #include -#include #include #include "binfmt.h" @@ -81,11 +80,13 @@ static int exec_internal(FAR const char *filename, FAR const posix_spawnattr_t *attr, bool spawn) { FAR struct binary_s *bin; - int pid; - int ret; #ifndef CONFIG_BINFMT_LOADABLE struct binary_s sbin; +#endif + int pid; + int ret; +#ifndef CONFIG_BINFMT_LOADABLE bin = &sbin; memset(bin, 0, sizeof(*bin)); #else diff --git a/binfmt/binfmt_loadmodule.c b/binfmt/binfmt_loadmodule.c index 4d5f9416de0..06d56c0c9b5 100644 --- a/binfmt/binfmt_loadmodule.c +++ b/binfmt/binfmt_loadmodule.c @@ -134,6 +134,14 @@ static int load_absmodule(FAR struct binary_s *bin, FAR const char *filename, binfmt_dumpmodule(bin); break; } + else if (ret == -EACCES) + { + /* Access explicitly denied -- stop here; do not let a fallback + * loader bypass the execute-permission check that already ran. + */ + + break; + } } return ret; diff --git a/binfmt/builtin.c b/binfmt/builtin.c index b2116806f46..5ec818b3dd9 100644 --- a/binfmt/builtin.c +++ b/binfmt/builtin.c @@ -34,6 +34,8 @@ #include #include +#include "binfmt.h" + #ifdef CONFIG_BUILTIN /**************************************************************************** @@ -76,6 +78,9 @@ static int builtin_loadbinary(FAR struct binary_s *binp, FAR const struct builtin_s *builtin; FAR char *name; int index; +#ifdef CONFIG_SCHED_USER_IDENTITY + int chk; +#endif binfo("Loading file: %s\n", filename); @@ -105,14 +110,21 @@ static int builtin_loadbinary(FAR struct binary_s *binp, return -ENOENT; } +#ifdef CONFIG_SCHED_USER_IDENTITY + binp->uid = builtin->uid; + binp->gid = builtin->gid; + binp->mode = builtin->mode; + + chk = binfmt_checkexecperm(binp); + if (chk < 0) + { + return chk; + } +#endif + binp->entrypt = builtin->main; binp->stacksize = builtin->stacksize; binp->priority = builtin->priority; -#ifdef CONFIG_SCHED_USER_IDENTITY - binp->uid = builtin->uid; - binp->gid = builtin->gid; - binp->mode = builtin->mode; -#endif return OK; } diff --git a/binfmt/elf.c b/binfmt/elf.c index 087c73589ae..cfe146cb26e 100644 --- a/binfmt/elf.c +++ b/binfmt/elf.c @@ -37,6 +37,8 @@ #include #include +#include "binfmt.h" + #ifdef CONFIG_ELF /**************************************************************************** @@ -110,6 +112,20 @@ static int elf_loadbinary(FAR struct binary_s *binp, goto errout_with_init; } +#ifdef CONFIG_SCHED_USER_IDENTITY + /* Save IDs and mode from file system before loading segments */ + + binp->uid = loadinfo.fileuid; + binp->gid = loadinfo.filegid; + binp->mode = loadinfo.filemode; + + ret = binfmt_checkexecperm(binp); + if (ret < 0) + { + goto errout_with_init; + } +#endif + /* Load the program binary */ ret = libelf_load_with_addrenv(&loadinfo); @@ -201,14 +217,6 @@ static int elf_loadbinary(FAR struct binary_s *binp, binp->mod.nfini = loadinfo.nfini; #endif -#ifdef CONFIG_SCHED_USER_IDENTITY - /* Save IDs and mode from file system */ - - binp->uid = loadinfo.fileuid; - binp->gid = loadinfo.filegid; - binp->mode = loadinfo.filemode; -#endif - libelf_dumpentrypt(&loadinfo); #ifdef CONFIG_PIC if (loadinfo.gotindex >= 0) diff --git a/binfmt/nxflat.c b/binfmt/nxflat.c index 010cf42546a..f390e5081f5 100644 --- a/binfmt/nxflat.c +++ b/binfmt/nxflat.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -36,10 +37,13 @@ #include +#include #include #include #include +#include "binfmt.h" + #ifdef CONFIG_NXFLAT /**************************************************************************** @@ -142,6 +146,9 @@ static int nxflat_loadbinary(FAR struct binary_s *binp, int nexports) { struct nxflat_loadinfo_s loadinfo; /* Contains globals for libnxflat */ +#ifdef CONFIG_SCHED_USER_IDENTITY + struct stat st; +#endif int ret; binfo("Loading file: %s\n", filename); @@ -156,6 +163,25 @@ static int nxflat_loadbinary(FAR struct binary_s *binp, goto errout; } +#ifdef CONFIG_SCHED_USER_IDENTITY + ret = file_fstat(&loadinfo.file, &st); + if (ret < 0) + { + berr("Failed to stat NXFLAT program binary: %d\n", ret); + goto errout_with_init; + } + + binp->uid = st.st_uid; + binp->gid = st.st_gid; + binp->mode = st.st_mode; + + ret = binfmt_checkexecperm(binp); + if (ret < 0) + { + goto errout_with_init; + } +#endif + /* Load the program binary */ ret = nxflat_load(&loadinfo);