You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go程序中personality(2)返回值时而异常的原因排查

Go程序调用personality(2)后获取返回值异常波动的问题分析与解决

问题背景

你通过golang.org/x/sys/unix包的unix.Syscall调用personality(2)系统调用,传入ADDR_NO_RANDOMIZE参数禁用ASLR。之后程序进入无限循环,调用personality(0xffffffff)获取当前persona,发现返回值在预期的0x00040000和异常的0x00000000之间来回切换。但/proc/<PID>/personality始终显示00040000,strace也未发现其他修改persona的系统调用,且等价逻辑的C程序无此问题。

核心原因

personality(2)的设置是线程级属性,而非进程级。Go语言的goroutine由运行时调度器管理,会在多个OS线程之间动态切换。你最初调用personality(2)设置ASLR禁用时,只是在当前goroutine绑定的某个OS线程上生效;当goroutine被调度到其他未设置该persona的OS线程时,调用personality(0xffffffff)获取的就是该线程默认的persona值(0x00000000),因此出现返回值来回切换的现象。

而你的等价C程序大概率是单线程实现,整个程序生命周期都在同一个线程中执行,所以不会出现这种调度导致的属性不一致问题。

解决方案

方案1:将goroutine绑定到固定OS线程

使用runtime.LockOSThread()将执行personality设置和检查的goroutine绑定到当前OS线程,避免被调度到其他线程。示例代码如下:

package main

import (
    "fmt"
    "runtime"
    "syscall"
    "golang.org/x/sys/unix"
)

const ADDR_NO_RANDOMIZE = 0x00040000

func main() {
    // 锁定goroutine到当前OS线程,后续操作均在此线程执行
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()

    // 设置personality禁用ASLR
    _, _, err := unix.Syscall(unix.SYS_PERSONALITY, uintptr(ADDR_NO_RANDOMIZE), 0, 0)
    if err != syscall.Errno(0) {
        fmt.Printf("Failed to set personality: %v\n", err)
        return
    }

    // 循环检查persona状态
    for {
        persona, _, err := unix.Syscall(unix.SYS_PERSONALITY, uintptr(0xffffffff), 0, 0)
        if err != syscall.Errno(0) {
            fmt.Printf("Failed to get personality: %v\n", err)
            return
        }

        fmt.Printf("Current persona: 0x%08x\n", persona)
        if (persona & ADDR_NO_RANDOMIZE) != 0 {
            fmt.Println("ADDR_NO_RANDOMIZE is enabled (ASLR disabled)")
        } else {
            fmt.Println("ADDR_NO_RANDOMIZE is disabled (ASLR enabled)")
        }

        syscall.Sleep(1)
    }
}

绑定线程后,goroutine不会被调度到其他线程,每次获取的persona都会是你设置的0x00040000,与/proc/<PID>/personality显示一致。

方案2:启动前通过系统命令全局设置

如果需要整个进程的所有线程都禁用ASLR,可以在启动Go程序前使用setarch命令设置进程personality:

setarch $(uname -m) -R ./your-go-program

该命令会在进程启动时为所有线程设置ADDR_NO_RANDOMIZE属性,无需在代码中调用personality(2)。

内容的提问来源于stack exchange,提问作者Fysac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:33:41