2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 10:07:12 +00:00

Merge in r1413 and r1418: report correct filename/line number on errors

in the parser.

r1413 Nominated-by: Kees Cook <kees@ubuntu.com>
r1413 Acked-By: Steve Beattie <sbeattie@ubuntu.com>
r1418 Nominated-by: Steve Beattie <sbeattie@ubuntu.com>
r1418 Acked-By: Kees Cook <kees@ubuntu.com>
r1418 Acked-By: John Johansen <john.johansen@canonical.com>
This commit is contained in:
Steve Beattie 2010-06-25 12:58:17 -07:00
parent 26624648f8
commit 8525087270
14 changed files with 311 additions and 27 deletions

View File

@ -270,3 +270,63 @@ static char *stripblanks(char *s)
*s = 0;
return c;
}
struct include_stack_t {
char *filename;
int lineno;
struct include_stack_t *next;
};
struct include_stack_t *include_stack_head = NULL;
static void start_include_position(char *filename)
{
if (current_filename)
free(current_filename);
current_filename = strdup(filename ? filename : "stdin");
current_lineno = 1;
}
void push_include_stack(char *filename)
{
struct include_stack_t *include = NULL;
include = malloc(sizeof(*include));
if (!include) {
perror("malloc of included file stack tracker");
/* failures in this area are non-fatal */
return;
}
include->filename = strdup(current_filename);
include->lineno = current_lineno;
include->next = include_stack_head;
include_stack_head = include;
start_include_position(filename);
}
void pop_include_stack(void)
{
struct include_stack_t *include = NULL;
if (!include_stack_head)
return;
include = include_stack_head;
include_stack_head = include->next;
if (current_filename)
free(current_filename);
current_filename = include->filename;
current_lineno = include->lineno;
free(include);
}
void reset_include_stack(char *filename)
{
while (include_stack_head)
pop_include_stack();
start_include_position(filename);
}

View File

@ -1,5 +1,3 @@
/* $Id$ */
/*
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
* NOVELL (All rights reserved)
@ -21,6 +19,8 @@
#define PARSER_INCLUDE_H
extern int preprocess_only;
extern int current_lineno;
extern char *current_filename;
extern int add_search_dir(char *dir);
extern void init_base_dir(void);
@ -29,4 +29,8 @@ extern void parse_default_paths(void);
extern int do_include_preprocessing(char *profilename);
FILE *search_path(char *filename, char **fullpath);
extern void push_include_stack(char *filename);
extern void pop_include_stack(void);
extern void reset_include_stack(char *filename);
#endif

View File

@ -49,7 +49,8 @@
#endif
#define NPDEBUG(fmt, args...) /* Do nothing */
int current_lineno = 1;
int current_lineno = 1;
char *current_filename = NULL;
struct ignored_suffix_t {
char * text;
@ -87,7 +88,8 @@ void include_filename(char *filename, int search)
}
if (!include_file)
yyerror(_("Could not open '%s'"), fullpath);
yyerror(_("Could not open '%s'"),
fullpath ? fullpath: filename);
if (fstat(fileno(include_file), &my_stat))
yyerror(_("fstat failed for '%s'"), fullpath);
@ -95,6 +97,7 @@ void include_filename(char *filename, int search)
if (S_ISREG(my_stat.st_mode)) {
yyin = include_file;
PDEBUG("Opened include \"%s\"\n", fullpath);
push_include_stack(fullpath);
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
}
@ -139,8 +142,9 @@ void include_filename(char *filename, int search)
yyerror(_("stat failed for '%s'"), dirent_path);
if (S_ISREG(my_stat.st_mode)) {
if (!(yyin = fopen(dirent_path,"r")))
yyerror(_("Could not open '%s'"), filename);
PDEBUG("Opened include \"%s\"\n", filename);
yyerror(_("Could not open '%s' in '%s'"), dirent_path, filename);
PDEBUG("Opened include \"%s\" in \"%s\"\n", dirent_path, filename);
push_include_stack(dirent_path);
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
}
@ -227,6 +231,7 @@ LT_EQUAL <=
}
<<EOF>> {
pop_include_stack();
yypop_buffer_state();
if ( !YY_CURRENT_BUFFER ) yyterminate();
}
@ -421,7 +426,6 @@ LT_EQUAL <=
#include/.*\r?\n { /* include */
PDEBUG("Matched #include\n");
current_lineno++;
BEGIN(INCLUDE);
}

View File

@ -85,8 +85,6 @@ int perms_create = 0; /* perms contain create flag */
char *profile_namespace = NULL;
int flag_changehat_version = FLAG_CHANGEHAT_1_5;
extern int current_lineno;
/* per-profile settings */
int force_complain = 0;
char *profilename = NULL;
@ -224,8 +222,10 @@ void pwarn(char *fmt, ...)
if (conf_quiet || names_only || option == OPTION_REMOVE)
return;
rc = asprintf(&newfmt, _("Warning (%s line %d): %s"),
rc = asprintf(&newfmt, _("Warning from %s (%s%sline %d): %s"),
profilename ? profilename : "stdin",
current_filename ? current_filename : "",
current_filename ? " " : "",
current_lineno,
fmt);
if (!newfmt)
@ -695,12 +695,13 @@ int process_binary(int option, char *profilename)
return retval;
}
void reset_parser(void)
void reset_parser(char *filename)
{
free_aliases();
free_symtabs();
free_policies();
reset_regex();
reset_include_stack(filename);
}
int process_profile(int option, char *profilename)
@ -796,7 +797,7 @@ int process_profile(int option, char *profilename)
if (yyin)
yyrestart(yyin);
reset_parser();
reset_parser(profilename);
retval = yyparse();
if (retval != 0)

View File

@ -32,6 +32,7 @@
/* #define DEBUG */
#include "parser.h"
#include "parser_include.h"
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@ -63,10 +64,6 @@
#define CAP_TO_MASK(x) (1ull << (x))
/* from lex_config, for nice error messages */
/* extern char *current_file; */
extern int current_lineno;
struct value_list {
char *value;
struct value_list *next;
@ -1109,10 +1106,15 @@ void yyerror(char *msg, ...)
va_end(arg);
if (profilename) {
PERROR(_("AppArmor parser error in %s at line %d: %s\n"),
profilename, current_lineno, buf);
PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
profilename,
current_filename ? " in " : "",
current_filename ? current_filename : "",
current_lineno, buf);
} else {
PERROR(_("AppArmor parser error, line %d: %s\n"),
PERROR(_("AppArmor parser error,%s%s line %d: %s\n"),
current_filename ? " in " : "",
current_filename ? current_filename : "",
current_lineno, buf);
}

View File

@ -1,8 +1,9 @@
#
# $Id$
#
PROVE=/usr/bin/prove
TESTS=simple.pl
PARSER_DIR=..
PARSER_BIN=apparmor_parser
PARSER=$(PARSER_DIR)/$(PARSER_BIN)
ifeq ($(VERBOSE),1)
PROVE_ARG=-v
@ -10,9 +11,23 @@ endif
all: tests
.PHONY: tests
tests: ../apparmor_parser
.PHONY: tests error_output parser_sanity
tests: error_output parser_sanity
error_output: $(PARSER)
$(PARSER) -S -I errors >/dev/null errors/okay.sd
LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/single.sd | \
grep -q "AppArmor parser error for errors/single.sd in errors/single.sd at line 3: Could not open 'failure'"
LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/double.sd | \
grep -q "AppArmor parser error for errors/double.sd in errors/includes/busted at line 67: Could not open 'does-not-exist'"
LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/modefail.sd | \
grep -q "AppArmor parser error for errors/modefail.sd in errors/modefail.sd at line 6: syntax error"
LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/multi_include.sd | \
grep -q "AppArmor parser error for errors/multi_include.sd in errors/multi_include.sd at line 12: Could not open 'failure'"
@echo "Error Output: PASS"
parser_sanity: $(PARSER)
$(Q)${PROVE} ${PROVE_ARG} ${TESTS}
../apparmor_parser:
make -C .. apparmor_parser
$(PARSER):
make -C $(PARSER_DIR) $(PARSER_BIN)

View File

@ -64,5 +64,3 @@ The simple script looks for a few special comments in the profile,
loop.
Otherwise, the profile is passed on as-is to the subdomain parser.
$Id$

View File

@ -0,0 +1,5 @@
#
/does/not/exist {
#include <includes/base>
#include <includes/busted>
}

View File

@ -0,0 +1,81 @@
# $Id$
# ------------------------------------------------------------------
#
# Copyright (C) 2002-2005 Novell/SUSE
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
# (Note that the ldd profile has inlined this file; if you make
# modifications here, please consider including them in the ldd
# profile as well.)
# The __canary_death_handler function writes a time-stamped log
# message to /dev/log for logging by syslogd. So, /dev/log, timezones,
# and localisations of date should be available EVERYWHERE, so
# StackGuard, FormatGuard, etc., alerts can be properly logged.
/dev/log w,
/dev/urandom r,
/etc/locale/** r,
/etc/localtime r,
/usr/share/locale/** r,
/usr/share/zoneinfo/** r,
/usr/lib64/locale/** r,
/usr/lib64/gconv/*.so r,
/usr/lib64/gconv/gconv-modules* r,
/usr/lib/locale/** r,
/usr/lib/gconv/*.so r,
/usr/lib/gconv/gconv-modules* r,
# used by glibc when binding to ephemeral ports
/etc/bindresvport.blacklist r,
# ld.so.cache and ld are used to load shared libraries; they are best
# available everywhere
/etc/ld.so.cache r,
# 'px' requires a profile to be available for the transition to
# function; without a loaded profile, the kernel will fail the exec.
/lib/ld-*.so px,
/lib64/ld-*.so px,
/opt/*-linux-uclibc/lib/ld-uClibc*so* px,
# we might as well allow everything to use common libraries
/lib/lib*.so* r,
/lib/tls/lib*.so* r,
/lib/power4/lib*.so* r,
/lib/power5/lib*.so* r,
/lib/power5+/lib*.so* r,
/lib64/power4/lib*.so* r,
/lib64/power5/lib*.so* r,
/lib64/power5+/lib*.so* r,
/usr/lib/*.so* r,
/usr/lib/tls/lib*.so* r,
/usr/lib/power4/lib*.so* r,
/usr/lib/power5/lib*.so* r,
/usr/lib/power5+/lib*.so* r,
/lib64/lib*.so* r,
/lib64/tls/lib*.so* r,
/usr/lib64/*.so* r,
/usr/lib64/tls/lib*.so* r,
# /dev/null is pretty harmless and frequently used
/dev/null rw,
# as is /dev/zero
/dev/zero rw,
# Sometimes used to determine kernel/user interfaces to use
/proc/sys/kernel/version r,
# Depending on which glibc routine uses this file, base may not be the
# best place -- but many profiles require it, and it is quite harmless.
/proc/sys/kernel/ngroups_max r,
# glibc's sysconf(3) routine to determine free memory, etc
/proc/meminfo r,
/proc/stat r,
/proc/cpuinfo r,

View File

@ -0,0 +1,83 @@
# $Id$
# ------------------------------------------------------------------
#
# Copyright (C) 2002-2005 Novell/SUSE
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
# (Note that the ldd profile has inlined this file; if you make
# modifications here, please consider including them in the ldd
# profile as well.)
# The __canary_death_handler function writes a time-stamped log
# message to /dev/log for logging by syslogd. So, /dev/log, timezones,
# and localisations of date should be available EVERYWHERE, so
# StackGuard, FormatGuard, etc., alerts can be properly logged.
/dev/log w,
/dev/urandom r,
/etc/locale/** r,
/etc/localtime r,
/usr/share/locale/** r,
/usr/share/zoneinfo/** r,
/usr/lib64/locale/** r,
/usr/lib64/gconv/*.so r,
/usr/lib64/gconv/gconv-modules* r,
/usr/lib/locale/** r,
/usr/lib/gconv/*.so r,
/usr/lib/gconv/gconv-modules* r,
# used by glibc when binding to ephemeral ports
/etc/bindresvport.blacklist r,
# ld.so.cache and ld are used to load shared libraries; they are best
# available everywhere
/etc/ld.so.cache r,
# 'px' requires a profile to be available for the transition to
# function; without a loaded profile, the kernel will fail the exec.
/lib/ld-*.so px,
/lib64/ld-*.so px,
/opt/*-linux-uclibc/lib/ld-uClibc*so* px,
# we might as well allow everything to use common libraries
/lib/lib*.so* r,
/lib/tls/lib*.so* r,
/lib/power4/lib*.so* r,
/lib/power5/lib*.so* r,
/lib/power5+/lib*.so* r,
/lib64/power4/lib*.so* r,
/lib64/power5/lib*.so* r,
/lib64/power5+/lib*.so* r,
/usr/lib/*.so* r,
/usr/lib/tls/lib*.so* r,
/usr/lib/power4/lib*.so* r,
/usr/lib/power5/lib*.so* r,
/usr/lib/power5+/lib*.so* r,
/lib64/lib*.so* r,
/lib64/tls/lib*.so* r,
/usr/lib64/*.so* r,
/usr/lib64/tls/lib*.so* r,
#include <does-not-exist>
# /dev/null is pretty harmless and frequently used
/dev/null rw,
# as is /dev/zero
/dev/zero rw,
# Sometimes used to determine kernel/user interfaces to use
/proc/sys/kernel/version r,
# Depending on which glibc routine uses this file, base may not be the
# best place -- but many profiles require it, and it is quite harmless.
/proc/sys/kernel/ngroups_max r,
# glibc's sysconf(3) routine to determine free memory, etc
/proc/meminfo r,
/proc/stat r,
/proc/cpuinfo r,

View File

@ -0,0 +1,7 @@
# 1
# 2
# 3
/does/not/exist { # 4
/lib/lib*.so rm, # 5
/fail abcdefgh, # 6
} # 7

View File

@ -0,0 +1,13 @@
#
#
#
/does/not/exist {
#include <includes/base>
#include <includes/base>
#include <includes/base>
#include <includes/base>
/bin/true rix,
#include <failure>
}

View File

@ -0,0 +1,4 @@
#
/does/not/exist {
#include <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#
#include <failure>
#
/does/not/exist {
#include <includes/base>
}