Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Aug 2013 17:45:00 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r254603 - in head/sys: kern security/mac security/mac_biba security/mac_mls security/mac_stub security/mac_test sys
Message-ID:  <201308211745.r7LHj0o5085520@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Aug 21 17:45:00 2013
New Revision: 254603
URL: http://svnweb.freebsd.org/changeset/base/254603

Log:
  Implement read(2)/write(2) and neccessary lseek(2) for posix shmfd.
  Add MAC framework entries for posix shm read and write.
  
  Do not allow implicit extension of the underlying memory segment past
  the limit set by ftruncate(2) by either of the syscalls.  Read and
  write returns short i/o, lseek(2) fails with EINVAL when resulting
  offset does not fit into the limit.
  
  Discussed with:	alc
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/kern/uipc_shm.c
  head/sys/security/mac/mac_framework.h
  head/sys/security/mac/mac_policy.h
  head/sys/security/mac/mac_posix_shm.c
  head/sys/security/mac_biba/mac_biba.c
  head/sys/security/mac_mls/mac_mls.c
  head/sys/security/mac_stub/mac_stub.c
  head/sys/security/mac_test/mac_test.c
  head/sys/sys/mman.h

Modified: head/sys/kern/uipc_shm.c
==============================================================================
--- head/sys/kern/uipc_shm.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/kern/uipc_shm.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sx.h>
 #include <sys/time.h>
 #include <sys/vnode.h>
+#include <sys/unistd.h>
 
 #include <security/mac/mac_framework.h>
 
@@ -119,6 +120,7 @@ static fo_stat_t	shm_stat;
 static fo_close_t	shm_close;
 static fo_chmod_t	shm_chmod;
 static fo_chown_t	shm_chown;
+static fo_seek_t	shm_seek;
 
 /* File descriptor operations. */
 static struct fileops shm_ops = {
@@ -133,7 +135,8 @@ static struct fileops shm_ops = {
 	.fo_chmod = shm_chmod,
 	.fo_chown = shm_chown,
 	.fo_sendfile = invfo_sendfile,
-	.fo_flags = DFLAG_PASSABLE
+	.fo_seek = shm_seek,
+	.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
 };
 
 FEATURE(posix_shm, "POSIX shared memory");
@@ -233,19 +236,96 @@ uiomove_object(vm_object_t obj, off_t ob
 }
 
 static int
+shm_seek(struct file *fp, off_t offset, int whence, struct thread *td)
+{
+	struct shmfd *shmfd;
+	off_t foffset;
+	int error;
+
+	shmfd = fp->f_data;
+	foffset = foffset_lock(fp, 0);
+	error = 0;
+	switch (whence) {
+	case L_INCR:
+		if (foffset < 0 ||
+		    (offset > 0 && foffset > OFF_MAX - offset)) {
+			error = EOVERFLOW;
+			break;
+		}
+		offset += foffset;
+		break;
+	case L_XTND:
+		if (offset > 0 && shmfd->shm_size > OFF_MAX - offset) {
+			error = EOVERFLOW;
+			break;
+		}
+		offset += shmfd->shm_size;
+		break;
+	case L_SET:
+		break;
+	default:
+		error = EINVAL;
+	}
+	if (error == 0) {
+		if (offset < 0 || offset > shmfd->shm_size)
+			error = EINVAL;
+		else
+			*(off_t *)(td->td_retval) = offset;
+	}
+	foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0);
+	return (error);
+}
+
+static int
 shm_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
     int flags, struct thread *td)
 {
+	struct shmfd *shmfd;
+	void *rl_cookie;
+	int error;
 
-	return (EOPNOTSUPP);
+	shmfd = fp->f_data;
+	foffset_lock_uio(fp, uio, flags);
+	rl_cookie = rangelock_rlock(&shmfd->shm_rl, uio->uio_offset,
+	    uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx);
+#ifdef MAC
+	error = mac_posixshm_check_read(active_cred, fp->f_cred, shmfd);
+	if (error)
+		return (error);
+#endif
+	error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio);
+	rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx);
+	foffset_unlock_uio(fp, uio, flags);
+	return (error);
 }
 
 static int
 shm_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
     int flags, struct thread *td)
 {
+	struct shmfd *shmfd;
+	void *rl_cookie;
+	int error;
 
-	return (EOPNOTSUPP);
+	shmfd = fp->f_data;
+#ifdef MAC
+	error = mac_posixshm_check_write(active_cred, fp->f_cred, shmfd);
+	if (error)
+		return (error);
+#endif
+	foffset_lock_uio(fp, uio, flags);
+	if ((flags & FOF_OFFSET) == 0) {
+		rl_cookie = rangelock_wlock(&shmfd->shm_rl, 0, OFF_MAX,
+		    &shmfd->shm_mtx);
+	} else {
+		rl_cookie = rangelock_wlock(&shmfd->shm_rl, uio->uio_offset,
+		    uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx);
+	}
+
+	error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio);
+	rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx);
+	foffset_unlock_uio(fp, uio, flags);
+	return (error);
 }
 
 static int
@@ -471,6 +551,8 @@ shm_alloc(struct ucred *ucred, mode_t mo
 	shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime =
 	    shmfd->shm_birthtime;
 	refcount_init(&shmfd->shm_refs, 1);
+	mtx_init(&shmfd->shm_mtx, "shmrl", NULL, MTX_DEF);
+	rangelock_init(&shmfd->shm_rl);
 #ifdef MAC
 	mac_posixshm_init(shmfd);
 	mac_posixshm_create(ucred, shmfd);
@@ -495,6 +577,8 @@ shm_drop(struct shmfd *shmfd)
 #ifdef MAC
 		mac_posixshm_destroy(shmfd);
 #endif
+		rangelock_destroy(&shmfd->shm_rl);
+		mtx_destroy(&shmfd->shm_mtx);
 		vm_object_deallocate(shmfd->shm_object);
 		free(shmfd, M_SHMFD);
 	}

Modified: head/sys/security/mac/mac_framework.h
==============================================================================
--- head/sys/security/mac/mac_framework.h	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac/mac_framework.h	Wed Aug 21 17:45:00 2013	(r254603)
@@ -243,6 +243,8 @@ int	mac_posixshm_check_mmap(struct ucred
 	    int prot, int flags);
 int	mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
 	    accmode_t accmode);
+int	mac_posixshm_check_read(struct ucred *active_cred,
+	    struct ucred *file_cred, struct shmfd *shmfd);
 int	mac_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
 	    mode_t mode);
 int	mac_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd,
@@ -252,6 +254,8 @@ int	mac_posixshm_check_stat(struct ucred
 int	mac_posixshm_check_truncate(struct ucred *active_cred,
 	    struct ucred *file_cred, struct shmfd *shmfd);
 int	mac_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd);
+int	mac_posixshm_check_write(struct ucred *active_cred,
+	    struct ucred *file_cred, struct shmfd *shmfd);
 void 	mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd);
 void	mac_posixshm_destroy(struct shmfd *);
 void	mac_posixshm_init(struct shmfd *);

Modified: head/sys/security/mac/mac_policy.h
==============================================================================
--- head/sys/security/mac/mac_policy.h	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac/mac_policy.h	Wed Aug 21 17:45:00 2013	(r254603)
@@ -363,6 +363,9 @@ typedef int	(*mpo_posixshm_check_mmap_t)
 typedef int	(*mpo_posixshm_check_open_t)(struct ucred *cred,
 		    struct shmfd *shmfd, struct label *shmlabel,
 		    accmode_t accmode);
+typedef int	(*mpo_posixshm_check_read_t)(struct ucred *active_cred,
+		    struct ucred *file_cred, struct shmfd *shmfd,
+		    struct label *shmlabel);
 typedef int	(*mpo_posixshm_check_setmode_t)(struct ucred *cred,
 		    struct shmfd *shmfd, struct label *shmlabel,
 		    mode_t mode);
@@ -377,6 +380,9 @@ typedef int	(*mpo_posixshm_check_truncat
 		    struct label *shmlabel);
 typedef int	(*mpo_posixshm_check_unlink_t)(struct ucred *cred,
 		    struct shmfd *shmfd, struct label *shmlabel);
+typedef int	(*mpo_posixshm_check_write_t)(struct ucred *active_cred,
+		    struct ucred *file_cred, struct shmfd *shmfd,
+		    struct label *shmlabel);
 typedef void	(*mpo_posixshm_create_t)(struct ucred *cred,
 		    struct shmfd *shmfd, struct label *shmlabel);
 typedef void	(*mpo_posixshm_destroy_label_t)(struct label *label);
@@ -818,11 +824,13 @@ struct mac_policy_ops {
 	mpo_posixshm_check_create_t		mpo_posixshm_check_create;
 	mpo_posixshm_check_mmap_t		mpo_posixshm_check_mmap;
 	mpo_posixshm_check_open_t		mpo_posixshm_check_open;
+	mpo_posixshm_check_read_t		mpo_posixshm_check_read;
 	mpo_posixshm_check_setmode_t		mpo_posixshm_check_setmode;
 	mpo_posixshm_check_setowner_t		mpo_posixshm_check_setowner;
 	mpo_posixshm_check_stat_t		mpo_posixshm_check_stat;
 	mpo_posixshm_check_truncate_t		mpo_posixshm_check_truncate;
 	mpo_posixshm_check_unlink_t		mpo_posixshm_check_unlink;
+	mpo_posixshm_check_write_t		mpo_posixshm_check_write;
 	mpo_posixshm_create_t			mpo_posixshm_create;
 	mpo_posixshm_destroy_label_t		mpo_posixshm_destroy_label;
 	mpo_posixshm_init_label_t		mpo_posixshm_init_label;

Modified: head/sys/security/mac/mac_posix_shm.c
==============================================================================
--- head/sys/security/mac/mac_posix_shm.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac/mac_posix_shm.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -228,3 +228,37 @@ mac_posixshm_check_setowner(struct ucred
 
 	return (error);
 }
+
+MAC_CHECK_PROBE_DEFINE3(posixshm_check_read, "struct ucred *",
+    "struct ucred *", "struct shmfd *");
+
+int
+mac_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shmfd)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(posixshm_check_read, active_cred,
+	    file_cred, shmfd, shmfd->shm_label);
+	MAC_CHECK_PROBE3(posixshm_check_read, error, active_cred,
+	    file_cred, shmfd);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE3(posixshm_check_write, "struct ucred *",
+    "struct ucred *", "struct shmfd *");
+
+int
+mac_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shmfd)
+{
+	int error;
+
+	MAC_POLICY_CHECK_NOSLEEP(posixshm_check_write, active_cred,
+	    file_cred, shmfd, shmfd->shm_label);
+	MAC_CHECK_PROBE3(posixshm_check_write, error, active_cred,
+	    file_cred, shmfd);
+
+	return (error);
+}

Modified: head/sys/security/mac_biba/mac_biba.c
==============================================================================
--- head/sys/security/mac_biba/mac_biba.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac_biba/mac_biba.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -1759,6 +1759,24 @@ biba_posixshm_check_open(struct ucred *c
 }
 
 static int
+biba_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *vp, struct label *shmlabel)
+{
+	struct mac_biba *subj, *obj;
+
+	if (!biba_enabled || !revocation_enabled)
+		return (0);
+
+	subj = SLOT(active_cred->cr_label);
+	obj = SLOT(shmlabel);
+
+	if (!biba_dominate_effective(obj, subj))
+		return (EACCES);
+
+	return (0);
+}
+
+static int
 biba_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel, mode_t mode)
 {
@@ -1848,6 +1866,24 @@ biba_posixshm_check_unlink(struct ucred 
 	return (0);
 }
 
+static int
+biba_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *vp, struct label *shmlabel)
+{
+	struct mac_biba *subj, *obj;
+
+	if (!biba_enabled || !revocation_enabled)
+		return (0);
+
+	subj = SLOT(active_cred->cr_label);
+	obj = SLOT(shmlabel);
+
+	if (!biba_dominate_effective(obj, subj))
+		return (EACCES);
+
+	return (0);
+}
+
 static void
 biba_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel)
@@ -3657,11 +3693,13 @@ static struct mac_policy_ops mac_biba_op
 
 	.mpo_posixshm_check_mmap = biba_posixshm_check_mmap,
 	.mpo_posixshm_check_open = biba_posixshm_check_open,
+	.mpo_posixshm_check_read = biba_posixshm_check_read,
 	.mpo_posixshm_check_setmode = biba_posixshm_check_setmode,
 	.mpo_posixshm_check_setowner = biba_posixshm_check_setowner,
 	.mpo_posixshm_check_stat = biba_posixshm_check_stat,
 	.mpo_posixshm_check_truncate = biba_posixshm_check_truncate,
 	.mpo_posixshm_check_unlink = biba_posixshm_check_unlink,
+	.mpo_posixshm_check_write = biba_posixshm_check_write,
 	.mpo_posixshm_create = biba_posixshm_create,
 	.mpo_posixshm_destroy_label = biba_destroy_label,
 	.mpo_posixshm_init_label = biba_init_label,

Modified: head/sys/security/mac_mls/mac_mls.c
==============================================================================
--- head/sys/security/mac_mls/mac_mls.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac_mls/mac_mls.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -1651,6 +1651,24 @@ mls_posixshm_check_open(struct ucred *cr
 }
 
 static int
+mls_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shm, struct label *shmlabel)
+{
+	struct mac_mls *subj, *obj;
+
+	if (!mls_enabled || !revocation_enabled)
+		return (0);
+
+	subj = SLOT(active_cred->cr_label);
+	obj = SLOT(shmlabel);
+
+	if (!mls_dominate_effective(subj, obj))
+		return (EACCES);
+
+	return (0);
+}
+
+static int
 mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel, mode_t mode)
 {
@@ -1740,6 +1758,24 @@ mls_posixshm_check_unlink(struct ucred *
 	return (0);
 }
 
+static int
+mls_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shm, struct label *shmlabel)
+{
+	struct mac_mls *subj, *obj;
+
+	if (!mls_enabled || !revocation_enabled)
+		return (0);
+
+	subj = SLOT(active_cred->cr_label);
+	obj = SLOT(shmlabel);
+
+	if (!mls_dominate_effective(subj, obj))
+		return (EACCES);
+
+	return (0);
+}
+
 static void
 mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel)
@@ -3280,11 +3316,13 @@ static struct mac_policy_ops mls_ops =
 
 	.mpo_posixshm_check_mmap = mls_posixshm_check_mmap,
 	.mpo_posixshm_check_open = mls_posixshm_check_open,
+	.mpo_posixshm_check_read = mls_posixshm_check_read,
 	.mpo_posixshm_check_setmode = mls_posixshm_check_setmode,
 	.mpo_posixshm_check_setowner = mls_posixshm_check_setowner,
 	.mpo_posixshm_check_stat = mls_posixshm_check_stat,
 	.mpo_posixshm_check_truncate = mls_posixshm_check_truncate,
 	.mpo_posixshm_check_unlink = mls_posixshm_check_unlink,
+	.mpo_posixshm_check_write = mls_posixshm_check_write,
 	.mpo_posixshm_create = mls_posixshm_create,
 	.mpo_posixshm_destroy_label = mls_destroy_label,
 	.mpo_posixshm_init_label = mls_init_label,

Modified: head/sys/security/mac_stub/mac_stub.c
==============================================================================
--- head/sys/security/mac_stub/mac_stub.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac_stub/mac_stub.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -757,6 +757,14 @@ stub_posixshm_check_open(struct ucred *c
 }
 
 static int
+stub_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shm, struct label *shmlabel)
+{
+
+	return (0);
+}
+
+static int
 stub_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel, mode_t mode)
 {
@@ -796,6 +804,14 @@ stub_posixshm_check_unlink(struct ucred 
 	return (0);
 }
 
+static int
+stub_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
+    struct shmfd *shm, struct label *shmlabel)
+{
+
+	return (0);
+}
+
 static void
 stub_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
     struct label *shmlabel)
@@ -1782,11 +1798,13 @@ static struct mac_policy_ops stub_ops =
 	.mpo_posixshm_check_create = stub_posixshm_check_create,
 	.mpo_posixshm_check_mmap = stub_posixshm_check_mmap,
 	.mpo_posixshm_check_open = stub_posixshm_check_open,
+	.mpo_posixshm_check_read = stub_posixshm_check_read,
 	.mpo_posixshm_check_setmode = stub_posixshm_check_setmode,
 	.mpo_posixshm_check_setowner = stub_posixshm_check_setowner,
 	.mpo_posixshm_check_stat = stub_posixshm_check_stat,
 	.mpo_posixshm_check_truncate = stub_posixshm_check_truncate,
 	.mpo_posixshm_check_unlink = stub_posixshm_check_unlink,
+	.mpo_posixshm_check_write = stub_posixshm_check_write,
 	.mpo_posixshm_create = stub_posixshm_create,
 	.mpo_posixshm_destroy_label = stub_destroy_label,
 	.mpo_posixshm_init_label = stub_init_label,

Modified: head/sys/security/mac_test/mac_test.c
==============================================================================
--- head/sys/security/mac_test/mac_test.c	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/security/mac_test/mac_test.c	Wed Aug 21 17:45:00 2013	(r254603)
@@ -1423,6 +1423,21 @@ test_posixshm_check_open(struct ucred *c
 	return (0);
 }
 
+COUNTER_DECL(posixshm_check_read);
+static int
+test_posixshm_check_read(struct ucred *active_cred,
+    struct ucred *file_cred, struct shmfd *shm, struct label *shmlabel)
+{
+
+	LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+	if (file_cred != NULL)
+		LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+	LABEL_CHECK(shmlabel, MAGIC_POSIX_SHM);
+	COUNTER_INC(posixshm_check_read);
+
+	return (0);
+}
+
 COUNTER_DECL(posixshm_check_setmode);
 static int
 test_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
@@ -1485,6 +1500,21 @@ test_posixshm_check_unlink(struct ucred 
 	return (0);
 }
 
+COUNTER_DECL(posixshm_check_write);
+static int
+test_posixshm_check_write(struct ucred *active_cred,
+    struct ucred *file_cred, struct shmfd *shm, struct label *shmlabel)
+{
+
+	LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+	if (file_cred != NULL)
+		LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+	LABEL_CHECK(shmlabel, MAGIC_POSIX_SHM);
+	COUNTER_INC(posixshm_check_write);
+
+	return (0);
+}
+
 COUNTER_DECL(posixshm_create);
 static void
 test_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
@@ -3114,11 +3144,13 @@ static struct mac_policy_ops test_ops =
 	.mpo_posixshm_check_create = test_posixshm_check_create,
 	.mpo_posixshm_check_mmap = test_posixshm_check_mmap,
 	.mpo_posixshm_check_open = test_posixshm_check_open,
+	.mpo_posixshm_check_read = test_posixshm_check_read,
 	.mpo_posixshm_check_setmode = test_posixshm_check_setmode,
 	.mpo_posixshm_check_setowner = test_posixshm_check_setowner,
 	.mpo_posixshm_check_stat = test_posixshm_check_stat,
 	.mpo_posixshm_check_truncate = test_posixshm_check_truncate,
 	.mpo_posixshm_check_unlink = test_posixshm_check_unlink,
+	.mpo_posixshm_check_write = test_posixshm_check_write,
 	.mpo_posixshm_create = test_posixshm_create,
 	.mpo_posixshm_destroy_label = test_posixshm_destroy_label,
 	.mpo_posixshm_init_label = test_posixshm_init_label,

Modified: head/sys/sys/mman.h
==============================================================================
--- head/sys/sys/mman.h	Wed Aug 21 17:36:01 2013	(r254602)
+++ head/sys/sys/mman.h	Wed Aug 21 17:45:00 2013	(r254603)
@@ -190,6 +190,10 @@ typedef	__size_t	size_t;
 #endif
 
 #if defined(_KERNEL) || defined(_WANT_FILE)
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/rangelock.h>
 #include <vm/vm.h>
 
 struct file;
@@ -214,6 +218,9 @@ struct shmfd {
 
 	struct label	*shm_label;		/* MAC label */
 	const char	*shm_path;
+
+	struct rangelock shm_rl;
+	struct mtx	shm_mtx;
 };
 #endif
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308211745.r7LHj0o5085520>