英文:
setgid/setuid has no effect on compiled golang code 1.19
问题
以下是翻译的内容:
➜ go version
go version go1.19.6 linux/amd64
➜ uname -a
Linux dmitry-desktop 6.1.18-200.fc37.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:09:14 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
我无法使用可执行文件的 setuid/setguid 位运行编译的 Golang 应用程序。
我已经在可执行文件 main
上设置了 +s
权限,所有者是 test
用户。我尝试从 dmitry
用户调用该文件,期望文件会使用 test
的 uid,但实际上并没有发生。
[test@dmitry-desktop setguid]$ whoami
test
[test@dmitry-desktop setguid]$ id
uid=1001(test) gid=1002(test) groups=1002(test) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[test@dmitry-desktop setguid]$ ./main
[test@dmitry-desktop setguid]$ ls -la
total 1356
drwxrwxr-x. 2 test test 100 Mar 26 14:07 .
drwxrwxrwt. 48 root root 1780 Mar 26 14:07 ..
-rwsr-sr-x. 1 test test 1.9M Mar 26 14:16 main
-rw-r--r--. 1 test test 225 Mar 26 13:58 main.go
-rw-r--r--. 1 test test 9 Mar 26 14:07 test_file
[test@dmitry-desktop setguid]$ go build main.go
[test@dmitry-desktop setguid]$ chmod u+s main
[test@dmitry-desktop setguid]$ chmod g+s main
[test@dmitry-desktop setguid]$ ls -la main
-rwsr-sr-x. 1 test test 1943252 Mar 26 14:18 main
[test@dmitry-desktop setguid]$ ./main
Real UID: 1001
Effective UID: 1001
Real UID: 1001
Effective UID: 1001
现在我使用不同的用户运行相同的 main 文件
➜ whoami
dmitry
✗ /tmp/setguid/main
Real UID: 1000
Effective UID: 1000
Real UID: 1000
Effective UID: 1000
panic: open /tmp/setguid/test_file: permission denied
goroutine 1 [running]:
main.check(...)
/tmp/setguid/main.go:14
main.main()
/tmp/setguid/main.go:32 +0xe5
main.go
package main
import (
"os"
"syscall"
"log"
"fmt"
"time"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
printdelay()
errgid := syscall.Setuid(syscall.Getuid())
if errgid != nil {
log.Fatal(errgid)
os.Exit(1)
}
printdelay()
d1 := []byte("hello\ngo\n")
err := os.WriteFile("/tmp/setguid/test_file", d1, 0644)
check(err)
}
func printdelay() {
fmt.Printf("Real UID: %d\n", syscall.Getuid())
fmt.Printf("Effective UID: %d\n", syscall.Geteuid())
time.Sleep(7 * time.Second)
}
然后我尝试了以下操作:
sudo /sbin/setcap cap_setuid=ep main
chown root:root main
chmod +s main
ls -la main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
然后我修改了我的 go 文件
// errgid := syscall.Setuid(syscall.Getuid())
errgid := syscall.Setuid(1001)
并尝试调用它:
✗ id
uid=1000(dmitry) gid=1000(dmitry) groups=1000(dmitry),10(wheel),969(plugdev),971(wireshark),975(docker) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c102
➜ ./main
Real UID: 1000
Effective UID: 1000
2023/03/26 14:33:04 operation not permitted
我错过了什么?
英文:
➜ go version
go version go1.19.6 linux/amd64
➜ uname -a
Linux dmitry-desktop 6.1.18-200.fc37.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:09:14 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
I am unable to run compiled golang app using setuid/setguid bits of the executable file.
I have set +s
permission on the executable main
file, owned by test
user. I'm trying to invoke that file from dmitry
user expecting the file would use test
uid, but it's not happening.
[test@dmitry-desktop setguid]$ whoami
test
[test@dmitry-desktop setguid]$ id
uid=1001(test) gid=1002(test) groups=1002(test) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[test@dmitry-desktop setguid]$ ./main
[test@dmitry-desktop setguid]$ ls -la
total 1356
drwxrwxr-x. 2 test test 100 Mar 26 14:07 .
drwxrwxrwt. 48 root root 1780 Mar 26 14:07 ..
-rwsr-sr-x. 1 test test 1.9M Mar 26 14:16 main
-rw-r--r--. 1 test test 225 Mar 26 13:58 main.go
-rw-r--r--. 1 test test 9 Mar 26 14:07 test_file
[test@dmitry-desktop setguid]$ go build main.go
[test@dmitry-desktop setguid]$ chmod u+s main
[test@dmitry-desktop setguid]$ chmod g+s main
[test@dmitry-desktop setguid]$ ls -la main
-rwsr-sr-x. 1 test test 1943252 Mar 26 14:18 main
[test@dmitry-desktop setguid]$ ./main
Real UID: 1001
Effective UID: 1001
Real UID: 1001
Effective UID: 1001
now I run the same main from a different user
➜ whoami
dmitry
✗ /tmp/setguid/main
Real UID: 1000
Effective UID: 1000
Real UID: 1000
Effective UID: 1000
panic: open /tmp/setguid/test_file: permission denied
goroutine 1 [running]:
main.check(...)
/tmp/setguid/main.go:14
main.main()
/tmp/setguid/main.go:32 +0xe5
main.go
package main
import (
"os"
"syscall"
"log"
"fmt"
"time"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
printdelay()
errgid := syscall.Setuid(syscall.Getuid())
if errgid != nil {
log.Fatal(errgid)
os.Exit(1)
}
printdelay()
d1 := []byte("hello\ngo\n")
err := os.WriteFile("/tmp/setguid/test_file", d1, 0644)
check(err)
}
func printdelay() {
fmt.Printf("Real UID: %d\n", syscall.Getuid())
fmt.Printf("Effective UID: %d\n", syscall.Geteuid())
time.Sleep(7 * time.Second)
}
then I tried the following:
sudo /sbin/setcap cap_setuid=ep main
chown root:root main
chmod +s main
ls -la main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
then I modify my go file to
// errgid := syscall.Setuid(syscall.Getuid())
errgid := syscall.Setuid(1001)
and trying to invoke it:
✗ id
uid=1000(dmitry) gid=1000(dmitry) groups=1000(dmitry),10(wheel),969(plugdev),971(wireshark),975(docker) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c102
➜ ./main
Real UID: 1000
Effective UID: 1000
2023/03/26 14:33:04 operation not permitted
what am I missing?
答案1
得分: 1
您没有提到在修改源代码后是否重新构建了 main
。我认为您已经重新构建了。请注意,在重新构建后,main
的所有者和文件能力可能会发生变化。我还认为您在重新构建后运行了 setcap
和 chown
命令。请编辑问题以列出真实的步骤。
所以我认为这里的问题是 chown
命令会改变文件的能力。您应该在 chown
之后运行 setcap
。请参考下面的命令和输出:
$ getcap main # 首先,没有文件能力
$ sudo setcap cap_setuid=ep main
$ getcap main # 现在添加了文件能力 "cap_setuid=ep"
main cap_setuid=ep
$ sudo chown root:root main
$ getcap main # <== "chown" 后没有文件能力
$ ./main
Real UID: 1000
Effective UID: 1000
2023/03/27 16:43:58 operation not permitted
$ sudo setcap cap_setuid=ep main
$ getcap main # 恢复文件能力
main cap_setuid=ep
$ ./main
Real UID: 1000
Effective UID: 1000
Real UID: 1001
Effective UID: 1001
英文:
> ### then I tried the following:
>
>
> sudo /sbin/setcap cap_setuid=ep main
> chown root:root main
> chmod +s main
> ls -la main
> -rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
>
>
> then I modify my go file to
>
>
> // errgid := syscall.Setuid(syscall.Getuid())
> errgid := syscall.Setuid(1001)
>
>
> and trying to invoke it:
You do not mention whether you have rebuilt main
after modifying the source code. I believe you have. Please note that the owner and file capabilities of main
could be changed after the rebuild. I also believe that you have run the setcap
and chown
commands after the rebuild. Please edit the question to list the real steps.
So I think the issue here is that the command chown
will change the file capabilities. You should run setcap
after chown
. See the commands and the output below:
$ getcap main # at first, no file capabilities
$ sudo setcap cap_setuid=ep main
$ getcap main # now the file capability "cap_setuid=ep" is added
main cap_setuid=ep
$ sudo chown root:root main
$ getcap main # <== no file capabilities after "chown"
$ ./main
Real UID: 1000
Effective UID: 1000
2023/03/27 16:43:58 operation not permitted
$ sudo setcap cap_setuid=ep main
$ getcap main # bring back the file capability
main cap_setuid=ep
$ ./main
Real UID: 1000
Effective UID: 1000
Real UID: 1001
Effective UID: 1001
答案2
得分: 0
首先,在尝试任何操作之前,你必须确保存储main
二进制文件的位置位于支持以特权运行的文件系统上。假设你想将其存储在/tmp/
目录中,那么哪些挂载选项适用于该目录?
$ findmnt -v -T /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp tmpfs tmpfs rw,nosuid,nodev,seclabel,size=32756364k,nr_inodes=1048576,in
这里的nosuid
选项意味着即使你可以在该目录下更改文件的特权位(setuid或capabilities),内核在运行程序时也不会遵守这些设置。根据你问题中的细节,我认为这很可能是你遇到的问题。
此外,对于一个程序来说,设置了setuid-root会完全覆盖文件的capabilities。因此,你对二进制文件添加特权的尝试是多余的。它唯一能获得的特权来自setuid-root部分。
如果你找到一个可以写入的目录,而且该目录没有挂载nosuid
选项,你可以使用它。如果一切都失败了:sudo mkdir /hack ; sudo chmod go+w /hack ; findmnt -v -T /hack
将提供一个稍后可以清理的目录。
在这个目录中,你可以复制你的二进制文件,然后选择以下配置之一:
$ cd /hack
$ sudo /sbin/setcap cap_setuid=ep main
$ /sbin/getcap main
main cap_setuid=ep
或者执行以下操作:
$ cd /hack
$ sudo chown root.root main
$ sudo chmod +s main
$ ls -l main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
英文:
First, before you try anything, you have to be sure the place you are storing your main
binary is on a filesystem that supports it running with privilege. Let's say, you want to store it in /tmp/
, what mount options cover that directory?
$ findmnt -v -T /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp tmpfs tmpfs rw,nosuid,nodev,seclabel,size=32756364k,nr_inodes=1048576,in
The option nosuid
here means that even though you can change the privilege bits on the file (setuid or capabilities) under that directory, they will not be honored by the kernel when the program is run. Based on the details in your question, I think this is likely to be the problem you are experiencing.
Further, setuid-root on a program completely overrides file capabilities. So your attempts to add privilege to your binary are redundant. The only privilege it will get is from the setuid-root part.
If you find a directory that you can write to that is mounted without the nosuid
option, you can use that. If all else fails: sudo mkdir /hack ; sudo chmod go+w /hack ; findmnt -v -T /hack
will provide something you can clean up later.
In this directory, you can copy your binary, then pick one of the following to configure it:
$ cd /hack
$ sudo /sbin/setcap cap_setuid=ep main
$ /sbin/getcap main
main cap_setuid=ep
Or do this:
$ cd /hack
$ sudo chown root.root main
$ sudo chmod +s main
$ ls -l main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论