Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
10 changes: 10 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
1 change: 1 addition & 0 deletions lib/libnpf/npf.expsym
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ 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
1 change: 1 addition & 0 deletions lib/libnpf/npf.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ 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 *);
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
22 changes: 22 additions & 0 deletions sys/net/npf/npf.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ 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 uint8_t npf_netmask_t;

#define NPF_MAX_NETMASK (128)
Expand Down Expand Up @@ -372,6 +381,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
10 changes: 9 additions & 1 deletion 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,10 +239,18 @@ 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);

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

if (error) {
npf_stats_inc(npf, NPF_STAT_BLOCK_RULESET);
goto block;
Expand Down
9 changes: 9 additions & 0 deletions sys/net/npf/npf_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ typedef struct npf_rprocset npf_rprocset_t;
typedef struct npf_alg npf_alg_t;
typedef struct npf_natpolicy npf_natpolicy_t;
typedef struct npf_conn npf_conn_t;
typedef struct r_id rid_t;

struct npf_conndb;
struct npf_table;
Expand All @@ -95,6 +96,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 +430,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 +442,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 +477,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
95 changes: 95 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,6 +659,9 @@ 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;
}

Expand Down Expand Up @@ -716,6 +723,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 +954,76 @@ 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;
int matched = 0;

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;

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;

matched |= npf_match_rid(rl->uid, sock_uid);
}

return matched;
}

/*
* npf_rule_conclude: return decision and the flags for conclusion.
*
Expand Down
2 changes: 1 addition & 1 deletion sys/rump/net/lib/libnpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,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
8 changes: 8 additions & 0 deletions usr.sbin/npf/npfctl/npf_build.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,14 @@ npfctl_build_rule(uint32_t attr, const char *ifname, sa_family_t family,
npfctl_build_code(rl, family, popts, fopts);
}

if (fopts->uid.op != NPF_OP_NONE) {
npf_rule_setrid(rl, fopts->uid, "r_user");
}

if (fopts->gid.op != NPF_OP_NONE) {
npf_rule_setrid(rl, fopts->gid, "r_group");
}

if (rproc) {
npf_rule_setproc(rl, rproc);
}
Expand Down
48 changes: 48 additions & 0 deletions usr.sbin/npf/npfctl/npf_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ __RCSID("$NetBSD: npf_data.c,v 1.30 2019/01/19 21:19:32 rmind Exp $");
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <pwd.h>
#include <grp.h>

#include "npfctl.h"

Expand Down Expand Up @@ -267,6 +269,52 @@ npfctl_parse_table_id(const char *name)
return npfvar_create_element(NPFVAR_TABLE, &tid, sizeof(u_int));
}

int
npfctl_parse_user(const char *user, uint32_t *uid)
{
if (!strcmp(user, "unknown"))
*uid = UID_MAX;
else {
struct passwd *pw;

if ((pw = getpwnam(user)) == NULL) {
return -1;
}
*uid = pw->pw_uid;
}
return 0;
}

int
npfctl_parse_group(const char *group, uint32_t *gid)
{
if (!strcmp(group, "unknown"))
*gid = GID_MAX;
else {
struct group *grp;

if ((grp = getgrnam(group)) == NULL) {
return -1;
}
*gid = grp->gr_gid;
}
return 0;
}

/*
* this function is called for both gid and uid init in parser
* both uid and gid are both uint32_t
*/
struct r_id
npfctl_init_rid(uint32_t id1, uint32_t id2, uint8_t op)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass the rid pointer to be initialized to avoid extra copies.

{
struct r_id rid;
rid.id[0] = id1;
rid.id[1] = id2;
rid.op = op;
return rid;
}

/*
* npfctl_parse_port_range: create a port-range variable. Note that the
* passed port numbers should be in host byte order.
Expand Down
Loading