Skip to content
Closed
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
26 changes: 26 additions & 0 deletions lib/libnpf/npf.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,16 @@ npf_rule_setproc(nl_rule_t *rl, const char *name)
return nvlist_error(rl->rule_dict);
}


/* use a single id hack for both user and group */
int
npf_rule_setrid(nl_rule_t *rl, struct r_id rid, const char *name)
{
uint64_t uid_element[3] = { rid.id[0], rid.id[1], rid.op };
nvlist_add_number_array(rl->rule_dict, name, uid_element, 3);
return nvlist_error(rl->rule_dict);
}

void *
npf_rule_export(nl_rule_t *rl, size_t *length)
{
Expand Down Expand Up @@ -843,6 +853,22 @@ npf_rule_getproc(nl_rule_t *rl)
return dnvlist_get_string(rl->rule_dict, "rproc", NULL);
}

int
npf_rule_getrid(struct r_id *r_id, nl_rule_t *rl, const char *key)
{
if (nvlist_exists_number_array(rl->rule_dict, key)) {
size_t nitems;
const uint64_t *rid = nvlist_get_number_array(rl->rule_dict, key, &nitems);
assert(nitems == 3);

r_id->id[0] = (uint32_t)rid[0];
r_id->id[1] = (uint32_t)rid[1];
r_id->op = (uint8_t)rid[2];
return 0;
}
return -1;
}

uint64_t
npf_rule_getid(nl_rule_t *rl)
{
Expand Down
2 changes: 2 additions & 0 deletions lib/libnpf/npf.expsym
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ npf_rule_getinfo
npf_rule_getinterface
npf_rule_getname
npf_rule_getproc
npf_rule_getrid
npf_rule_insert
npf_rule_iterate
npf_rule_setcode
npf_rule_setinfo
npf_rule_setkey
npf_rule_setprio
npf_rule_setproc
npf_rule_setrid
npf_ruleset_add
npf_ruleset_flush
npf_ruleset_remkey
Expand Down
2 changes: 2 additions & 0 deletions lib/libnpf/npf.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,15 @@ nl_rule_t * npf_rule_create(const char *, uint32_t, const char *);
int npf_rule_setcode(nl_rule_t *, int, const void *, size_t);
int npf_rule_setprio(nl_rule_t *, int);
int npf_rule_setproc(nl_rule_t *, const char *);
int npf_rule_setrid(nl_rule_t *, struct r_id, const char *);
int npf_rule_setkey(nl_rule_t *, const void *, size_t);
int npf_rule_setinfo(nl_rule_t *, const void *, size_t);
const char * npf_rule_getname(nl_rule_t *);
uint32_t npf_rule_getattr(nl_rule_t *);
const char * npf_rule_getinterface(nl_rule_t *);
const void * npf_rule_getinfo(nl_rule_t *, size_t *);
const char * npf_rule_getproc(nl_rule_t *);
int npf_rule_getrid(struct r_id *, nl_rule_t *, const char *);
uint64_t npf_rule_getid(nl_rule_t *);
const void * npf_rule_getcode(nl_rule_t *, int *, size_t *);
bool npf_rule_exists_p(nl_config_t *, const char *);
Expand Down
2 changes: 1 addition & 1 deletion sys/modules/npf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SRCS= npf.c npf_alg.c npf_conf.c npf_ctl.c npf_handler.c
SRCS+= npf_bpf.c npf_if.c npf_inet.c npf_mbuf.c npf_nat.c
SRCS+= npf_params.c npf_ruleset.c npf_rproc.c
SRCS+= npf_conn.c npf_conndb.c npf_connkey.c npf_portmap.c
SRCS+= npf_state.c npf_state_tcp.c npf_tableset.c
SRCS+= npf_state.c npf_state_tcp.c npf_tableset.c npf_socket.c
SRCS+= lpm.c npf_sendpkt.c npf_worker.c npf_os.c npf_ifaddr.c

SRCS+= nvlist.c nvpair.c nv_kern_netbsd.c dnvlist.c
Expand Down
1 change: 1 addition & 0 deletions sys/net/npf/files.npf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ file net/npf/npf_portmap.c npf
file net/npf/npf_alg.c npf
file net/npf/npf_sendpkt.c npf
file net/npf/npf_worker.c npf
file net/npf/npf_socket.c npf

file net/npf/npf_os.c npf
file net/npf/npf_ifaddr.c npf
Expand Down
23 changes: 23 additions & 0 deletions sys/net/npf/npf.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ typedef union {
uint32_t word32[4];
} npf_addr_t;


/*
* use a single type for both user id and group id
*/
struct r_id {
uint32_t id[2];
uint8_t op;
};

typedef struct r_id rid_t;
typedef uint8_t npf_netmask_t;

#define NPF_MAX_NETMASK (128)
Expand Down Expand Up @@ -372,6 +382,19 @@ typedef enum {
NPF_STATS_COUNT
} npf_stats_t;

/* unary and binary operators */
enum {
NPF_OP_NONE,
NPF_OP_EQ,
NPF_OP_NE,
NPF_OP_LE,
NPF_OP_LT,
NPF_OP_GE,
NPF_OP_GT,
NPF_OP_XRG,
NPF_OP_IRG
};

#define NPF_STATS_SIZE (sizeof(uint64_t) * NPF_STATS_COUNT)

#endif /* _NPF_NET_H_ */
10 changes: 10 additions & 0 deletions sys/net/npf/npf_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,16 @@ npf_mk_singlerule(npf_t *npf, const nvlist_t *req, nvlist_t *resp,
npf_rule_setcode(rl, type, bc, clen);
}

/* user and group ids filt option if set */
if (nvlist_exists_number_array(req, "r_user")) {
npf_rule_setrid(req, rl, "r_user");
}

if (nvlist_exists_number_array(req, "r_group")) {
npf_rule_setrid(req, rl, "r_group");
}


*rlret = rl;
return 0;
err:
Expand Down
13 changes: 11 additions & 2 deletions sys/net/npf/npf_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ npfk_packet_handler(npf_t *npf, struct mbuf **mp, ifnet_t *ifp, int di)
npf_conn_t *con;
npf_rule_t *rl;
npf_rproc_t *rp;
int error, decision, flags;
int error, decision, flags, id_match;
npf_match_info_t mi;
bool mff;

Expand Down Expand Up @@ -239,11 +239,20 @@ npfk_packet_handler(npf_t *npf, struct mbuf **mp, ifnet_t *ifp, int di)
KASSERT(rp == NULL);
rp = npf_rule_getrproc(rl);

/* check for matching process uid/gid before concluding */
id_match = npf_rule_match_rid(rl, &npc, di);

/* Conclude with the rule and release the lock. */
error = npf_rule_conclude(rl, &mi);
npf_config_read_exit(npf, slock);

if (error) {
/* reverse between pass and block conditions */
if (id_match != -1 && !id_match) {
error = npf_rule_reverse(&npc, &mi, error);
}

/* reject packets whose addr-port pair matches no sockets */
if (id_match == ENOTCONN || error) {
npf_stats_inc(npf, NPF_STAT_BLOCK_RULESET);
goto block;
}
Expand Down
8 changes: 8 additions & 0 deletions sys/net/npf/npf_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef struct npf_conndb npf_conndb_t;
typedef struct npf_table npf_table_t;
typedef struct npf_tableset npf_tableset_t;
typedef struct npf_algset npf_algset_t;
typedef uint32_t (*get_rid_t)(kauth_cred_t);

#ifdef __NetBSD__
typedef void ebr_t;
Expand Down Expand Up @@ -428,6 +429,7 @@ void npf_ruleset_gc(npf_ruleset_t *);
npf_rule_t * npf_ruleset_inspect(npf_cache_t *, const npf_ruleset_t *,
const int, const int);
int npf_rule_conclude(const npf_rule_t *, npf_match_info_t *);
int npf_rule_reverse(npf_cache_t *, npf_match_info_t *, int);

/* Rule interface. */
npf_rule_t * npf_rule_alloc(npf_t *, const nvlist_t *);
Expand All @@ -439,6 +441,10 @@ npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *);
void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
npf_rproc_t * npf_rule_getrproc(const npf_rule_t *);

int npf_socket_lookup_rid(npf_cache_t *, get_rid_t, uint32_t *, int);
void npf_rule_setrid(const nvlist_t *, npf_rule_t *, const char *);
int npf_rule_match_rid(npf_rule_t *, npf_cache_t *, int);

void npf_ext_init(npf_t *);
void npf_ext_fini(npf_t *);
int npf_ext_construct(npf_t *, const char *,
Expand Down Expand Up @@ -470,6 +476,8 @@ void npf_state_tcp_sysinit(npf_t *);
void npf_state_tcp_sysfini(npf_t *);
bool npf_state_tcp(npf_cache_t *, npf_state_t *, npf_flow_t);
int npf_state_tcp_timeout(npf_t *, const npf_state_t *);
/* uid/gid process matching */
int npf_match_rid(rid_t *, uint32_t);

/* Portmap. */
void npf_portmap_sysinit(void);
Expand Down
112 changes: 112 additions & 0 deletions sys/net/npf/npf_ruleset.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.52 2023/08/08 16:10:41 kardel Exp
#include <sys/queue.h>
#include <sys/mbuf.h>
#include <sys/types.h>
#include <sys/kauth.h>

#include <net/bpf.h>
#include <net/bpfjit.h>
Expand Down Expand Up @@ -118,6 +119,9 @@ struct npf_rule {
LIST_ENTRY(npf_rule) r_aentry;
nvlist_t * r_info;
size_t r_info_len;

rid_t uid;
rid_t gid;
};

#define SKIPTO_ADJ_FLAG (1U << 31)
Expand Down Expand Up @@ -655,9 +659,19 @@ npf_rule_alloc(npf_t *npf, const nvlist_t *rule)
}
memcpy(rl->r_key, key, len);
}

/* no gid/uid set yet */
rl->gid.op = rl->uid.op = NPF_OP_NONE;
return rl;
}

static void
npf_rid_export(nvlist_t *rl, struct r_id rid, const char *name)
{
uint64_t uid_element[3] = { rid.id[0], rid.id[1], rid.op };
nvlist_add_number_array(rl, name, uid_element, 3);
}

static nvlist_t *
npf_rule_export(npf_t *npf, const npf_rule_t *rl)
{
Expand Down Expand Up @@ -691,6 +705,12 @@ npf_rule_export(npf_t *npf, const npf_rule_t *rl)
if (rl->r_info) {
nvlist_add_binary(rule, "info", rl->r_info, rl->r_info_len);
}
if (rl->uid.op != NPF_OP_NONE) {
npf_rid_export(rule, rl->uid, "r_user");
}
if (rl->gid.op != NPF_OP_NONE) {
npf_rid_export(rule, rl->gid, "r_group");
}
if ((rp = npf_rule_getrproc(rl)) != NULL) {
const char *rname = npf_rproc_getname(rp);
nvlist_add_string(rule, "rproc", rname);
Expand All @@ -716,6 +736,24 @@ npf_rule_setcode(npf_rule_t *rl, const int type, void *code, size_t size)
rl->r_jcode = npf_bpf_compile(code, size);
}

void
npf_rule_setrid(const nvlist_t *req, npf_rule_t *rl, const char *name)
{
size_t nitems;
rid_t id;
const uint64_t *rid = nvlist_get_number_array(req, name, &nitems);
KASSERT(nitems == 3);

id.id[0] = (uint32_t)rid[0];
id.id[1] = (uint32_t)rid[1];
id.op = (uint8_t)rid[2];

if (!strcmp(name, "r_user"))
rl->uid = id;
else if (!strcmp(name, "r_group"))
rl->gid = id;
}

/*
* npf_rule_setrproc: assign a rule procedure and hold a reference on it.
*/
Expand Down Expand Up @@ -929,6 +967,80 @@ npf_ruleset_inspect(npf_cache_t *npc, const npf_ruleset_t *rlset,
return final_rl;
}

/*
* just exchange the flag attributes for pass/block for the diff protocols.
* for passing, we set the STATEFULNESS for TCP connection establishment
* if ret == 0, it is for a pass to be changed to block
* non-zero ret indicates a block to pass
* when we change to block, we assume the default RST rerturn for TCP
* when we change to pass, we ensure no bit field for RST for tcp and ICMP for udp
* finally change the ret condition too
*/
int
npf_rule_reverse(npf_cache_t *npc, npf_match_info_t *mi, int ret)
{
KASSERT(npf_iscached(npc, NPC_LAYER4));
switch(npc->npc_proto) {
case IPPROTO_TCP:
if (ret == 0) /* switch pass to block */ {
mi->mi_retfl &= !(NPF_RULE_PASS | NPF_RULE_STATEFUL |
NPF_RULE_GSTATEFUL);
mi->mi_retfl |= NPF_RULE_RETRST;
}
else /* block to pass */ {
mi->mi_retfl &= !(NPF_RULE_RETRST);
mi->mi_retfl |= (NPF_RULE_PASS | NPF_RULE_STATEFUL |
NPF_RULE_GSTATEFUL);
}
break;
case IPPROTO_UDP:
if (ret == 0) /* pass to block */ {
mi->mi_retfl &= !(NPF_RULE_PASS);
mi->mi_retfl |= NPF_RULE_RETICMP;
}
else /* block to pass */ {
mi->mi_retfl &= !(NPF_RULE_RETICMP);
mi->mi_retfl |= NPF_RULE_PASS;
}
break;
}

return (ret == 0) ? ENETUNREACH : 0;
}

/* only perform uid/gid checks when set */
int
npf_rule_match_rid(npf_rule_t *rl, npf_cache_t *npc, int dir)
{
uint32_t sock_gid, sock_uid;
bool uid_matched = false, gid_matched = false;

if (rl->gid.op == NPF_OP_NONE && rl->uid.op == NPF_OP_NONE)
return -1; /* quickly return if packet has nothing to do with rids */

KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));

if (rl->gid.op != NPF_OP_NONE) {
if (npf_socket_lookup_rid(npc, kauth_cred_getegid, &sock_gid, dir) == -1)
return ENOTCONN;

gid_matched = npf_match_rid(&rl->gid, sock_gid);
}
if (rl->uid.op != NPF_OP_NONE) {
if (npf_socket_lookup_rid(npc, kauth_cred_geteuid, &sock_uid, dir) == -1)
return ENOTCONN;

uid_matched = npf_match_rid(&rl->uid, sock_uid);
}

/* if both uid and gid are set on rule, both must be matching to agree */
if (rl->gid.op && rl->uid.op)
return gid_matched && uid_matched;
else
return gid_matched || uid_matched;
}

/*
* npf_rule_conclude: return decision and the flags for conclusion.
*
Expand Down
Loading