From 1f40a88b0ccc861dee094371aeeb29a3f70a2ee6 Mon Sep 17 00:00:00 2001 From: chengjingtao Date: Tue, 11 Mar 2025 18:57:45 +0800 Subject: [PATCH] Fix CVE-2021-27116 CVE-2021-27117 1. Adding O_NOFOLLOW flag to prevent symlink attacks These changes help protect against various security issues including: - Symlink attacks where attackers could trick the application into modifying unintended files - Privilege escalation through improper file permissions Signed-off-by: chengjingtao --- client/httplib/httplib.go | 3 ++- core/admin/profile.go | 6 ++++-- core/config/ini.go | 3 ++- core/config/json/json.go | 3 ++- core/config/toml/toml.go | 3 ++- core/config/xml/xml.go | 3 ++- core/config/yaml/yaml.go | 3 ++- server/web/session/sess_file.go | 9 +++++---- 8 files changed, 21 insertions(+), 12 deletions(-) diff --git a/client/httplib/httplib.go b/client/httplib/httplib.go index fca981ce..8ae4ad6a 100644 --- a/client/httplib/httplib.go +++ b/client/httplib/httplib.go @@ -44,6 +44,7 @@ import ( "os" "path/filepath" "strings" + "syscall" "time" "gopkg.in/yaml.v3" @@ -615,7 +616,7 @@ func (b *BeegoHTTPRequest) ToFile(filename string) error { if err != nil { return err } - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/core/admin/profile.go b/core/admin/profile.go index f85afaa2..b06dfc1e 100644 --- a/core/admin/profile.go +++ b/core/admin/profile.go @@ -24,6 +24,7 @@ import ( "runtime/debug" "runtime/pprof" "strconv" + "syscall" "time" "github.com/beego/beego/v2/core/utils" @@ -65,7 +66,8 @@ func ProcessInput(input string, w io.Writer) { // MemProf record memory profile in pprof func MemProf(w io.Writer) { filename := "mem-" + strconv.Itoa(pid) + ".memprof" - if f, err := os.Create(filename); err != nil { + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) + if err != nil { fmt.Fprintf(w, "create file %s error %s\n", filename, err.Error()) log.Fatal("record heap profile failed: ", err) } else { @@ -82,7 +84,7 @@ func MemProf(w io.Writer) { func GetCPUProfile(w io.Writer) { sec := 30 filename := "cpu-" + strconv.Itoa(pid) + ".pprof" - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) log.Fatal("record cpu profile failed: ", err) diff --git a/core/config/ini.go b/core/config/ini.go index 791fb59b..07497e83 100644 --- a/core/config/ini.go +++ b/core/config/ini.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" "sync" + "syscall" "github.com/mitchellh/mapstructure" ) @@ -346,7 +347,7 @@ func (c *IniConfigContainer) GetSection(section string) (map[string]string, erro // BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Function. func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/core/config/json/json.go b/core/config/json/json.go index 1d764733..d05bccfa 100644 --- a/core/config/json/json.go +++ b/core/config/json/json.go @@ -23,6 +23,7 @@ import ( "strconv" "strings" "sync" + "syscall" "github.com/mitchellh/mapstructure" @@ -245,7 +246,7 @@ func (c *JSONConfigContainer) GetSection(section string) (map[string]string, err // SaveConfigFile save the config into file func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/core/config/toml/toml.go b/core/config/toml/toml.go index 297d16c8..b0fcfe1d 100644 --- a/core/config/toml/toml.go +++ b/core/config/toml/toml.go @@ -17,6 +17,7 @@ package toml import ( "os" "strings" + "syscall" "github.com/pelletier/go-toml" @@ -307,7 +308,7 @@ func (c *configContainer) OnChange(key string, fn func(value string)) { // SaveConfigFile create or override the file func (c *configContainer) SaveConfigFile(filename string) error { // Write configuration file by filename. - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/core/config/xml/xml.go b/core/config/xml/xml.go index 8aa7e26b..09503e85 100644 --- a/core/config/xml/xml.go +++ b/core/config/xml/xml.go @@ -36,6 +36,7 @@ import ( "strconv" "strings" "sync" + "syscall" "github.com/mitchellh/mapstructure" @@ -247,7 +248,7 @@ func (c *ConfigContainer) GetSection(section string) (map[string]string, error) // SaveConfigFile save the config into file func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/core/config/yaml/yaml.go b/core/config/yaml/yaml.go index ea54a1bb..21b0286d 100644 --- a/core/config/yaml/yaml.go +++ b/core/config/yaml/yaml.go @@ -29,6 +29,7 @@ import ( "os" "strings" "sync" + "syscall" "gopkg.in/yaml.v3" @@ -291,7 +292,7 @@ func (c *ConfigContainer) GetSection(section string) (map[string]string, error) // SaveConfigFile save the config into file func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. - f, err := os.Create(filename) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return err } diff --git a/server/web/session/sess_file.go b/server/web/session/sess_file.go index 45be923e..1a090377 100644 --- a/server/web/session/sess_file.go +++ b/server/web/session/sess_file.go @@ -24,6 +24,7 @@ import ( "path/filepath" "strings" "sync" + "syscall" "time" ) @@ -99,13 +100,13 @@ func (fs *FileSessionStore) releaseSession(_ context.Context, _ http.ResponseWri _, err = os.Stat(filepath.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) var f *os.File if err == nil { - f, err = os.OpenFile(filepath.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0o777) + f, err = os.OpenFile(filepath.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR|syscall.O_NOFOLLOW, 0o600) if err != nil { SLogger.Println(err) return } } else if os.IsNotExist(err) && createIfNotExist { - f, err = os.Create(filepath.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) + f, err = os.OpenFile(filepath.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_CREATE|os.O_EXCL|os.O_RDWR|syscall.O_NOFOLLOW, 0o600) if err != nil { SLogger.Println(err) return @@ -163,7 +164,7 @@ func (fp *FileProvider) SessionRead(ctx context.Context, sid string) (Store, err return nil, err } case os.IsNotExist(err): - f, err = os.Create(sidPath) + f, err = os.OpenFile(sidPath, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return nil, err } @@ -288,7 +289,7 @@ func (fp *FileProvider) SessionRegenerate(ctx context.Context, oldsid, sid strin } // if old sid file not exist, just create new sid file and return - newf, err := os.Create(newSidFile) + newf, err := os.OpenFile(newSidFile, os.O_RDWR|os.O_CREATE|syscall.O_NOFOLLOW, 0600) if err != nil { return nil, err }