sudo - Is SetGID/SetUID on a Go[lang] binary safe? -
i've written simple
go program using yaml , mysql drivers intention of providing simple utility update database without exposing username , password credentials user executing program.
(i'm aware write in python or other scripting language , manage permissions delegations using sudo i'd try different approach here, own edification).
after building program i've used chgrp sys dbcreds.yaml && chmod 0640 dbcreds.yaml , chgrp sys ./myprog && chmod g+s ./myprog (as root) ... , seems work. (i tested access denied, should be, prior setgid step).
i tested strace results in permission denied (as should be). (for fun ran ltrace -s on it; under linux. expected did not see many normal libc function calls ... through surprised have seen few pthread_....() , 1 malloc() calls in listing. guess go runtime link system library functions after all).
my question: safe? there known way cause go program, such (below) core dump or expose memory after has read these private credentials? there way drop sgid privs after i've read credentials? there examples of suid/sgid exploits on go binaries? there better way this?
one other note: find gopkg.in/yaml.v2 semantics bit disconcerting. in yaml file have like:
--- user me pw mypassword but in code have use user , pw (capitalized) rather using lower case have expected. presume implementation decision authors of goyaml. 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()) // example purpose. should use proper error handling instead of panic } fmt.println("arg1: ", arg1, "\n") 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 c id >= ?") if err != nil { panic(err.error()) } defer stmtout.close() rows, err := stmtout.query(arg1) if err != nil { panic(err.error()) } defer rows.close() rows.next() { var quant int err = rows.scan(&quant) if err != nil { panic(err.error()) } fmt.println(quant) } }
a setuid/setgid go program reasonably safe, 1 major caveat. go setuid/setgid programs in general no more, , no less, secure c/c++ setuid/setgid programs.
it's true can force go program dump core running environment variable gotraceback=crash , sending signal. however, ok purposes because go program (try to) create core dump sending sigabrt signal. kernel not generate core dump setuid/setgid program killed signal.
the major caveat go on gnu/linux systems can not drop original user id. because of how setuid (and setgid, setgroups, setreuid, setregid, setresuid, , setresgid) implemented multi-threaded programs on gnu/linux. details @ http://golang.org/issue/1435 .
on final note uw , pw need capitalized because standard reflect package not permit writing unexported fields.
Comments
Post a Comment