Skip to content

Commit

Permalink
Merge 8c8efce into 3570b5c
Browse files Browse the repository at this point in the history
  • Loading branch information
pcmoore committed May 2, 2019
2 parents 3570b5c + 8c8efce commit 1070120
Show file tree
Hide file tree
Showing 22 changed files with 906 additions and 82 deletions.
3 changes: 3 additions & 0 deletions doc/man/man3/seccomp_api_get.3
Expand Up @@ -53,6 +53,9 @@ The SCMP_FLTATR_CTL_LOG filter attribute and the SCMP_ACT_LOG action are support
.TP
.B 4
The SCMP_FLTATR_CTL_SSB filter attribute is supported.
.TP
.B 5
The SCMP_ACT_NOTIFY action is supported.
.\" //////////////////////////////////////////////////////////////////////////
.SH RETURN VALUE
.\" //////////////////////////////////////////////////////////////////////////
Expand Down
100 changes: 100 additions & 0 deletions doc/man/man3/seccomp_notify_alloc.3
@@ -0,0 +1,100 @@
.TH "seccomp_notify_alloc" 3 "24 April 2019" "tycho@tycho.ws" "libseccomp Documentation"
.\" //////////////////////////////////////////////////////////////////////////
.SH NAME
.\" //////////////////////////////////////////////////////////////////////////
seccomp_notify_alloc, seccomp_notify_free, seccomp_notify_receive,
seccomp_notify_respond, seccomp_notify_id_valid, seccomp_notify_fd \- Manage seccomp notifications
.\" //////////////////////////////////////////////////////////////////////////
.SH SYNOPSIS
.\" //////////////////////////////////////////////////////////////////////////
.nf
.B #include <seccomp.h>
.sp
.BI "int seccomp_notify_alloc(struct seccomp_notif **" req ", struct seccomp_notif_resp **" resp ")"
.BI "void seccomp_notify_free(struct seccomp_notif *" req ", struct seccomp_notif_resp *" resp ")"
.BI "int seccomp_notify_receive(int " fd ", struct seccomp_notif *" req ")"
.BI "int seccomp_notify_respond(int " fd ", struct seccomp_notif_resp *" resp ")"
.BI "int seccomp_notify_id_valid(int " fd ", uint64_t " id ")"
.BI "int seccomp_notify_fd(const scmp_filter_ctx " ctx ")"
.sp
Link with \fI\-lseccomp\fP.
.fi
.\" //////////////////////////////////////////////////////////////////////////
.SH DESCRIPTION
.\" //////////////////////////////////////////////////////////////////////////
.P
The
.BR seccomp_notify_alloc ()
function dynamically allocates enough memory for a seccomp notification and
response. Note that one should always use these functions and not depend on the
structure sizes in headers, since the size can vary depending on the kernel
version. This function takes care to ask the kernel how big each structure
should be, and allocates the right amount of memory. The
.BR seccomp_notify_free ()
function frees memory allocated by
.BR seccomp_notify_alloc ().
.P
The
.BR seccomp_notify_receive ()
function receives a notification from a seccomp notify fd (obtained from
.BR seccomp_notify_fd ()).
.P
The
.BR seccomp_notify_respond ()
function sends a response to a particular notification. The id field should be
the same as the id from the request, so that the kernel knows which request
this response corresponds to.
.P
The
.BR seccomp_notify_id_valid ()
function checks to see if the syscall from a particualr notification request is
still valid, i.e. if the task is still alive. See NOTES below for details on
race conditions.
.P
The
.BR seccomp_notify_fd ()
returns the notification fd of a filter after it has been loaded.
.\" //////////////////////////////////////////////////////////////////////////
.SH RETURN VALUE
.\" //////////////////////////////////////////////////////////////////////////
.P
The
.BR seccomp_notify_alloc (),
.BR seccomp_notify_receive (),
and
.BR seccomp_notify_respond ()
functions all return 0 on success, -1 on failure.
.P
The
.BR seccomp_notify_id_valid ()
returns 0 if the id is valid, and -ENOENT if it is not.
.P
The
.BR seccomp_notify_fd ()
returns the notification fd of the loaded filter.
.\" //////////////////////////////////////////////////////////////////////////
.SH NOTES
.\" //////////////////////////////////////////////////////////////////////////
.P
Care should be taken to avoid two different time of check/time of use errors.
First, after opening any resources relevant to the pid for a notification (e.g.
/proc/pid/mem for reading tracee memory to make policy decisions), applications
should call
.BR seccomp_notify_id_valid ()
to make sure that the resources the application has opened correspond to the
right pid, i.e. that the pid didn't die and a different task take its place.
.P
Second, the classic time of check/time of use issue with seccomp memory should
also be avoided: applications should copy any memory they wish to use to make
decisions from the tracee into its own address space before applying any policy
decisions, since a multi-threaded tracee may edit the memory at any time,
including after it's used to make a policy decision.
.P
A complete example of how to avoid these two races is available in the Linux
Kernel source tree at
.BR /samples/seccomp/user-trap.c.
.\" //////////////////////////////////////////////////////////////////////////
.SH AUTHOR
.\" //////////////////////////////////////////////////////////////////////////
Tycho Andersen <tycho@tycho.ws>
.\" //////////////////////////////////////////////////////////////////////////
1 change: 1 addition & 0 deletions doc/man/man3/seccomp_notify_fd.3
@@ -0,0 +1 @@
.so man3/seccomp_notify_alloc.3
1 change: 1 addition & 0 deletions doc/man/man3/seccomp_notify_free.3
@@ -0,0 +1 @@
.so man3/seccomp_notify_alloc.3
1 change: 1 addition & 0 deletions doc/man/man3/seccomp_notify_id_valid.3
@@ -0,0 +1 @@
.so man3/seccomp_notify_alloc.3
1 change: 1 addition & 0 deletions doc/man/man3/seccomp_notify_receive.3
@@ -0,0 +1 @@
.so man3/seccomp_notify_alloc.3
1 change: 1 addition & 0 deletions doc/man/man3/seccomp_notify_respond.3
@@ -0,0 +1 @@
.so man3/seccomp_notify_alloc.3
93 changes: 93 additions & 0 deletions include/seccomp.h.in
Expand Up @@ -26,6 +26,8 @@
#include <inttypes.h>
#include <asm/unistd.h>
#include <linux/audit.h>
#include <linux/types.h>
#include <linux/seccomp.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -319,6 +321,10 @@ struct scmp_arg_cmp {
* Throw a SIGSYS signal
*/
#define SCMP_ACT_TRAP 0x00030000U
/**
* Notifies userspace
*/
#define SCMP_ACT_NOTIFY 0x7fc00000U
/**
* Return the specified error code
*/
Expand All @@ -336,6 +342,25 @@ struct scmp_arg_cmp {
*/
#define SCMP_ACT_ALLOW 0x7fff0000U

/* SECCOMP_RET_USER_NOTIF was added in kernel v5.0. */
#ifndef SECCOMP_RET_USER_NOTIF
#define SECCOMP_RET_USER_NOTIF 0x7fc00000U

struct seccomp_notif {
__u64 id;
__u32 pid;
__u32 flags;
struct seccomp_data data;
};

struct seccomp_notif_resp {
__u64 id;
__s64 val;
__s32 error;
__u32 flags;
};
#endif

/*
* functions
*/
Expand Down Expand Up @@ -369,6 +394,7 @@ const struct scmp_version *seccomp_version(void);
* support for the SCMP_ACT_LOG action
* support for the SCMP_ACT_KILL_PROCESS action
* 4 : support for the SCMP_FLTATR_CTL_SSB filter attrbute
* 5 : support for the SCMP_ACT_NOTIFY action
*
*/
unsigned int seccomp_api_get(void);
Expand Down Expand Up @@ -673,6 +699,73 @@ int seccomp_rule_add_exact_array(scmp_filter_ctx ctx,
unsigned int arg_cnt,
const struct scmp_arg_cmp *arg_array);

/**
* Allocate a pair of notification request/response structures.
* @param req the request location
* @param resp the response location
*
* This function allocates a pair of request/response structure by computing
* the correct sized based on the currently running kernel. It returns zero on
* success, and negative values on failure.
*
*/
int seccomp_notify_alloc(struct seccomp_notif **req,
struct seccomp_notif_resp **resp);

/**
* Free a pair of notification request/response structures.
* @param req the request location
* @param resp the response location
*/
void seccomp_notify_free(struct seccomp_notif *req,
struct seccomp_notif_resp *resp);

/**
* Receive a notification from a seccomp notification fd.
* @param fd the notification fd
* @param req the request buffer to save into
*
* Blocks waiting for a notification on this fd. This function is thread safe
* (synchronization is performed in the kernel). Returns zero on success,
* negative values on error.
*
*/
int seccomp_notify_receive(int fd, struct seccomp_notif *req);

/**
* Send a notification response to a seccomp notification fd.
* @param fd the notification fd
* @param resp the response buffer to use
*
* Sends a notification response on this fd. This function is thread safe
* (synchronization is performed in the kernel). Returns zero on success,
* negative values on error.
*
*/
int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp);

/**
* Check if a notification id is still valid.
* @param fd the notification fd
* @param id the id to test
*
* Checks to see if a notification id is still valid. Returns 0 on success, and
* negative values on failure.
*
*/
int seccomp_notify_id_valid(int fd, uint64_t id);

/**
* Return the notification fd from a filter that has already been loaded.
* @param ctx the filter context
*
* This returns the listener fd that was generated when the seccomp policy was
* loaded. This is only valid after seccomp_load() with a filter that makes
* use of SCMP_ACT_NOTIFY.
*
*/
int seccomp_notify_fd(const scmp_filter_ctx ctx);

/**
* Generate seccomp Pseudo Filter Code (PFC) and export it to a file
* @param ctx the filter context
Expand Down
72 changes: 68 additions & 4 deletions src/api.c
Expand Up @@ -27,13 +27,15 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/ioctl.h>

#include <seccomp.h>

#include "arch.h"
#include "db.h"
#include "gen_pfc.h"
#include "gen_bpf.h"
#include "helper.h"
#include "system.h"

#define API __attribute__((visibility("default")))
Expand Down Expand Up @@ -112,6 +114,10 @@ static unsigned int _seccomp_api_update(void)
sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 1)
level = 4;

if (level == 4 &&
sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER) == 1)
level = 5;

/* update the stored api level and return */
seccomp_api_level = level;
return seccomp_api_level;
Expand Down Expand Up @@ -163,6 +169,16 @@ API int seccomp_api_set(unsigned int level)
sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, true);
sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, true);
break;
case 5:
sys_set_seccomp_syscall(true);
sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC, true);
sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_LOG, true);
sys_set_seccomp_action(SCMP_ACT_LOG, true);
sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, true);
sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, true);
sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER, true);
sys_set_seccomp_action(SCMP_ACT_NOTIFY, true);
break;
default:
return -EINVAL;
}
Expand All @@ -174,7 +190,7 @@ API int seccomp_api_set(unsigned int level)
/* NOTE - function header comment in include/seccomp.h */
API scmp_filter_ctx seccomp_init(uint32_t def_action)
{
if (db_action_valid(def_action) < 0)
if (db_col_action_valid(NULL, def_action) < 0)
return NULL;

return db_col_init(def_action);
Expand All @@ -185,7 +201,8 @@ API int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)
{
struct db_filter_col *col = (struct db_filter_col *)ctx;

if (ctx == NULL || db_action_valid(def_action) < 0)
/* use a NULL filter collection here since we are resetting it */
if (ctx == NULL || db_col_action_valid(NULL, def_action) < 0)
return -EINVAL;

return db_col_reset(col, def_action);
Expand Down Expand Up @@ -425,7 +442,7 @@ API int seccomp_rule_add_array(scmp_filter_ctx ctx,
if (db_col_valid(col) || _syscall_valid(col, syscall))
return -EINVAL;

rc = db_action_valid(action);
rc = db_col_action_valid(col, action);
if (rc < 0)
return rc;
if (action == col->attr.act_default)
Expand Down Expand Up @@ -474,7 +491,7 @@ API int seccomp_rule_add_exact_array(scmp_filter_ctx ctx,
if (db_col_valid(col) || _syscall_valid(col, syscall))
return -EINVAL;

rc = db_action_valid(action);
rc = db_col_action_valid(col, action);
if (rc < 0)
return rc;
if (action == col->attr.act_default)
Expand Down Expand Up @@ -510,6 +527,53 @@ API int seccomp_rule_add_exact(scmp_filter_ctx ctx,
return rc;
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_notify_alloc(struct seccomp_notif **req,
struct seccomp_notif_resp **resp)
{
return sys_notify_alloc(req, resp);
}

/* NOTE - function header comment in include/seccomp.h */
API void seccomp_notify_free(struct seccomp_notif *req,
struct seccomp_notif_resp *resp)
{
if (req)
free(req);
if (resp)
free(resp);
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_notify_receive(int fd, struct seccomp_notif *req)
{
return sys_notify_receive(fd, req);
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp)
{
return sys_notify_respond(fd, resp);
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_notify_id_valid(int fd, uint64_t id)
{
return sys_notify_id_valid(fd, id);
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_notify_fd(const scmp_filter_ctx ctx)
{
struct db_filter_col *col;

if (_ctx_valid(ctx))
return -EINVAL;
col = (struct db_filter_col *)ctx;

return col->notify_fd;
}

/* NOTE - function header comment in include/seccomp.h */
API int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd)
{
Expand Down

0 comments on commit 1070120

Please sign in to comment.