Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redis/lua-script: pass gids to check permission #3902

Merged
merged 6 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions pkg/meta/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func testMeta(t *testing.T, m Meta) {
testTrash(t, m)
testParents(t, m)
testRemove(t, m)
testResolve(t, m)
testStickyBit(t, m)
testLocks(t, m)
testListLocks(t, m)
Expand Down Expand Up @@ -979,6 +980,45 @@ func testLocks(t *testing.T, m Meta) {
}
}

func testResolve(t *testing.T, m Meta) {
var inode, parent Ino
var attr, pattr Attr
if st := m.Mkdir(NewContext(1, 65534, []uint32{65534}), 1, "d", 0770, 0, 0, &parent, &pattr); st != 0 {
t.Fatalf("mkdir d: %s", st)
}
if pattr.Uid != 65534 || pattr.Gid != 65534 {
t.Fatalf("attr %+v", pattr)
}
if st := m.Create(NewContext(1, 65534, []uint32{65534}), parent, "f", 0644, 0, 0, &inode, &attr); st != 0 {
t.Fatalf("create /d/f: %s", st)
}

defer func() {
if st := m.Remove(NewContext(0, 65534, []uint32{65534}), parent, "f", nil); st != 0 {
t.Fatalf("remove /d/f by owner: %s", st)
}
if st := m.Rmdir(NewContext(0, 65534, []uint32{65534}), 1, "d"); st != 0 {
t.Fatalf("rmdir /d by owner: %s", st)
}
}()

if st := m.Resolve(NewContext(0, 65534, []uint32{65534}), 1, "/d/f", &inode, &attr); st != 0 {
if st == syscall.ENOTSUP {
return
}
t.Fatalf("resolve /d/f by owner: %s", st)
}
if st := m.Resolve(NewContext(0, 65533, []uint32{65534}), 1, "/d/f", &inode, &attr); st != 0 {
t.Fatalf("resolve /d/f by group: %s", st)
}
if st := m.Resolve(NewContext(0, 65533, []uint32{65533, 65534}), 1, "/d/f", &inode, &attr); st != 0 {
t.Fatalf("resolve /d/f by multi-group: %s", st)
}
if st := m.Resolve(NewContext(0, 65533, []uint32{65533}), 1, "/d/f", &inode, &attr); st != syscall.EACCES {
t.Fatalf("resolve /d/f by non-group: %s", st)
}
}

func testRemove(t *testing.T, m Meta) {
ctx := Background
var inode, parent Ino
Expand Down
21 changes: 15 additions & 6 deletions pkg/meta/lua_scripts.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

//nolint
// nolint
package meta

const scriptLookup = `
Expand Down Expand Up @@ -55,7 +55,16 @@ local function lookup(parent, name)
return struct.unpack(">BI8", buf)
end

local function can_access(ino, uid, gid)
local function has_value(tab, val)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end

local function can_access(ino, uid, gids)
if uid == 0 then
return true
end
Expand All @@ -64,23 +73,23 @@ local function can_access(ino, uid, gid)
local mode = 0
if attr.uid == uid then
mode = math.floor(attr.mode / 64) % 8
elseif attr.gid == gid then
elseif has_value(gids, tostring(attr.gid)) then
mode = math.floor(attr.mode / 8) % 8
else
mode = attr.mode % 8
end
return mode % 2 == 1
end

local function resolve(parent, path, uid, gid)
local function resolve(parent, path, uid, gids)
local _maxIno = 4503599627370495
local _type = 2
for name in string.gmatch(path, "[^/]+") do
if _type == 3 or parent > _maxIno then
error("ENOTSUP")
elseif _type ~= 2 then
error("ENOTDIR")
elseif parent > 1 and not can_access(parent, uid, gid) then
elseif parent > 1 and not can_access(parent, uid, gids) then
error("EACCESS")
end
_type, parent = lookup(parent, name)
Expand All @@ -91,5 +100,5 @@ local function resolve(parent, path, uid, gid)
return {parent, redis.call('GET', "i" .. string.format("%.f", parent))}
end

return resolve(tonumber(KEYS[1]), KEYS[2], tonumber(KEYS[3]), tonumber(KEYS[4]))
return resolve(tonumber(KEYS[1]), KEYS[2], tonumber(KEYS[3]), ARGV)
`
11 changes: 7 additions & 4 deletions pkg/meta/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,13 @@ func (m *redisMeta) Resolve(ctx Context, parent Ino, path string, inode *Ino, at
}
defer m.timeit("Resolve", time.Now())
parent = m.checkRoot(parent)
args := []string{parent.String(), path,
strconv.FormatUint(uint64(ctx.Uid()), 10),
strconv.FormatUint(uint64(ctx.Gid()), 10)}
res, err := m.rdb.EvalSha(ctx, m.shaResolve, args).Result()
keys := []string{parent.String(), path,
strconv.FormatUint(uint64(ctx.Uid()), 10)}
var gids []interface{}
for _, gid := range ctx.Gids() {
gids = append(gids, strconv.FormatUint(uint64(gid), 10))
}
res, err := m.rdb.EvalSha(ctx, m.shaResolve, keys, gids...).Result()
var returnedIno int64
var returnedAttr string
st := m.handleLuaResult("resolve", res, err, &returnedIno, &returnedAttr)
Expand Down
5 changes: 4 additions & 1 deletion sdk/java/libjfs/guid.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ func (m *mapping) lookupUser(name string) uint32 {
return id
}
if !m.local {
return m.genGuid(name)
id := m.genGuid(name)
m.usernames[name] = id
m.userIDs[id] = name
return id
}
if name == "root" { // root in hdfs sdk is a normal user
id = m.genGuid(name)
Expand Down
26 changes: 26 additions & 0 deletions sdk/java/src/test/java/io/juicefs/JuiceFileSystemTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -894,4 +894,30 @@ public void testInnerSymlink() throws Exception {
assertEquals("inner_sym_link", status.getPath().getName());
assertEquals(14, status.getLen());
}

public void testUserWithMultiGroups() throws Exception {
Path users = new Path("/etc/users");
Path groups = new Path("/etc/groups_multi");

writeFile(fs, users, "tom:2001\n");
writeFile(fs, groups, "groupa:3001:tom\ngroupb:3002:tom");

Configuration conf = new Configuration(cfg);
conf.set("juicefs.users", users.toUri().getPath());
conf.set("juicefs.groups", groups.toUri().getPath());

FileSystem superFs = createNewFs(conf, "hdfs", new String[]{"hadoop"});
Path testDir = new Path("/test_multi_group/d1");
superFs.mkdirs(testDir);
superFs.setOwner(testDir.getParent(), "hdfs", "groupb");
superFs.setOwner(testDir, "hdfs", "groupb");
superFs.setPermission(testDir.getParent(), FsPermission.createImmutable((short) 0770));
superFs.setPermission(testDir, FsPermission.createImmutable((short) 0770));

FileSystem tomFs = createNewFs(conf, "tom", new String[]{"randgroup"});
tomFs.listStatus(testDir);

tomFs.close();
superFs.close();
}
}