Jail and capability mode for shm_rename; add audit support for shm_rename

Co-mingling two things here:

  * Addressing some feedback from Konstantin and Kyle re: jail,
    capability mode, and a few other things
  * Adding audit support as promised.

The audit support change includes a partial refresh of OpenBSM from
upstream, where the change to add shm_rename has already been
accepted. Matthew doesn't plan to work on refreshing anything else to
support audit for those new event types.

Submitted by:	Matthew Bryan <matthew.bryan@isilon.com>
Reviewed by:	kib
Relnotes:	Yes
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D22083
This commit is contained in:
David Bright 2019-11-18 13:31:16 +00:00
parent d2e690132e
commit 2d5603fe65
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354808
12 changed files with 140 additions and 93 deletions

View File

@ -601,6 +601,19 @@
43238:AUE_SETLOGINCLASS:setloginclass(2):pc
43239:AUE_POSIX_FADVISE:posix_fadvise(2):no
43240:AUE_SCTP_GENERIC_SENDMSG_IOV:sctp_generic_sendmsg_iov(2):nt
43241:AUE_ABORT2:abort(2):pc
43242:AUE_SEMTIMEDWAIT:sem_timedwait(3):ip
43243:AUE_SEMDESTROY:sem_destroy(3):ip
43244:AUE_SEMGETVALUE:sem_getvalue(3):ip
43245:AUE_SEMINIT:sem_init(3):ip
43246:AUE_SEMPOST:sem_post(3):ip
43247:AUE_SEMTRYWAIT:sem_trywait(3):ip
43258:AUE_SEMWAIT:sem_wait(3):ip
43259:AUE_FGETUUID:fgetuuid(2):ip
43260:AUE_GETUUID:getuuid(2):ip
43261:AUE_LGETUUID:lgetuuid(2):ip
43262:AUE_EXECVEAT:execveat(2):pc,ex
43263:AUE_SHMRENAME:shm_rename(2):ip
#
# Solaris userspace events.
#

View File

@ -640,6 +640,19 @@
#define AUE_SETLOGINCLASS 43238 /* FreeBSD-specific. */
#define AUE_POSIX_FADVISE 43239 /* FreeBSD-specific. */
#define AUE_SCTP_GENERIC_SENDMSG_IOV 43240 /* FreeBSD-specific. */
#define AUE_ABORT2 43241 /* FreeBSD-specific. */
#define AUE_SEMTIMEDWAIT 43242 /* FreeBSD-specific. */
#define AUE_SEMDESTROY 43243 /* FreeBSD-specific. */
#define AUE_SEMGETVALUE 43244 /* FreeBSD-specific. */
#define AUE_SEMINIT 43245 /* FreeBSD-specific. */
#define AUE_SEMPOST 43246 /* FreeBSD-specific. */
#define AUE_SEMTRYWAIT 43247 /* FreeBSD-specific. */
#define AUE_SEMWAIT 43258 /* FreeBSD-specific. */
#define AUE_FGETUUID 43259 /* CADETS. */
#define AUE_GETUUID 43260 /* CADETS. */
#define AUE_LGETUUID 43261 /* CADETS. */
#define AUE_EXECVEAT 43262 /* FreeBSD/Linux. */
#define AUE_SHMRENAME 43263 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
@ -794,12 +807,6 @@
#define AUE_REMOVEXATTR AUE_NULL
#define AUE_SBRK AUE_NULL
#define AUE_SELECT AUE_NULL
#define AUE_SEMDESTROY AUE_NULL
#define AUE_SEMGETVALUE AUE_NULL
#define AUE_SEMINIT AUE_NULL
#define AUE_SEMPOST AUE_NULL
#define AUE_SEMTRYWAIT AUE_NULL
#define AUE_SEMWAIT AUE_NULL
#define AUE_SEMWAITSIGNAL AUE_NULL
#define AUE_SETITIMER AUE_NULL
#define AUE_SETSGROUPS AUE_NULL

View File

@ -644,6 +644,19 @@
#define AUE_SETLOGINCLASS 43238 /* FreeBSD-specific. */
#define AUE_POSIX_FADVISE 43239 /* FreeBSD-specific. */
#define AUE_SCTP_GENERIC_SENDMSG_IOV 43240 /* FreeBSD-specific. */
#define AUE_ABORT2 43241 /* FreeBSD-specific. */
#define AUE_SEMTIMEDWAIT 43242 /* FreeBSD-specific. */
#define AUE_SEMDESTROY 43243 /* FreeBSD-specific. */
#define AUE_SEMGETVALUE 43244 /* FreeBSD-specific. */
#define AUE_SEMINIT 43245 /* FreeBSD-specific. */
#define AUE_SEMPOST 43246 /* FreeBSD-specific. */
#define AUE_SEMTRYWAIT 43247 /* FreeBSD-specific. */
#define AUE_SEMWAIT 43258 /* FreeBSD-specific. */
#define AUE_FGETUUID 43259 /* CADETS. */
#define AUE_GETUUID 43260 /* CADETS. */
#define AUE_LGETUUID 43261 /* CADETS. */
#define AUE_EXECVEAT 43262 /* FreeBSD/Linux. */
#define AUE_SHMRENAME 43263 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
@ -798,12 +811,6 @@
#define AUE_REMOVEXATTR AUE_NULL
#define AUE_SBRK AUE_NULL
#define AUE_SELECT AUE_NULL
#define AUE_SEMDESTROY AUE_NULL
#define AUE_SEMGETVALUE AUE_NULL
#define AUE_SEMINIT AUE_NULL
#define AUE_SEMPOST AUE_NULL
#define AUE_SEMTRYWAIT AUE_NULL
#define AUE_SEMWAIT AUE_NULL
#define AUE_SEMWAITSIGNAL AUE_NULL
#define AUE_SETITIMER AUE_NULL
#define AUE_SETSGROUPS AUE_NULL

View File

@ -661,5 +661,5 @@ struct sysent freebsd32_sysent[] = {
{ AS(copy_file_range_args), (sy_call_t *)sys_copy_file_range, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 569 = copy_file_range */
{ AS(freebsd32___sysctlbyname_args), (sy_call_t *)freebsd32___sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 570 = freebsd32___sysctlbyname */
{ AS(shm_open2_args), (sy_call_t *)sys_shm_open2, AUE_SHMOPEN, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 571 = shm_open2 */
{ AS(shm_rename_args), (sy_call_t *)sys_shm_rename, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 572 = shm_rename */
{ AS(shm_rename_args), (sy_call_t *)sys_shm_rename, AUE_SHMRENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 572 = shm_rename */
};

View File

@ -1157,7 +1157,7 @@
571 AUE_SHMOPEN NOPROTO { int shm_open2( \
const char *path, int flags, mode_t mode, \
int shmflags, const char *name); }
572 AUE_NULL NOPROTO { int shm_rename(const char *path_from, \
572 AUE_SHMRENAME NOPROTO { int shm_rename(const char *path_from, \
const char *path_to, int flags); }
; vim: syntax=off

View File

@ -627,5 +627,5 @@ struct sysent sysent[] = {
{ AS(copy_file_range_args), (sy_call_t *)sys_copy_file_range, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 569 = copy_file_range */
{ AS(__sysctlbyname_args), (sy_call_t *)sys___sysctlbyname, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 570 = __sysctlbyname */
{ AS(shm_open2_args), (sy_call_t *)sys_shm_open2, AUE_SHMOPEN, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 571 = shm_open2 */
{ AS(shm_rename_args), (sy_call_t *)sys_shm_rename, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 572 = shm_rename */
{ AS(shm_rename_args), (sy_call_t *)sys_shm_rename, AUE_SHMRENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 572 = shm_rename */
};

View File

@ -3205,7 +3205,7 @@
_In_z_ const char *name
);
}
572 AUE_NULL STD {
572 AUE_SHMRENAME STD {
int shm_rename(
_In_z_ const char *path_from,
_In_z_ const char *path_to,

View File

@ -122,6 +122,8 @@ static struct shmfd *shm_lookup(char *path, Fnv32_t fnv);
static int shm_remove(char *path, Fnv32_t fnv, struct ucred *ucred);
static int shm_dotruncate_locked(struct shmfd *shmfd, off_t length,
void *rl_cookie);
static int shm_copyin_path(struct thread *td, const char *userpath_in,
char **path_out);
static fo_rdwr_t shm_read;
static fo_rdwr_t shm_write;
@ -421,6 +423,44 @@ shm_close(struct file *fp, struct thread *td)
return (0);
}
static int
shm_copyin_path(struct thread *td, const char *userpath_in, char **path_out) {
int error;
char *path;
const char *pr_path;
size_t pr_pathlen;
path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
pr_path = td->td_ucred->cr_prison->pr_path;
/* Construct a full pathname for jailed callers. */
pr_pathlen = strcmp(pr_path, "/") ==
0 ? 0 : strlcpy(path, pr_path, MAXPATHLEN);
error = copyinstr(userpath_in, path + pr_pathlen,
MAXPATHLEN - pr_pathlen, NULL);
if (error != 0)
goto out;
#ifdef KTRACE
if (KTRPOINT(curthread, KTR_NAMEI))
ktrnamei(path);
#endif
/* Require paths to start with a '/' character. */
if (path[pr_pathlen] != '/') {
error = EINVAL;
goto out;
}
*path_out = path;
out:
if (error != 0)
free(path, M_SHMFD);
return (error);
}
static int
shm_dotruncate_locked(struct shmfd *shmfd, off_t length, void *rl_cookie)
{
@ -707,9 +747,7 @@ kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode,
struct shmfd *shmfd;
struct file *fp;
char *path;
const char *pr_path;
void *rl_cookie;
size_t pr_pathlen;
Fnv32_t fnv;
mode_t cmode;
int fd, error;
@ -767,25 +805,10 @@ kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode,
shmfd = shm_alloc(td->td_ucred, cmode);
shmfd->shm_seals = initial_seals;
} else {
path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
pr_path = td->td_ucred->cr_prison->pr_path;
/* Construct a full pathname for jailed callers. */
pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
: strlcpy(path, pr_path, MAXPATHLEN);
error = copyinstr(userpath, path + pr_pathlen,
MAXPATHLEN - pr_pathlen, NULL);
#ifdef KTRACE
if (error == 0 && KTRPOINT(curthread, KTR_NAMEI))
ktrnamei(path);
#endif
/* Require paths to start with a '/' character. */
if (error == 0 && path[pr_pathlen] != '/')
error = EINVAL;
if (error) {
error = shm_copyin_path(td, userpath, &path);
if (error != 0) {
fdclose(td, fp, fd);
fdrop(fp, td);
free(path, M_SHMFD);
return (error);
}
@ -918,25 +941,13 @@ int
sys_shm_unlink(struct thread *td, struct shm_unlink_args *uap)
{
char *path;
const char *pr_path;
size_t pr_pathlen;
Fnv32_t fnv;
int error;
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
pr_path = td->td_ucred->cr_prison->pr_path;
pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
: strlcpy(path, pr_path, MAXPATHLEN);
error = copyinstr(uap->path, path + pr_pathlen, MAXPATHLEN - pr_pathlen,
NULL);
if (error) {
free(path, M_TEMP);
error = shm_copyin_path(td, uap->path, &path);
if (error != 0)
return (error);
}
#ifdef KTRACE
if (KTRPOINT(curthread, KTR_NAMEI))
ktrnamei(path);
#endif
AUDIT_ARG_UPATH1_CANON(path);
fnv = fnv_32_str(path, FNV1_32_INIT);
sx_xlock(&shm_dict_lock);
@ -958,6 +969,7 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
int flags;
flags = uap->flags;
AUDIT_ARG_FFLAGS(flags);
/*
* Make sure the user passed only valid flags.
@ -981,22 +993,25 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
goto out;
}
/*
* Malloc zone M_SHMFD, since this path may end up freed later from
* M_SHMFD if we end up doing an insert.
*/
path_from = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
error = copyinstr(uap->path_from, path_from, MAXPATHLEN, NULL);
if (error)
/* Renaming to or from anonymous makes no sense */
if (uap->path_from == SHM_ANON || uap->path_to == SHM_ANON) {
error = EINVAL;
goto out;
}
error = shm_copyin_path(td, uap->path_from, &path_from);
if (error != 0)
goto out;
path_to = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
error = copyinstr(uap->path_to, path_to, MAXPATHLEN, NULL);
if (error)
error = shm_copyin_path(td, uap->path_to, &path_to);
if (error != 0)
goto out;
AUDIT_ARG_UPATH1_CANON(path_from);
AUDIT_ARG_UPATH2_CANON(path_to);
/* Rename with from/to equal is a no-op */
if (strncmp(path_from, path_to, MAXPATHLEN) == 0)
if (strcmp(path_from, path_to) == 0)
goto out;
fnv_from = fnv_32_str(path_from, FNV1_32_INIT);
@ -1006,16 +1021,14 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
fd_from = shm_lookup(path_from, fnv_from);
if (fd_from == NULL) {
sx_xunlock(&shm_dict_lock);
error = ENOENT;
goto out;
goto out_locked;
}
fd_to = shm_lookup(path_to, fnv_to);
if ((flags & SHM_RENAME_NOREPLACE) != 0 && fd_to != NULL) {
sx_xunlock(&shm_dict_lock);
error = EEXIST;
goto out;
goto out_locked;
}
/*
@ -1031,10 +1044,9 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
*/
KASSERT(error != ENOENT, ("Our shm disappeared during shm_rename: %s",
path_from));
if (error) {
if (error != 0) {
shm_drop(fd_from);
sx_xunlock(&shm_dict_lock);
goto out;
goto out_locked;
}
/*
@ -1057,15 +1069,16 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
* operation.
*/
error = shm_remove(path_to, fnv_to, td->td_ucred);
if (error && error != ENOENT) {
if (error != 0 && error != ENOENT) {
shm_insert(path_from, fnv_from, fd_from);
shm_drop(fd_from);
/* Don't free path_from now, since the hash references it */
path_from = NULL;
sx_xunlock(&shm_dict_lock);
goto out;
goto out_locked;
}
error = 0;
shm_insert(path_to, fnv_to, fd_from);
/* Don't free path_to now, since the hash references it */
@ -1073,30 +1086,24 @@ sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
/* We kept a ref when we removed, and incremented again in insert */
shm_drop(fd_from);
#ifdef DEBUG
KASSERT(fd_from->shm_refs > 0, ("Expected >0 refs; got: %d\n",
fd_from->shm_refs));
#endif
if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) {
shm_insert(path_from, fnv_from, fd_to);
path_from = NULL;
shm_drop(fd_to);
#ifdef DEBUG
KASSERT(fd_to->shm_refs > 0, ("Expected >0 refs; got: %d\n",
fd_to->shm_refs));
#endif
}
error = 0;
out_locked:
sx_xunlock(&shm_dict_lock);
out:
if (path_from != NULL)
free(path_from, M_SHMFD);
if (path_to != NULL)
free(path_to, M_SHMFD);
return(error);
free(path_from, M_SHMFD);
free(path_to, M_SHMFD);
return (error);
}
int

View File

@ -1565,6 +1565,16 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau)
}
break;
/* shm_rename is a non-Posix extension to the Posix shm implementation */
case AUE_SHMRENAME:
UPATH1_TOKENS;
UPATH2_TOKENS;
if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
kau_write(rec, tok);
}
break;
/* AUE_SHMOPEN, AUE_SHMUNLINK, AUE_SEMOPEN, AUE_SEMCLOSE
* and AUE_SEMUNLINK are Posix IPC */
case AUE_SHMOPEN:

View File

@ -118,6 +118,15 @@
#define MAP_ALIGNMENT_SHIFT 24
#define MAP_ALIGNMENT_MASK MAP_ALIGNED(0xff)
#define MAP_ALIGNED_SUPER MAP_ALIGNED(1) /* align on a superpage */
/*
* Flags provided to shm_rename
*/
/* Don't overwrite dest, if it exists */
#define SHM_RENAME_NOREPLACE (1 << 0)
/* Atomically swap src and dest */
#define SHM_RENAME_EXCHANGE (1 << 1)
#endif /* __BSD_VISIBLE */
#if __POSIX_VISIBLE >= 199309
@ -133,14 +142,6 @@
*/
#define MAP_FAILED ((void *)-1)
/*
* Flags provided to shm_rename
*/
/* Don't overwrite dest, if it exists */
#define SHM_RENAME_NOREPLACE (1 << 0)
/* Atomically swap src and dest */
#define SHM_RENAME_EXCHANGE (1 << 1)
/*
* msync() flags
*/
@ -321,11 +322,11 @@ int posix_madvise(void *, size_t, int);
int mlockall(int);
int munlockall(void);
int shm_open(const char *, int, mode_t);
int shm_rename(const char *, const char *, int);
int shm_unlink(const char *);
#endif
#if __BSD_VISIBLE
int memfd_create(const char *, unsigned int);
int shm_rename(const char *, const char *, int);
#endif
__END_DECLS

View File

@ -3129,7 +3129,7 @@ int freebsd12_shm_open(struct thread *, struct freebsd12_shm_open_args *);
#define SYS_AUE_copy_file_range AUE_NULL
#define SYS_AUE___sysctlbyname AUE_SYSCTL
#define SYS_AUE_shm_open2 AUE_SHMOPEN
#define SYS_AUE_shm_rename AUE_NULL
#define SYS_AUE_shm_rename AUE_SHMRENAME
#undef PAD_
#undef PADL_

View File

@ -53,7 +53,7 @@ static unsigned int test_path_idx = 0;
static void
gen_a_test_path(char *path)
{
snprintf(path, TEST_PATH_LEN, "%s/tmp.XXXXXX%d",
snprintf(path, TEST_PATH_LEN, "/%s/tmp.XXXXXX%d",
getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"),
test_path_idx);
@ -232,12 +232,14 @@ ATF_TC_BODY(rename_from_nonexisting, tc)
int rc;
gen_test_path();
gen_test_path2();
rc = shm_rename(test_path, test_path2, 0);
if (rc != -1)
atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
if (errno != ENOENT)
atf_tc_fail("Expected ENOENT to rename of nonexistent shm");
atf_tc_fail("Expected ENOENT to rename of nonexistent shm; got %d",
errno);
}
ATF_TC_WITHOUT_HEAD(rename_to_anon);