Skip to content

Commit 3370649

Browse files
authored
Merge pull request #36 from hyperf/perm
fix: check permission
2 parents 6fdd702 + f44019e commit 3370649

10 files changed

+85
-31
lines changed

.travis.yml

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ sudo: required
44

55
matrix:
66
include:
7-
- php: 7.2
8-
env: SW_VERSION="4.5.2"
97
- php: 7.3
10-
env: SW_VERSION="4.5.2"
8+
env: SW_VERSION="4.6.4"
119
- php: 7.4
12-
env: SW_VERSION="4.5.2"
10+
env: SW_VERSION="4.6.4"
1311

1412
services:
1513
- mongodb

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/fatih/pool v3.0.0+incompatible
77
github.com/oklog/run v1.1.0
88
github.com/pkg/errors v0.9.1
9-
go.mongodb.org/mongo-driver v1.3.3
109
github.com/spiral/goridge/v2 v2.4.4
10+
go.mongodb.org/mongo-driver v1.3.3
11+
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2
1112
)

pkg/config/config_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func testHas(t *testing.T) {
5555
}
5656

5757
func TestAll(t *testing.T) {
58-
gotask.SetGo2PHPAddress("/tmp/test.sock")
58+
gotask.SetGo2PHPAddress("../../tests/test.sock")
5959
for i := 0; i < 50; i++ {
6060
t.Run("testAll", func(t *testing.T) {
6161
t.Parallel()

pkg/gotask/server.go

+51-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/rpc"
99
"os"
1010
"os/signal"
11+
"path"
1112
"syscall"
1213
"time"
1314

@@ -79,14 +80,16 @@ func Run() error {
7980

8081
if *address != "" {
8182
network, addr := parseAddr(*address)
82-
if err := clearAddr(network, addr); err != nil {
83-
return errors.Wrap(err, "Cannot remove existing unix socket")
83+
cleanup, err := checkAddr(network, addr)
84+
if err != nil {
85+
return errors.Wrap(err, "cannot remove existing unix socket")
8486
}
87+
defer cleanup()
88+
8589
ln, err := net.Listen(network, addr)
8690
if err != nil {
87-
return errors.Wrap(err, "Unable to listen")
91+
return errors.Wrap(err, "unable to listen")
8892
}
89-
defer clearAddr(network, addr)
9093

9194
g.Add(func() error {
9295
for {
@@ -135,16 +138,6 @@ func Run() error {
135138
return g.Run()
136139
}
137140

138-
func clearAddr(network string, addr string) error {
139-
if network != "unix" {
140-
return nil
141-
}
142-
if _, err := os.Stat(addr); os.IsNotExist(err) {
143-
return nil
144-
}
145-
return os.Remove(addr)
146-
}
147-
148141
// Add an actor (function) to the group. Each actor must be pre-emptable by an
149142
// interrupt function. That is, if interrupt is invoked, execute should return.
150143
// Also, it must be safe to call interrupt even after execute has returned.
@@ -154,3 +147,47 @@ func clearAddr(network string, addr string) error {
154147
func Add(execute func() error, interrupt func(error)) {
155148
g.Add(execute, interrupt)
156149
}
150+
151+
func checkAddr(network, addr string) (func(), error) {
152+
if network != "unix" {
153+
return func() {}, nil
154+
}
155+
if _, err := os.Stat(addr); !os.IsNotExist(err) {
156+
return func() {}, os.Remove(addr)
157+
}
158+
if err := os.MkdirAll(path.Dir(addr), os.ModePerm); err != nil {
159+
return func() {}, err
160+
}
161+
if ok, err := isWritable(path.Dir(addr)); err != nil || !ok {
162+
return func() {}, errors.Wrap(err, "socket directory is not writable")
163+
}
164+
return func() { os.Remove(addr) }, nil
165+
}
166+
167+
func isWritable(path string) (isWritable bool, err error) {
168+
info, err := os.Stat(path)
169+
if err != nil {
170+
return false, err
171+
}
172+
173+
if !info.IsDir() {
174+
return false, fmt.Errorf("%s isn't a directory", path)
175+
}
176+
177+
// Check if the user bit is enabled in file permission
178+
if info.Mode().Perm()&(1<<(uint(7))) == 0 {
179+
return false, fmt.Errorf("write permission bit is not set on this %s for user", path)
180+
}
181+
182+
var stat syscall.Stat_t
183+
if err = syscall.Stat(path, &stat); err != nil {
184+
return false, err
185+
}
186+
187+
err = nil
188+
if uint32(os.Geteuid()) != stat.Uid {
189+
return false, errors.Errorf("user doesn't have permission to write to %s", path)
190+
}
191+
192+
return true, nil
193+
}

pkg/gotask/server_test.go

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,40 @@
11
package gotask
22

33
import (
4+
"io/ioutil"
45
"log"
56
"os"
67
"testing"
78
)
89

910
func TestClearAddr(t *testing.T) {
10-
if err := clearAddr("unix", "/tmp/non-exist.sock"); err != nil {
11-
t.Errorf("clearAddr should not return error for non-exist files")
11+
dir, _ := ioutil.TempDir("", "")
12+
defer os.Remove(dir)
13+
14+
if _, err := checkAddr("unix", dir+"/non-exist.sock"); err != nil {
15+
t.Errorf("checkAddr should not return error for non-exist files")
1216
}
13-
if err := clearAddr("tcp", "127.0.0.1:6000"); err != nil {
14-
t.Errorf("clearAddr should not return error for tcp ports")
17+
if _, err := checkAddr("tcp", "127.0.0.1:6000"); err != nil {
18+
t.Errorf("checkAddr should not return error for tcp ports")
1519
}
1620
file, err := os.Create("/tmp/temp.sock")
1721
if err != nil {
1822
log.Fatal(err)
1923
}
2024
defer file.Close()
21-
if err := clearAddr("unix", "/tmp/temp.sock"); err != nil {
22-
t.Errorf("clearAddr should be able to clear unix socket")
25+
if _, err := checkAddr("unix", "/tmp/temp.sock"); err != nil {
26+
t.Errorf("checkAddr should be able to clear unix socket")
2327
}
2428
_, err = os.Stat("/tmp/temp.sock")
2529
if !os.IsNotExist(err) {
2630
t.Errorf("unix socket are not cleared, %v", err)
2731
}
32+
33+
if _, err := checkAddr("unix", dir+"/path/to/dir/temp.sock"); err != nil {
34+
t.Errorf("checkAddr should be able to create directory if not exist")
35+
}
36+
37+
if _, err := checkAddr("unix", "/private/temp.sock"); err == nil {
38+
t.Error("unix socket shouldn't be created")
39+
}
2840
}

pkg/log/log_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func testInfo(t *testing.T) {
1717

1818
func TestAll(t *testing.T) {
1919
t.Parallel()
20-
gotask.SetGo2PHPAddress("/tmp/test.sock")
20+
gotask.SetGo2PHPAddress("../../tests/test.sock")
2121
for i := 0; i < 50; i++ {
2222
t.Run("testAll", func(t *testing.T) {
2323
t.Parallel()

src/ConfigProvider.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,14 @@ public function __invoke(): array
7171

7272
public static function address()
7373
{
74+
if (defined(BASE_PATH)) {
75+
$root = BASE_PATH . '/runtime';
76+
} else {
77+
$root = '/tmp';
78+
}
79+
7480
$appName = env('APP_NAME');
7581
$socketName = $appName . '_' . uniqid();
76-
return "/tmp/{$socketName}.sock";
82+
return $root . "/{$socketName}.sock";
7783
}
7884
}

tests/Cases/AbstractTestCase.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*/
2929
abstract class AbstractTestCase extends TestCase
3030
{
31-
const UNIX_SOCKET = '/tmp/test.sock';
31+
const UNIX_SOCKET = __DIR__ . '/test.sock';
3232

3333
public function setUp(): void
3434
{

tests/Cases/CoroutineSocketTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
class CoroutineSocketTest extends AbstractTestCase
2626
{
27-
const UNIX_SOCKET = '/tmp/test.sock';
27+
const UNIX_SOCKET = __DIR__ . '/test.sock';
2828

2929
/**
3030
* @var Process

tests/TestServer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
require __DIR__ . '/../vendor/autoload.php';
2828
define('BASE_PATH', __DIR__);
2929

30-
const ADDR = '/tmp/test.sock';
30+
const ADDR = __DIR__ . '/test.sock';
3131
@unlink(ADDR);
3232
$container = new Container(new DefinitionSource([], new ScanConfig()));
3333
$container->set(ConfigInterface::class, new Config([

0 commit comments

Comments
 (0)