add security

This commit is contained in:
mii
2022-07-07 11:49:53 +09:00
parent 8805271801
commit a1d0d04f1d
15 changed files with 349 additions and 147 deletions

BIN
gpsl.exe Normal file

Binary file not shown.

View File

@ -1,7 +1,7 @@
use gpsl::{
gpsl::GPSL,
vm::gpsl::GPSL,
source::Source,
std::*,
external_function::*,
tokenizer::Tokenizer,
parser::Parser
};
@ -14,7 +14,7 @@ fn main() {
let mut source = Source::new(fs::read_to_string(&(args.last().unwrap())).expect("Cannot read file."));
let mut tokenizer = Tokenizer::new();
tokenizer.tokenize(&mut source);
tokenizer.tokenize(&mut source).unwrap();
let mut parser = Parser {
tokenizer,
@ -26,4 +26,4 @@ fn main() {
if let Err(err) = res {
println!("Error: {:?}", err);
}
}
}

19
src/bin/test.rs Normal file
View File

@ -0,0 +1,19 @@
use std::collections::VecDeque;
fn main() {
println!("testing binary");
let mut queue: VecDeque<i64> = VecDeque::new();
queue.push_back(1i64);
queue.push_back(2i64);
queue.push_back(3i64);
for x in 0..queue.len() {
println!("{}", queue[x]);
}
println!("{:?}", queue);
println!("{:?}", queue.len());
}

63
src/external_function.rs Normal file
View File

@ -0,0 +1,63 @@
use crate::{variable::Variable, permission::Permission};
#[derive(PartialEq)]
pub enum ExternalFuncStatus {
SUCCESS,
NOTFOUND,
ERROR,
REJECTED,
}
pub struct ExternalFuncReturn {
pub status: ExternalFuncStatus,
pub value: Option<Variable>
}
#[allow(dead_code)]
pub const STD_FUNC: fn(String, Vec<Variable>, Vec<Permission>, Vec<Permission>) -> ExternalFuncReturn = |name, args, accept, reject| {
let name = name.as_str();
match name {
"println" => {
if accept.contains(&Permission::StdIo) && !reject.contains(&Permission::StdIo) {
match &args[0] {
Variable::Text { value } => println!("{}", value),
Variable::Number { value } => println!("{}", value),
_ => {}
}
ExternalFuncReturn {
status: ExternalFuncStatus::SUCCESS,
value: None
}
} else {
ExternalFuncReturn {
status: ExternalFuncStatus::REJECTED,
value: None
}
}
}
"print" => {
if accept.contains(&Permission::StdIo) && !reject.contains(&Permission::StdIo) {
match &args[0] {
Variable::Text { value } => print!("{}", value),
Variable::Number { value } => print!("{}", value),
_ => {}
}
ExternalFuncReturn {
status: ExternalFuncStatus::SUCCESS,
value: None
}
} else {
ExternalFuncReturn {
status: ExternalFuncStatus::REJECTED,
value: None
}
}
}
_ => {
ExternalFuncReturn {
status: ExternalFuncStatus::NOTFOUND,
value: None
}
}
}
};

View File

@ -5,6 +5,7 @@ WS
-> skip
;
DOLLER: '$' ;
ADD: '+' ;
SUB: '-' ;
MUL: '*' ;
@ -31,6 +32,8 @@ LPAREN: '(' ;
RPAREN: ')' ;
LCURL: '{' ;
RCURL: '}' ;
LBRACKET: '[' ;
RBRACKET: ']' ;
ARROW: '->' ;
FN: 'fn' ;

View File

@ -7,22 +7,24 @@ function: FN IDENT LPAREN (IDENT COLON IDENT COMMA?)* RPAREN (ARROW IDENT)? bloc
program: stmt* ;
stmt: let
| block
| return
| if
| while
| for
| expr SEMICOLON
stmt: let
| block
| return
| if
| while
| for
| expr SEMICOLON
;
let: LET IDENT COLON IDENT SEMICOLON ;
block: LCURL stmt* RCURL ;
block: permission? LCURL stmt* RCURL ;
return: RETURN expr? SEMICOLON ;
if: IF LPAREN expr RPAREN stmt (ELSE stmt)? ;
while: WHILE LPAREN expr RPAREN stmt ;
for: FOR LPAREN expr? SEMICOLON expr? SEMICOLON expr? RPAREN stmt ;
permission: DOLLER LPAREN ( IDENT LBRACKET ( IDENT COMMA? )* RBRACKET COMMA? )* RPAREN ;
expr: assign ;
assign: equality (EQ assign)? ;
equality: relational (EQEQ relational | NE relational | CONJ)* ;
@ -33,7 +35,7 @@ mul: unary (MUL unary | DIV unary | DIV_ASSIGNMENT unary | MUL_ASSIGNMENT unary)
primary: LPAREN expr RPAREN | function_call | TEXT | NUM ;
function_call: IDENT LPAREN (unary COMMA?)* RPAREN ;
unary: ADD primary
| SUB primary
| primary
unary: ADD primary
| SUB primary
| primary
;

View File

@ -1,10 +1,11 @@
pub mod node;
pub mod parser;
pub mod gpsl;
pub mod vm;
pub mod source;
pub mod token;
pub mod tokenizer;
pub mod variable;
pub mod std;
pub mod external_function;
pub mod permission;
#[macro_use]
extern crate log;

View File

@ -20,6 +20,10 @@ pub enum Node {
args: HashMap<String, String>,
body: Vec<Box<Node>>
},
Permission {
accept: Vec<String>,
reject: Vec<String>
},
Operator {
kind: NodeKind,
lhs: Box<Node>,
@ -54,15 +58,17 @@ pub enum Node {
},
Block {
stmts: Vec<Box<Node>>,
permission: Option<Box<Node>>
},
Define {
name: String,
var_type: String,
},
Call {
name: String,
args: Vec<Box<Node>>,
}
name: String,
args: Vec<Box<Node>>,
},
None
}
impl Node {

View File

@ -10,11 +10,14 @@ pub struct Parser {
}
impl Parser {
pub fn functions(&mut self) -> Result<Vec<Box<Node>>, String> {
let mut nodes: Vec<Box<Node>> = vec![];
pub fn functions(&mut self) -> Result<HashMap<String, Box<Node>>, String> {
let mut nodes: HashMap<String, Box<Node>> = HashMap::new();
loop {
if self.tokenizer.current_token().kind != TokenKind::EOF {
nodes.push(self.function()?);
let function = self.function()?;
if let Node::Function{name, .. } = *function.clone() {
nodes.insert(name, function);
}
} else {
return Ok(nodes);
}
@ -40,6 +43,7 @@ impl Parser {
self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(","));
args.insert(name, type_str);
}
let mut nodes: Vec<Box<Node>> = vec![];
debug!("parsing body node");
loop {
@ -73,13 +77,13 @@ impl Parser {
}
/*
stmt: let
| block
| return
| if
| while
| for
| expr SEMICOLON
stmt: let
| block
| return
| if
| while
| for
| expr SEMICOLON
;
*/
pub fn stmt(&mut self) -> Result<Box<Node>, String> {
@ -99,9 +103,16 @@ impl Parser {
}));
}
debug!("parsing permission");
let permission = if self.tokenizer.current_token().str == "$" {
Some(self.permission()?)
} else {
None
};
if self
.tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("{"))
.consume_kind_str(TokenKind::RESERVED, String::from("{")) || permission != None
{
let mut stmts: Vec<Box<Node>> = vec![];
loop {
@ -109,7 +120,7 @@ impl Parser {
.tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("}"))
{
return Ok(Box::new(Node::Block { stmts }));
return Ok(Box::new(Node::Block { stmts, permission: permission }));
} else {
stmts.push(self.stmt()?);
}
@ -196,6 +207,39 @@ impl Parser {
return node;
}
/*
permission: DOLLER LPAREN ( IDENT LBRACKET ( IDENT COMMA? )* RBRACKET COMMA? )* RPAREN ;
*/
pub fn permission(&mut self) -> Result<Box<Node>, String> {
self.tokenizer.expect(String::from("$"))?;
self.tokenizer.expect(String::from("("))?;
let mut accept: Vec<String> = vec![];
let mut reject: Vec<String> = vec![];
while !self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(")")) {
let name = self.tokenizer.expect_ident()?;
if name != "accept" && name != "reject" {
return Err(String::from(format!("Unexpected: {}", name)));
}
self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from("["));
while !self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from("]")) {
let permission = self.tokenizer.expect_ident()?;
self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(","));
if name == "accept" {
accept.push(permission);
} else if name == "reject" {
reject.push(permission);
}
}
self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(","));
}
Ok(Box::new(Node::Permission { accept, reject }))
}
/*
expr: assign ;
*/
@ -329,11 +373,11 @@ impl Parser {
args.push(self.unary()?);
self.tokenizer.consume(String::from(","));
}
self.tokenizer.expect(String::from(")"))?;
return Ok(Box::new(Node::Call {
name: node.clone(),
args: args,
name: node.clone(),
args: args,
}))
}
return Ok(Node::new_lvar_node(node.clone()));
@ -351,9 +395,9 @@ impl Parser {
}
/*
unary: ADD primary
| SUB primary
| primary
unary: ADD primary
| SUB primary
| primary
;
*/
pub fn unary(&mut self) -> Result<Box<Node>, String> {

16
src/permission.rs Normal file
View File

@ -0,0 +1,16 @@
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Permission {
Administrator,
StdIo
}
impl Permission {
pub fn from_string(permission: &str) -> Self {
match permission {
"Administrator" => Self::Administrator,
"StdIo" => Self::StdIo,
_ => panic!("Permission not found.")
}
}
}

View File

@ -1,37 +0,0 @@
use crate::variable::Variable;
use crate::gpsl::*;
#[allow(dead_code)]
pub const STD_FUNC: fn(String, Vec<Variable>) -> ExternalFuncReturn = |name, args| {
let name = name.as_str();
match name {
"println" => {
match &args[0] {
Variable::Text { value } => println!("{}", value),
Variable::Number { value } => println!("{}", value),
_ => {}
}
ExternalFuncReturn {
status: ExternalFuncStatus::SUCCESS,
value: None
}
}
"print" => {
match &args[0] {
Variable::Text { value } => print!("{}", value),
Variable::Number { value } => print!("{}", value),
_ => {}
}
ExternalFuncReturn {
status: ExternalFuncStatus::SUCCESS,
value: None
}
}
_ => {
ExternalFuncReturn {
status: ExternalFuncStatus::NOTFOUND,
value: None
}
}
}
};

View File

@ -113,6 +113,7 @@ impl Tokenizer {
String::from("-="),
String::from("*="),
String::from("/="),
String::from("$"),
String::from("+"),
String::from("-"),
String::from("*"),
@ -123,6 +124,8 @@ impl Tokenizer {
String::from("}"),
String::from("("),
String::from(")"),
String::from("["),
String::from("]"),
String::from("=="),
String::from("!="),
String::from(">="),
@ -152,7 +155,7 @@ impl Tokenizer {
Ok(t) => t,
Err(_) => String::from(""),
};
source.get_char(is('"'));
source.get_char(is('"'))?;
self.tokens.push(Token {
kind: TokenKind::TEXT,
str: text,

View File

@ -1,38 +1,35 @@
use crate::external_function::{ExternalFuncReturn, ExternalFuncStatus};
use crate::node::*;
use crate::parser::*;
use crate::permission::Permission;
use crate::source::Source;
use crate::tokenizer::*;
use crate::variable::*;
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::string::*;
use uuid::Uuid;
#[derive(PartialEq)]
pub enum ExternalFuncStatus {
SUCCESS,
NOTFOUND,
ERROR,
}
pub struct ExternalFuncReturn {
pub status: ExternalFuncStatus,
pub value: Option<Variable>
#[derive(Clone, Debug)]
pub struct Block {
pub accept: Vec<Permission>,
pub reject: Vec<Permission>,
pub variables: HashMap<String, LocalVariable>,
pub is_split: bool
}
pub struct GPSL {
pub functions: Option<Vec<Box<Node>>>,
pub functions: Option<HashMap<String, Box<Node>>>,
pub global_variables: Vec<Variable>,
pub source: Source,
pub l_vars: HashMap<String, LocalVariable>,
pub external_func: Vec<fn(String, Vec<Variable>) -> ExternalFuncReturn>
pub blocks: VecDeque<Block>,
pub external_func: Vec<fn(String, Vec<Variable>, Vec<Permission>, Vec<Permission>) -> ExternalFuncReturn>
}
#[derive(Clone, Debug)]
pub struct LocalVariable {
pub name: String,
pub value: Variable,
pub status: VariableStatus,
}
#[derive(Clone, Debug)]
pub struct VariableStatus {
pub initialized: bool,
}
@ -44,16 +41,46 @@ impl VariableStatus {
}
impl GPSL {
pub fn new(source: Source, functions: Option<Vec<Box<Node>>>, external_func: Vec<fn(String, Vec<Variable>) -> ExternalFuncReturn>) -> GPSL {
pub fn new(source: Source, functions: Option<HashMap<String, Box<Node>>>, external_func: Vec<fn(String, Vec<Variable>, Vec<Permission>, Vec<Permission>) -> ExternalFuncReturn>) -> GPSL {
GPSL {
source,
functions,
global_variables: vec![],
l_vars: HashMap::new(),
blocks: VecDeque::new(),
external_func
}
}
pub fn get_local_var_mut(&mut self, name: &String) -> Option<&mut LocalVariable> {
for x in 0..self.blocks.len() {
if self.blocks[x].variables.contains_key(name) {
return self.blocks[x].variables.get_mut(name);
}
if self.blocks[x].is_split {
break
}
}
None
}
pub fn get_local_var(&mut self, name: &String) -> Option<LocalVariable> {
for x in 0..self.blocks.len() {
if self.blocks[x].variables.contains_key(name) {
if let Some(var) = self.blocks[x].variables.get(name).clone() {
return Some(var.clone());
} else {
return None;
}
}
if self.blocks[x].is_split {
break
}
}
None
}
pub fn extract_number(node: Variable) -> Result<usize, String> {
match node {
Variable::Number { value } => {
@ -78,33 +105,54 @@ impl GPSL {
}
if let Some(functions) = self.functions.clone() {
for function in functions {
match *function {
Node::Function { name, body, args } => {
if name == function_name {
for program in body {
if let Ok(Some(res)) = self.evaluate(program) {
match res {
Variable::Return { value } => {
return Ok(Some(*value));
}
_ => {}
}
debug!("functions: {:?}", functions.iter().map(|f| format!("{},", f.0)).collect::<String>());
debug!("{}: {}", &function_name, functions.contains_key(&function_name));
if functions.contains_key(&function_name) {
if let Node::Function { body, .. } = &*(functions[&function_name]) {
for program in body {
let block = {
let blocks = self.blocks.clone();
blocks.front().unwrap().clone()
};
self.blocks.push_front(Block {
accept: block.accept.clone(),
reject: block.reject.clone(),
variables: HashMap::new(),
is_split: true
});
let res = self.evaluate(Box::new(*program.clone()));
if let Ok(Some(res)) = res {
match res {
Variable::Return { value } => {
return Ok(Some(*value));
}
_ => {}
}
return Ok(None);
} else if let Err(err) = res {
return Err(err);
}
},
_ => {}
self.blocks.pop_front();
}
}
return Ok(None);
}
}
debug!("Searching external: {}, ({:?})", &function_name, args_value);
for func in f {
let res = func(function_name.clone(), args_value.clone());
let block = self.blocks.front().unwrap();
let res = func(function_name.clone(), args_value.clone(), block.accept.clone(), block.reject.clone());
if res.status == ExternalFuncStatus::SUCCESS {
return Ok(res.value);
}
if res.status == ExternalFuncStatus::REJECTED {
return Err("External function rejected.".to_string());
}
}
Err(format!("Function not found: {}", function_name))
@ -121,13 +169,15 @@ impl GPSL {
}
Node::Operator { kind, lhs, rhs } => {
if kind == NodeKind::ASSIGN {
debug!("Assign: {:?}", self.blocks.front());
let rhs = self.evaluate(rhs);
if let Ok(Some(rhs)) = rhs {
match *(lhs.clone()) {
Node::Lvar { value } => {
self.l_vars.get_mut(&value).unwrap().value = rhs;
self.l_vars.get_mut(&value).unwrap().status.initialized = true
self.get_local_var_mut(&value).unwrap().value = rhs;
self.get_local_var_mut(&value).unwrap().status.initialized = true;
}
_ => {}
}
@ -201,7 +251,7 @@ impl GPSL {
Err(err) => { Err(err) }
}
},
NodeKind::EQ => {
if lhs == rhs {
Ok(Some(Variable::Number {
@ -276,7 +326,7 @@ impl GPSL {
}
}
Node::Lvar { value } => {
return Ok(Some(self.l_vars.get(&value).unwrap().value.clone()));
return Ok(Some(self.get_local_var(&value).unwrap().value.clone()));
}
Node::Return { lhs } => {
if let Ok(Some(lhs)) = self.evaluate(lhs) {
@ -299,7 +349,7 @@ impl GPSL {
} {
if let Ok(Some(res)) = self.evaluate(stmt) {
match res.clone() {
Variable::Return { value } => {
Variable::Return { .. } => {
return Ok(Some(res));
}
_ => {}
@ -310,7 +360,7 @@ impl GPSL {
Some(else_stmt) => {
if let Ok(Some(res)) = self.evaluate(else_stmt) {
match res.clone() {
Variable::Return { value } => {
Variable::Return { .. } => {
return Ok(Some(res));
}
_ => {}
@ -370,13 +420,13 @@ impl GPSL {
}
}
},
None => {
None => {
Variable::Number {
value: 1
}
}
}
};
while match cond {
Variable::Number { value } => value == 1,
_ => false
@ -398,28 +448,46 @@ impl GPSL {
}
}
},
None => {
None => {
Variable::Number {
value: 1
}
}
}
};
}
return Ok(None);
}
Node::Block { stmts } => {
Node::Block { stmts, permission } => {
let accept = self.blocks.front().unwrap().accept.clone();
let reject = self.blocks.front().unwrap().reject.clone();
let (accept, reject) = if let Node::Permission { accept, reject } = *permission.unwrap_or(Box::new(Node::None)) {
(accept.iter().map(|p| Permission::from_string(p)).collect(), reject.iter().map(|p| Permission::from_string(p)).collect())
} else {
(accept, reject)
};
self.blocks.push_front(Block {
accept: accept,
reject: reject,
variables: HashMap::new(),
is_split: false
});
for stmt in stmts {
let ret = self.evaluate(stmt)?;
if let Some(ret) = ret {
match ret.clone() {
Variable::Return { value } => {
Variable::Return { .. } => {
return Ok(Some(ret));
}
_ => {}
}
}
}
self.blocks.pop_front();
return Ok(None);
}
Node::Define { name, var_type } => {
@ -434,7 +502,7 @@ impl GPSL {
} else {
return Err(format!("{}: 未知の型です。", var_type));
};
self.l_vars.insert(
self.blocks.front_mut().unwrap().variables.insert(
name.clone(),
LocalVariable {
name,
@ -442,34 +510,38 @@ impl GPSL {
status: VariableStatus::default(),
},
);
debug!("Define: {:?}", self.blocks.front());
return Ok(None);
}
_ => { Ok(None) },
}
}
pub fn run(&mut self, function_name: String, function_args: Vec<Box<Node>>) -> Result<Variable, String> {
pub fn run(&mut self, function_name: String, _: Vec<Box<Node>>) -> Result<Variable, String> {
debug!("functions: {:?}", self.functions);
debug!("searching {}", function_name);
self.blocks.push_front(Block {
accept: vec![Permission::Administrator, Permission::StdIo],
reject: vec![],
variables: HashMap::new(),
is_split: true
});
if let Some(functions) = self.functions.clone() {
for function in functions {
match *function {
Node::Function { name, body, args } => {
if name == function_name {
debug!("running: {}", function_name);
for program in body {
if let Ok(Some(res)) = self.evaluate(program) {
match res {
Variable::Return { value } => {
return Ok(*value);
}
_ => {}
}
}
if let Node::Function { body, .. } = &*(functions[&function_name]) {
for program in body {
let res = self.evaluate(Box::new(*program.clone()));
if let Ok(Some(res)) = res {
match res {
Variable::Return { value } => {
return Ok(*value);
}
_ => {}
}
},
_ => {}
} else if let Err(err) = res {
return Err(err);
}
}
}
}

1
src/vm/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod gpsl;

View File

@ -1,5 +1,14 @@
fn main() {
let a: String;
a = "test";
println(a);
fn untrusted_function(a: num) $(accept[StdIo]) {
println("test");
}
fn main() $(accept[Administrator, StdIo]) {
println("1");
$(accept[StdIo], reject[Administrator]) {
untrusted_function();
}
println("2");
}