Skip to content

Commit

Permalink
disallow create files in trash directory (#3864)
Browse files Browse the repository at this point in the history
  • Loading branch information
davies authored Jul 3, 2023
1 parent 52f3428 commit cc616e7
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 24 deletions.
2 changes: 1 addition & 1 deletion cmd/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func doRestore(m meta.Meta, hour string, putBack bool, threads int) {
ps := bytes.SplitN(e.Name, []byte("-"), 3)
dst, _ := strconv.Atoi(string(ps[0]))
if putBack || parents[meta.Ino(dst)] {
err = m.Rename(ctx, parent, string(e.Name), meta.Ino(dst), string(ps[2]), meta.RenameNoReplace, nil, nil)
err = m.Rename(ctx, parent, string(e.Name), meta.Ino(dst), string(ps[2]), meta.RenameNoReplace|meta.RenameRestore, nil, nil)
if err != 0 {
logger.Warnf("restore %s: %s", string(e.Name), err)
failed.Increment()
Expand Down
28 changes: 28 additions & 0 deletions pkg/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,20 @@ func (fs *FileSystem) Mkdir(ctx meta.Context, p string, mode uint16, umask uint1
}
var inode Ino
err = fs.m.Mkdir(ctx, fi.inode, path.Base(p), mode, umask, 0, &inode, nil)
if err == syscall.ENOENT && fi.inode != 1 {
// parent be moved into trash, try again
if fs.conf.DirEntryTimeout > 0 {
parent := parentDir(p)
if fi, err := fs.resolve(ctx, parentDir(parent), true); err == 0 {
fs.invalidateEntry(fi.inode, path.Base(parent))
}
}
if fi2, e := fs.resolve(ctx, parentDir(p), true); e != 0 {
return e
} else if fi2.inode != fi.inode {
err = fs.m.Mkdir(ctx, fi2.inode, path.Base(p), mode, umask, 0, &inode, nil)
}
}
fs.invalidateEntry(fi.inode, path.Base(p))
return
}
Expand Down Expand Up @@ -767,6 +781,20 @@ func (fs *FileSystem) Create(ctx meta.Context, p string, mode uint16, umask uint
return
}
err = fs.m.Create(ctx, fi.inode, path.Base(p), mode&07777, umask, syscall.O_EXCL, &inode, attr)
if err == syscall.ENOENT && fi.inode != 1 {
// dir be moved into trash, try again
if fs.conf.DirEntryTimeout > 0 {
parent := parentDir(p)
if fi, err := fs.resolve(ctx, parentDir(parent), true); err == 0 {
fs.invalidateEntry(fi.inode, path.Base(parent))
}
}
if fi2, e := fs.resolve(ctx, parentDir(p), true); e != 0 {
return nil, e
} else if fi2.inode != fi.inode {
err = fs.m.Create(ctx, fi2.inode, path.Base(p), mode&07777, umask, syscall.O_EXCL, &inode, attr)
}
}
if err == 0 {
fi = AttrToFileInfo(inode, attr)
fi.name = path.Base(p)
Expand Down
4 changes: 2 additions & 2 deletions pkg/meta/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -1512,7 +1512,7 @@ func (m *baseMeta) Rename(ctx Context, parentSrc Ino, nameSrc string, parentDst
return syscall.ENOENT
}
switch flags {
case 0, RenameNoReplace, RenameExchange:
case 0, RenameNoReplace, RenameExchange, RenameNoReplace | RenameRestore:
case RenameWhiteout, RenameNoReplace | RenameWhiteout:
return syscall.ENOTSUP
default:
Expand Down Expand Up @@ -1658,7 +1658,7 @@ func (m *baseMeta) Open(ctx Context, inode Ino, flags uint32, attr *Attr) (rerr
return
}

if attr.Flags&FlagImmutable != 0 {
if attr.Flags&FlagImmutable != 0 || attr.Parent > TrashInode {
if flags&(syscall.O_WRONLY|syscall.O_RDWR) != 0 {
return syscall.EPERM
}
Expand Down
29 changes: 26 additions & 3 deletions pkg/meta/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1436,14 +1436,37 @@ func testTrash(t *testing.T, m Meta) {
if st := m.GetAttr(ctx, inode, attr); st != 0 || attr.Parent != TrashInode+1 {
t.Fatalf("getattr f(%d): %s, attr %+v", inode, st, attr)
}
if st := m.Mkdir(ctx, 1, "d2", 0755, 022, 0, &inode, attr); st != 0 {
if st := m.Truncate(ctx, inode, 0, 1<<30, attr, false); st != syscall.EPERM {
t.Fatalf("should not truncate a file in trash")
}
if st := m.Open(ctx, inode, uint32(syscall.O_RDWR), attr); st != syscall.EPERM {
t.Fatalf("should not fallocate a file in trash")
}
if st := m.SetAttr(ctx, inode, SetAttrMode, 1, &Attr{Mode: 0}); st != syscall.EPERM {
t.Fatalf("should not change mode of a file in trash")
}
var parent2 Ino
if st := m.Mkdir(ctx, 1, "d2", 0755, 022, 0, &parent2, attr); st != 0 {
t.Fatalf("mkdir d2: %s", st)
}
if st := m.Rmdir(ctx, 1, "d2"); st != 0 {
t.Fatalf("rmdir d2: %s", st)
}
if st := m.GetAttr(ctx, inode, attr); st != 0 || attr.Parent != TrashInode+1 {
t.Fatalf("getattr d2(%d): %s, attr %+v", inode, st, attr)
if st := m.GetAttr(ctx, parent2, attr); st != 0 || attr.Parent != TrashInode+1 {
t.Fatalf("getattr d2(%d): %s, attr %+v", parent2, st, attr)
}
var tino Ino
if st := m.Mkdir(ctx, parent2, "d3", 0777, 022, 0, &tino, attr); st != syscall.ENOENT {
t.Fatalf("mkdir inside trash should fail")
}
if st := m.Create(ctx, parent2, "d3", 0755, 022, 0, &tino, attr); st != syscall.ENOENT {
t.Fatalf("create inside trash should fail")
}
if st := m.Link(ctx, inode, parent2, "ttlink", attr); st != syscall.ENOENT {
t.Fatalf("link inside trash should fail")
}
if st := m.Rename(ctx, 1, "d", parent2, "ttlink", 0, &tino, attr); st != syscall.ENOENT {
t.Fatalf("link inside trash should fail")
}
if st := m.Rename(ctx, 1, "f1", 1, "d", 0, &inode, attr); st != 0 {
t.Fatalf("rename f1 -> d: %s", st)
Expand Down
3 changes: 3 additions & 0 deletions pkg/meta/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ const (
RenameNoReplace = 1 << iota
RenameExchange
RenameWhiteout
_renameReserved1
_renameReserved2
RenameRestore // internal
)

const (
Expand Down
24 changes: 18 additions & 6 deletions pkg/meta/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ func (m *redisMeta) Truncate(ctx Context, inode Ino, flags uint8, length uint64,
return err
}
m.parseAttr(a, &t)
if t.Typ != TypeFile {
if t.Typ != TypeFile || t.Flags&(FlagImmutable|FlagAppend) != 0 || t.Parent > TrashInode {
return syscall.EPERM
}
if !skipPermCheck {
Expand Down Expand Up @@ -1065,10 +1065,7 @@ func (m *redisMeta) Fallocate(ctx Context, inode Ino, mode uint8, off uint64, si
if t.Typ == TypeFIFO {
return syscall.EPIPE
}
if t.Typ != TypeFile {
return syscall.EPERM
}
if (t.Flags & FlagImmutable) != 0 {
if t.Typ != TypeFile || (t.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
if st := m.Access(ctx, inode, MODE_MASK_W, &t); st != 0 {
Expand Down Expand Up @@ -1134,6 +1131,9 @@ func (m *redisMeta) doSetAttr(ctx Context, inode Ino, set uint16, sugidclearmode
return err
}
m.parseAttr(a, &cur)
if cur.Parent > TrashInode {
return syscall.EPERM
}
now := time.Now()
dirtyAttr, st := m.mergeAttr(ctx, inode, set, &cur, attr, now)
if st != 0 {
Expand Down Expand Up @@ -1232,6 +1232,9 @@ func (m *redisMeta) doMknod(ctx Context, parent Ino, name string, _type uint8, m
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
return st
}
Expand Down Expand Up @@ -1633,7 +1636,7 @@ func (m *redisMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentD
return err
}
if err == nil {
if flags == RenameNoReplace {
if flags&RenameNoReplace != 0 {
return syscall.EEXIST
}
dtyp, dino = m.parseEntry(dbuf)
Expand Down Expand Up @@ -1671,6 +1674,9 @@ func (m *redisMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentD
if dattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if flags&RenameRestore == 0 && dattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parentDst, MODE_MASK_W|MODE_MASK_X, &dattr); st != 0 {
return st
}
Expand Down Expand Up @@ -1881,6 +1887,9 @@ func (m *redisMeta) doLink(ctx Context, inode, parent Ino, name string, attr *At
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
return st
}
Expand Down Expand Up @@ -4324,6 +4333,9 @@ func (m *redisMeta) doAttachDirNode(ctx Context, parent Ino, dstIno Ino, name st
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if (pattr.Flags & FlagImmutable) != 0 {
return syscall.EPERM
}
Expand Down
30 changes: 24 additions & 6 deletions pkg/meta/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,9 @@ func (m *dbMeta) doSetAttr(ctx Context, inode Ino, set uint16, sugidclearmode ui
}
var curAttr Attr
m.parseAttr(&cur, &curAttr)
if curAttr.Parent > TrashInode {
return syscall.EPERM
}
now := time.Now()
dirtyAttr, st := m.mergeAttr(ctx, inode, set, &curAttr, attr, now)
if st != 0 {
Expand Down Expand Up @@ -958,7 +961,7 @@ func (m *dbMeta) Truncate(ctx Context, inode Ino, flags uint8, length uint64, at
if !ok {
return syscall.ENOENT
}
if nodeAttr.Type != TypeFile {
if nodeAttr.Type != TypeFile || nodeAttr.Flags&(FlagImmutable|FlagAppend) != 0 || nodeAttr.Parent > TrashInode {
return syscall.EPERM
}
m.parseAttr(&nodeAttr, attr)
Expand Down Expand Up @@ -1061,10 +1064,7 @@ func (m *dbMeta) Fallocate(ctx Context, inode Ino, mode uint8, off uint64, size
if nodeAttr.Type == TypeFIFO {
return syscall.EPIPE
}
if nodeAttr.Type != TypeFile {
return syscall.EPERM
}
if (nodeAttr.Flags & FlagImmutable) != 0 {
if nodeAttr.Type != TypeFile || (nodeAttr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
if (nodeAttr.Flags&FlagAppend) != 0 && (mode&^fallocKeepSize) != 0 {
Expand Down Expand Up @@ -1217,6 +1217,9 @@ func (m *dbMeta) doMknod(ctx Context, parent Ino, name string, _type uint8, mode
}
var pattr Attr
m.parseAttr(&pn, &pattr)
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
return st
}
Expand Down Expand Up @@ -1641,6 +1644,9 @@ func (m *dbMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
var spattr, dpattr Attr
m.parseAttr(&spn, &spattr)
m.parseAttr(&dpn, &dpattr)
if flags&RenameRestore == 0 && dpattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parentSrc, MODE_MASK_W|MODE_MASK_X, &spattr); st != 0 {
return st
}
Expand Down Expand Up @@ -1707,7 +1713,7 @@ func (m *dbMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
now := time.Now().UnixNano()
dn = node{Inode: de.Inode}
if ok {
if flags == RenameNoReplace {
if flags&RenameNoReplace != 0 {
return syscall.EEXIST
}
dino = de.Inode
Expand Down Expand Up @@ -1920,6 +1926,9 @@ func (m *dbMeta) doLink(ctx Context, inode, parent Ino, name string, attr *Attr)
if pn.Type != TypeDirectory {
return syscall.ENOTDIR
}
if pn.Parent > TrashInode {
return syscall.ENOENT
}
var pattr Attr
m.parseAttr(&pn, &pattr)
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
Expand Down Expand Up @@ -4016,6 +4025,15 @@ func (m *dbMeta) doAttachDirNode(ctx Context, parent Ino, inode Ino, name string
if !ok {
return syscall.ENOENT
}
if n.Type != TypeDirectory {
return syscall.ENOTDIR
}
if n.Parent > TrashInode {
return syscall.ENOENT
}
if (n.Flags & FlagImmutable) != 0 {
return syscall.EPERM
}
n.Nlink++
now := time.Now().UnixNano()
n.Mtime = now / 1e3
Expand Down
24 changes: 18 additions & 6 deletions pkg/meta/tkv.go
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,9 @@ func (m *kvMeta) doSetAttr(ctx Context, inode Ino, set uint16, sugidclearmode ui
return syscall.ENOENT
}
m.parseAttr(a, &cur)
if cur.Parent > TrashInode {
return syscall.EPERM
}
now := time.Now()
dirtyAttr, st := m.mergeAttr(ctx, inode, set, &cur, attr, now)
if st != 0 {
Expand Down Expand Up @@ -905,7 +908,7 @@ func (m *kvMeta) Truncate(ctx Context, inode Ino, flags uint8, length uint64, at
}
t = Attr{}
m.parseAttr(a, &t)
if t.Typ != TypeFile {
if t.Typ != TypeFile || t.Flags&(FlagImmutable|t.Flags&FlagAppend) != 0 || t.Parent > TrashInode {
return syscall.EPERM
}
if !skipPermCheck {
Expand Down Expand Up @@ -998,10 +1001,7 @@ func (m *kvMeta) Fallocate(ctx Context, inode Ino, mode uint8, off uint64, size
if t.Typ == TypeFIFO {
return syscall.EPIPE
}
if t.Typ != TypeFile {
return syscall.EPERM
}
if (t.Flags & FlagImmutable) != 0 {
if t.Typ != TypeFile || (t.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
if (t.Flags&FlagAppend) != 0 && (mode&^fallocKeepSize) != 0 {
Expand Down Expand Up @@ -1127,6 +1127,9 @@ func (m *kvMeta) doMknod(ctx Context, parent Ino, name string, _type uint8, mode
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
return st
}
Expand Down Expand Up @@ -1505,6 +1508,9 @@ func (m *kvMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
if dattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if flags&RenameRestore == 0 && dattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parentDst, MODE_MASK_W|MODE_MASK_X, &dattr); st != 0 {
return st
}
Expand All @@ -1527,7 +1533,7 @@ func (m *kvMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
var supdate, dupdate bool
now := time.Now()
if dbuf != nil {
if flags == RenameNoReplace {
if flags&RenameNoReplace != 0 {
return syscall.EEXIST
}
dtyp, dino = m.parseEntry(dbuf)
Expand Down Expand Up @@ -1717,6 +1723,9 @@ func (m *kvMeta) doLink(ctx Context, inode, parent Ino, name string, attr *Attr)
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if st := m.Access(ctx, parent, MODE_MASK_W, &pattr); st != 0 {
return st
}
Expand Down Expand Up @@ -3463,6 +3472,9 @@ func (m *kvMeta) doAttachDirNode(ctx Context, parent Ino, inode Ino, name string
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Parent > TrashInode {
return syscall.ENOENT
}
if (pattr.Flags & FlagImmutable) != 0 {
return syscall.EPERM
}
Expand Down

0 comments on commit cc616e7

Please sign in to comment.