【问题标题】:Combining R plumber and RAppArmor结合 R 管道工和 RAppArmor
【发布时间】:2020-12-10 14:11:34
【问题描述】:

我只是想以某种方式组合管道工和 RAppArmor 包,用户可以使用管道工 API 将代码发送到服务器,然后在 RAppArmor 中的配置文件的帮助下安全地评估该服务器。我怎样才能使以下代码工作:

#* Evaluate the result
#* @post /eval_res
function(func){
  library("RAppArmor")
  data <- cbind(rnorm(100),rnorm(100))
  eval.secure(nrow(data),profile="r-user")
}

此代码块是稍后发生的事情的简化版本。到目前为止,似乎函数中指定的任何对象,例如鉴于 r-user 中的用户限制(RAppArmor 的标准配置文件),无法将数据传递给 eval.secure。我什至尝试通过编辑配置文件来允许 r-user 完全访问 /**,但没有成功。在 localhost 上打开管道工并使用带有 curl --data "func=function(x){return(nrow(x))}" "http://localhost:8000/eval_res" 的 curl 来获取 eval.secure() 的结果会导致空答案 {}。相同的代码在没有 eval.secure() 的情况下工作并正确返回 [100]。有人可以帮助我,以便我更好地理解问题甚至修复代码吗?

我目前的解决方法是在 eval.secure() 之前将所有内容保存到 csv,然后在 eval.secure 中读取它,授予对 r-user 配置文件中该文件夹的访问权限,但这绝对不是一个令人信服的解决方案。

对于那些对函数感到困惑的人:在后面的步骤中,选项 func 将包含一些将被解析和评估的代码,但对于这个小例子,我认为它只会增加不必要的复杂性。

提前致谢!

【问题讨论】:

    标签: r plumber apparmor


    【解决方案1】:
    library("RAppArmor")
    
    #* Evaluate the result
    #* @post /eval_res
    function(func){
      data <- cbind(rnorm(100),rnorm(100))
      unix::eval_safe(nrow(data), profile="r-user")
    }
    

    所以

    library("RAppArmor")
    
    #* Evaluate the result
    #* @post /eval_res
    function(func){
      data <- cbind(rnorm(100),rnorm(100))
      unix::eval_safe(eval(parse(text=func)), profile="r-user")
    }
    

    eval.secure 只需将所有参数传递给unix::eval_safeeval.secure 不起作用的原因是因为eval_safe 期望在其parent.frame() 中找到您的变量,而在eval.secure 的情况下是一个空函数体。

    eval_safeparent.frame()的使用

    function (expr, tmp = tempfile("fork"), std_out = stdout(), std_err = stderr(), 
        timeout = 0, priority = NULL, uid = NULL, gid = NULL, rlimits = NULL, 
        profile = NULL, device = pdf) 
    {
        orig_expr <- substitute(expr)
        out <- eval_fork(expr = tryCatch({
            if (length(priority)) 
                setpriority(priority)
            if (length(rlimits)) 
                set_rlimits(rlimits)
            if (length(gid)) 
                setgid(gid)
            if (length(uid)) 
                setuid(uid)
            if (length(profile)) 
                aa_change_profile(profile)
            if (length(device)) 
                options(device = device)
            graphics.off()
            options(menu.graphics = FALSE)
    ------> serialize(withVisible(eval(orig_expr, parent.frame())), 
                NULL)
        }, error = function(e) {
            old_class <- attr(e, "class")
            structure(e, class = c(old_class, "eval_fork_error"))
        }, finally = substitute(graphics.off())), tmp = tmp, timeout = timeout, 
            std_out = std_out, std_err = std_err)
        if (inherits(out, "eval_fork_error")) 
            base::stop(out)
        res <- unserialize(out)
        if (res$visible) 
            res$value
        else invisible(res$value)
    }
    
    # parent.frame() in eval_safe when using eval.secure
    function (...) 
    {
      # nothing here  
      unix::eval_safe(...)
    }
    
    # parent.frame() when using eval_safe directly
    function(func){
      data <- cbind(rnorm(100),rnorm(100))
      # Your stuff is here
      unix::eval_safe(nrow(data), profile="r-user")
    }
    

    【讨论】:

    • 这正是我所需要的。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2015-01-18
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    相关资源
    最近更新 更多