1 |
/* |
/* |
2 |
* security/ccsecurity/network.c |
* security/ccsecurity/network.c |
3 |
* |
* |
4 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
* Copyright (C) 2005-2010 NTT DATA CORPORATION |
5 |
* |
* |
6 |
* Version: 1.7.0-pre 2009/08/24 |
* Version: 1.7.2 2010/04/01 |
7 |
* |
* |
8 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
9 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
47 |
* @min: Pointer to store min address. |
* @min: Pointer to store min address. |
48 |
* @max: Pointer to store max address. |
* @max: Pointer to store max address. |
49 |
* |
* |
50 |
* Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise. |
* Returns CCS_IP_ADDRESS_TYPE_IPv6 if @address is an IPv6, |
51 |
|
* CCS_IP_ADDRESS_TYPE_IPv4 if @address is an IPv4, |
52 |
|
* CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP otherwise. |
53 |
*/ |
*/ |
54 |
int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
55 |
{ |
{ |
67 |
min[i] = htons(min[i]); |
min[i] = htons(min[i]); |
68 |
max[i] = htons(max[i]); |
max[i] = htons(max[i]); |
69 |
} |
} |
70 |
return 2; |
return CCS_IP_ADDRESS_TYPE_IPv6; |
71 |
} |
} |
72 |
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
73 |
&min[0], &min[1], &min[2], &min[3], |
&min[0], &min[1], &min[2], &min[3], |
77 |
+ (((u8) min[2]) << 8) + (u8) min[3]); |
+ (((u8) min[2]) << 8) + (u8) min[3]); |
78 |
memmove(min, &ip, sizeof(ip)); |
memmove(min, &ip, sizeof(ip)); |
79 |
if (count == 8) |
if (count == 8) |
80 |
ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16) |
ip = htonl((((u8) max[0]) << 24) |
81 |
|
+ (((u8) max[1]) << 16) |
82 |
+ (((u8) max[2]) << 8) + (u8) max[3]); |
+ (((u8) max[2]) << 8) + (u8) max[3]); |
83 |
memmove(max, &ip, sizeof(ip)); |
memmove(max, &ip, sizeof(ip)); |
84 |
return 1; |
return CCS_IP_ADDRESS_TYPE_IPv4; |
85 |
} |
} |
86 |
return 0; |
return CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
87 |
|
} |
88 |
|
|
89 |
|
/** |
90 |
|
* ccs_print_ipv4 - Print an IPv4 address. |
91 |
|
* |
92 |
|
* @buffer: Buffer to write to. |
93 |
|
* @buffer_len: Size of @buffer. |
94 |
|
* @min_ip: Min address in host byte order. |
95 |
|
* @max_ip: Max address in host byte order. |
96 |
|
* |
97 |
|
* Returns nothing. |
98 |
|
*/ |
99 |
|
void ccs_print_ipv4(char *buffer, const int buffer_len, |
100 |
|
const u32 min_ip, const u32 max_ip) |
101 |
|
{ |
102 |
|
memset(buffer, 0, buffer_len); |
103 |
|
snprintf(buffer, buffer_len - 1, "%u.%u.%u.%u%c%u.%u.%u.%u", |
104 |
|
HIPQUAD(min_ip), min_ip == max_ip ? '\0' : '-', |
105 |
|
HIPQUAD(max_ip)); |
106 |
} |
} |
107 |
|
|
108 |
#if !defined(NIP6) |
#if !defined(NIP6) |
118 |
* |
* |
119 |
* @buffer: Buffer to write to. |
* @buffer: Buffer to write to. |
120 |
* @buffer_len: Size of @buffer. |
* @buffer_len: Size of @buffer. |
121 |
* @ip: Pointer to "struct in6_addr". |
* @min_ip: Pointer to "struct in6_addr". |
122 |
|
* @max_ip: Pointer to "struct in6_addr". |
123 |
* |
* |
124 |
* Returns nothing. |
* Returns nothing. |
125 |
*/ |
*/ |
126 |
void ccs_print_ipv6(char *buffer, const int buffer_len, |
void ccs_print_ipv6(char *buffer, const int buffer_len, |
127 |
const struct in6_addr *ip) |
const struct in6_addr *min_ip, |
128 |
|
const struct in6_addr *max_ip) |
129 |
{ |
{ |
130 |
memset(buffer, 0, buffer_len); |
memset(buffer, 0, buffer_len); |
131 |
snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip)); |
snprintf(buffer, buffer_len - 1, |
132 |
|
"%x:%x:%x:%x:%x:%x:%x:%x%c%x:%x:%x:%x:%x:%x:%x:%x", |
133 |
|
NIP6(*min_ip), min_ip == max_ip ? '\0' : '-', |
134 |
|
NIP6(*max_ip)); |
135 |
} |
} |
136 |
|
|
137 |
/** |
/** |
195 |
/* using host byte order to allow u32 comparison than memcmp().*/ |
/* using host byte order to allow u32 comparison than memcmp().*/ |
196 |
const u32 ip = ntohl(*address); |
const u32 ip = ntohl(*address); |
197 |
int error; |
int error; |
198 |
char buf[64]; |
char buf[128]; |
199 |
ccs_assert_read_lock(); |
const struct ccs_domain_info * const domain = ccs_current_domain(); |
200 |
if (ccs_init_request_info(&r, NULL, |
if (ccs_init_request_info(&r, CCS_MAC_NETWORK_UDP_BIND + operation) |
201 |
CCS_MAC_NETWORK_UDP_BIND + operation) |
== CCS_CONFIG_DISABLED) |
|
== CCS_MAC_MODE_DISABLED) |
|
202 |
return 0; |
return 0; |
|
memset(buf, 0, sizeof(buf)); |
|
203 |
if (is_ipv6) |
if (is_ipv6) |
204 |
ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) |
ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) |
205 |
address); |
address, (const struct in6_addr *) address); |
206 |
else |
else |
207 |
snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip)); |
ccs_print_ipv4(buf, sizeof(buf), ip, ip); |
208 |
do { |
do { |
209 |
error = -EPERM; |
error = -EPERM; |
210 |
list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) { |
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
211 |
struct ccs_ip_network_acl *acl; |
struct ccs_ip_network_acl *acl; |
212 |
if (ptr->is_deleted || |
if (ptr->is_deleted || |
213 |
ptr->type != CCS_TYPE_IP_NETWORK_ACL) |
ptr->type != CCS_TYPE_IP_NETWORK_ACL) |
250 |
break; |
break; |
251 |
error = ccs_supervisor(&r, CCS_KEYWORD_ALLOW_NETWORK |
error = ccs_supervisor(&r, CCS_KEYWORD_ALLOW_NETWORK |
252 |
"%s %s %u\n", keyword, buf, port); |
"%s %s %u\n", keyword, buf, port); |
253 |
} while (error == 1); |
} while (error == CCS_RETRY_REQUEST); |
254 |
if (r.mode != CCS_MAC_MODE_ENFORCING) |
if (r.mode != CCS_CONFIG_ENFORCING) |
255 |
error = 0; |
error = 0; |
256 |
return error; |
return error; |
257 |
} |
} |
270 |
const u32 *address, const u16 port) |
const u32 *address, const u16 port) |
271 |
{ |
{ |
272 |
const int idx = ccs_read_lock(); |
const int idx = ccs_read_lock(); |
273 |
const int error = ccs_network_entry2(is_ipv6, operation, |
const int error = ccs_network_entry2(is_ipv6, operation, address, |
274 |
address, port); |
port); |
275 |
ccs_read_unlock(idx); |
ccs_read_unlock(idx); |
276 |
return error; |
return error; |
277 |
} |
} |
278 |
|
|
279 |
|
static bool ccs_is_same_ip_network_acl(const struct ccs_acl_info *a, |
280 |
|
const struct ccs_acl_info *b) |
281 |
|
{ |
282 |
|
const struct ccs_ip_network_acl *p1 = container_of(a, typeof(*p1), |
283 |
|
head); |
284 |
|
const struct ccs_ip_network_acl *p2 = container_of(b, typeof(*p2), |
285 |
|
head); |
286 |
|
return ccs_is_same_acl_head(&p1->head, &p2->head) |
287 |
|
&& p1->address_type == p2->address_type && |
288 |
|
p1->address.ipv4.min == p2->address.ipv4.min && |
289 |
|
p1->address.ipv6.min == p2->address.ipv6.min && |
290 |
|
p1->address.ipv4.max == p2->address.ipv4.max && |
291 |
|
p1->address.ipv6.max == p2->address.ipv6.max && |
292 |
|
p1->address.group == p2->address.group && |
293 |
|
ccs_is_same_number_union(&p1->port, &p2->port); |
294 |
|
} |
295 |
|
|
296 |
|
static bool ccs_merge_ip_network_acl(struct ccs_acl_info *a, |
297 |
|
struct ccs_acl_info *b, |
298 |
|
const bool is_delete) |
299 |
|
{ |
300 |
|
struct ccs_ip_network_acl *p1 = container_of(a, typeof(*p1), head); |
301 |
|
const u16 perm = container_of(b, typeof(*p1), head)->perm; |
302 |
|
if (is_delete) { |
303 |
|
p1->perm &= ~perm; |
304 |
|
} else { |
305 |
|
if (p1->head.is_deleted) |
306 |
|
p1->perm = 0; |
307 |
|
p1->perm |= perm; |
308 |
|
} |
309 |
|
return !p1->perm; |
310 |
|
} |
311 |
|
|
312 |
/** |
/** |
313 |
* ccs_write_network_policy - Write "struct ccs_ip_network_acl" list. |
* ccs_write_network_policy - Write "struct ccs_ip_network_acl" list. |
314 |
* |
* |
323 |
struct ccs_condition *condition, |
struct ccs_condition *condition, |
324 |
const bool is_delete) |
const bool is_delete) |
325 |
{ |
{ |
|
struct ccs_ip_network_acl *entry = NULL; |
|
|
struct ccs_acl_info *ptr; |
|
326 |
struct ccs_ip_network_acl e = { |
struct ccs_ip_network_acl e = { |
327 |
.head.type = CCS_TYPE_IP_NETWORK_ACL, |
.head.type = CCS_TYPE_IP_NETWORK_ACL, |
328 |
.head.cond = condition, |
.head.cond = condition, |
373 |
else |
else |
374 |
return -EINVAL; |
return -EINVAL; |
375 |
switch (ccs_parse_ip_address(w[2], min_address, max_address)) { |
switch (ccs_parse_ip_address(w[2], min_address, max_address)) { |
376 |
case 2: |
case CCS_IP_ADDRESS_TYPE_IPv6: |
377 |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv6; |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv6; |
378 |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
379 |
min_address); |
min_address); |
382 |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
383 |
goto out; |
goto out; |
384 |
break; |
break; |
385 |
case 1: |
case CCS_IP_ADDRESS_TYPE_IPv4: |
386 |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv4; |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv4; |
387 |
/* use host byte order to allow u32 comparison.*/ |
/* use host byte order to allow u32 comparison.*/ |
388 |
e.address.ipv4.min = ntohl(*(u32 *) min_address); |
e.address.ipv4.min = ntohl(*(u32 *) min_address); |
392 |
if (w[2][0] != '@') |
if (w[2][0] != '@') |
393 |
return -EINVAL; |
return -EINVAL; |
394 |
e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
395 |
e.address.group = ccs_get_address_group(w[2] + 1); |
e.address.group = ccs_get_group(w[2] + 1, CCS_ADDRESS_GROUP); |
396 |
if (!e.address.group) |
if (!e.address.group) |
397 |
return -ENOMEM; |
return -ENOMEM; |
398 |
break; |
break; |
399 |
} |
} |
400 |
if (!ccs_parse_number_union(w[3], &e.port)) |
if (!ccs_parse_number_union(w[3], &e.port)) |
401 |
goto out; |
goto out; |
402 |
if (!is_delete) |
error = ccs_update_domain_policy(&e.head, sizeof(e), is_delete, domain, |
403 |
entry = kmalloc(sizeof(e), GFP_KERNEL); |
ccs_is_same_ip_network_acl, |
404 |
mutex_lock(&ccs_policy_lock); |
ccs_merge_ip_network_acl); |
|
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
|
|
struct ccs_ip_network_acl *acl = |
|
|
container_of(ptr, struct ccs_ip_network_acl, |
|
|
head); |
|
|
if (ptr->type != CCS_TYPE_IP_NETWORK_ACL || |
|
|
ptr->cond != condition || |
|
|
ccs_memcmp(acl, &e, offsetof(typeof(e), address_type), |
|
|
sizeof(e))) |
|
|
continue; |
|
|
if (is_delete) { |
|
|
acl->perm &= ~e.perm; |
|
|
if (!acl->perm) |
|
|
ptr->is_deleted = true; |
|
|
} else { |
|
|
if (ptr->is_deleted) |
|
|
acl->perm = 0; |
|
|
acl->perm |= e.perm; |
|
|
ptr->is_deleted = false; |
|
|
} |
|
|
error = 0; |
|
|
break; |
|
|
} |
|
|
if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) { |
|
|
ccs_add_domain_acl(domain, &entry->head); |
|
|
entry = NULL; |
|
|
error = 0; |
|
|
} |
|
|
mutex_unlock(&ccs_policy_lock); |
|
405 |
out: |
out: |
406 |
if (w[2][0] == '@') |
if (w[2][0] == '@') |
407 |
ccs_put_address_group(e.address.group); |
ccs_put_group(e.address.group); |
408 |
else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) { |
else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) { |
409 |
ccs_put_ipv6_address(e.address.ipv6.min); |
ccs_put_ipv6_address(e.address.ipv6.min); |
410 |
ccs_put_ipv6_address(e.address.ipv6.max); |
ccs_put_ipv6_address(e.address.ipv6.max); |
411 |
} |
} |
412 |
ccs_put_number_union(&e.port); |
ccs_put_number_union(&e.port); |
|
kfree(entry); |
|
413 |
return error; |
return error; |
414 |
} |
} |
415 |
|
|
422 |
* |
* |
423 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
424 |
*/ |
*/ |
425 |
static inline int ccs_network_listen_acl(const bool is_ipv6, |
static int ccs_network_listen_acl(const bool is_ipv6, const u8 *address, |
426 |
const u8 *address, |
const u16 port) |
|
const u16 port) |
|
427 |
{ |
{ |
428 |
return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN, |
return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN, |
429 |
(const u32 *) address, ntohs(port)); |
(const u32 *) address, ntohs(port)); |
439 |
* |
* |
440 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
441 |
*/ |
*/ |
442 |
static inline int ccs_network_connect_acl(const bool is_ipv6, |
static int ccs_network_connect_acl(const bool is_ipv6, const int sock_type, |
443 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, |
|
|
const u16 port) |
|
444 |
{ |
{ |
445 |
u8 operation; |
u8 operation; |
446 |
switch (sock_type) { |
switch (sock_type) { |
494 |
* |
* |
495 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
496 |
*/ |
*/ |
497 |
static inline int ccs_network_accept_acl(const bool is_ipv6, |
static int ccs_network_accept_acl(const bool is_ipv6, const u8 *address, |
498 |
const u8 *address, |
const u16 port) |
|
const u16 port) |
|
499 |
{ |
{ |
500 |
int retval; |
int retval; |
501 |
current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
515 |
* |
* |
516 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
517 |
*/ |
*/ |
518 |
static inline int ccs_network_sendmsg_acl(const bool is_ipv6, |
static int ccs_network_sendmsg_acl(const bool is_ipv6, const int sock_type, |
519 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, |
|
|
const u16 port) |
|
520 |
{ |
{ |
521 |
u8 operation; |
u8 operation; |
522 |
if (sock_type == SOCK_DGRAM) |
if (sock_type == SOCK_DGRAM) |
537 |
* |
* |
538 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
539 |
*/ |
*/ |
540 |
static inline int ccs_network_recvmsg_acl(const bool is_ipv6, |
static int ccs_network_recvmsg_acl(const bool is_ipv6, const int sock_type, |
541 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, |
|
|
const u16 port) |
|
542 |
{ |
{ |
543 |
int retval; |
int retval; |
544 |
const u8 operation |
const u8 operation |
551 |
return retval; |
return retval; |
552 |
} |
} |
553 |
|
|
554 |
|
#ifndef CONFIG_NET |
555 |
|
|
556 |
|
void __init ccs_network_init(void) |
557 |
|
{ |
558 |
|
} |
559 |
|
|
560 |
|
#else |
561 |
|
|
562 |
#define MAX_SOCK_ADDR 128 /* net/socket.c */ |
#define MAX_SOCK_ADDR 128 /* net/socket.c */ |
563 |
|
|
564 |
/* Check permission for creating a socket. */ |
/* Check permission for creating a socket. */ |
565 |
int ccs_socket_create_permission(int family, int type, int protocol) |
static int __ccs_socket_create_permission(int family, int type, int protocol) |
566 |
{ |
{ |
567 |
int error = 0; |
int error = 0; |
568 |
/* Nothing to do if I am a kernel service. */ |
/* Nothing to do if I am a kernel service. */ |
592 |
} |
} |
593 |
|
|
594 |
/* Check permission for listening a TCP socket. */ |
/* Check permission for listening a TCP socket. */ |
595 |
int ccs_socket_listen_permission(struct socket *sock) |
static int __ccs_socket_listen_permission(struct socket *sock) |
596 |
{ |
{ |
597 |
int error = 0; |
int error = 0; |
598 |
char addr[MAX_SOCK_ADDR]; |
char addr[MAX_SOCK_ADDR]; |
633 |
} |
} |
634 |
|
|
635 |
/* Check permission for setting the remote IP address/port pair of a socket. */ |
/* Check permission for setting the remote IP address/port pair of a socket. */ |
636 |
int ccs_socket_connect_permission(struct socket *sock, struct sockaddr *addr, |
static int __ccs_socket_connect_permission(struct socket *sock, |
637 |
int addr_len) |
struct sockaddr *addr, int addr_len) |
638 |
{ |
{ |
639 |
int error = 0; |
int error = 0; |
640 |
const unsigned int type = sock->type; |
const unsigned int type = sock->type; |
691 |
} |
} |
692 |
|
|
693 |
/* Check permission for setting the local IP address/port pair of a socket. */ |
/* Check permission for setting the local IP address/port pair of a socket. */ |
694 |
int ccs_socket_bind_permission(struct socket *sock, struct sockaddr *addr, |
static int __ccs_socket_bind_permission(struct socket *sock, |
695 |
int addr_len) |
struct sockaddr *addr, int addr_len) |
696 |
{ |
{ |
697 |
int error = 0; |
int error = 0; |
698 |
const unsigned int type = sock->type; |
const unsigned int type = sock->type; |
744 |
* |
* |
745 |
* Currently, the LSM hook for this purpose is not provided. |
* Currently, the LSM hook for this purpose is not provided. |
746 |
*/ |
*/ |
747 |
int ccs_socket_accept_permission(struct socket *sock, struct sockaddr *addr) |
static int __ccs_socket_accept_permission(struct socket *sock, |
748 |
|
struct sockaddr *addr) |
749 |
{ |
{ |
750 |
int error = 0; |
int error = 0; |
751 |
int addr_len; |
int addr_len; |
782 |
} |
} |
783 |
|
|
784 |
/* Check permission for sending a datagram via a UDP or RAW socket. */ |
/* Check permission for sending a datagram via a UDP or RAW socket. */ |
785 |
int ccs_socket_sendmsg_permission(struct socket *sock, struct sockaddr *addr, |
static int __ccs_socket_sendmsg_permission(struct socket *sock, |
786 |
int addr_len) |
struct msghdr *msg, int size) |
787 |
{ |
{ |
788 |
|
struct sockaddr *addr = (struct sockaddr *) msg->msg_name; |
789 |
|
const int addr_len = msg->msg_namelen; |
790 |
int error = 0; |
int error = 0; |
791 |
const int type = sock->type; |
const int type = sock->type; |
792 |
/* Nothing to do if I am a kernel service. */ |
/* Nothing to do if I am a kernel service. */ |
819 |
else |
else |
820 |
port = htons(sock->sk->sk_protocol); |
port = htons(sock->sk->sk_protocol); |
821 |
error = ccs_network_sendmsg_acl(false, type, |
error = ccs_network_sendmsg_acl(false, type, |
822 |
(u8 *) &addr4->sin_addr, |
(u8 *) &addr4->sin_addr, port); |
|
port); |
|
823 |
break; |
break; |
824 |
} |
} |
825 |
return error; |
return error; |
827 |
|
|
828 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
829 |
#if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5 |
#if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5 |
830 |
|
#if !defined(AX_MAJOR) || AX_MAJOR != 3 || !defined(AX_MINOR) || AX_MINOR < 2 |
831 |
|
|
832 |
static inline struct iphdr *ip_hdr(const struct sk_buff *skb) |
static inline struct iphdr *ip_hdr(const struct sk_buff *skb) |
833 |
{ |
{ |
846 |
|
|
847 |
#endif |
#endif |
848 |
#endif |
#endif |
849 |
|
#endif |
850 |
|
|
851 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) |
852 |
static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, |
static void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, |
891 |
* |
* |
892 |
* Currently, the LSM hook for this purpose is not provided. |
* Currently, the LSM hook for this purpose is not provided. |
893 |
*/ |
*/ |
894 |
int ccs_socket_recvmsg_permission(struct sock *sk, struct sk_buff *skb, |
static int __ccs_socket_recvmsg_permission(struct sock *sk, |
895 |
const unsigned int flags) |
struct sk_buff *skb, |
896 |
|
const unsigned int flags) |
897 |
{ |
{ |
898 |
int error = 0; |
int error = 0; |
899 |
const unsigned int type = sk->sk_type; |
const unsigned int type = sk->sk_type; |
955 |
/* Hope less harmful than -EPERM. */ |
/* Hope less harmful than -EPERM. */ |
956 |
return -ENOMEM; |
return -ENOMEM; |
957 |
} |
} |
958 |
EXPORT_SYMBOL(ccs_socket_recvmsg_permission); |
|
959 |
|
void __init ccs_network_init(void) |
960 |
|
{ |
961 |
|
ccsecurity_ops.socket_create_permission = |
962 |
|
__ccs_socket_create_permission; |
963 |
|
ccsecurity_ops.socket_listen_permission = |
964 |
|
__ccs_socket_listen_permission; |
965 |
|
ccsecurity_ops.socket_connect_permission = |
966 |
|
__ccs_socket_connect_permission; |
967 |
|
ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission; |
968 |
|
ccsecurity_ops.socket_accept_permission = |
969 |
|
__ccs_socket_accept_permission; |
970 |
|
ccsecurity_ops.socket_sendmsg_permission = |
971 |
|
__ccs_socket_sendmsg_permission; |
972 |
|
ccsecurity_ops.socket_recvmsg_permission = |
973 |
|
__ccs_socket_recvmsg_permission; |
974 |
|
} |
975 |
|
|
976 |
|
#endif |