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::{ use gpsl::{
gpsl::GPSL, vm::gpsl::GPSL,
source::Source, source::Source,
std::*, external_function::*,
tokenizer::Tokenizer, tokenizer::Tokenizer,
parser::Parser 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 source = Source::new(fs::read_to_string(&(args.last().unwrap())).expect("Cannot read file."));
let mut tokenizer = Tokenizer::new(); let mut tokenizer = Tokenizer::new();
tokenizer.tokenize(&mut source); tokenizer.tokenize(&mut source).unwrap();
let mut parser = Parser { let mut parser = Parser {
tokenizer, tokenizer,

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

View File

@@ -17,12 +17,14 @@ stmt: let
; ;
let: LET IDENT COLON IDENT SEMICOLON ; let: LET IDENT COLON IDENT SEMICOLON ;
block: LCURL stmt* RCURL ; block: permission? LCURL stmt* RCURL ;
return: RETURN expr? SEMICOLON ; return: RETURN expr? SEMICOLON ;
if: IF LPAREN expr RPAREN stmt (ELSE stmt)? ; if: IF LPAREN expr RPAREN stmt (ELSE stmt)? ;
while: WHILE LPAREN expr RPAREN stmt ; while: WHILE LPAREN expr RPAREN stmt ;
for: FOR LPAREN expr? SEMICOLON expr? SEMICOLON 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 ; expr: assign ;
assign: equality (EQ assign)? ; assign: equality (EQ assign)? ;
equality: relational (EQEQ relational | NE relational | CONJ)* ; equality: relational (EQEQ relational | NE relational | CONJ)* ;

View File

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

View File

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

View File

@@ -10,11 +10,14 @@ pub struct Parser {
} }
impl Parser { impl Parser {
pub fn functions(&mut self) -> Result<Vec<Box<Node>>, String> { pub fn functions(&mut self) -> Result<HashMap<String, Box<Node>>, String> {
let mut nodes: Vec<Box<Node>> = vec![]; let mut nodes: HashMap<String, Box<Node>> = HashMap::new();
loop { loop {
if self.tokenizer.current_token().kind != TokenKind::EOF { 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 { } else {
return Ok(nodes); return Ok(nodes);
} }
@@ -40,6 +43,7 @@ impl Parser {
self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(",")); self.tokenizer.consume_kind_str(TokenKind::RESERVED, String::from(","));
args.insert(name, type_str); args.insert(name, type_str);
} }
let mut nodes: Vec<Box<Node>> = vec![]; let mut nodes: Vec<Box<Node>> = vec![];
debug!("parsing body node"); debug!("parsing body node");
loop { loop {
@@ -99,9 +103,16 @@ impl Parser {
})); }));
} }
debug!("parsing permission");
let permission = if self.tokenizer.current_token().str == "$" {
Some(self.permission()?)
} else {
None
};
if self if self
.tokenizer .tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("{")) .consume_kind_str(TokenKind::RESERVED, String::from("{")) || permission != None
{ {
let mut stmts: Vec<Box<Node>> = vec![]; let mut stmts: Vec<Box<Node>> = vec![];
loop { loop {
@@ -109,7 +120,7 @@ impl Parser {
.tokenizer .tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("}")) .consume_kind_str(TokenKind::RESERVED, String::from("}"))
{ {
return Ok(Box::new(Node::Block { stmts })); return Ok(Box::new(Node::Block { stmts, permission: permission }));
} else { } else {
stmts.push(self.stmt()?); stmts.push(self.stmt()?);
} }
@@ -196,6 +207,39 @@ impl Parser {
return node; 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 ; expr: assign ;
*/ */

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("$"),
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("]"),
String::from("=="), String::from("=="),
String::from("!="), String::from("!="),
String::from(">="), String::from(">="),
@@ -152,7 +155,7 @@ impl Tokenizer {
Ok(t) => t, Ok(t) => t,
Err(_) => String::from(""), Err(_) => String::from(""),
}; };
source.get_char(is('"')); source.get_char(is('"'))?;
self.tokens.push(Token { self.tokens.push(Token {
kind: TokenKind::TEXT, kind: TokenKind::TEXT,
str: text, str: text,

View File

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

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; fn untrusted_function(a: num) $(accept[StdIo]) {
a = "test"; println("test");
println(a); }
fn main() $(accept[Administrator, StdIo]) {
println("1");
$(accept[StdIo], reject[Administrator]) {
untrusted_function();
}
println("2");
} }