dongmanni6916 2015-05-31 00:50
浏览 88
已采纳

Go [lang]二进制文件上的SetGID / SetUID是否安全?

I've written a simple go program using YAML and the MySQL drivers with the intention of providing a simple utility to update a database without exposing the username and password credentials to the user executing the program.

(I'm well aware that I could also write this in Python or some other scripting language and manage the permissions delegations using sudo but I'd like to try a different approach here, for my own edification).

After building the program I've used chgrp sys dbcreds.yaml && chmod 0640 dbcreds.yaml and chgrp sys ./myprog && chmod g+s ./myprog (as root) ... and everything seems to work. (I also tested that access was denied, as it should be, prior to the setGID step).

I also tested strace and that results in permission denied (as it should be). (For fun I also ran ltrace -S on it; this is under Linux. As expected I did not see many normal libc function calls ... through I am surprised to have seen a few pthread_....() and one malloc() calls in that listing. I guess the GO runtime does link to some system library functions after all).

My question: is this safe? Is there any known way to cause a Go program, such as this (below) to core dump or expose its memory after it has read these private credentials? Is there a way to drop my SGID privs after I've read my credentials? Are there any examples of SUID/SGID exploits on Go binaries? Is there a better way to do this? Is there a way to proactive prevent core dumps or ensure that sensitive data (credentials) would not be in core dumps?

One other note: I find the gopkg.in/yaml.v2 semantics to be a bit disconcerting. In my YAML file I have something like:

---
user me
pw mypassword

But in my code I have to use User and Pw (capitalized) rather than using lower case as I would have expected. I presume this is an implementation decision by the authors of Goyaml. Is that so?

#!go
package main

import (
    "fmt"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "os"
    "strconv"
)

type Creds struct {
    User string
    Pw   string
}

func main() {

    filename := "./dbcreds.yaml"
    var creds Creds
    conf, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }
    err = yaml.Unmarshal(conf, &creds)
    if err != nil {
        panic(err)
    }

    var arg1 int
    arg1, err = strconv.Atoi(os.Args[1])
    if err != nil {
        panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
    }

    fmt.Println("arg1: ", arg1, "
")
    dsn := fmt.Sprintf("%s:%s@/mydatabase", creds.User, creds.Pw)
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()

    err = db.Ping()
    if err != nil {
        panic(err.Error())
    }

    stmtOut, err := db.Prepare("SELECT quant FROM c WHERE id >= ?")
    if err != nil {
        panic(err.Error())
    }
    defer stmtOut.Close()

    rows, err := stmtOut.Query(arg1)
    if err != nil {
        panic(err.Error())
    }
    defer rows.Close()

    for rows.Next() {
        var quant int
        err = rows.Scan(&quant)
        if err != nil {
            panic(err.Error())
        }
        fmt.Println(quant)
    }
}
  • 写回答

1条回答 默认 最新

  • dpftppc9674 2015-05-31 16:52
    关注

    A setuid/setgid Go program is reasonably safe, with one major caveat. Go setuid/setgid programs are in general no more, and no less, secure than C/C++ setuid/setgid programs.

    It's true that you can force a Go program to dump core by running it with the environment variable GOTRACEBACK=crash and then sending it a signal. However, this is OK for your purposes because the Go program will (try to) create the core dump by sending itself the SIGABRT signal. The kernel will not generate a core dump for a setuid/setgid program killed by a signal.

    The major caveat for Go is that on GNU/Linux systems you can not drop back to the original user ID. This is because of how setuid (and setgid, setgroups, setreuid, setregid, setresuid, and setresgid) are implemented for multi-threaded programs on GNU/Linux. The details are at http://golang.org/issue/1435 .

    On your final note Uw and Pw need to be capitalized because the standard reflect package does not permit writing to unexported fields.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥30 python代码,帮调试,帮帮忙吧