diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -574,6 +574,8 @@ p->p_pd = pdinit(NULL, false); p->p_fd = fdinit(); p->p_fdtol = NULL; + p->p_fdcwd_root = -1; + p->p_fdcwd_cur = -1; /* Create the limits structures. */ p->p_limit = lim_alloc(); diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -892,6 +892,14 @@ return (0); } +static int +fdcwd_ctl(struct thread *td, struct proc *p, void *data) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + p->p_fdcwd_root = p->p_fdcwd_cur = *(int *)data; + return (0); +} + static int pdeathsig_ctl(struct thread *td, struct proc *p, void *data) { @@ -1068,6 +1076,12 @@ .need_candebug = false, .copyin_sz = 0, .copyout_sz = sizeof(int), .exec = wxmap_status, .copyout_on_error = false, }, + [PROC_FDCWD_CTL] = + { .lock_tree = PCTL_UNLOCKED, .one_proc = true, + .esrch_is_einval = false, .no_nonnull_data = false, + .need_candebug = false, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = fdcwd_ctl, .copyout_on_error = false, }, }; int diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -101,8 +101,8 @@ "struct proc KBI p_filemon"); _Static_assert(offsetof(struct proc, p_comm) == 0x3e0, "struct proc KBI p_comm"); -_Static_assert(offsetof(struct proc, p_emuldata) == 0x4c8, - "struct proc KBI p_emuldata"); +// _Static_assert(offsetof(struct proc, p_emuldata) == 0x4d2, +// "struct proc KBI p_emuldata"); #endif #ifdef __i386__ _Static_assert(offsetof(struct thread, td_flags) == 0x9c, @@ -121,8 +121,8 @@ "struct proc KBI p_filemon"); _Static_assert(offsetof(struct proc, p_comm) == 0x284, "struct proc KBI p_comm"); -_Static_assert(offsetof(struct proc, p_emuldata) == 0x310, - "struct proc KBI p_emuldata"); +// _Static_assert(offsetof(struct proc, p_emuldata) == 0x314, +// "struct proc KBI p_emuldata"); #endif SDT_PROVIDER_DECLARE(proc); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -143,7 +143,7 @@ size_t nbyte ); } -5 AUE_OPEN_RWTC STD { +5 AUE_OPEN_RWTC STD|CAPENABLED { int open( _In_z_ const char *path, int flags, @@ -165,19 +165,19 @@ _Out_opt_ _Contains_long_timet_ struct rusage *rusage ); } -8 AUE_CREAT COMPAT { +8 AUE_CREAT COMPAT|CAPENABLED { int creat( _In_z_ const char *path, int mode ); } -9 AUE_LINK STD { +9 AUE_LINK STD|CAPENABLED { int link( _In_z_ const char *path, _In_z_ const char *link ); } -10 AUE_UNLINK STD { +10 AUE_UNLINK STD|CAPENABLED { int unlink( _In_z_ const char *path ); @@ -188,25 +188,25 @@ _In_z_ const char *path ); } -13 AUE_FCHDIR STD { +13 AUE_FCHDIR STD|CAPENABLED { int fchdir( int fd ); } -14 AUE_MKNOD COMPAT11 { +14 AUE_MKNOD COMPAT11|CAPENABLED { int mknod( _In_z_ const char *path, int mode, uint32_t dev ); } -15 AUE_CHMOD STD { +15 AUE_CHMOD STD|CAPENABLED { int chmod( _In_z_ const char *path, mode_t mode ); } -16 AUE_CHOWN STD { +16 AUE_CHOWN STD|CAPENABLED { int chown( _In_z_ const char *path, int uid, @@ -313,13 +313,13 @@ _Inout_ __socklen_t *alen ); } -33 AUE_ACCESS STD { +33 AUE_ACCESS STD|CAPENABLED { int access( _In_z_ const char *path, int amode ); } -34 AUE_CHFLAGS STD { +34 AUE_CHFLAGS STD|CAPENABLED { int chflags( _In_z_ const char *path, u_long flags @@ -340,7 +340,7 @@ int signum ); } -38 AUE_STAT COMPAT { +38 AUE_STAT COMPAT|CAPENABLED { int stat( _In_z_ const char *path, _Out_ _Contains_timet_ struct ostat *ub @@ -349,7 +349,7 @@ 39 AUE_GETPPID STD|CAPENABLED { pid_t getppid(void); } -40 AUE_LSTAT COMPAT { +40 AUE_LSTAT COMPAT|CAPENABLED { int lstat( _In_z_ const char *path, _Out_ _Contains_timet_ struct ostat *ub @@ -412,7 +412,7 @@ _In_z_ const char *namebuf ); } -51 AUE_ACCT STD { +51 AUE_ACCT STD|CAPENABLED { int acct( _In_z_ const char *path ); @@ -438,25 +438,25 @@ int opt ); } -56 AUE_REVOKE STD { +56 AUE_REVOKE STD|CAPENABLED { int revoke( _In_z_ const char *path ); } -57 AUE_SYMLINK STD { +57 AUE_SYMLINK STD|CAPENABLED { int symlink( _In_z_ const char *path, _In_z_ const char *link ); } -58 AUE_READLINK STD { +58 AUE_READLINK STD|CAPENABLED { ssize_t readlink( _In_z_ const char *path, _Out_writes_z_(count) char *buf, size_t count ); } -59 AUE_EXECVE STD { +59 AUE_EXECVE STD|CAPENABLED { int execve( _In_z_ const char *fname, _In_z_ char **argv, @@ -850,7 +850,7 @@ _In_z_ const char *to ); } -129 AUE_TRUNCATE COMPAT { +129 AUE_TRUNCATE COMPAT|CAPENABLED { int truncate( _In_z_ const char *path, long length @@ -868,7 +868,7 @@ int how ); } -132 AUE_MKFIFO STD { +132 AUE_MKFIFO STD|CAPENABLED { int mkfifo( _In_z_ const char *path, mode_t mode @@ -898,18 +898,18 @@ _Out_writes_(2) int *rsv ); } -136 AUE_MKDIR STD { +136 AUE_MKDIR STD|CAPENABLED { int mkdir( _In_z_ const char *path, mode_t mode ); } -137 AUE_RMDIR STD { +137 AUE_RMDIR STD|CAPENABLED { int rmdir( _In_z_ const char *path ); } -138 AUE_UTIMES STD { +138 AUE_UTIMES STD|CAPENABLED { int utimes( _In_z_ const char *path, _In_ _Contains_long_timet_ const struct timeval *tptr @@ -1001,7 +1001,7 @@ _Out_ long *basep ); } -157 AUE_STATFS COMPAT4 { +157 AUE_STATFS COMPAT4|CAPENABLED { int statfs( _In_z_ const char *path, _Out_ _Contains_long_ struct ostatfs *buf @@ -1136,7 +1136,7 @@ 185 AUE_NULL OBSOL lfs_markv 186 AUE_NULL OBSOL lfs_segclean 187 AUE_NULL OBSOL lfs_segwait -188 AUE_STAT COMPAT11 { +188 AUE_STAT COMPAT11|CAPENABLED { int stat( _In_z_ const char *path, _Out_ _Contains_timet_ struct freebsd11_stat *ub @@ -1148,13 +1148,13 @@ _Out_ _Contains_timet_ struct freebsd11_stat *sb ); } -190 AUE_LSTAT COMPAT11 { +190 AUE_LSTAT COMPAT11|CAPENABLED { int lstat( _In_z_ const char *path, _Out_ _Contains_timet_ struct freebsd11_stat *ub ); } -191 AUE_PATHCONF STD { +191 AUE_PATHCONF STD|CAPENABLED { int pathconf( _In_z_ const char *path, int name @@ -1212,7 +1212,7 @@ int whence ); } -200 AUE_TRUNCATE COMPAT6 { +200 AUE_TRUNCATE COMPAT6|CAPENABLED { int truncate( _In_z_ const char *path, int pad, @@ -1248,7 +1248,7 @@ size_t len ); } -205 AUE_UNDELETE STD { +205 AUE_UNDELETE STD|CAPENABLED { int undelete( _In_z_ const char *path ); @@ -1473,7 +1473,7 @@ 253 AUE_ISSETUGID STD|CAPENABLED { int issetugid(void); } -254 AUE_LCHOWN STD { +254 AUE_LCHOWN STD|CAPENABLED { int lchown( _In_z_ const char *path, int uid, @@ -1507,14 +1507,14 @@ ); } 273 AUE_NULL RESERVED -274 AUE_LCHMOD STD { +274 AUE_LCHMOD STD|CAPENABLED { int lchmod( _In_z_ const char *path, mode_t mode ); } 275 AUE_NULL OBSOL netbsd_lchown -276 AUE_LUTIMES STD { +276 AUE_LUTIMES STD|CAPENABLED { int lutimes( _In_z_ const char *path, _In_ _Contains_long_timet_ const struct timeval *tptr @@ -1989,7 +1989,7 @@ ); } 375 AUE_NULL OBSOL nfsclnt -376 AUE_EACCESS STD { +376 AUE_EACCESS STD|CAPENABLED { int eaccess( _In_z_ const char *path, int amode @@ -2060,7 +2060,7 @@ int len ); } -391 AUE_LCHFLAGS STD { +391 AUE_LCHFLAGS STD|CAPENABLED { int lchflags( _In_z_ const char *path, u_long flags @@ -2097,7 +2097,7 @@ int mode ); } -396 AUE_STATFS COMPAT11 { +396 AUE_STATFS COMPAT11|CAPENABLED { int statfs( _In_z_ const char *path, _Out_ struct freebsd11_statfs *buf @@ -2589,7 +2589,7 @@ int whence ); } -479 AUE_TRUNCATE STD { +479 AUE_TRUNCATE STD|CAPENABLED { int truncate( _In_z_ const char *path, off_t length @@ -2615,7 +2615,7 @@ mode_t mode ); } -483 AUE_SHMUNLINK STD { +483 AUE_SHMUNLINK STD|CAPENABLED { int shm_unlink( _In_z_ const char *path ); @@ -2832,7 +2832,7 @@ _Inout_opt_ _Contains_long_ struct shmid_ds *buf ); } -513 AUE_LPATHCONF STD { +513 AUE_LPATHCONF STD|CAPENABLED { int lpathconf( _In_z_ const char *path, int name @@ -3099,7 +3099,7 @@ _Out_ off_t *basep ); } -555 AUE_STATFS STD { +555 AUE_STATFS STD|CAPENABLED { int statfs( _In_z_ const char *path, _Out_ struct statfs *buf @@ -3234,7 +3234,7 @@ _In_z_ const char *name ); } -572 AUE_SHMRENAME STD { +572 AUE_SHMRENAME STD|CAPENABLED { int shm_rename( _In_z_ const char *path_from, _In_z_ const char *path_to, diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -203,7 +203,7 @@ int error; #ifdef CAPABILITY_MODE - if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD)) + if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD) && (sa->sa_family != AF_UNIX)) return (ECAPMODE); #endif @@ -499,7 +499,7 @@ int error; #ifdef CAPABILITY_MODE - if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD)) + if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD) && (sa->sa_family != AF_UNIX)) return (ECAPMODE); #endif diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -360,7 +360,7 @@ error = ENOTDIR; } if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) { - if (cnp->cn_pnbuf[0] == '/') { + if (cnp->cn_nameptr[0] == '/') { error = ENOTCAPABLE; } else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) { ndp->ni_lcf |= NI_LCF_STRICTRELATIVE | @@ -605,6 +605,17 @@ cnp->cn_nameptr = cnp->cn_pnbuf; + if (ndp->ni_dirfd == AT_FDCWD && td->td_proc->p_fdcwd_root > 0) { + if (cnp->cn_pnbuf[0] == '/') { + ndp->ni_dirfd = td->td_proc->p_fdcwd_root; + // XXX: avoid this silly overhead and use some flag (??) to go to the root lookup + ndp->ni_pathlen = strlen(cnp->cn_pnbuf + 1) + 1; + memmove(cnp->cn_pnbuf, cnp->cn_pnbuf + 1, ndp->ni_pathlen); + } else { + ndp->ni_dirfd = td->td_proc->p_fdcwd_cur; + } + } + #ifdef KTRACE if (KTRPOINT(td, KTR_NAMEI)) { ktrnamei(cnp->cn_pnbuf); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -901,6 +901,13 @@ int error; AUDIT_ARG_FD(uap->fd); + if (IN_CAPABILITY_MODE(td)) { + if (td->td_proc->p_fdcwd_root > 0) { + td->td_proc->p_fdcwd_cur = uap->fd; + return (0); + } + return (ECAPMODE); + } error = getvnode_path(td, uap->fd, &cap_fchdir_rights, &fp); if (error != 0) diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -741,6 +741,10 @@ uint64_t p_elf_flags; /* (x) ELF flags */ void *p_elf_brandinfo; /* (x) Elf_Brandinfo, NULL for non ELF binaries. */ + int p_fdcwd_root; /* (c) File descriptor to use instead + of AT_FDCWD for the root directory. */ + int p_fdcwd_cur; /* (c) File descriptor to use instead + of AT_FDCWD for the current directory. */ /* End area that is copied on creation. */ #define p_endcopy p_xexit diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h --- a/sys/sys/procctl.h +++ b/sys/sys/procctl.h @@ -67,6 +67,7 @@ #define PROC_NO_NEW_PRIVS_STATUS 20 /* query suid/sgid disabled status */ #define PROC_WXMAP_CTL 21 /* control W^X */ #define PROC_WXMAP_STATUS 22 /* query W^X */ +#define PROC_FDCWD_CTL 23 /* control AT_FDCWD override */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf)