Skip to content

Commit 6fba898

Browse files
cschauflerpcmoore
authored andcommitted
lsm: ensure the correct LSM context releaser
Add a new lsm_context data structure to hold all the information about a "security context", including the string, its size and which LSM allocated the string. The allocation information is necessary because LSMs have different policies regarding the lifecycle of these strings. SELinux allocates and destroys them on each use, whereas Smack provides a pointer to an entry in a list that never goes away. Update security_release_secctx() to use the lsm_context instead of a (char *, len) pair. Change its callers to do likewise. The LSMs supporting this hook have had comments added to remind the developer that there is more work to be done. The BPF security module provides all LSM hooks. While there has yet to be a known instance of a BPF configuration that uses security contexts, the possibility is real. In the existing implementation there is potential for multiple frees in that case. Cc: linux-integrity@vger.kernel.org Cc: netdev@vger.kernel.org Cc: audit@vger.kernel.org Cc: netfilter-devel@vger.kernel.org To: Pablo Neira Ayuso <pablo@netfilter.org> Cc: linux-nfs@vger.kernel.org Cc: Todd Kjos <tkjos@google.com> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> [PM: subject tweak] Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 40384c8 commit 6fba898

File tree

19 files changed

+165
-107
lines changed

19 files changed

+165
-107
lines changed

drivers/android/binder.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,8 +3017,7 @@ static void binder_transaction(struct binder_proc *proc,
30173017
struct binder_context *context = proc->context;
30183018
int t_debug_id = atomic_inc_return(&binder_last_id);
30193019
ktime_t t_start_time = ktime_get();
3020-
char *secctx = NULL;
3021-
u32 secctx_sz = 0;
3020+
struct lsm_context lsmctx;
30223021
struct list_head sgc_head;
30233022
struct list_head pf_head;
30243023
const void __user *user_buffer = (const void __user *)
@@ -3297,7 +3296,8 @@ static void binder_transaction(struct binder_proc *proc,
32973296
size_t added_size;
32983297

32993298
security_cred_getsecid(proc->cred, &secid);
3300-
ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
3299+
ret = security_secid_to_secctx(secid, &lsmctx.context,
3300+
&lsmctx.len);
33013301
if (ret) {
33023302
binder_txn_error("%d:%d failed to get security context\n",
33033303
thread->pid, proc->pid);
@@ -3306,7 +3306,7 @@ static void binder_transaction(struct binder_proc *proc,
33063306
return_error_line = __LINE__;
33073307
goto err_get_secctx_failed;
33083308
}
3309-
added_size = ALIGN(secctx_sz, sizeof(u64));
3309+
added_size = ALIGN(lsmctx.len, sizeof(u64));
33103310
extra_buffers_size += added_size;
33113311
if (extra_buffers_size < added_size) {
33123312
binder_txn_error("%d:%d integer overflow of extra_buffers_size\n",
@@ -3340,23 +3340,23 @@ static void binder_transaction(struct binder_proc *proc,
33403340
t->buffer = NULL;
33413341
goto err_binder_alloc_buf_failed;
33423342
}
3343-
if (secctx) {
3343+
if (lsmctx.context) {
33443344
int err;
33453345
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
33463346
ALIGN(tr->offsets_size, sizeof(void *)) +
33473347
ALIGN(extra_buffers_size, sizeof(void *)) -
3348-
ALIGN(secctx_sz, sizeof(u64));
3348+
ALIGN(lsmctx.len, sizeof(u64));
33493349

33503350
t->security_ctx = t->buffer->user_data + buf_offset;
33513351
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
33523352
t->buffer, buf_offset,
3353-
secctx, secctx_sz);
3353+
lsmctx.context, lsmctx.len);
33543354
if (err) {
33553355
t->security_ctx = 0;
33563356
WARN_ON(1);
33573357
}
3358-
security_release_secctx(secctx, secctx_sz);
3359-
secctx = NULL;
3358+
security_release_secctx(&lsmctx);
3359+
lsmctx.context = NULL;
33603360
}
33613361
t->buffer->debug_id = t->debug_id;
33623362
t->buffer->transaction = t;
@@ -3400,7 +3400,7 @@ static void binder_transaction(struct binder_proc *proc,
34003400
off_end_offset = off_start_offset + tr->offsets_size;
34013401
sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
34023402
sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
3403-
ALIGN(secctx_sz, sizeof(u64));
3403+
ALIGN(lsmctx.len, sizeof(u64));
34043404
off_min = 0;
34053405
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
34063406
buffer_offset += sizeof(binder_size_t)) {
@@ -3779,8 +3779,8 @@ static void binder_transaction(struct binder_proc *proc,
37793779
binder_alloc_free_buf(&target_proc->alloc, t->buffer);
37803780
err_binder_alloc_buf_failed:
37813781
err_bad_extra_size:
3782-
if (secctx)
3783-
security_release_secctx(secctx, secctx_sz);
3782+
if (lsmctx.context)
3783+
security_release_secctx(&lsmctx);
37843784
err_get_secctx_failed:
37853785
kfree(tcomplete);
37863786
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);

fs/ceph/xattr.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1446,12 +1446,16 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
14461446

14471447
void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
14481448
{
1449+
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
1450+
struct lsm_context scaff; /* scaffolding */
1451+
#endif
14491452
#ifdef CONFIG_CEPH_FS_POSIX_ACL
14501453
posix_acl_release(as_ctx->acl);
14511454
posix_acl_release(as_ctx->default_acl);
14521455
#endif
14531456
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
1454-
security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen);
1457+
lsmcontext_init(&scaff, as_ctx->sec_ctx, as_ctx->sec_ctxlen, 0);
1458+
security_release_secctx(&scaff);
14551459
#endif
14561460
#ifdef CONFIG_FS_ENCRYPTION
14571461
kfree(as_ctx->fscrypt_auth);

fs/nfs/nfs4proc.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,12 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
138138
static inline void
139139
nfs4_label_release_security(struct nfs4_label *label)
140140
{
141-
if (label)
142-
security_release_secctx(label->label, label->len);
141+
struct lsm_context scaff; /* scaffolding */
142+
143+
if (label) {
144+
lsmcontext_init(&scaff, label->label, label->len, 0);
145+
security_release_secctx(&scaff);
146+
}
143147
}
144148
static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
145149
{

fs/nfsd/nfs4xdr.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,8 +3644,12 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
36443644

36453645
out:
36463646
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
3647-
if (args.context)
3648-
security_release_secctx(args.context, args.contextlen);
3647+
if (args.context) {
3648+
struct lsm_context scaff; /* scaffolding */
3649+
3650+
lsmcontext_init(&scaff, args.context, args.contextlen, 0);
3651+
security_release_secctx(&scaff);
3652+
}
36493653
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
36503654
kfree(args.acl);
36513655
if (tempfh) {

include/linux/lsm_hook_defs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, char **secdata,
300300
LSM_HOOK(int, -EOPNOTSUPP, lsmprop_to_secctx, struct lsm_prop *prop,
301301
char **secdata, u32 *seclen)
302302
LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
303-
LSM_HOOK(void, LSM_RET_VOID, release_secctx, char *secdata, u32 seclen)
303+
LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsm_context *cp)
304304
LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
305305
LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
306306
LSM_HOOK(int, 0, inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)

include/linux/security.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,37 @@ extern unsigned long dac_mmap_min_addr;
225225
#define dac_mmap_min_addr 0UL
226226
#endif
227227

228+
/*
229+
* A "security context" is the text representation of
230+
* the information used by LSMs.
231+
* This structure contains the string, its length, and which LSM
232+
* it is useful for.
233+
*/
234+
struct lsm_context {
235+
char *context; /* Provided by the module */
236+
u32 len;
237+
int id; /* Identifies the module */
238+
};
239+
240+
/**
241+
* lsmcontext_init - initialize an lsmcontext structure.
242+
* @cp: Pointer to the context to initialize
243+
* @context: Initial context, or NULL
244+
* @size: Size of context, or 0
245+
* @id: Which LSM provided the context
246+
*
247+
* Fill in the lsmcontext from the provided information.
248+
* This is a scaffolding function that will be removed when
249+
* lsm_context integration is complete.
250+
*/
251+
static inline void lsmcontext_init(struct lsm_context *cp, char *context,
252+
u32 size, int id)
253+
{
254+
cp->id = id;
255+
cp->context = context;
256+
cp->len = size;
257+
}
258+
228259
/*
229260
* Values used in the task_security_ops calls
230261
*/
@@ -556,7 +587,7 @@ int security_ismaclabel(const char *name);
556587
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
557588
int security_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, u32 *seclen);
558589
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
559-
void security_release_secctx(char *secdata, u32 seclen);
590+
void security_release_secctx(struct lsm_context *cp);
560591
void security_inode_invalidate_secctx(struct inode *inode);
561592
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
562593
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
@@ -1545,7 +1576,7 @@ static inline int security_secctx_to_secid(const char *secdata,
15451576
return -EOPNOTSUPP;
15461577
}
15471578

1548-
static inline void security_release_secctx(char *secdata, u32 seclen)
1579+
static inline void security_release_secctx(struct lsm_context *cp)
15491580
{
15501581
}
15511582

include/net/scm.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,17 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
105105
#ifdef CONFIG_SECURITY_NETWORK
106106
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
107107
{
108-
char *secdata;
109-
u32 seclen;
108+
struct lsm_context ctx;
110109
int err;
111110

112111
if (test_bit(SOCK_PASSSEC, &sock->flags)) {
113-
err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
112+
err = security_secid_to_secctx(scm->secid, &ctx.context,
113+
&ctx.len);
114114

115115
if (!err) {
116-
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
117-
security_release_secctx(secdata, seclen);
116+
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, ctx.len,
117+
ctx.context);
118+
security_release_secctx(&ctx);
118119
}
119120
}
120121
}

kernel/audit.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,8 +1221,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
12211221
struct audit_buffer *ab;
12221222
u16 msg_type = nlh->nlmsg_type;
12231223
struct audit_sig_info *sig_data;
1224-
char *ctx = NULL;
1225-
u32 len;
1224+
struct lsm_context lsmctx;
12261225

12271226
err = audit_netlink_ok(skb, msg_type);
12281227
if (err)
@@ -1472,27 +1471,29 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
14721471
break;
14731472
}
14741473
case AUDIT_SIGNAL_INFO:
1475-
len = 0;
14761474
if (lsmprop_is_set(&audit_sig_lsm)) {
1477-
err = security_lsmprop_to_secctx(&audit_sig_lsm, &ctx,
1478-
&len);
1475+
err = security_lsmprop_to_secctx(&audit_sig_lsm,
1476+
&lsmctx.context,
1477+
&lsmctx.len);
14791478
if (err)
14801479
return err;
14811480
}
1482-
sig_data = kmalloc(struct_size(sig_data, ctx, len), GFP_KERNEL);
1481+
sig_data = kmalloc(struct_size(sig_data, ctx, lsmctx.len),
1482+
GFP_KERNEL);
14831483
if (!sig_data) {
14841484
if (lsmprop_is_set(&audit_sig_lsm))
1485-
security_release_secctx(ctx, len);
1485+
security_release_secctx(&lsmctx);
14861486
return -ENOMEM;
14871487
}
14881488
sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
14891489
sig_data->pid = audit_sig_pid;
14901490
if (lsmprop_is_set(&audit_sig_lsm)) {
1491-
memcpy(sig_data->ctx, ctx, len);
1492-
security_release_secctx(ctx, len);
1491+
memcpy(sig_data->ctx, lsmctx.context, lsmctx.len);
1492+
security_release_secctx(&lsmctx);
14931493
}
14941494
audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
1495-
sig_data, struct_size(sig_data, ctx, len));
1495+
sig_data, struct_size(sig_data, ctx,
1496+
lsmctx.len));
14961497
kfree(sig_data);
14971498
break;
14981499
case AUDIT_TTY_GET: {
@@ -2180,23 +2181,22 @@ void audit_log_key(struct audit_buffer *ab, char *key)
21802181
int audit_log_task_context(struct audit_buffer *ab)
21812182
{
21822183
struct lsm_prop prop;
2183-
char *ctx = NULL;
2184-
unsigned len;
2184+
struct lsm_context ctx;
21852185
int error;
21862186

21872187
security_current_getlsmprop_subj(&prop);
21882188
if (!lsmprop_is_set(&prop))
21892189
return 0;
21902190

2191-
error = security_lsmprop_to_secctx(&prop, &ctx, &len);
2191+
error = security_lsmprop_to_secctx(&prop, &ctx.context, &ctx.len);
21922192
if (error) {
21932193
if (error != -EINVAL)
21942194
goto error_path;
21952195
return 0;
21962196
}
21972197

2198-
audit_log_format(ab, " subj=%s", ctx);
2199-
security_release_secctx(ctx, len);
2198+
audit_log_format(ab, " subj=%s", ctx.context);
2199+
security_release_secctx(&ctx);
22002200
return 0;
22012201

22022202
error_path:

kernel/auditsc.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,8 +1098,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
10981098
char *comm)
10991099
{
11001100
struct audit_buffer *ab;
1101-
char *ctx = NULL;
1102-
u32 len;
1101+
struct lsm_context ctx;
11031102
int rc = 0;
11041103

11051104
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
@@ -1110,12 +1109,12 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
11101109
from_kuid(&init_user_ns, auid),
11111110
from_kuid(&init_user_ns, uid), sessionid);
11121111
if (lsmprop_is_set(prop)) {
1113-
if (security_lsmprop_to_secctx(prop, &ctx, &len)) {
1112+
if (security_lsmprop_to_secctx(prop, &ctx.context, &ctx.len)) {
11141113
audit_log_format(ab, " obj=(none)");
11151114
rc = 1;
11161115
} else {
1117-
audit_log_format(ab, " obj=%s", ctx);
1118-
security_release_secctx(ctx, len);
1116+
audit_log_format(ab, " obj=%s", ctx.context);
1117+
security_release_secctx(&ctx);
11191118
}
11201119
}
11211120
audit_log_format(ab, " ocomm=");
@@ -1371,6 +1370,7 @@ static void audit_log_time(struct audit_context *context, struct audit_buffer **
13711370

13721371
static void show_special(struct audit_context *context, int *call_panic)
13731372
{
1373+
struct lsm_context lsmcxt;
13741374
struct audit_buffer *ab;
13751375
int i;
13761376

@@ -1401,7 +1401,8 @@ static void show_special(struct audit_context *context, int *call_panic)
14011401
*call_panic = 1;
14021402
} else {
14031403
audit_log_format(ab, " obj=%s", ctx);
1404-
security_release_secctx(ctx, len);
1404+
lsmcontext_init(&lsmcxt, ctx, len, 0);
1405+
security_release_secctx(&lsmcxt);
14051406
}
14061407
}
14071408
if (context->ipc.has_perm) {
@@ -1560,15 +1561,15 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
15601561
MAJOR(n->rdev),
15611562
MINOR(n->rdev));
15621563
if (lsmprop_is_set(&n->oprop)) {
1563-
char *ctx = NULL;
1564-
u32 len;
1564+
struct lsm_context ctx;
15651565

1566-
if (security_lsmprop_to_secctx(&n->oprop, &ctx, &len)) {
1566+
if (security_lsmprop_to_secctx(&n->oprop, &ctx.context,
1567+
&ctx.len)) {
15671568
if (call_panic)
15681569
*call_panic = 2;
15691570
} else {
1570-
audit_log_format(ab, " obj=%s", ctx);
1571-
security_release_secctx(ctx, len);
1571+
audit_log_format(ab, " obj=%s", ctx.context);
1572+
security_release_secctx(&ctx);
15721573
}
15731574
}
15741575

net/ipv4/ip_sockglue.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,20 +128,20 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
128128

129129
static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
130130
{
131-
char *secdata;
132-
u32 seclen, secid;
131+
struct lsm_context ctx;
132+
u32 secid;
133133
int err;
134134

135135
err = security_socket_getpeersec_dgram(NULL, skb, &secid);
136136
if (err)
137137
return;
138138

139-
err = security_secid_to_secctx(secid, &secdata, &seclen);
139+
err = security_secid_to_secctx(secid, &ctx.context, &ctx.len);
140140
if (err)
141141
return;
142142

143-
put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
144-
security_release_secctx(secdata, seclen);
143+
put_cmsg(msg, SOL_IP, SCM_SECURITY, ctx.len, ctx.context);
144+
security_release_secctx(&ctx);
145145
}
146146

147147
static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)

0 commit comments

Comments
 (0)