Page MenuHomeFreeBSD

D9030.diff
No OneTemporary

D9030.diff

Index: include/unistd.h
===================================================================
--- include/unistd.h
+++ include/unistd.h
@@ -431,6 +431,7 @@
int faccessat(int, const char *, int, int);
int fchownat(int, const char *, uid_t, gid_t, int);
int fexecve(int, char *const [], char *const []);
+int ffexecve(int, int, char *const [], char *const []);
int linkat(int, const char *, int, const char *, int);
ssize_t readlinkat(int, const char * __restrict, char * __restrict, size_t);
int symlinkat(const char *, int, const char *);
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -366,7 +366,8 @@
cpuset.2 cpuset_setid.2
MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2
MLINKS+=dup.2 dup2.2
-MLINKS+=execve.2 fexecve.2
+MLINKS+=execve.2 fexecve.2 \
+ execve.2 ffexecve.2
MLINKS+=extattr_get_file.2 extattr.2 \
extattr_get_file.2 extattr_delete_fd.2 \
extattr_get_file.2 extattr_delete_file.2 \
Index: lib/libc/sys/execve.2
===================================================================
--- lib/libc/sys/execve.2
+++ lib/libc/sys/execve.2
@@ -33,7 +33,8 @@
.Os
.Sh NAME
.Nm execve ,
-.Nm fexecve
+.Nm fexecve,
+.Nm ffexecve
.Nd execute a file
.Sh LIBRARY
.Lb libc
@@ -43,6 +44,8 @@
.Fn execve "const char *path" "char *const argv[]" "char *const envp[]"
.Ft int
.Fn fexecve "int fd" "char *const argv[]" "char *const envp[]"
+.Ft int
+.Fn ffexecve "int interp" "int fd" "char *const argv[]" "char *const envp[]"
.Sh DESCRIPTION
The
.Fn execve
@@ -62,6 +65,15 @@
.Fa fd
instead of a
.Fa path .
+The
+.Fn ffexecve
+system call is equivalent to
+.Fn fexecve
+except that the run-time linker for the file is specified explicitly
+by the file descriptor
+.Fa interp
+instead of implicitly via the kernel's default logic
+(e.g., using the run-time linker specified in an ELF program header).
This file is either an executable object file,
or a file of data for an interpreter.
An executable object file consists of an identifying header,
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1084,3 +1084,5 @@
id_t id, \
const struct vm_domain_policy *policy); }
550 AUE_FSYNC NOPROTO { int fdatasync(int fd); }
+551 AUE_NULL STD { int ffexecve(int rtld, int bin, char **argv, \
+ char **envv); }
Index: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf
+++ sys/kern/capabilities.conf
@@ -176,6 +176,7 @@
## such as disallowing privilege escalation.
##
fexecve
+ffexecve
##
## Allow flock(2), subject to capability rights.
Index: sys/kern/imgact_aout.c
===================================================================
--- sys/kern/imgact_aout.c
+++ sys/kern/imgact_aout.c
@@ -166,6 +166,14 @@
int error;
/*
+ * The a.out image activator doesn't support an explicit interpreter
+ * (or any interpreter, for that matter).
+ */
+ if (imgp->args->interpreter != -1) {
+ return (ENOEXEC);
+ }
+
+ /*
* Linux and *BSD binaries look very much alike,
* only the machine id is different:
* 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
Index: sys/kern/imgact_binmisc.c
===================================================================
--- sys/kern/imgact_binmisc.c
+++ sys/kern/imgact_binmisc.c
@@ -583,6 +583,13 @@
struct sbuf *sname;
char *s, *d;
+ /*
+ * This image activator doesn't support an explicit interpreter.
+ */
+ if (imgp->args->interpreter != -1) {
+ return (EINVAL);
+ }
+
/* Do we have an interpreter for the given image header? */
sx_slock(&interp_list_sx);
if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) {
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -89,8 +89,10 @@
static int __elfN(check_header)(const Elf_Ehdr *hdr);
static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp,
const char *interp, int interp_name_len, int32_t *osrel);
-static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr,
+static int __elfN(load_file)(struct proc *p, struct vnode *vp, u_long *addr,
u_long *entry, size_t pagesize);
+static int __elfN(load_path)(struct proc *p, const char *path, u_long *addr,
+ u_long *entry, size_t pagesize);
static int __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset,
caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot,
size_t pagesize);
@@ -642,17 +644,15 @@
* the entry point for the loaded file.
*/
static int
-__elfN(load_file)(struct proc *p, const char *file, u_long *addr,
+__elfN(load_file)(struct proc *p, struct vnode *vp, u_long *addr,
u_long *entry, size_t pagesize)
{
struct {
- struct nameidata nd;
struct vattr attr;
struct image_params image_params;
} *tempdata;
const Elf_Ehdr *hdr = NULL;
const Elf_Phdr *phdr = NULL;
- struct nameidata *nd;
struct vattr *attr;
struct image_params *imgp;
vm_prot_t prot;
@@ -660,17 +660,7 @@
u_long base_addr = 0;
int error, i, numsegs;
-#ifdef CAPABILITY_MODE
- /*
- * XXXJA: This check can go away once we are sufficiently confident
- * that the checks in namei() are correct.
- */
- if (IN_CAPABILITY_MODE(curthread))
- return (ECAPMODE);
-#endif
-
tempdata = malloc(sizeof(*tempdata), M_TEMP, M_WAITOK);
- nd = &tempdata->nd;
attr = &tempdata->attr;
imgp = &tempdata->image_params;
@@ -683,14 +673,7 @@
imgp->image_header = NULL;
imgp->object = NULL;
imgp->execlabel = NULL;
-
- NDINIT(nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE, file, curthread);
- if ((error = namei(nd)) != 0) {
- nd->ni_vp = NULL;
- goto fail;
- }
- NDFREE(nd, NDF_ONLY_PNBUF);
- imgp->vp = nd->ni_vp;
+ imgp->vp = vp;
/*
* Check permissions, modes, uid, etc on the file, and "open" it.
@@ -707,9 +690,9 @@
* Also make certain that the interpreter stays the same, so set
* its VV_TEXT flag, too.
*/
- VOP_SET_TEXT(nd->ni_vp);
+ VOP_SET_TEXT(vp);
- imgp->object = nd->ni_vp->v_object;
+ imgp->object = vp->v_object;
hdr = (const Elf_Ehdr *)imgp->image_header;
if ((error = __elfN(check_header)(hdr)) != 0)
@@ -762,17 +745,47 @@
if (imgp->firstpage)
exec_unmap_first_page(imgp);
- if (nd->ni_vp)
- vput(nd->ni_vp);
-
+ vput(vp);
free(tempdata, M_TEMP);
return (error);
}
+/*
+ * Load a file into memory as specified by a path.
+ */
+static int
+__elfN(load_path)(struct proc *p, const char *path, u_long *addr,
+ u_long *entry, size_t pagesize)
+{
+ struct nameidata nd;
+ struct vnode *vp = NULL;
+ int error;
+
+#ifdef CAPABILITY_MODE
+ /*
+ * XXXJA: This check can go away once we are sufficiently confident
+ * that the checks in namei() are correct.
+ */
+ if (IN_CAPABILITY_MODE(curthread))
+ return (ECAPMODE);
+#endif
+
+ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE, path, curthread);
+ error = namei(&nd);
+ vp = nd.ni_vp;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (error != 0) {
+ return (error);
+ }
+
+ return __elfN(load_file)(p, vp, addr, entry, pagesize);
+}
+
static int
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
{
+ cap_rights_t rights;
struct thread *td;
const Elf_Ehdr *hdr;
const Elf_Phdr *phdr;
@@ -786,7 +799,7 @@
u_long text_size, data_size, total_size, text_addr, data_addr;
u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr;
int32_t osrel;
- int error, i, n, interp_name_len, have_interp;
+ int error, i, n, interp_fd, interp_name_len, have_interp;
hdr = (const Elf_Ehdr *)imgp->image_header;
@@ -836,6 +849,10 @@
break;
case PT_INTERP:
/* Path to interpreter */
+ if (interp != NULL) {
+ /* ffexecve() is overriding the interpreter */
+ break;
+ }
if (phdr[i].p_filesz > MAXPATHLEN) {
uprintf("Invalid PT_INTERP\n");
error = ENOEXEC;
@@ -1031,12 +1048,32 @@
if (interp != NULL) {
have_interp = FALSE;
VOP_UNLOCK(imgp->vp, 0);
- if (brand_info->emul_path != NULL &&
+ if ((interp_fd = imgp->args->interpreter) != -1) {
+ /* ffexecve() is overriding the interpreter */
+ error = fgetvp_exec(td, interp_fd,
+ cap_rights_init(&rights, CAP_FEXECVE), &imgp->vp);
+ if (error) {
+ uprintf("failed getting interpreter from FD %d",
+ interp_fd);
+ goto ret;
+ }
+
+ error = vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
+ if (error) {
+ goto ret;
+ }
+
+ error = __elfN(load_file)(imgp->proc, imgp->vp, &addr,
+ &imgp->entry_addr, sv->sv_pagesize);
+ if (error == 0)
+ have_interp = TRUE;
+ }
+ if (!have_interp && brand_info->emul_path != NULL &&
brand_info->emul_path[0] != '\0') {
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
snprintf(path, MAXPATHLEN, "%s%s",
brand_info->emul_path, interp);
- error = __elfN(load_file)(imgp->proc, path, &addr,
+ error = __elfN(load_path)(imgp->proc, path, &addr,
&imgp->entry_addr, sv->sv_pagesize);
free(path, M_TEMP);
if (error == 0)
@@ -1045,13 +1082,13 @@
if (!have_interp && newinterp != NULL &&
(brand_info->interp_path == NULL ||
strcmp(interp, brand_info->interp_path) == 0)) {
- error = __elfN(load_file)(imgp->proc, newinterp, &addr,
+ error = __elfN(load_path)(imgp->proc, newinterp, &addr,
&imgp->entry_addr, sv->sv_pagesize);
if (error == 0)
have_interp = TRUE;
}
if (!have_interp) {
- error = __elfN(load_file)(imgp->proc, interp, &addr,
+ error = __elfN(load_path)(imgp->proc, interp, &addr,
&imgp->entry_addr, sv->sv_pagesize);
}
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
Index: sys/kern/imgact_gzip.c
===================================================================
--- sys/kern/imgact_gzip.c
+++ sys/kern/imgact_gzip.c
@@ -76,6 +76,13 @@
struct inflate infl;
struct vmspace *vmspace;
+ /*
+ * This image activator doesn't support an explicit interpreter.
+ */
+ if (imgp->args->interpreter != -1) {
+ return (EINVAL);
+ }
+
/* If these four are not OK, it isn't a gzip file */
if (p[0] != 0x1f)
return -1; /* 0 Simply magic */
Index: sys/kern/imgact_shell.c
===================================================================
--- sys/kern/imgact_shell.c
+++ sys/kern/imgact_shell.c
@@ -107,6 +107,14 @@
struct vattr vattr;
struct sbuf *sname;
+ /*
+ * This image activator doesn't support an explicit interpreter.
+ * TODO(JA): consider adding support for an explicit shell interpreter
+ */
+ if (imgp->args->interpreter != -1) {
+ return (EINVAL);
+ }
+
/* a shell script? */
if (((const short *)image_header)[0] != SHELLMAGIC)
return (-1);
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -252,6 +252,35 @@
}
#ifndef _SYS_SYSPROTO_H_
+struct ffexecve_args {
+ int interpreter;
+ int fd;
+ char **argv;
+ char **envv;
+}
+#endif
+int
+sys_ffexecve(struct thread *td, struct ffexecve_args *uap)
+{
+ struct image_args args;
+ struct vmspace *oldvmspace;
+ int error;
+
+ error = pre_execve(td, &oldvmspace);
+ if (error != 0)
+ return (error);
+ error = exec_copyin_args(&args, NULL, UIO_SYSSPACE,
+ uap->argv, uap->envv);
+ if (error == 0) {
+ args.interpreter = uap->interpreter;
+ args.fd = uap->fd;
+ error = kern_execve(td, &args, NULL);
+ }
+ post_execve(td, error, oldvmspace);
+ return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
struct __mac_execve_args {
char *fname;
char **argv;
@@ -498,7 +527,8 @@
* so that it can be used by process_exec handlers to determine
* credential/setid changes.
*
- * Don't honor setuid/setgid if the filesystem prohibits it or if
+ * Don't honor setuid/setgid if the filesystem prohibits it, if
+ * employing a user-specified run-time interpreter or if
* the process is being traced.
*
* We disable setuid/setgid/etc in capability mode on the basis
@@ -523,6 +553,7 @@
#endif
if (credential_changing &&
+ (imgp->args->interpreter == -1) &&
#ifdef CAPABILITY_MODE
((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) &&
#endif
@@ -1172,6 +1203,11 @@
return (EFAULT);
/*
+ * Don't override the imgact-specified interpreter by default.
+ */
+ args->interpreter = -1;
+
+ /*
* Allocate demand-paged memory for the file name, argument, and
* environment strings.
*/
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -997,6 +997,8 @@
id_t id, const struct \
vm_domain_policy_entry *policy); }
550 AUE_FSYNC STD { int fdatasync(int fd); }
+551 AUE_NULL STD { int ffexecve(int interpreter, int fd, \
+ char **argv, char **envv); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: sys/sys/imgact.h
===================================================================
--- sys/sys/imgact.h
+++ sys/sys/imgact.h
@@ -51,6 +51,7 @@
int stringspace; /* space left in arg & env buffer */
int argc; /* count of argument strings */
int envc; /* count of environment strings */
+ int interpreter; /* descriptor of interpreter to override with */
int fd; /* file descriptor of the executable */
struct filedesc *fdp; /* new file descriptor table */
};

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 27, 10:06 PM (8 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16216067
Default Alt Text
D9030.diff (13 KB)

Event Timeline