61e8c76047
with privilege elevation no suid or sgid binaries are necessary any longer. Applications can be executed completely unprivileged. Systrace raises the privileges for a single system call depending on the configured policy. Idea from discussions with Perry Metzger, Dug Song and Marcus Watts. Approved by christos and thorpej.
457 lines
8.5 KiB
Plaintext
457 lines
8.5 KiB
Plaintext
/* $NetBSD: parse.y,v 1.5 2002/10/11 21:54:58 provos Exp $ */
|
|
/* $OpenBSD: parse.y,v 1.9 2002/08/04 04:15:50 provos Exp $ */
|
|
|
|
/*
|
|
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Niels Provos.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
%{
|
|
#include <sys/cdefs.h>
|
|
__RCSID("$NetBSD: parse.y,v 1.5 2002/10/11 21:54:58 provos Exp $");
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/tree.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <err.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
|
|
#include "intercept.h"
|
|
#include "systrace.h"
|
|
#include "systrace-errno.h"
|
|
#include "filter.h"
|
|
|
|
void yyrestart(FILE *);
|
|
|
|
struct logic *parse_newsymbol(char *, int, char *);
|
|
|
|
int yylex(void);
|
|
int yyparse(void);
|
|
int yyerror(const char *, ...);
|
|
|
|
int errors = 0;
|
|
struct filter *myfilter;
|
|
extern char *mystring;
|
|
extern int myoff;
|
|
extern int iamroot;
|
|
|
|
%}
|
|
|
|
%token AND OR NOT LBRACE RBRACE LSQBRACE RSQBRACE THEN MATCH PERMIT DENY
|
|
%token EQ NEQ TRUE SUB NSUB INPATH LOG COMMA IF USER GROUP EQUAL NEQUAL AS
|
|
%token COLON
|
|
%token <string> STRING
|
|
%token <string> CMDSTRING
|
|
%token <number> NUMBER
|
|
%type <logic> expression
|
|
%type <logic> symbol
|
|
%type <action> action
|
|
%type <number> typeoff
|
|
%type <number> logcode
|
|
%type <uid> uid
|
|
%type <gid> gid
|
|
%type <string> errorcode
|
|
%type <predicate> predicate
|
|
%type <elevate> elevate;
|
|
%union {
|
|
int number;
|
|
char *string;
|
|
short action;
|
|
struct logic *logic;
|
|
struct predicate predicate;
|
|
struct elevate elevate;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
}
|
|
%%
|
|
|
|
fullexpression : expression THEN action errorcode logcode elevate predicate
|
|
{
|
|
int flags = 0, errorcode = SYSTRACE_EPERM;
|
|
|
|
switch ($3) {
|
|
case ICPOLICY_NEVER:
|
|
if ($4 == NULL)
|
|
break;
|
|
errorcode = systrace_error_translate($4);
|
|
if (errorcode == -1)
|
|
yyerror("Unknown error code: %s", $4);
|
|
break;
|
|
case ICPOLICY_PERMIT:
|
|
if ($4 == NULL)
|
|
break;
|
|
if (!strcasecmp($4, "inherit"))
|
|
flags = PROCESS_INHERIT_POLICY;
|
|
else if (!strcasecmp($4, "detach"))
|
|
flags = PROCESS_DETACH;
|
|
else
|
|
yyerror("Unknown flag: %s", $4);
|
|
break;
|
|
}
|
|
|
|
if ($5)
|
|
flags |= SYSCALL_LOG;
|
|
|
|
if ($4 != NULL)
|
|
free($4);
|
|
|
|
myfilter = calloc(1, sizeof(struct filter));
|
|
if (myfilter == NULL) {
|
|
yyerror("calloc");
|
|
break;
|
|
}
|
|
myfilter->logicroot = $1;
|
|
myfilter->match_action = $3;
|
|
myfilter->match_error = errorcode;
|
|
myfilter->match_flags = flags;
|
|
myfilter->match_predicate = $7;
|
|
myfilter->elevate = $6;
|
|
}
|
|
;
|
|
|
|
errorcode : /* Empty */
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
| LSQBRACE STRING RSQBRACE
|
|
{
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
logcode : /* Empty */
|
|
{
|
|
$$ = 0;
|
|
}
|
|
| LOG
|
|
{
|
|
$$ = 1;
|
|
}
|
|
;
|
|
|
|
|
|
uid: STRING
|
|
{
|
|
struct passwd *pw;
|
|
if ((pw = getpwnam($1)) == NULL) {
|
|
yyerror("Unknown user %s", $1);
|
|
break;
|
|
}
|
|
|
|
$$ = pw->pw_uid;
|
|
}
|
|
|
|
gid: STRING
|
|
{
|
|
struct group *gr;
|
|
if ((gr = getgrnam($1)) == NULL) {
|
|
yyerror("Unknown group %s", $1);
|
|
break;
|
|
}
|
|
|
|
$$ = gr->gr_gid;
|
|
}
|
|
|
|
elevate: /* Empty */
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
}
|
|
| AS uid
|
|
{
|
|
if (!iamroot) {
|
|
yyerror("Privilege elevation not allowed.");
|
|
break;
|
|
}
|
|
|
|
$$.e_flags = ELEVATE_UID;
|
|
$$.e_uid = $2;
|
|
}
|
|
| AS uid COLON gid
|
|
{
|
|
if (!iamroot) {
|
|
yyerror("Privilege elevation not allowed.");
|
|
break;
|
|
}
|
|
|
|
$$.e_flags = ELEVATE_UID|ELEVATE_GID;
|
|
$$.e_uid = $2;
|
|
$$.e_gid = $4;
|
|
}
|
|
| AS COLON gid
|
|
{
|
|
if (!iamroot) {
|
|
yyerror("Privilege elevation not allowed.");
|
|
break;
|
|
}
|
|
|
|
$$.e_flags = ELEVATE_GID;
|
|
$$.e_gid = $3;
|
|
}
|
|
|
|
predicate : /* Empty */
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
}
|
|
| COMMA IF USER EQUAL uid
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
$$.p_uid = $5;
|
|
$$.p_flags = PREDIC_UID;
|
|
}
|
|
| COMMA IF USER NEQUAL uid
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
$$.p_uid = $5;
|
|
$$.p_flags = PREDIC_UID | PREDIC_NEGATIVE;
|
|
}
|
|
| COMMA IF GROUP EQUAL gid
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
$$.p_gid = $5;
|
|
$$.p_flags = PREDIC_GID;
|
|
}
|
|
| COMMA IF GROUP NEQUAL gid
|
|
{
|
|
memset(&$$, 0, sizeof($$));
|
|
$$.p_gid = $5;
|
|
$$.p_flags = PREDIC_GID | PREDIC_NEGATIVE;
|
|
}
|
|
|
|
expression : symbol
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| NOT expression
|
|
{
|
|
struct logic *node;
|
|
node = calloc(1, sizeof(struct logic));
|
|
if (node == NULL) {
|
|
yyerror("calloc");
|
|
break;
|
|
}
|
|
node->op = LOGIC_NOT;
|
|
node->left = $2;
|
|
$$ = node;
|
|
}
|
|
| LBRACE expression RBRACE
|
|
{
|
|
$$ = $2;
|
|
}
|
|
| expression AND expression
|
|
{
|
|
struct logic *node;
|
|
node = calloc(1, sizeof(struct logic));
|
|
if (node == NULL) {
|
|
yyerror("calloc");
|
|
break;
|
|
}
|
|
node->op = LOGIC_AND;
|
|
node->left = $1;
|
|
node->right = $3;
|
|
$$ = node;
|
|
}
|
|
| expression OR expression
|
|
{
|
|
struct logic *node;
|
|
node = calloc(1, sizeof(struct logic));
|
|
if (node == NULL) {
|
|
yyerror("calloc");
|
|
break;
|
|
}
|
|
node->op = LOGIC_OR;
|
|
node->left = $1;
|
|
node->right = $3;
|
|
$$ = node;
|
|
}
|
|
;
|
|
|
|
symbol : STRING typeoff MATCH CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_fnmatch;
|
|
$$ = node;
|
|
}
|
|
| STRING typeoff EQ CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_stringmatch;
|
|
$$ = node;
|
|
}
|
|
| STRING typeoff NEQ CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_negstringmatch;
|
|
$$ = node;
|
|
}
|
|
| STRING typeoff SUB CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_substrmatch;
|
|
$$ = node;
|
|
}
|
|
| STRING typeoff NSUB CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_negsubstrmatch;
|
|
$$ = node;
|
|
}
|
|
| STRING typeoff INPATH CMDSTRING
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol($1, $2, $4)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_inpath;
|
|
$$ = node;
|
|
}
|
|
| TRUE
|
|
{
|
|
struct logic *node;
|
|
|
|
if ((node = parse_newsymbol(NULL, -1, NULL)) == NULL)
|
|
break;
|
|
|
|
node->filter_match = filter_true;
|
|
$$ = node;
|
|
}
|
|
;
|
|
|
|
typeoff : /* empty */
|
|
{
|
|
$$ = -1;
|
|
}
|
|
| LSQBRACE NUMBER RSQBRACE
|
|
{
|
|
if ($2 < 0 || $2 >= INTERCEPT_MAXSYSCALLARGS) {
|
|
yyerror("Bad offset: %d", $2);
|
|
break;
|
|
}
|
|
$$ = $2;
|
|
}
|
|
;
|
|
action : PERMIT
|
|
{
|
|
$$ = ICPOLICY_PERMIT;
|
|
}
|
|
| DENY
|
|
{
|
|
$$ = ICPOLICY_NEVER;
|
|
}
|
|
%%
|
|
|
|
int
|
|
yyerror(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
errors = 1;
|
|
|
|
va_start(ap, fmt);
|
|
vfprintf(stdout, fmt, ap);
|
|
fprintf(stdout, "\n");
|
|
va_end(ap);
|
|
return (0);
|
|
}
|
|
|
|
struct logic *
|
|
parse_newsymbol(char *type, int typeoff, char *data)
|
|
{
|
|
struct logic *node;
|
|
|
|
node = calloc(1, sizeof(struct logic));
|
|
|
|
if (node == NULL) {
|
|
yyerror("calloc");
|
|
return (NULL);
|
|
}
|
|
node->op = LOGIC_SINGLE;
|
|
node->type = type;
|
|
node->typeoff = typeoff;
|
|
if (data) {
|
|
/* For the root user, variable expansion may change */
|
|
if (iamroot) {
|
|
node->filterdata = data;
|
|
if (filter_needexpand(data))
|
|
node->flags |= LOGIC_NEEDEXPAND;
|
|
} else {
|
|
node->filterdata = strdup(filter_expand(data));
|
|
free(data);
|
|
}
|
|
if (node->filterdata == NULL) {
|
|
yyerror("strdup");
|
|
return (NULL);
|
|
}
|
|
node->filterlen = strlen(node->filterdata) + 1;
|
|
}
|
|
|
|
return (node);
|
|
}
|
|
|
|
int
|
|
parse_filter(char *name, struct filter **pfilter)
|
|
{
|
|
|
|
errors = 0;
|
|
|
|
myfilter = NULL;
|
|
mystring = name;
|
|
myoff = 0;
|
|
|
|
yyparse();
|
|
yyrestart(NULL);
|
|
*pfilter = myfilter;
|
|
return (errors ? -1 : 0);
|
|
}
|